summaryrefslogtreecommitdiff
path: root/gpxe/src
diff options
context:
space:
mode:
Diffstat (limited to 'gpxe/src')
-rw-r--r--gpxe/src/Makefile193
-rw-r--r--gpxe/src/Makefile.housekeeping489
-rw-r--r--gpxe/src/arch/i386/Config148
-rw-r--r--gpxe/src/arch/i386/Makefile140
-rw-r--r--gpxe/src/arch/i386/Makefile.efi10
-rw-r--r--gpxe/src/arch/i386/Makefile.pcbios55
-rw-r--r--gpxe/src/arch/i386/core/dumpregs.c6
-rw-r--r--gpxe/src/arch/i386/core/gdbidt.S8
-rw-r--r--gpxe/src/arch/i386/core/gdbmach.c4
-rw-r--r--gpxe/src/arch/i386/core/nap.c12
-rw-r--r--gpxe/src/arch/i386/core/pic8259.c1
-rw-r--r--gpxe/src/arch/i386/core/rdtsc_timer.c87
-rw-r--r--gpxe/src/arch/i386/core/relocate.c12
-rw-r--r--gpxe/src/arch/i386/core/stack.S2
-rw-r--r--gpxe/src/arch/i386/core/stack16.S2
-rw-r--r--gpxe/src/arch/i386/core/start32.S325
-rw-r--r--gpxe/src/arch/i386/core/timer2.c (renamed from gpxe/src/arch/i386/core/i386_timer.c)24
-rw-r--r--gpxe/src/arch/i386/core/video_subr.c2
-rw-r--r--gpxe/src/arch/i386/core/virtaddr.S2
-rw-r--r--gpxe/src/arch/i386/core/x86_io.c94
-rw-r--r--gpxe/src/arch/i386/drivers/net/undiisr.S6
-rw-r--r--gpxe/src/arch/i386/drivers/net/undinet.c71
-rw-r--r--gpxe/src/arch/i386/drivers/net/undionly.c18
-rw-r--r--gpxe/src/arch/i386/drivers/net/undirom.c4
-rw-r--r--gpxe/src/arch/i386/drivers/timer_bios.c57
-rw-r--r--gpxe/src/arch/i386/drivers/timer_rdtsc.c69
-rw-r--r--gpxe/src/arch/i386/firmware/pcbios/bios_console.c4
-rw-r--r--gpxe/src/arch/i386/firmware/pcbios/e820mangler.S51
-rw-r--r--gpxe/src/arch/i386/firmware/pcbios/gateA20.c13
-rw-r--r--gpxe/src/arch/i386/firmware/pcbios/hidemem.c32
-rw-r--r--gpxe/src/arch/i386/firmware/pcbios/memmap.c29
-rw-r--r--gpxe/src/arch/i386/image/bzimage.c2
-rw-r--r--gpxe/src/arch/i386/image/com32.c44
-rw-r--r--gpxe/src/arch/i386/image/comboot.c44
-rw-r--r--gpxe/src/arch/i386/image/multiboot.c12
-rw-r--r--gpxe/src/arch/i386/image/nbi.c18
-rw-r--r--gpxe/src/arch/i386/image/pxe_image.c14
-rw-r--r--gpxe/src/arch/i386/include/bios.h3
-rw-r--r--gpxe/src/arch/i386/include/biosint.h15
-rw-r--r--gpxe/src/arch/i386/include/bits/byteswap.h45
-rw-r--r--gpxe/src/arch/i386/include/bits/compiler.h25
-rw-r--r--gpxe/src/arch/i386/include/bits/elf.h91
-rw-r--r--gpxe/src/arch/i386/include/bits/elf_x.h5
-rw-r--r--gpxe/src/arch/i386/include/bits/errfile.h6
-rw-r--r--gpxe/src/arch/i386/include/bits/io.h12
-rw-r--r--gpxe/src/arch/i386/include/bits/nap.h13
-rw-r--r--gpxe/src/arch/i386/include/bits/smbios.h12
-rw-r--r--gpxe/src/arch/i386/include/bits/stdint.h8
-rw-r--r--gpxe/src/arch/i386/include/bits/timer.h13
-rw-r--r--gpxe/src/arch/i386/include/bits/timer2.h8
-rw-r--r--gpxe/src/arch/i386/include/bits/uaccess.h8
-rw-r--r--gpxe/src/arch/i386/include/bits/umalloc.h12
-rw-r--r--gpxe/src/arch/i386/include/comboot.h51
-rw-r--r--gpxe/src/arch/i386/include/gdbmach.h2
-rw-r--r--gpxe/src/arch/i386/include/gpxe/abft.h (renamed from gpxe/src/include/gpxe/abft.h)0
-rw-r--r--gpxe/src/arch/i386/include/gpxe/bios_nap.h16
-rw-r--r--gpxe/src/arch/i386/include/gpxe/bios_smbios.h16
-rw-r--r--gpxe/src/arch/i386/include/gpxe/bios_timer.h42
-rw-r--r--gpxe/src/arch/i386/include/gpxe/ibft.h (renamed from gpxe/src/include/gpxe/ibft.h)0
-rw-r--r--gpxe/src/arch/i386/include/gpxe/memtop_umalloc.h16
-rw-r--r--gpxe/src/arch/i386/include/gpxe/rdtsc_timer.h37
-rw-r--r--gpxe/src/arch/i386/include/gpxe/timer2.h12
-rw-r--r--gpxe/src/arch/i386/include/gpxe/x86_io.h151
-rw-r--r--gpxe/src/arch/i386/include/int13.h1
-rw-r--r--gpxe/src/arch/i386/include/io.h265
-rwxr-xr-x[-rw-r--r--]gpxe/src/arch/i386/include/librm.h303
-rw-r--r--gpxe/src/arch/i386/include/pci_io.h35
-rw-r--r--gpxe/src/arch/i386/include/pxe.h (renamed from gpxe/src/include/pxe.h)0
-rw-r--r--gpxe/src/arch/i386/include/pxe_addr.h17
-rw-r--r--gpxe/src/arch/i386/include/pxe_api.h (renamed from gpxe/src/include/pxe_api.h)0
-rw-r--r--gpxe/src/arch/i386/include/pxe_call.h2
-rw-r--r--gpxe/src/arch/i386/include/pxe_types.h (renamed from gpxe/src/include/pxe_types.h)5
-rw-r--r--gpxe/src/arch/i386/include/realmode.h93
-rw-r--r--gpxe/src/arch/i386/include/registers.h13
-rw-r--r--gpxe/src/arch/i386/include/setjmp.h36
-rw-r--r--gpxe/src/arch/i386/include/smbios.h60
-rw-r--r--gpxe/src/arch/i386/include/undi.h10
-rw-r--r--gpxe/src/arch/i386/include/virtaddr.h105
-rw-r--r--gpxe/src/arch/i386/interface/pcbios/abft.c (renamed from gpxe/src/core/abft.c)0
-rw-r--r--gpxe/src/arch/i386/interface/pcbios/aoeboot.c (renamed from gpxe/src/usr/aoeboot.c)27
-rw-r--r--gpxe/src/arch/i386/interface/pcbios/bios_nap.c14
-rw-r--r--gpxe/src/arch/i386/interface/pcbios/bios_smbios.c84
-rw-r--r--gpxe/src/arch/i386/interface/pcbios/bios_timer.c63
-rw-r--r--gpxe/src/arch/i386/interface/pcbios/biosint.c11
-rw-r--r--gpxe/src/arch/i386/interface/pcbios/ibft.c (renamed from gpxe/src/core/ibft.c)0
-rw-r--r--gpxe/src/arch/i386/interface/pcbios/int13.c14
-rw-r--r--gpxe/src/arch/i386/interface/pcbios/iscsiboot.c (renamed from gpxe/src/usr/iscsiboot.c)27
-rw-r--r--gpxe/src/arch/i386/interface/pcbios/memtop_umalloc.c (renamed from gpxe/src/arch/i386/core/umalloc.c)34
-rw-r--r--gpxe/src/arch/i386/interface/pcbios/pcibios.c (renamed from gpxe/src/arch/i386/core/pcibios.c)11
-rw-r--r--gpxe/src/arch/i386/interface/pxe/pxe_call.c4
-rw-r--r--gpxe/src/arch/i386/interface/pxe/pxe_entry.S33
-rw-r--r--gpxe/src/arch/i386/interface/pxe/pxe_errors.c (renamed from gpxe/src/interface/pxe/pxe_errors.c)0
-rw-r--r--gpxe/src/arch/i386/interface/pxe/pxe_file.c (renamed from gpxe/src/interface/pxe/pxe_file.c)0
-rw-r--r--gpxe/src/arch/i386/interface/pxe/pxe_loader.c (renamed from gpxe/src/interface/pxe/pxe_loader.c)0
-rw-r--r--gpxe/src/arch/i386/interface/pxe/pxe_preboot.c (renamed from gpxe/src/interface/pxe/pxe_preboot.c)2
-rw-r--r--gpxe/src/arch/i386/interface/pxe/pxe_tftp.c (renamed from gpxe/src/interface/pxe/pxe_tftp.c)13
-rw-r--r--gpxe/src/arch/i386/interface/pxe/pxe_udp.c (renamed from gpxe/src/interface/pxe/pxe_udp.c)0
-rw-r--r--gpxe/src/arch/i386/interface/pxe/pxe_undi.c (renamed from gpxe/src/interface/pxe/pxe_undi.c)30
-rw-r--r--gpxe/src/arch/i386/interface/syslinux/com32_call.c6
-rw-r--r--gpxe/src/arch/i386/interface/syslinux/comboot_call.c229
-rw-r--r--gpxe/src/arch/i386/prefix/boot1a.S410
-rw-r--r--gpxe/src/arch/i386/prefix/dskprefix.S10
-rw-r--r--gpxe/src/arch/i386/prefix/hdprefix.S10
-rw-r--r--gpxe/src/arch/i386/prefix/kkpxeprefix.S8
-rw-r--r--gpxe/src/arch/i386/prefix/libprefix.S200
-rw-r--r--gpxe/src/arch/i386/prefix/lkrnprefix.S10
-rw-r--r--gpxe/src/arch/i386/prefix/nbiprefix.S17
-rw-r--r--gpxe/src/arch/i386/prefix/pxeprefix.S171
-rw-r--r--gpxe/src/arch/i386/prefix/romprefix.S186
-rw-r--r--gpxe/src/arch/i386/scripts/i386.lds279
-rwxr-xr-x[-rw-r--r--]gpxe/src/arch/i386/transitions/librm.S53
-rwxr-xr-x[-rw-r--r--]gpxe/src/arch/i386/transitions/librm_mgmt.c101
-rw-r--r--gpxe/src/arch/x86/Makefile9
-rw-r--r--gpxe/src/arch/x86/Makefile.efi28
-rw-r--r--gpxe/src/arch/x86/core/pcidirect.c (renamed from gpxe/src/arch/i386/core/pcidirect.c)9
-rw-r--r--gpxe/src/arch/x86/core/x86_string.c (renamed from gpxe/src/arch/i386/core/i386_string.c)4
-rw-r--r--gpxe/src/arch/x86/include/bits/pci_io.h13
-rw-r--r--gpxe/src/arch/x86/include/bits/string.h (renamed from gpxe/src/arch/i386/include/bits/string.h)4
-rw-r--r--gpxe/src/arch/x86/include/gpxe/efi/efix86_nap.h16
-rw-r--r--gpxe/src/arch/x86/include/gpxe/pcibios.h (renamed from gpxe/src/arch/i386/include/pcibios.h)55
-rw-r--r--gpxe/src/arch/x86/include/gpxe/pcidirect.h (renamed from gpxe/src/arch/i386/include/pcidirect.h)53
-rw-r--r--gpxe/src/arch/x86/interface/efi/efix86_nap.c46
-rw-r--r--gpxe/src/arch/x86/prefix/efidrvprefix.c44
-rw-r--r--gpxe/src/arch/x86/prefix/efiprefix.c39
-rw-r--r--gpxe/src/arch/x86/scripts/efi.lds105
-rw-r--r--gpxe/src/arch/x86_64/Makefile41
-rw-r--r--gpxe/src/arch/x86_64/Makefile.efi14
-rw-r--r--gpxe/src/arch/x86_64/include/bits/byteswap.h22
-rw-r--r--gpxe/src/arch/x86_64/include/bits/compiler.h14
-rw-r--r--gpxe/src/arch/x86_64/include/bits/endian.h6
-rw-r--r--gpxe/src/arch/x86_64/include/bits/errfile.h11
-rw-r--r--gpxe/src/arch/x86_64/include/bits/io.h10
-rw-r--r--gpxe/src/arch/x86_64/include/bits/nap.h12
-rw-r--r--gpxe/src/arch/x86_64/include/bits/smbios.h10
-rw-r--r--gpxe/src/arch/x86_64/include/bits/stdint.h21
-rw-r--r--gpxe/src/arch/x86_64/include/bits/timer.h10
-rw-r--r--gpxe/src/arch/x86_64/include/bits/uaccess.h10
-rw-r--r--gpxe/src/arch/x86_64/include/bits/umalloc.h10
-rw-r--r--gpxe/src/arch/x86_64/include/gdbmach.h51
-rw-r--r--gpxe/src/arch/x86_64/include/limits.h59
-rw-r--r--gpxe/src/config.h175
-rw-r--r--gpxe/src/config/.gitignore1
-rw-r--r--gpxe/src/config/console.h21
-rw-r--r--gpxe/src/config/defaults.h8
-rw-r--r--gpxe/src/config/defaults/efi.h21
-rw-r--r--gpxe/src/config/defaults/pcbios.h29
-rw-r--r--gpxe/src/config/general.h123
-rw-r--r--gpxe/src/config/ioapi.h15
-rw-r--r--gpxe/src/config/isa.h15
-rw-r--r--gpxe/src/config/nap.h15
-rw-r--r--gpxe/src/config/serial.h28
-rw-r--r--gpxe/src/config/timer.h15
-rw-r--r--gpxe/src/config/umalloc.h12
-rw-r--r--gpxe/src/core/base64.c66
-rw-r--r--gpxe/src/core/config.c44
-rw-r--r--gpxe/src/core/console.c6
-rw-r--r--gpxe/src/core/cwuri.c5
-rw-r--r--gpxe/src/core/debug.c6
-rw-r--r--gpxe/src/core/gdbudp.c2
-rw-r--r--gpxe/src/core/getkey.c14
-rw-r--r--gpxe/src/core/image.c29
-rw-r--r--gpxe/src/core/main.c36
-rw-r--r--gpxe/src/core/malloc.c2
-rw-r--r--gpxe/src/core/monojob.c7
-rw-r--r--gpxe/src/core/null_nap.c3
-rw-r--r--gpxe/src/core/nvo.c2
-rw-r--r--gpxe/src/core/pc_kbd.c2
-rw-r--r--gpxe/src/core/process.c2
-rw-r--r--gpxe/src/core/serial.c2
-rw-r--r--gpxe/src/core/settings.c68
-rw-r--r--gpxe/src/core/timer.c91
-rw-r--r--gpxe/src/core/uri.c8
-rw-r--r--gpxe/src/core/uuid.c2
-rw-r--r--gpxe/src/core/xfer.c11
-rw-r--r--gpxe/src/crypto/asn1.c31
-rw-r--r--gpxe/src/crypto/axtls/axtls_asn1.c867
-rw-r--r--gpxe/src/crypto/cryptoLayer.h120
-rw-r--r--gpxe/src/crypto/framework.c86
-rw-r--r--gpxe/src/crypto/matrixssl/mpi.h487
-rw-r--r--gpxe/src/crypto/matrixssl/pscrypto.h661
-rw-r--r--gpxe/src/crypto/ssl.c136
-rw-r--r--gpxe/src/crypto/ssl.h19
-rw-r--r--gpxe/src/crypto/ssl_constructs.h342
-rw-r--r--gpxe/src/crypto/x509.c181
-rw-r--r--gpxe/src/dl360.gpxe4
-rw-r--r--gpxe/src/drivers/bitbash/i2c_bit.c147
-rw-r--r--gpxe/src/drivers/block/ata.c8
-rw-r--r--gpxe/src/drivers/block/ramdisk.c8
-rw-r--r--gpxe/src/drivers/block/scsi.c40
-rw-r--r--gpxe/src/drivers/bus/eisa.c2
-rw-r--r--gpxe/src/drivers/bus/isa.c6
-rw-r--r--gpxe/src/drivers/bus/isapnp.c4
-rw-r--r--gpxe/src/drivers/bus/mca.c2
-rw-r--r--gpxe/src/drivers/bus/pci.c5
-rw-r--r--gpxe/src/drivers/bus/virtio-pci.c64
-rw-r--r--gpxe/src/drivers/bus/virtio-ring.c134
-rw-r--r--gpxe/src/drivers/infiniband/arbel.c171
-rw-r--r--gpxe/src/drivers/infiniband/hermon.c172
-rw-r--r--gpxe/src/drivers/infiniband/ib_packet.c234
-rw-r--r--gpxe/src/drivers/infiniband/ib_sma.c553
-rw-r--r--gpxe/src/drivers/infiniband/ib_smc.c166
-rw-r--r--gpxe/src/drivers/infiniband/linda.c2397
-rw-r--r--gpxe/src/drivers/infiniband/linda.h271
-rw-r--r--gpxe/src/drivers/infiniband/linda_fw.c1067
-rw-r--r--gpxe/src/drivers/infiniband/qib_7220_regs.h1763
-rw-r--r--gpxe/src/drivers/infiniband/qib_genbits.pl95
-rw-r--r--gpxe/src/drivers/net/3c509.c2
-rw-r--r--gpxe/src/drivers/net/3c515.c2
-rw-r--r--gpxe/src/drivers/net/3c595.c2
-rw-r--r--gpxe/src/drivers/net/3c90x.c4
-rw-r--r--gpxe/src/drivers/net/b44.c949
-rw-r--r--gpxe/src/drivers/net/b44.h467
-rw-r--r--gpxe/src/drivers/net/cs89x0.c4
-rw-r--r--gpxe/src/drivers/net/davicom.c4
-rw-r--r--gpxe/src/drivers/net/dmfe.c20
-rw-r--r--gpxe/src/drivers/net/e1000/e1000.c34
-rw-r--r--gpxe/src/drivers/net/e1000/e1000.h3
-rw-r--r--gpxe/src/drivers/net/e1000/e1000_hw.c14
-rw-r--r--gpxe/src/drivers/net/e1000/e1000_osdep.h50
-rw-r--r--gpxe/src/drivers/net/eepro100.c8
-rw-r--r--gpxe/src/drivers/net/epic100.c4
-rw-r--r--gpxe/src/drivers/net/etherfabric.c5486
-rw-r--r--gpxe/src/drivers/net/etherfabric_nic.h201
-rw-r--r--gpxe/src/drivers/net/forcedeth.c2
-rw-r--r--gpxe/src/drivers/net/ipoib.c579
-rw-r--r--[-rwxr-xr-x]gpxe/src/drivers/net/mtnic.c1038
-rw-r--r--[-rwxr-xr-x]gpxe/src/drivers/net/mtnic.h283
-rw-r--r--gpxe/src/drivers/net/natsemi.c11
-rw-r--r--gpxe/src/drivers/net/ne2k_isa.c373
-rw-r--r--gpxe/src/drivers/net/phantom/phantom.c1517
-rw-r--r--gpxe/src/drivers/net/phantom/phantom.h155
-rw-r--r--gpxe/src/drivers/net/pnic.c2
-rw-r--r--gpxe/src/drivers/net/prism2.c2
-rw-r--r--gpxe/src/drivers/net/prism2_pci.c9
-rw-r--r--gpxe/src/drivers/net/prism2_plx.c5
-rw-r--r--gpxe/src/drivers/net/r8169.c3099
-rw-r--r--gpxe/src/drivers/net/r8169.h566
-rw-r--r--gpxe/src/drivers/net/rtl8139.c3
-rw-r--r--gpxe/src/drivers/net/sis900.c8
-rw-r--r--gpxe/src/drivers/net/sundance.c5
-rw-r--r--gpxe/src/drivers/net/tg3.c5
-rw-r--r--gpxe/src/drivers/net/tulip.c4
-rw-r--r--gpxe/src/drivers/net/via-rhine.c48
-rw-r--r--gpxe/src/drivers/net/via-velocity.c4
-rw-r--r--gpxe/src/drivers/net/virtio-net.c289
-rw-r--r--gpxe/src/drivers/net/w89c840.c4
-rw-r--r--gpxe/src/hci/commands/config_cmd.c2
-rw-r--r--gpxe/src/hci/commands/dhcp_cmd.c90
-rw-r--r--gpxe/src/hci/commands/login_cmd.c27
-rw-r--r--gpxe/src/hci/mucurses/ansi_screen.c2
-rw-r--r--gpxe/src/hci/mucurses/widgets/editbox.c11
-rw-r--r--gpxe/src/hci/mucurses/wininit.c4
-rw-r--r--gpxe/src/hci/tui/login_ui.c135
-rw-r--r--gpxe/src/hci/tui/settings_ui.c2
-rw-r--r--gpxe/src/image/default.gpxe2
-rw-r--r--gpxe/src/image/efi_image.c106
-rw-r--r--gpxe/src/image/elf.c2
-rw-r--r--gpxe/src/image/embed.S7
-rw-r--r--gpxe/src/image/embedded.c109
-rw-r--r--gpxe/src/image/script.c11
-rw-r--r--gpxe/src/include/byteswap.h35
-rw-r--r--gpxe/src/include/compiler.h38
-rw-r--r--gpxe/src/include/elf.h4
-rw-r--r--gpxe/src/include/gpxe/aoe.h33
-rw-r--r--gpxe/src/include/gpxe/api.h82
-rw-r--r--gpxe/src/include/gpxe/asn1.h6
-rw-r--r--gpxe/src/include/gpxe/base64.h24
-rw-r--r--gpxe/src/include/gpxe/bitops.h227
-rw-r--r--gpxe/src/include/gpxe/blockdev.h20
-rw-r--r--gpxe/src/include/gpxe/dhcp.h147
-rw-r--r--gpxe/src/include/gpxe/dhcppkt.h31
-rw-r--r--gpxe/src/include/gpxe/editbox.h12
-rw-r--r--gpxe/src/include/gpxe/efi/Base.h329
-rw-r--r--gpxe/src/include/gpxe/efi/Guid/PcAnsi.h58
-rw-r--r--gpxe/src/include/gpxe/efi/Guid/SmBios.h34
-rw-r--r--gpxe/src/include/gpxe/efi/Ia32/ProcessorBind.h215
-rw-r--r--gpxe/src/include/gpxe/efi/IndustryStandard/Pci22.h601
-rw-r--r--gpxe/src/include/gpxe/efi/IndustryStandard/PeImage.h752
-rw-r--r--gpxe/src/include/gpxe/efi/LICENCE40
-rw-r--r--gpxe/src/include/gpxe/efi/Pi/PiBootMode.h43
-rw-r--r--gpxe/src/include/gpxe/efi/Pi/PiDependency.h47
-rw-r--r--gpxe/src/include/gpxe/efi/Pi/PiDxeCis.h642
-rw-r--r--gpxe/src/include/gpxe/efi/Pi/PiFirmwareFile.h242
-rw-r--r--gpxe/src/include/gpxe/efi/Pi/PiFirmwareVolume.h154
-rw-r--r--gpxe/src/include/gpxe/efi/Pi/PiHob.h295
-rw-r--r--gpxe/src/include/gpxe/efi/Pi/PiMultiPhase.h104
-rw-r--r--gpxe/src/include/gpxe/efi/PiDxe.h25
-rw-r--r--gpxe/src/include/gpxe/efi/ProcessorBind.h14
-rw-r--r--gpxe/src/include/gpxe/efi/Protocol/ComponentName2.h174
-rw-r--r--gpxe/src/include/gpxe/efi/Protocol/Cpu.h291
-rw-r--r--gpxe/src/include/gpxe/efi/Protocol/CpuIo.h128
-rw-r--r--gpxe/src/include/gpxe/efi/Protocol/DebugSupport.h634
-rw-r--r--gpxe/src/include/gpxe/efi/Protocol/DevicePath.h535
-rw-r--r--gpxe/src/include/gpxe/efi/Protocol/DriverBinding.h153
-rw-r--r--gpxe/src/include/gpxe/efi/Protocol/NetworkInterfaceIdentifier.h74
-rw-r--r--gpxe/src/include/gpxe/efi/Protocol/PciIo.h519
-rw-r--r--gpxe/src/include/gpxe/efi/Protocol/PciRootBridgeIo.h393
-rw-r--r--gpxe/src/include/gpxe/efi/Protocol/SimpleNetwork.h593
-rw-r--r--gpxe/src/include/gpxe/efi/Protocol/SimpleTextIn.h136
-rw-r--r--gpxe/src/include/gpxe/efi/Protocol/SimpleTextOut.h404
-rw-r--r--gpxe/src/include/gpxe/efi/Uefi.h27
-rw-r--r--gpxe/src/include/gpxe/efi/Uefi/UefiBaseType.h200
-rw-r--r--gpxe/src/include/gpxe/efi/Uefi/UefiGpt.h62
-rw-r--r--gpxe/src/include/gpxe/efi/Uefi/UefiInternalFormRepresentation.h1590
-rw-r--r--gpxe/src/include/gpxe/efi/Uefi/UefiMultiPhase.h210
-rw-r--r--gpxe/src/include/gpxe/efi/Uefi/UefiPxe.h1756
-rw-r--r--gpxe/src/include/gpxe/efi/Uefi/UefiSpec.h1916
-rw-r--r--gpxe/src/include/gpxe/efi/X64/ProcessorBind.h247
-rw-r--r--gpxe/src/include/gpxe/efi/efi.h131
-rw-r--r--gpxe/src/include/gpxe/efi/efi_io.h178
-rw-r--r--gpxe/src/include/gpxe/efi/efi_pci.h146
-rw-r--r--gpxe/src/include/gpxe/efi/efi_smbios.h16
-rw-r--r--gpxe/src/include/gpxe/efi/efi_timer.h16
-rw-r--r--gpxe/src/include/gpxe/efi/efi_uaccess.h88
-rw-r--r--gpxe/src/include/gpxe/efi/efi_umalloc.h16
-rwxr-xr-xgpxe/src/include/gpxe/efi/import.pl75
-rw-r--r--gpxe/src/include/gpxe/embedded.h9
-rw-r--r--gpxe/src/include/gpxe/errfile.h16
-rw-r--r--gpxe/src/include/gpxe/ethernet.h2
-rw-r--r--gpxe/src/include/gpxe/fakedhcp.h4
-rw-r--r--gpxe/src/include/gpxe/features.h24
-rw-r--r--gpxe/src/include/gpxe/i2c.h68
-rw-r--r--gpxe/src/include/gpxe/ib_mad.h364
-rw-r--r--gpxe/src/include/gpxe/ib_packet.h147
-rw-r--r--gpxe/src/include/gpxe/ib_sma.h63
-rw-r--r--gpxe/src/include/gpxe/ib_smc.h18
-rw-r--r--gpxe/src/include/gpxe/icmp.h23
-rw-r--r--gpxe/src/include/gpxe/image.h19
-rw-r--r--gpxe/src/include/gpxe/in.h4
-rw-r--r--gpxe/src/include/gpxe/infiniband.h540
-rw-r--r--gpxe/src/include/gpxe/init.h1
-rw-r--r--gpxe/src/include/gpxe/io.h504
-rw-r--r--gpxe/src/include/gpxe/iobuf.h38
-rw-r--r--gpxe/src/include/gpxe/ipoib.h47
-rw-r--r--gpxe/src/include/gpxe/keys.h29
-rw-r--r--gpxe/src/include/gpxe/login_ui.h12
-rw-r--r--gpxe/src/include/gpxe/nap.h54
-rw-r--r--gpxe/src/include/gpxe/netdevice.h83
-rw-r--r--gpxe/src/include/gpxe/null_nap.h21
-rw-r--r--gpxe/src/include/gpxe/open.h2
-rw-r--r--gpxe/src/include/gpxe/pci.h2
-rw-r--r--gpxe/src/include/gpxe/pci_io.h122
-rw-r--r--gpxe/src/include/gpxe/resolv.h2
-rw-r--r--gpxe/src/include/gpxe/retry.h9
-rw-r--r--gpxe/src/include/gpxe/rotate.h27
-rw-r--r--gpxe/src/include/gpxe/sanboot.h14
-rw-r--r--gpxe/src/include/gpxe/settings.h33
-rw-r--r--gpxe/src/include/gpxe/smbios.h140
-rw-r--r--gpxe/src/include/gpxe/socket.h14
-rw-r--r--gpxe/src/include/gpxe/tcpip.h7
-rw-r--r--gpxe/src/include/gpxe/timer.h95
-rw-r--r--gpxe/src/include/gpxe/tls.h26
-rw-r--r--gpxe/src/include/gpxe/uaccess.h317
-rw-r--r--gpxe/src/include/gpxe/udp.h1
-rw-r--r--gpxe/src/include/gpxe/umalloc.h55
-rw-r--r--gpxe/src/include/gpxe/uri.h1
-rw-r--r--gpxe/src/include/gpxe/virtio-pci.h (renamed from gpxe/src/drivers/net/virtio-pci.h)39
-rw-r--r--gpxe/src/include/gpxe/virtio-ring.h (renamed from gpxe/src/drivers/net/virtio-ring.h)59
-rw-r--r--gpxe/src/include/gpxe/x509.h39
-rw-r--r--gpxe/src/include/gpxe/xfer.h4
-rw-r--r--gpxe/src/include/nic.h1
-rw-r--r--gpxe/src/include/stddef.h6
-rw-r--r--gpxe/src/include/stdlib.h1
-rw-r--r--gpxe/src/include/unistd.h18
-rw-r--r--gpxe/src/include/usr/aoeboot.h6
-rw-r--r--gpxe/src/include/usr/autoboot.h6
-rw-r--r--gpxe/src/include/usr/dhcpmgmt.h3
-rw-r--r--gpxe/src/include/usr/iscsiboot.h6
-rw-r--r--gpxe/src/interface/efi/efi_console.c274
-rw-r--r--gpxe/src/interface/efi/efi_init.c122
-rw-r--r--gpxe/src/interface/efi/efi_io.c203
-rw-r--r--gpxe/src/interface/efi/efi_pci.c81
-rw-r--r--gpxe/src/interface/efi/efi_smbios.c62
-rw-r--r--gpxe/src/interface/efi/efi_snp.c1145
-rw-r--r--gpxe/src/interface/efi/efi_strerror.c43
-rw-r--r--gpxe/src/interface/efi/efi_timer.c116
-rw-r--r--gpxe/src/interface/efi/efi_uaccess.c37
-rw-r--r--gpxe/src/interface/efi/efi_umalloc.c96
-rw-r--r--gpxe/src/interface/smbios/smbios.c (renamed from gpxe/src/arch/i386/firmware/pcbios/smbios.c)120
-rw-r--r--gpxe/src/interface/smbios/smbios_settings.c (renamed from gpxe/src/arch/i386/firmware/pcbios/smbios_settings.c)25
-rw-r--r--gpxe/src/libgcc/__divdi3.c2
-rw-r--r--gpxe/src/libgcc/__moddi3.c2
-rw-r--r--gpxe/src/libgcc/__udivdi3.c2
-rw-r--r--gpxe/src/libgcc/__udivmoddi4.c2
-rw-r--r--gpxe/src/libgcc/__umoddi3.c2
-rw-r--r--gpxe/src/libgcc/libgcc.h24
-rw-r--r--gpxe/src/net/aoe.c209
-rw-r--r--gpxe/src/net/arp.c4
-rw-r--r--gpxe/src/net/dhcppkt.c78
-rw-r--r--gpxe/src/net/ethernet.c61
-rw-r--r--gpxe/src/net/fakedhcp.c43
-rw-r--r--gpxe/src/net/icmp.c101
-rw-r--r--gpxe/src/net/icmpv6.c2
-rw-r--r--gpxe/src/net/infiniband.c351
-rw-r--r--gpxe/src/net/ipv4.c27
-rw-r--r--gpxe/src/net/ipv6.c1
-rw-r--r--gpxe/src/net/netdevice.c88
-rw-r--r--gpxe/src/net/retry.c12
-rw-r--r--gpxe/src/net/tcp.c23
-rw-r--r--gpxe/src/net/tcp/ftp.c63
-rw-r--r--gpxe/src/net/tcp/http.c45
-rw-r--r--gpxe/src/net/tcp/iscsi.c2
-rw-r--r--gpxe/src/net/tcpip.c9
-rw-r--r--gpxe/src/net/tls.c214
-rw-r--r--gpxe/src/net/udp.c38
-rw-r--r--gpxe/src/net/udp/dhcp.c1431
-rw-r--r--gpxe/src/net/udp/dns.c76
-rw-r--r--gpxe/src/net/udp/slam.c4
-rw-r--r--gpxe/src/net/udp/tftp.c67
-rw-r--r--gpxe/src/netboot.gpxe4
-rw-r--r--gpxe/src/tests/gdbstub_test.S4
-rwxr-xr-x[-rw-r--r--]gpxe/src/tests/gdbstub_test.gdb0
-rw-r--r--gpxe/src/usr/autoboot.c72
-rw-r--r--gpxe/src/usr/dhcpmgmt.c11
-rw-r--r--gpxe/src/usr/ifmgmt.c34
-rw-r--r--gpxe/src/usr/imgmgmt.c13
-rw-r--r--gpxe/src/usr/pxemenu.c381
-rw-r--r--gpxe/src/util/.gitignore3
-rwxr-xr-xgpxe/src/util/disrom.pl47
-rw-r--r--gpxe/src/util/efirom.c280
-rw-r--r--gpxe/src/util/elf2efi.c803
-rwxr-xr-xgpxe/src/util/geniso2
-rwxr-xr-x[-rw-r--r--]gpxe/src/util/mergerom.pl0
-rwxr-xr-xgpxe/src/util/mkconfig.pl205
-rwxr-xr-xgpxe/src/util/sortobjdump.pl2
-rw-r--r--gpxe/src/util/zbin.c27
426 files changed, 45127 insertions, 13530 deletions
diff --git a/gpxe/src/Makefile b/gpxe/src/Makefile
index 6c42da6a..147f6997 100644
--- a/gpxe/src/Makefile
+++ b/gpxe/src/Makefile
@@ -1,19 +1,17 @@
-# Location to place generated files
+###############################################################################
#
-BIN := bin
-
-# Initialise variables that get added to throughout the various Makefiles
+# Initialise various variables
#
-MAKEDEPS := Makefile .toolcheck .echocheck
-SRCDIRS :=
-SRCS :=
-NON_AUTO_SRCS :=
-DRIVERS :=
-ROMS :=
-MEDIA :=
-NON_AUTO_MEDIA :=
-# Locations of utilities
+CLEANUP :=
+CFLAGS :=
+ASFLAGS :=
+LDFLAGS :=
+MAKEDEPS := Makefile
+
+###############################################################################
+#
+# Locations of tools
#
HOST_CC := gcc
RM := rm -f
@@ -35,109 +33,20 @@ NM := $(CROSS_COMPILE)nm
OBJDUMP := $(CROSS_COMPILE)objdump
PARSEROM := $(PERL) ./util/parserom.pl
MAKEROM := $(PERL) ./util/makerom.pl
-MKCONFIG := $(PERL) ./util/mkconfig.pl
SYMCHECK := $(PERL) ./util/symcheck.pl
SORTOBJDUMP := $(PERL) ./util/sortobjdump.pl
NRV2B := ./util/nrv2b
ZBIN := ./util/zbin
+ELF2EFI32 := ./util/elf2efi32
+ELF2EFI64 := ./util/elf2efi64
+EFIROM := ./util/efirom
DOXYGEN := doxygen
-# If invoked with no build target, print out a helpfully suggestive
-# message.
-#
-noargs : blib $(BIN)/NIC $(BIN)/gpxe.dsk $(BIN)/gpxe.iso $(BIN)/gpxe.usb $(BIN)/undionly.kpxe
- @$(ECHO) '==========================================================='
- @$(ECHO)
- @$(ECHO) 'To create a bootable floppy, type'
- @$(ECHO) ' cat $(BIN)/gpxe.dsk > /dev/fd0'
- @$(ECHO) 'where /dev/fd0 is your floppy drive. This will erase any'
- @$(ECHO) 'data already on the disk.'
- @$(ECHO)
- @$(ECHO) 'To create a bootable USB key, type'
- @$(ECHO) ' cat $(BIN)/gpxe.usb > /dev/sdX'
- @$(ECHO) 'where /dev/sdX is your USB key, and is *not* a real hard'
- @$(ECHO) 'disk on your system. This will erase any data already on'
- @$(ECHO) 'the USB key.'
- @$(ECHO)
- @$(ECHO) 'To create a bootable CD-ROM, burn the ISO image '
- @$(ECHO) '$(BIN)/gpxe.iso to a blank CD-ROM.'
- @$(ECHO)
- @$(ECHO) 'These images contain drivers for all supported cards. You'
- @$(ECHO) 'can build more customised images, and ROM images, using'
- @$(ECHO) ' make bin/<rom-name>.<output-format>'
- @$(ECHO)
- @$(ECHO) '==========================================================='
-
-# If no architecture is specified in Config or on the command-line,
-# use that of the build machine.
-#
-ARCH := $(shell uname -m | sed -e 's,i[3456789]86,i386,')
-
-# handle x86_64 like i386, but set -m32 option for 32bit code only
-ifeq ($(ARCH),x86_64)
-ARCH := i386
-CFLAGS += -m32
-ASFLAGS += --32
-LDFLAGS += -m elf_i386
-endif
-
-# Drag in architecture-specific Config
-#
-MAKEDEPS += arch/$(ARCH)/Config
-include arch/$(ARCH)/Config
-
-# Common flags
-#
-CFLAGS += -I include -I arch/$(ARCH)/include -I . -DARCH=$(ARCH)
-CFLAGS += -Os -ffreestanding
-CFLAGS += -Wall -W
-CFLAGS += -g
-CFLAGS += $(EXTRA_CFLAGS)
-ASFLAGS += $(EXTRA_ASFLAGS)
-LDFLAGS += $(EXTRA_LDFLAGS)
-
-# Embedded image, if present
+###############################################################################
#
-EMBEDDED_IMAGE = /dev/null
-
-ifneq ($(NO_WERROR),1)
-CFLAGS += -Werror
-endif
-
-# CFLAGS for specific object types
-#
-CFLAGS_c +=
-CFLAGS_S += -DASSEMBLY
-
-# Base object name of the current target
-#
-OBJECT = $(firstword $(subst ., ,$(@F)))
-
-# CFLAGS for specific object files. You can define
-# e.g. CFLAGS_rtl8139, and have those flags automatically used when
-# compiling bin/rtl8139.o.
-#
-OBJ_CFLAGS = $(CFLAGS_$(OBJECT)) -DOBJECT=$(subst -,_,$(OBJECT))
-$(BIN)/%.flags :
- @$(ECHO) $(OBJ_CFLAGS)
-
-# Rules for specific object types.
-#
-COMPILE_c = $(CC) $(CFLAGS) $(CFLAGS_c) $(OBJ_CFLAGS)
-RULE_c = $(Q)$(COMPILE_c) -c $< -o $@
-RULE_c_to_dbg%.o = $(Q)$(COMPILE_c) -Ddebug_$(OBJECT)=$* -c $< -o $@
-RULE_c_to_c = $(Q)$(COMPILE_c) -E -c $< > $@
-RULE_c_to_s = $(Q)$(COMPILE_c) -S -g0 -c $< -o $@
-
-PREPROCESS_S = $(CPP) $(CFLAGS) $(CFLAGS_S) $(OBJ_CFLAGS)
-ASSEMBLE_S = $(AS) $(ASFLAGS)
-RULE_S = $(Q)$(PREPROCESS_S) $< | $(ASSEMBLE_S) -o $@
-RULE_S_to_s = $(Q)$(PREPROCESS_S) $< > $@
-
-DEBUG_TARGETS += dbg%.o c s
-
# SRCDIRS lists all directories containing source files.
#
+SRCDIRS :=
SRCDIRS += libgcc
SRCDIRS += core
SRCDIRS += proto
@@ -151,7 +60,7 @@ SRCDIRS += drivers/block
SRCDIRS += drivers/nvs
SRCDIRS += drivers/bitbash
SRCDIRS += drivers/infiniband
-SRCDIRS += interface/pxe
+SRCDIRS += interface/pxe interface/efi interface/smbios
SRCDIRS += tests
SRCDIRS += crypto crypto/axtls crypto/matrixssl
SRCDIRS += hci hci/commands hci/tui
@@ -161,25 +70,69 @@ SRCDIRS += usr
# NON_AUTO_SRCS lists files that are excluded from the normal
# automatic build system.
#
-NON_AUTO_SRCS += core/elf_loader.c
+NON_AUTO_SRCS :=
NON_AUTO_SRCS += drivers/net/prism2.c
-# Rules for finalising files. TGT_MAKEROM_FLAGS is defined as part of
-# the automatic build system and varies by target; it includes the
-# "-p 0x1234,0x5678" string to set the PCI IDs.
+###############################################################################
+#
+# Default build target: build the most common targets and print out a
+# helpfully suggestive message
#
-FINALISE_rom = $(MAKEROM) $(MAKEROM_FLAGS) $(TGT_MAKEROM_FLAGS) \
- -i$(IDENT) -s 0 $@
+all : bin/blib.a bin/gpxe.dsk bin/gpxe.iso bin/gpxe.usb bin/undionly.kpxe
+ @$(ECHO) '==========================================================='
+ @$(ECHO)
+ @$(ECHO) 'To create a bootable floppy, type'
+ @$(ECHO) ' cat bin/gpxe.dsk > /dev/fd0'
+ @$(ECHO) 'where /dev/fd0 is your floppy drive. This will erase any'
+ @$(ECHO) 'data already on the disk.'
+ @$(ECHO)
+ @$(ECHO) 'To create a bootable USB key, type'
+ @$(ECHO) ' cat bin/gpxe.usb > /dev/sdX'
+ @$(ECHO) 'where /dev/sdX is your USB key, and is *not* a real hard'
+ @$(ECHO) 'disk on your system. This will erase any data already on'
+ @$(ECHO) 'the USB key.'
+ @$(ECHO)
+ @$(ECHO) 'To create a bootable CD-ROM, burn the ISO image '
+ @$(ECHO) 'bin/gpxe.iso to a blank CD-ROM.'
+ @$(ECHO)
+ @$(ECHO) 'These images contain drivers for all supported cards. You'
+ @$(ECHO) 'can build more customised images, and ROM images, using'
+ @$(ECHO) ' make bin/<rom-name>.<output-format>'
+ @$(ECHO)
+ @$(ECHO) '==========================================================='
+
+###############################################################################
+#
+# Build targets that do nothing but might be tried by users
+#
+configure :
+ @$(ECHO) "No configuration needed."
+
+install :
+ @$(ECHO) "No installation required."
-# Some ROMs require specific flags to be passed to makerom.pl
+###############################################################################
#
-MAKEROM_FLAGS_3c503 = -3
+# Version number calculations
+#
+VERSION_MAJOR = 0
+VERSION_MINOR = 9
+VERSION_PATCH = 6
+EXTRAVERSION = +
+MM_VERSION = $(VERSION_MAJOR).$(VERSION_MINOR)
+VERSION = $(MM_VERSION).$(VERSION_PATCH)$(EXTRAVERSION)
+CFLAGS += -DVERSION_MAJOR=$(VERSION_MAJOR) \
+ -DVERSION_MINOR=$(VERSION_MINOR) \
+ -DVERSION_PATCH=$(VERSION_PATCH) \
+ -DVERSION=\"$(VERSION)\"
+IDENT = '$(@F) $(VERSION) (GPL) etherboot.org'
+version :
+ @$(ECHO) $(VERSION)
-# Drag in architecture-specific Makefile
+###############################################################################
+#
+# Drag in the bulk of the build system
#
-MAKEDEPS += arch/$(ARCH)/Makefile
-include arch/$(ARCH)/Makefile
-# Drag in the automatic build system and other housekeeping functions
MAKEDEPS += Makefile.housekeeping
include Makefile.housekeeping
diff --git a/gpxe/src/Makefile.housekeeping b/gpxe/src/Makefile.housekeeping
index 9e11ceb4..2146d9cb 100644
--- a/gpxe/src/Makefile.housekeeping
+++ b/gpxe/src/Makefile.housekeeping
@@ -1,50 +1,10 @@
# -*- makefile -*- : Force emacs to use Makefile mode
-
+#
# This file contains various boring housekeeping functions that would
# otherwise seriously clutter up the main Makefile.
-# Objects to be removed by "make clean"
-#
-CLEANUP := $(BIN)/*.* # *.* to avoid catching the "CVS" directory
-
-# Version number calculations
-#
-VERSION_MAJOR = 0
-VERSION_MINOR = 9
-VERSION_PATCH = 5
-EXTRAVERSION =
-MM_VERSION = $(VERSION_MAJOR).$(VERSION_MINOR)
-VERSION = $(MM_VERSION).$(VERSION_PATCH)$(EXTRAVERSION)
-CFLAGS += -DVERSION_MAJOR=$(VERSION_MAJOR) \
- -DVERSION_MINOR=$(VERSION_MINOR) \
- -DVERSION=\"$(VERSION)\"
-IDENT = '$(@F) $(VERSION) (GPL) etherboot.org'
-version :
- @$(ECHO) $(VERSION)
-
-configure :
- @$(ECHO) "No configuration needed."
-
-install :
- @$(ECHO) "No installation required. Generated images will be placed in the" $(BIN) "directory."
-
-# Check for tools that can cause failed builds
+###############################################################################
#
-.toolcheck : Makefile
- @if $(CC) -v 2>&1 | grep -is 'gcc version 2\.96' > /dev/null; then \
- $(ECHO) 'gcc 2.96 is unsuitable for compiling Etherboot'; \
- $(ECHO) 'Use gcc 2.95 or gcc 3.x instead'; \
- exit 1; \
- fi
- @if [ `perl -e 'use bytes; print chr(255)' | wc -c` = 2 ]; then \
- $(ECHO) 'Your Perl version has a Unicode handling bug'; \
- $(ECHO) 'Execute this command before compiling Etherboot:'; \
- $(ECHO) 'export LANG=$${LANG%.UTF-8}'; \
- exit 1; \
- fi
- @$(TOUCH) $@
-VERYCLEANUP += .toolcheck
-
# Find a usable "echo -e" substitute.
#
TAB := $(shell $(PRINTF) '\t')
@@ -86,20 +46,51 @@ else
@$(ECHO) "No usable \"echo -e\" substitute found"
@exit 1
endif
+MAKEDEPS += .echocheck
VERYCLEANUP += .echocheck
echo :
@$(ECHO) "Using \"$(ECHO_E)\" for \"echo -e\""
-# Build verbosity
+###############################################################################
+#
+# Determine host OS
+#
+HOST_OS := $(shell uname -s)
+hostos :
+ @$(ECHO) $(HOST_OS)
+
+###############################################################################
+#
+# Check for tools that can cause failed builds
+#
+.toolcheck :
+ @if $(CC) -v 2>&1 | grep -is 'gcc version 2\.96' > /dev/null; then \
+ $(ECHO) 'gcc 2.96 is unsuitable for compiling Etherboot'; \
+ $(ECHO) 'Use gcc 2.95 or gcc 3.x instead'; \
+ exit 1; \
+ fi
+ @if [ `perl -e 'use bytes; print chr(255)' | wc -c` = 2 ]; then \
+ $(ECHO) 'Your Perl version has a Unicode handling bug'; \
+ $(ECHO) 'Execute this command before compiling Etherboot:'; \
+ $(ECHO) 'export LANG=$${LANG%.UTF-8}'; \
+ exit 1; \
+ fi
+ @$(TOUCH) $@
+MAKEDEPS += .toolcheck
+VERYCLEANUP += .toolcheck
+
+###############################################################################
+#
+# Check for various tool workarounds
#
-ifeq ($(V),1)
-Q =
-QM = @\#
-else
-Q = @
-QM = @
-endif
+
+# Make syntax does not allow use of comma or space in certain places.
+# This ugly workaround is suggested in the manual.
+#
+COMMA := ,
+EMPTY :=
+SPACE := $(EMPTY) $(EMPTY)
# Check for an old version of gas (binutils 2.9.1)
#
@@ -112,18 +103,154 @@ oldgas :
# default, even when -ffreestanding is specified. We therefore need
# to disable -fstack-protector if the compiler supports it.
#
-SP_TEST = $(CC) -fno-stack-protector -x c -E - < /dev/null >/dev/null 2>&1
+SP_TEST = $(CC) -fno-stack-protector -x c -c /dev/null \
+ -o /dev/null >/dev/null 2>&1
SP_FLAGS := $(shell $(SP_TEST) && $(ECHO) '-fno-stack-protector')
CFLAGS += $(SP_FLAGS)
-# compiler.h is needed for our linking and debugging system
+###############################################################################
+#
+# Build verbosity
+#
+ifeq ($(V),1)
+Q :=
+QM := @\#
+else
+Q := @
+QM := @
+endif
+
+###############################################################################
+#
+# Set BIN according to whatever was specified on the command line as
+# the build target.
+#
+
+# Determine how many different BIN directories are mentioned in the
+# make goals.
+#
+BIN_GOALS := $(filter bin/% bin-%,$(MAKECMDGOALS))
+BIN_GOAL_BINS := $(foreach BG,$(BIN_GOALS),$(firstword $(subst /, ,$(BG))))
+NUM_BINS := $(words $(sort $(BIN_GOAL_BINS)))
+
+ifeq ($(NUM_BINS),0)
+
+# No BIN directory was specified. Set BIN to "bin" as a sensible
+# default.
+
+BIN := bin
+
+else # NUM_BINS == 0
+
+ifeq ($(NUM_BINS),1)
+
+# If exactly one BIN directory was specified, set BIN to match this
+# directory.
+#
+BIN := $(firstword $(BIN_GOAL_BINS))
+
+else # NUM_BINS == 1
+
+# More than one BIN directory was specified. We cannot handle the
+# latter case within a single make invocation, so set up recursive
+# targets for each BIN directory.
+#
+# Leave $(BIN) undefined. This has implications for any target that
+# depends on $(BIN); such targets should be made conditional upon the
+# existence of $(BIN).
#
-CFLAGS += -include compiler.h
+$(BIN_GOALS) : % : BIN_RECURSE
+ $(Q)$(MAKE) --no-print-directory BIN=$(firstword $(subst /, ,$@)) $@
+.PHONY : BIN_RECURSE
+
+endif # NUM_BINS == 1
+endif # NUM_BINS == 0
+
+ifdef BIN
+
+# Create $(BIN) directory if it doesn't exist yet
+#
+ifeq ($(wildcard $(BIN)),)
+$(shell $(MKDIR) -p $(BIN))
+endif
+
+# Target to allow e.g. "make bin-efi arch"
+#
+$(BIN) :
+ @# Do nothing, silently
+.PHONY : $(BIN)
+
+# Remove everything in $(BIN) for a "make clean"
+#
+CLEANUP += $(BIN)/*.* # Avoid picking up directories
+
+endif # defined(BIN)
+
+# Determine whether or not we need to include the dependency files
+#
+NO_DEP_TARGETS := $(BIN) clean veryclean
+ifeq ($(MAKECMDGOALS),)
+NEED_DEPS := 1
+endif
+ifneq ($(strip $(filter-out $(NO_DEP_TARGETS),$(MAKECMDGOALS))),)
+NEED_DEPS := 1
+endif
+
+###############################################################################
+#
+# Select build architecture and platform based on $(BIN)
+#
+# BIN has the form bin[-[arch-]platform]
+
+ARCHS := $(patsubst arch/%,%,$(wildcard arch/*))
+PLATFORMS := $(patsubst config/defaults/%.h,%,\
+ $(wildcard config/defaults/*.h))
+archs :
+ @$(ECHO) $(ARCHS)
+
+platforms :
+ @$(ECHO) $(PLATFORMS)
+
+ifdef BIN
+
+# Determine architecture portion of $(BIN), if present
+BIN_ARCH := $(strip $(foreach A,$(ARCHS),\
+ $(patsubst bin-$(A)-%,$(A),\
+ $(filter bin-$(A)-%,$(BIN)))))
-# config/%.h files are generated from config.h using mkconfig.pl
-config/%.h : config*.h
- $(MKCONFIG) config.h
-CLEANUP += config/*.h
+# Determine platform portion of $(BIN), if present
+ifeq ($(BIN_ARCH),)
+BIN_PLATFORM := $(patsubst bin-%,%,$(filter bin-%,$(BIN)))
+else
+BIN_PLATFORM := $(patsubst bin-$(BIN_ARCH)-%,%,$(BIN))
+endif
+
+# Determine build architecture
+DEFAULT_ARCH := i386
+ARCH := $(firstword $(BIN_ARCH) $(DEFAULT_ARCH))
+CFLAGS += -DARCH=$(ARCH)
+arch :
+ @$(ECHO) $(ARCH)
+.PHONY : arch
+
+# Determine build platform
+DEFAULT_PLATFORM := pcbios
+PLATFORM := $(firstword $(BIN_PLATFORM) $(DEFAULT_PLATFORM))
+CFLAGS += -DPLATFORM=$(PLATFORM)
+platform :
+ @$(ECHO) $(PLATFORM)
+
+endif # defined(BIN)
+
+# Include architecture-specific Makefile
+ifdef ARCH
+MAKEDEPS += arch/$(ARCH)/Makefile
+include arch/$(ARCH)/Makefile
+endif
+
+###############################################################################
+#
+# Source file handling
# SRCDIRS lists all directories containing source files.
srcdirs :
@@ -144,6 +271,68 @@ AUTO_SRCS = $(filter-out $(NON_AUTO_SRCS),$(SRCS))
autosrcs :
@$(ECHO) $(AUTO_SRCS)
+# Just about everything else in this section depends upon having
+# $(BIN) set
+
+ifdef BIN
+
+# Common flags
+#
+CFLAGS += -I include -I arch/$(ARCH)/include -I .
+CFLAGS += -Os -ffreestanding
+CFLAGS += -Wall -W -Wformat-nonliteral
+CFLAGS += -g
+CFLAGS += $(EXTRA_CFLAGS)
+ASFLAGS += $(EXTRA_ASFLAGS)
+LDFLAGS += $(EXTRA_LDFLAGS)
+
+# Embedded image(s), or default if not set
+#
+EMBEDDED_IMAGE = image/default.gpxe
+
+# Inhibit -Werror if NO_WERROR is specified on make command line
+#
+ifneq ($(NO_WERROR),1)
+CFLAGS += -Werror
+ASFLAGS += --fatal-warnings
+endif
+
+# compiler.h is needed for our linking and debugging system
+#
+CFLAGS += -include compiler.h
+
+# CFLAGS for specific object types
+#
+CFLAGS_c +=
+CFLAGS_S += -DASSEMBLY
+
+# Base object name of the current target
+#
+OBJECT = $(firstword $(subst ., ,$(@F)))
+
+# CFLAGS for specific object files. You can define
+# e.g. CFLAGS_rtl8139, and have those flags automatically used when
+# compiling bin/rtl8139.o.
+#
+OBJ_CFLAGS = $(CFLAGS_$(OBJECT)) -DOBJECT=$(subst -,_,$(OBJECT))
+$(BIN)/%.flags :
+ @$(ECHO) $(OBJ_CFLAGS)
+
+# Rules for specific object types.
+#
+COMPILE_c = $(CC) $(CFLAGS) $(CFLAGS_c) $(OBJ_CFLAGS)
+RULE_c = $(Q)$(COMPILE_c) -c $< -o $@
+RULE_c_to_dbg%.o = $(Q)$(COMPILE_c) -Ddebug_$(OBJECT)=$* -c $< -o $@
+RULE_c_to_c = $(Q)$(COMPILE_c) -E -c $< > $@
+RULE_c_to_s = $(Q)$(COMPILE_c) -S -g0 -c $< -o $@
+
+PREPROCESS_S = $(CPP) $(CFLAGS) $(CFLAGS_S) $(OBJ_CFLAGS)
+ASSEMBLE_S = $(AS) $(ASFLAGS)
+RULE_S = $(Q)$(PREPROCESS_S) $< | $(ASSEMBLE_S) -o $@
+RULE_S_to_s = $(Q)$(PREPROCESS_S) $< > $@
+
+DEBUG_TARGETS += dbg%.o c s
+
# We automatically generate rules for any file mentioned in AUTO_SRCS
# using the following set of templates. It would be cleaner to use
# $(eval ...), but this function exists only in GNU make >= 3.80.
@@ -157,7 +346,7 @@ autosrcs :
#
define src_template
- @$(ECHO) "Generating Makefile rules for $(1)"
+ @$(ECHO) " [DEPS] $(1)"
@$(MKDIR) -p $(dir $(2))
@$(RM) $(2)
@$(TOUCH) $(2)
@@ -182,13 +371,13 @@ define obj_template
-Wno-error -MM $(1) -MT "$(4)_DEPS" -MG -MP | \
sed 's/_DEPS\s*:/_DEPS =/' >> $(2)
@$(ECHO_E) '\n$$(BIN)/$(4).o : $(1) $$(MAKEDEPS) $$($(4)_DEPS)' \
- '\n\t$$(QM)$(ECHO) " [BUILD] $$@"\n' \
+ '\n\t$$(QM)$(ECHO) " [BUILD] $$@"' \
'\n\t$$(RULE_$(3))\n' \
'\nBOBJS += $$(BIN)/$(4).o\n' \
$(foreach TGT,$(DEBUG_TARGETS), \
$(if $(RULE_$(3)_to_$(TGT)), \
'\n$$(BIN)/$(4).$(TGT) : $(1) $$(MAKEDEPS) $$($(4)_DEPS)' \
- '\n\t$$(QM)$(ECHO) " [BUILD] $$@"\n' \
+ '\n\t$$(QM)$(ECHO) " [BUILD] $$@"' \
'\n\t$$(RULE_$(3)_to_$(TGT))\n' \
'\n$(TGT)_OBJS += $$(BIN)/$(4).$(TGT)\n' ) ) \
'\n$(2) : $$($(4)_DEPS)\n' \
@@ -205,7 +394,11 @@ $(BIN)/deps/%.d : % $(MAKEDEPS) $(PARSEROM)
# Calculate and include the list of Makefile rules files
#
AUTO_DEPS = $(patsubst %,$(BIN)/deps/%.d,$(AUTO_SRCS))
+ifdef NEED_DEPS
+ifneq ($(AUTO_DEPS),)
-include $(AUTO_DEPS)
+endif
+endif
autodeps :
@$(ECHO) $(AUTO_DEPS)
VERYCLEANUP += $(BIN)/deps
@@ -220,13 +413,31 @@ drivers :
roms :
@$(ECHO) $(ROMS)
-# Embedded binary
-$(BIN)/embedimg.bin: $(EMBEDDED_IMAGE)
- $(QM)$(ECHO) " [COPY] $@"
- $(Q)$(CP) -f $(EMBEDDED_IMAGE) $@
+# List of embedded images included in the last build of embedded.o.
+# This is needed in order to correctly rebuild embedded.o whenever the
+# list of objects changes.
+#
+EMBEDDED_LIST := $(BIN)/.embedded.list
+ifeq ($(wildcard $(EMBEDDED_LIST)),)
+EMBEDDED_LIST_IMAGE :=
+else
+EMBEDDED_LIST_IMAGE := $(shell cat $(EMBEDDED_LIST))
+endif
+ifneq ($(EMBEDDED_LIST_IMAGE),$(EMBEDDED_IMAGE))
+$(shell $(ECHO) "$(EMBEDDED_IMAGE)" > $(EMBEDDED_LIST))
+endif
+
+$(EMBEDDED_LIST) :
+
+VERYCLEANUP += $(EMBEDDED_LIST)
-$(BIN)/embed.o: $(BIN)/embedimg.bin
-CFLAGS_embed = -DEMBEDIMG=\"$(BIN)/embedimg.bin\"
+EMBEDDED_FILES := $(subst $(COMMA), ,$(EMBEDDED_IMAGE))
+EMBED_ALL := $(foreach i,$(shell seq 1 $(words $(EMBEDDED_FILES))),\
+ EMBED ( $(i), \"$(word $(i), $(EMBEDDED_FILES))\",\
+ \"$(notdir $(word $(i),$(EMBEDDED_FILES)))\" ))
+
+$(BIN)/embedded.o : $(EMBEDDED_FILES) $(EMBEDDED_LIST)
+CFLAGS_embedded = -DEMBED_ALL="$(EMBED_ALL)"
# Generate the NIC file from the parsed source files. The NIC file is
# only for rom-o-matic.
@@ -237,7 +448,7 @@ $(BIN)/NIC : $(AUTO_DEPS)
'it is only for rom-o-matic' >> $@
@$(ECHO) >> $@
@perl -ne 'chomp; print "$$1\n" if /\# NIC\t(.*)$$/' $^ >> $@
-CLEANUP += $(BIN)/NIC
+CLEANUP += $(BIN)/NIC # Doesn't match the $(BIN)/*.* pattern
# Analyse a target name (e.g. "bin/dfe538--prism2_pci.zrom.tmp") and
# derive the variables:
@@ -305,7 +516,6 @@ TGT_MAKEROM_FLAGS = $(strip $(MAKEROM_FLAGS_$(TGT_ROM_NAME)) \
# Calculate list of debugging versions of objects to be included in
# the target.
#
-COMMA := ,
DEBUG_LIST = $(subst $(COMMA), ,$(DEBUG))
DEBUG_OBJ_LEVEL = $(firstword $(word 2,$(subst :, ,$(1))) 1)
DEBUG_OBJ_BASE = $(word 1,$(subst :, ,$(1))).dbg$(call DEBUG_OBJ_LEVEL,$(1))
@@ -342,8 +552,13 @@ $(BIN)/%.info :
# in order to correctly rebuild blib whenever the list of objects
# changes.
#
-BLIB_LIST = $(BIN)/.blib.list
-ifneq ($(shell cat $(BLIB_LIST)),$(BLIB_OBJS))
+BLIB_LIST := $(BIN)/.blib.list
+ifeq ($(wildcard $(BLIB_LIST)),)
+BLIB_LIST_OBJS :=
+else
+BLIB_LIST_OBJS := $(shell cat $(BLIB_LIST))
+endif
+ifneq ($(BLIB_LIST_OBJS),$(BLIB_OBJS))
$(shell $(ECHO) "$(BLIB_OBJS)" > $(BLIB_LIST))
endif
@@ -396,10 +611,6 @@ $(BIN)/%.zbin : $(BIN)/%.bin $(BIN)/%.zinfo $(ZBIN)
$(QM)$(ECHO) " [ZBIN] $@"
$(Q)$(ZBIN) $(BIN)/$*.bin $(BIN)/$*.zinfo > $@
-# Build bochs symbol table
-$(BIN)/%.bxs : $(BIN)/%.tmp
- $(NM) $< | cut -d" " -f1,3 > $@
-
# Rules for each media format. These are generated and placed in an
# external Makefile fragment. We could do this via $(eval ...), but
# that would require make >= 3.80.
@@ -435,7 +646,7 @@ automedia :
#
define media_template
- @$(ECHO) "Generating Makefile rules for $(1) media"
+ @$(ECHO) " [MEDIADEPS] $(1)"
@$(MKDIR) -p $(dir $(2))
@$(RM) $(2)
@$(TOUCH) $(2)
@@ -459,7 +670,20 @@ $(BIN)/deps/%.media.d : $(MAKEDEPS)
MEDIA_DEPS = $(patsubst %,$(BIN)/deps/%.media.d,$(AUTO_MEDIA))
mediadeps :
@$(ECHO) $(MEDIA_DEPS)
+ifdef NEED_DEPS
+ifneq ($(MEDIA_DEPS),)
-include $(MEDIA_DEPS)
+endif
+endif
+
+# Wrap up binary blobs (for embedded images)
+#
+$(BIN)/%.o : payload/%.img
+ $(QM)echo " [WRAP] $@"
+ $(Q)$(LD) -b binary -r -o $@ $< --undefined obj_payload \
+ --defsym obj_$*=0
+
+BOBJS += $(patsubst payload/%.img,$(BIN)/%.o,$(wildcard payload/*.img))
# The "allXXXs" targets for each suffix
#
@@ -472,15 +696,23 @@ allpxes allisos alldsks : all%s : $(foreach DRIVER,$(DRIVERS),$(BIN)/$(DRIVER).%
$(BIN)/etherboot.% : $(BIN)/gpxe.%
ln -sf $(notdir $<) $@
-# Wrap up binary blobs
+endif # defined(BIN)
+
+###############################################################################
#
-$(BIN)/%.o : payload/%.img
- $(QM)echo " [WRAP] $@"
- $(Q)$(LD) -b binary -r -o $@ $< --undefined obj_payload \
- --defsym obj_$*=0
+# Rules for finalising files. TGT_MAKEROM_FLAGS is defined as part of
+# the automatic build system and varies by target; it includes the
+# "-p 0x1234,0x5678" string to set the PCI IDs.
+#
+FINALISE_rom = $(MAKEROM) $(MAKEROM_FLAGS) $(TGT_MAKEROM_FLAGS) \
+ -i$(IDENT) -s 0 $@
-BOBJS += $(patsubst payload/%.img,$(BIN)/%.o,$(wildcard payload/*.img))
+# Some ROMs require specific flags to be passed to makerom.pl
+#
+MAKEROM_FLAGS_3c503 = -3
+###############################################################################
+#
# The compression utilities
#
$(NRV2B) : util/nrv2b.c $(MAKEDEPS)
@@ -494,6 +726,29 @@ $(ZBIN) : util/zbin.c util/nrv2b.c $(MAKEDEPS)
$(Q)$(HOST_CC) -O2 -o $@ $<
CLEANUP += $(ZBIN)
+###############################################################################
+#
+# The EFI image converter
+#
+$(ELF2EFI32) : util/elf2efi.c $(MAKEDEPS)
+ $(QM)$(ECHO) " [HOSTCC] $@"
+ $(Q)$(HOST_CC) -DMDE_CPU_IA32 -idirafter include -O2 \
+ -o $@ $< -lbfd -liberty
+CLEANUP += $(ELF2EFI32)
+
+$(ELF2EFI64) : util/elf2efi.c $(MAKEDEPS)
+ $(QM)$(ECHO) " [HOSTCC] $@"
+ $(Q)$(HOST_CC) -DMDE_CPU_X64 -idirafter include -O2 \
+ -o $@ $< -lbfd -liberty
+CLEANUP += $(ELF2EFI64)
+
+$(EFIROM) : util/efirom.c $(MAKEDEPS)
+ $(QM)$(ECHO) " [HOSTCC] $@"
+ $(Q)$(HOST_CC) -idirafter include -O2 -o $@ $<
+CLEANUP += $(EFIROM)
+
+###############################################################################
+#
# Auto-incrementing build serial number. Append "bs" to your list of
# build targets to get a serial number printed at the end of the
# build. Enable -DBUILD_SERIAL in order to see it when the code runs.
@@ -517,27 +772,30 @@ bs : $(BUILDSERIAL_NOW)
@$(ECHO) $$(( $(shell cat $<) + 1 )) > $(BUILDSERIAL_NEXT)
@$(ECHO) "Build serial number is $(shell cat $<)"
-# List of available architectures
+###############################################################################
#
-ARCHS = $(filter-out CVS,$(patsubst arch/%,%,$(wildcard arch/*)))
-archs :
- @$(ECHO) $(ARCHS)
+# Build the TAGS file(s) for emacs
+#
+TAGS :
+ ctags -e -R -f $@ --exclude=bin
-OTHER_ARCHS = $(filter-out $(ARCH),$(ARCHS))
-otherarchs :
- @$(ECHO) $(OTHER_ARCHS)
+CLEANUP += TAGS
-# Build the TAGS file for emacs
+###############################################################################
#
-TAGS : TAGS.$(ARCH)
-
-TAGS.$(ARCH) :
- ctags -e -R -f $@ --exclude=bin \
- $(foreach ARCH,$(OTHER_ARCHS),--exclude=arch/$(ARCH))
-CLEANUP += TAGS*
+# Force rebuild for any given target
+#
+%.rebuild :
+ rm -f $*
+ $(Q)$(MAKE) $*
+###############################################################################
+#
# Symbol table checks
#
+
+ifdef BIN
+
SYMTAB = $(BIN)/symtab
$(SYMTAB) : $(BLIB)
$(OBJDUMP) -w -t $< > $@
@@ -547,14 +805,27 @@ CLEANUP += $(BIN)/symtab
symcheck : $(SYMTAB)
$(SYMCHECK) $<
-# Force rebuild for any given target
+endif # defined(BIN)
+
+###############################################################################
+#
+# Build bochs symbol table
#
-$(BIN)/%.rebuild :
- rm -f $(BIN)/$*
- $(MAKE) $(MAKEFLAGS) $(BIN)/$*
+ifdef BIN
+
+$(BIN)/%.bxs : $(BIN)/%.tmp
+ $(NM) $< | cut -d" " -f1,3 > $@
+
+endif # defined(BIN)
+
+###############################################################################
+#
# Documentation
#
+
+ifdef BIN
+
$(BIN)/doxygen.cfg : doxygen.cfg $(MAKEDEPS)
$(PERL) -pe 's{\@SRCDIRS\@}{$(SRCDIRS)}; ' \
-e 's{\@BIN\@}{$(BIN)}; ' \
@@ -578,6 +849,10 @@ docview :
$(ECHO) "Documentation index in $(BIN)/doc/html/index.html" ; \
fi
+endif # defined(BIN)
+
+###############################################################################
+#
# Clean-up
#
clean :
@@ -585,19 +860,3 @@ clean :
veryclean : clean
$(RM) -r $(VERYCLEANUP)
-
-# Make clean tarballs for release
-
-tarball : ../VERSION
- ($(ECHO) -n $(VERSION) ''; date -u +'%Y-%m-%d') > ../VERSION
- $(RM) -r /tmp/$(USER)/gpxe-$(VERSION)
- mkdir -p /tmp/$(USER)/gpxe-$(VERSION)
- cp -rP .. /tmp/$(USER)/gpxe-$(VERSION)
- ( cd /tmp/$(USER)/gpxe-$(VERSION)/src ; $(MAKE) veryclean ; $(RM) -r bin/deps )
- ( cd /tmp/$(USER); tar cf /tmp/$(USER)/gpxe-$(VERSION).tar --exclude ".git*" --exclude "#*" \
- --exclude "*~" gpxe-$(VERSION) )
- bzip2 -9 < /tmp/$(USER)/gpxe-$(VERSION).tar > /tmp/$(USER)/gpxe-$(VERSION).tar.bz2
- gzip -9 < /tmp/$(USER)/gpxe-$(VERSION).tar > /tmp/$(USER)/gpxe-$(VERSION).tar.gz
- $(RM) -r /tmp/$(USER)/gpxe-$(VERSION)
- $(RM) /tmp/$(USER)/gpxe-$(VERSION).tar
- ( cd /tmp/$(USER) ; tar -zxf /tmp/$(USER)/gpxe-$(VERSION).tar.gz )
diff --git a/gpxe/src/arch/i386/Config b/gpxe/src/arch/i386/Config
deleted file mode 100644
index 1c086ecc..00000000
--- a/gpxe/src/arch/i386/Config
+++ /dev/null
@@ -1,148 +0,0 @@
-# -*- makefile -*-
-
-##############################################################################
-##############################################################################
-#
-# IMPORTANT!
-#
-# The use of this file to set options that affect only single object
-# files is deprecated, because changing anything in this file results
-# in a complete rebuild, which is slow. All options are gradually
-# being migrated to config.h, which does not suffer from this problem.
-#
-# Only options that affect the entire build (e.g. overriding the $(CC)
-# Makefile variable) should be placed in here.
-#
-##############################################################################
-##############################################################################
-
-
-# Config for i386 Etherboot
-#
-# Do not delete the tag OptionDescription and /OptionDescription
-# It is used to automatically generate the documentation.
-#
-# @OptionDescrition@
-#
-# BIOS interface options:
-#
-# -DPCBIOS
-# Compile in support for the normal pcbios
-# -DLINUXBIOS
-# Compile in support for LinuxBIOS
-# -DBBS_BUT_NOT_PNP_COMPLIANT
-# Some BIOSes claim to be PNP but they don't conform
-# to the BBS spec which specifies that ES:DI must
-# point to the string $PnP on entry. This option
-# works around those. This option must be added to
-# LCONFIG.
-# -DNO_DELAYED_INT
-# Take control as soon as BIOS detects the ROM.
-# Normally hooks onto INT18H or INT19H. Use only if you
-# have a very non-conformant BIOS as it bypasses
-# BIOS initialisation of devices. This only works for
-# legacy ROMs, i.e. PCI_PNP_HEADER not defined.
-# This option was formerly called NOINT19H.
-# -DBOOT_INT18H
-# Etherboot normally hooks onto INT19H for legacy ROMs.
-# You can choose to hook onto INT18H (BASIC interpreter
-# entry point) instead. This entry point is used when
-# all boot devices have been exhausted. This option must
-# be added to LCONFIG.
-# -DCONFIG_PCI_DIRECT
-# Define this for PCI BIOSes that do not implement
-# BIOS32 or not correctly. Normally not needed.
-# Only works for BIOSes of a certain era.
-# -DCONFIG_TSC_CURRTICKS
-# Uses the processor time stamp counter instead of reading
-# the BIOS time counter. This allows Etherboot to work
-# even without a BIOS. This only works on late model
-# 486s and above.
-# -DCONFIG_NO_TIMER2
-# Some systems do not have timer2 implemented.
-# If you have a RTC this will allow you to roughly calibrate
-# it using outb instructions.
-#
-# Extended cpu options
-
-# -DCONFIG_X86_64
-# Compile in support for booting x86_64 64bit binaries.
-#
-# PXE loader options:
-#
-# -DPXELOADER_KEEP_ALL
-# Prevent PXE loader (prefix) from unloading the
-# PXE stack. You will want to use this if, for
-# example, you are booting via PXE-on-floppy.
-# You may want to use it under certain
-# circumstances when using the Etherboot UNDI
-# driver; these are complex and best practice is
-# not yet established.
-#
-# Obscure options you probably don't need to touch:
-#
-# -DIGNORE_E820_MAP
-# Ignore the memory map returned by the E820 BIOS
-# call. May be necessary on some buggy BIOSes.
-# -DT503_AUI
-# Use AUI by default on 3c503 cards.
-# -DFLATTEN_REAL_MODE
-# Use 4GB segment limits when calling out to or
-# returning to real-mode code. This is necessary to
-# work around some buggy code (e.g. OpenBSD's pxeboot)
-# that uses flat real-mode without being sufficiently
-# paranoid about the volatility of its segment limits.
-
-#
-# @/OptionDescription@
-
-# BIOS select don't change unless you know what you are doing
-# CFLAGS+= -DPCBIOS
-
-# Compile in k8/hammer support
-# CFLAGS+= -DCONFIG_X86_64
-
-# Options to make a version of Etherboot that will work under linuxBIOS.
-# CFLAGS+= -DLINUXBIOS -DCONFIG_TSC_CURRTICKS -DCONSOLE_SERIAL -DCOMCONSOLE=0x3f8 -DCOMPRESERVE -DCONFIG_PCI_DIRECT -DELF_IMAGE
-
-# These options affect the loader that is prepended to the Etherboot image
-# LCONFIG+= -DBBS_BUT_NOT_PNP_COMPLIANT
-# LCONFIG+= -DBOOT_INT18H
-
-# Produce code that will work with OpenBSD's pxeboot
-# CFLAGS+= -DFLATTEN_REAL_MODE
-
-CFLAGS+= -fstrength-reduce -fomit-frame-pointer -march=i386
-# Squeeze the code in as little space as possible.
-# gcc3 needs a different syntax to gcc2 if you want to avoid spurious warnings.
-GCC_VERSION = $(subst ., ,$(shell $(CC) -dumpversion))
-GCC_MAJORVERSION = $(firstword $(GCC_VERSION))
-ifeq ($(GCC_MAJORVERSION),2)
-CFLAGS+= -malign-jumps=1 -malign-loops=1 -malign-functions=1
-else
-CFLAGS+= -falign-jumps=1 -falign-loops=1 -falign-functions=1
-endif
-
-# this is almost always a win. the kernel uses it, too.
-CFLAGS+= -mpreferred-stack-boundary=2
-
-# use regparm for all functions - C functions called from assembly (or
-# vice versa) need __cdecl now
-CFLAGS+= -mregparm=3
-
-# use -mrtd (same __cdecl requirements as above)
-CFLAGS+= -mrtd
-
-# this is the logical complement to -mregparm=3.
-# it doesn't currently buy us anything, but if anything ever tries
-# to return small structures, let's be prepared
-CFLAGS+= -freg-struct-return
-
-LDFLAGS+= -N --no-check-sections
-
-ifeq "$(shell uname -s)" "FreeBSD"
-CFLAGS+= -DIMAGE_FREEBSD -DELF_IMAGE -DAOUT_IMAGE
-endif
-
-# An alternate location for isolinux.bin can be set here
-# ISOLINUX_BIN=/path/to/isolinux.bin
diff --git a/gpxe/src/arch/i386/Makefile b/gpxe/src/arch/i386/Makefile
index 97ca0774..1392bbac 100644
--- a/gpxe/src/arch/i386/Makefile
+++ b/gpxe/src/arch/i386/Makefile
@@ -1,3 +1,59 @@
+# Force i386-only instructions
+#
+CFLAGS += -march=i386
+
+# Code size reduction.
+#
+CFLAGS += -fstrength-reduce -fomit-frame-pointer
+
+# Code size reduction. gcc3 needs a different syntax to gcc2 if you
+# want to avoid spurious warnings.
+#
+GCC_VERSION := $(subst ., ,$(shell $(CC) -dumpversion))
+GCC_MAJOR := $(firstword $(GCC_VERSION))
+ifeq ($(GCC_MAJOR),2)
+CFLAGS += -malign-jumps=1 -malign-loops=1 -malign-functions=1
+else
+CFLAGS += -falign-jumps=1 -falign-loops=1 -falign-functions=1
+endif
+
+# Code size reduction. This is almost always a win. The kernel uses it, too.
+#
+CFLAGS += -mpreferred-stack-boundary=2
+
+# Code size reduction. Use regparm for all functions - C functions
+# called from assembly (or vice versa) need __asmcall now
+#
+CFLAGS += -mregparm=3
+
+# Code size reduction. Use -mrtd (same __asmcall requirements as above)
+CFLAGS += -mrtd
+
+# Code size reduction. This is the logical complement to -mregparm=3.
+# It doesn't currently buy us anything, but if anything ever tries to
+# return small structures, let's be prepared
+#
+CFLAGS += -freg-struct-return
+
+# Force 32-bit code even on an x86-64 machine
+#
+CFLAGS += -m32
+ASFLAGS += --32
+ifeq ($(HOST_OS),FreeBSD)
+LDFLAGS += -m elf_i386_fbsd
+else
+LDFLAGS += -m elf_i386
+endif
+
+# EFI requires -fshort-wchar, and nothing else currently uses wchar_t
+#
+CFLAGS += -fshort-wchar
+
+# We need to undefine the default macro "i386" when compiling .S
+# files, otherwise ".arch i386" translates to ".arch 1"...
+#
+CFLAGS += -Ui386
+
# Locations of utilities
#
ISOLINUX_BIN = /usr/lib/syslinux/isolinux.bin
@@ -22,85 +78,37 @@ NON_AUTO_SRCS += arch/i386/core/wince_loader.c
# unnrv2b.S is used to generate a 16-bit as well as a 32-bit object.
#
-OBJS_unnrv2b = unnrv2b unnrv2b16
-CFLAGS_unnrv2b16 = -DCODE16
+OBJS_unnrv2b = unnrv2b unnrv2b16
+CFLAGS_unnrv2b16 = -DCODE16
-# We need to undefine the default macro "i386" when compiling .S
-# files, otherwise ".arch i386" translates to ".arch 1"...
+# Include common x86 Makefile
+#
+MAKEDEPS += arch/x86/Makefile
+include arch/x86/Makefile
+
+# Include platform-specific Makefile
#
-CFLAGS_S += -Ui386
-
-# The i386 linker script
-#
-LDSCRIPT = arch/i386/scripts/i386.lds
-
-# Media types.
-#
-MEDIA += rom
-MEDIA += pxe
-MEDIA += kpxe
-MEDIA += elf
-MEDIA += elfd
-MEDIA += lmelf
-MEDIA += lmelfd
-MEDIA += lkrn
-MEDIA += bImage
-MEDIA += dsk
-MEDIA += nbi
-MEDIA += hd
-MEDIA += raw
-MEDIA += com
-MEDIA += exe
-
-# Special target for building Master Boot Record binary
-$(BIN)/mbr.bin : $(BIN)/mbr.o
- $(OBJCOPY) -O binary $< $@
+MAKEDEPS += arch/i386/Makefile.$(PLATFORM)
+include arch/i386/Makefile.$(PLATFORM)
# Some suffixes (e.g. %.fd0) are generated directly from other
# finished files (e.g. %.dsk), rather than having their own prefix.
# rule to write disk images to /dev/fd0
-NON_AUTO_MEDIA += fd0
+NON_AUTO_MEDIA += fd0
%fd0 : %dsk
- dd if=$< bs=512 conv=sync of=/dev/fd0
- sync
+ $(QM)$(ECHO) " [DD] $@"
+ $(Q)dd if=$< bs=512 conv=sync of=/dev/fd0
+ $(Q)sync
# rule to create padded disk images
-NON_AUTO_MEDIA += pdsk
+NON_AUTO_MEDIA += pdsk
%pdsk : %dsk
- cp $< $@
- $(PERL) ./util/dskpad.pl $@
-
-# rule to make a non-emulation ISO boot image
-NON_AUTO_MEDIA += iso
-%iso: %lkrn util/geniso
- ISOLINUX_BIN=$(ISOLINUX_BIN) bash util/geniso $@ $<
-
-# rule to make a floppy emulation ISO boot image
-NON_AUTO_MEDIA += liso
-%liso: %lkrn util/genliso
- bash util/genliso $@ $<
-
-# rule to make a USB disk image
-$(BIN)/usbdisk.bin : $(BIN)/usbdisk.o
- $(OBJCOPY) -O binary $< $@
-
-NON_AUTO_MEDIA += usb
-%usb: $(BIN)/usbdisk.bin %hd
- cat $^ > $@
+ $(QM)$(ECHO) " [DSKPAD] $@"
+ $(Q)cp $< $@
+ $(Q)$(PERL) ./util/dskpad.pl $@
# Add NON_AUTO_MEDIA to the media list, so that they show up in the
# output of "make"
#
MEDIA += $(NON_AUTO_MEDIA)
-
-# Shortcut to allow typing just
-# make bin-kir/%
-# rather than
-# make -f arch/i386/kir-Makefile bin-kir/%
-# for building a KEEP_IT_REAL flavour.
-#
-$(BIN)-kir/% : kir-target
- $(MAKE) -f arch/i386/kir-Makefile $(MAKECMDGOALS)
-
-.PHONY : kir-target
diff --git a/gpxe/src/arch/i386/Makefile.efi b/gpxe/src/arch/i386/Makefile.efi
new file mode 100644
index 00000000..8d651b04
--- /dev/null
+++ b/gpxe/src/arch/i386/Makefile.efi
@@ -0,0 +1,10 @@
+# -*- makefile -*- : Force emacs to use Makefile mode
+
+# Specify EFI image builder
+#
+ELF2EFI = $(ELF2EFI32)
+
+# Include generic EFI Makefile
+#
+MAKEDEPS += arch/x86/Makefile.efi
+include arch/x86/Makefile.efi
diff --git a/gpxe/src/arch/i386/Makefile.pcbios b/gpxe/src/arch/i386/Makefile.pcbios
new file mode 100644
index 00000000..64b3dac2
--- /dev/null
+++ b/gpxe/src/arch/i386/Makefile.pcbios
@@ -0,0 +1,55 @@
+# -*- makefile -*- : Force emacs to use Makefile mode
+
+# The i386 linker script
+#
+LDSCRIPT = arch/i386/scripts/i386.lds
+
+# Stop ld from complaining about our customised linker script
+#
+LDFLAGS += -N --no-check-sections
+
+# Media types.
+#
+MEDIA += rom
+MEDIA += pxe
+MEDIA += kpxe
+MEDIA += kkpxe
+MEDIA += elf
+MEDIA += elfd
+MEDIA += lmelf
+MEDIA += lmelfd
+MEDIA += lkrn
+MEDIA += bImage
+MEDIA += dsk
+MEDIA += nbi
+MEDIA += hd
+MEDIA += raw
+MEDIA += com
+MEDIA += exe
+
+# rule to make a non-emulation ISO boot image
+NON_AUTO_MEDIA += iso
+%iso: %lkrn util/geniso
+ $(QM)$(ECHO) " [GENISO] $@"
+ $(Q)ISOLINUX_BIN=$(ISOLINUX_BIN) bash util/geniso $@ $<
+
+# rule to make a floppy emulation ISO boot image
+NON_AUTO_MEDIA += liso
+%liso: %lkrn util/genliso
+ $(QM)$(ECHO) " [GENLISO] $@"
+ $(Q)bash util/genliso $@ $<
+
+# Special target for building Master Boot Record binary
+$(BIN)/mbr.bin : $(BIN)/mbr.o
+ $(QM)$(ECHO) " [OBJCOPY] $@"
+ $(Q)$(OBJCOPY) -O binary $< $@
+
+# rule to make a USB disk image
+$(BIN)/usbdisk.bin : $(BIN)/usbdisk.o
+ $(QM)$(ECHO) " [OBJCOPY] $@"
+ $(Q)$(OBJCOPY) -O binary $< $@
+
+NON_AUTO_MEDIA += usb
+%usb: $(BIN)/usbdisk.bin %hd
+ $(QM)$(ECHO) " [FINISH] $@"
+ $(Q)cat $^ > $@
diff --git a/gpxe/src/arch/i386/core/dumpregs.c b/gpxe/src/arch/i386/core/dumpregs.c
index 89426d58..82dc2184 100644
--- a/gpxe/src/arch/i386/core/dumpregs.c
+++ b/gpxe/src/arch/i386/core/dumpregs.c
@@ -1,7 +1,7 @@
#include <stdio.h>
#include <realmode.h>
-void __cdecl _dump_regs ( struct i386_all_regs *ix86 ) {
+void __asmcall _dump_regs ( struct i386_all_regs *ix86 ) {
__asm__ __volatile__ (
TEXT16_CODE ( ".globl dump_regs\n\t"
@@ -12,8 +12,8 @@ void __cdecl _dump_regs ( struct i386_all_regs *ix86 ) {
"addr32 leal 4(%%esp), %%esp\n\t"
"ret\n\t" ) : : );
- printf ( "EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx\n"
- "ESI=%08lx EDI=%08lx EBP=%08lx ESP=%08lx\n"
+ printf ( "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
+ "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
"CS=%04x SS=%04x DS=%04x ES=%04x FS=%04x GS=%04x\n",
ix86->regs.eax, ix86->regs.ebx, ix86->regs.ecx,
ix86->regs.edx, ix86->regs.esi, ix86->regs.edi,
diff --git a/gpxe/src/arch/i386/core/gdbidt.S b/gpxe/src/arch/i386/core/gdbidt.S
index 860f7b01..cd8b38a9 100644
--- a/gpxe/src/arch/i386/core/gdbidt.S
+++ b/gpxe/src/arch/i386/core/gdbidt.S
@@ -2,7 +2,7 @@
* Interrupt Descriptor Table (IDT) setup and interrupt handlers for GDB stub.
*/
-#include <virtaddr.h>
+#include <librm.h>
#define SIZEOF_I386_REGS 32
#define SIZEOF_I386_FLAGS 4
@@ -11,7 +11,7 @@
* Interrupt Descriptor Table
****************************************************************************
*/
- .section ".data16"
+ .section ".data16", "aw", @progbits
.globl idtr
idtr:
idt_limit:
@@ -68,7 +68,7 @@ idt_fixed:
* Destroys %ax, %bx, and %di.
****************************************************************************
*/
- .section ".text16"
+ .section ".text16", "ax", @progbits
.code16
.globl idt_init
idt_init:
@@ -100,7 +100,7 @@ idt_init:
* Interrupt handlers
****************************************************************************
*/
- .section ".text"
+ .section ".text", "ax", @progbits
.code32
/* POSIX signal numbers for reporting traps to GDB */
diff --git a/gpxe/src/arch/i386/core/gdbmach.c b/gpxe/src/arch/i386/core/gdbmach.c
index 5e72e4d0..97827ecb 100644
--- a/gpxe/src/arch/i386/core/gdbmach.c
+++ b/gpxe/src/arch/i386/core/gdbmach.c
@@ -19,7 +19,7 @@
#include <stddef.h>
#include <stdio.h>
#include <assert.h>
-#include <virtaddr.h>
+#include <gpxe/uaccess.h>
#include <gpxe/gdbstub.h>
#include <gdbmach.h>
@@ -142,7 +142,7 @@ static void gdbmach_enable_hwbps ( void ) {
__asm__ __volatile__ ( "movl %0, %%dr7\n" : : "r" ( dr7 ) );
}
-__cdecl void gdbmach_handler ( int signo, gdbreg_t *regs ) {
+__asmcall void gdbmach_handler ( int signo, gdbreg_t *regs ) {
gdbmach_disable_hwbps();
gdbstub_handler ( signo, regs );
gdbmach_enable_hwbps();
diff --git a/gpxe/src/arch/i386/core/nap.c b/gpxe/src/arch/i386/core/nap.c
deleted file mode 100644
index 12bb5699..00000000
--- a/gpxe/src/arch/i386/core/nap.c
+++ /dev/null
@@ -1,12 +0,0 @@
-
-#include <realmode.h>
-#include <bios.h>
-
-/**************************************************************************
- * Save power by halting the CPU until the next interrupt
- **************************************************************************/
-void cpu_nap ( void ) {
- __asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
- "hlt\n\t"
- "cli\n\t" ) : : );
-}
diff --git a/gpxe/src/arch/i386/core/pic8259.c b/gpxe/src/arch/i386/core/pic8259.c
index defe2e7d..8a0433dd 100644
--- a/gpxe/src/arch/i386/core/pic8259.c
+++ b/gpxe/src/arch/i386/core/pic8259.c
@@ -16,6 +16,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <gpxe/io.h>
#include <pic8259.h>
/** @file
diff --git a/gpxe/src/arch/i386/core/rdtsc_timer.c b/gpxe/src/arch/i386/core/rdtsc_timer.c
new file mode 100644
index 00000000..443c8ada
--- /dev/null
+++ b/gpxe/src/arch/i386/core/rdtsc_timer.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/** @file
+ *
+ * RDTSC timer
+ *
+ */
+
+#include <assert.h>
+#include <gpxe/timer.h>
+#include <gpxe/timer2.h>
+
+/**
+ * Number of TSC ticks per microsecond
+ *
+ * This is calibrated on the first use of the timer.
+ */
+static unsigned long rdtsc_ticks_per_usec;
+
+/**
+ * Delay for a fixed number of microseconds
+ *
+ * @v usecs Number of microseconds for which to delay
+ */
+static void rdtsc_udelay ( unsigned long usecs ) {
+ unsigned long start;
+ unsigned long elapsed;
+
+ /* Sanity guard, since we may divide by this */
+ if ( ! usecs )
+ usecs = 1;
+
+ start = currticks();
+ if ( rdtsc_ticks_per_usec ) {
+ /* Already calibrated; busy-wait until done */
+ do {
+ elapsed = ( currticks() - start );
+ } while ( elapsed < ( usecs * rdtsc_ticks_per_usec ) );
+ } else {
+ /* Not yet calibrated; use timer2 and calibrate
+ * based on result.
+ */
+ timer2_udelay ( usecs );
+ elapsed = ( currticks() - start );
+ rdtsc_ticks_per_usec = ( elapsed / usecs );
+ DBG ( "RDTSC timer calibrated: %ld ticks in %ld usecs "
+ "(%ld MHz)\n", elapsed, usecs,
+ ( rdtsc_ticks_per_usec << TSC_SHIFT ) );
+ }
+}
+
+/**
+ * Get number of ticks per second
+ *
+ * @ret ticks_per_sec Number of ticks per second
+ */
+static unsigned long rdtsc_ticks_per_sec ( void ) {
+
+ /* Calibrate timer, if not already done */
+ if ( ! rdtsc_ticks_per_usec )
+ udelay ( 1 );
+
+ /* Sanity check */
+ assert ( rdtsc_ticks_per_usec != 0 );
+
+ return ( rdtsc_ticks_per_usec * 1000 * 1000 );
+}
+
+PROVIDE_TIMER ( rdtsc, udelay, rdtsc_udelay );
+PROVIDE_TIMER_INLINE ( rdtsc, currticks );
+PROVIDE_TIMER ( rdtsc, ticks_per_sec, rdtsc_ticks_per_sec );
diff --git a/gpxe/src/arch/i386/core/relocate.c b/gpxe/src/arch/i386/core/relocate.c
index aa58ad65..bdc8498e 100644
--- a/gpxe/src/arch/i386/core/relocate.c
+++ b/gpxe/src/arch/i386/core/relocate.c
@@ -1,4 +1,4 @@
-#include <io.h>
+#include <gpxe/io.h>
#include <registers.h>
#include <gpxe/memmap.h>
@@ -18,8 +18,8 @@ extern char _max_align[];
#define max_align ( ( unsigned int ) _max_align )
/* Linker symbols */
-extern char _text[];
-extern char _end[];
+extern char _textdata[];
+extern char _etextdata[];
/* within 1MB of 4GB is too close.
* MAX_ADDR is the maximum address we can easily do DMA to.
@@ -39,7 +39,7 @@ extern char _end[];
* address space, and returns the physical address of the new location
* to the prefix in %edi.
*/
-__cdecl void relocate ( struct i386_all_regs *ix86 ) {
+__asmcall void relocate ( struct i386_all_regs *ix86 ) {
struct memory_map memmap;
unsigned long start, end, size, padded_size;
unsigned long new_start, new_end;
@@ -47,8 +47,8 @@ __cdecl void relocate ( struct i386_all_regs *ix86 ) {
/* Get memory map and current location */
get_memmap ( &memmap );
- start = virt_to_phys ( _text );
- end = virt_to_phys ( _end );
+ start = virt_to_phys ( _textdata );
+ end = virt_to_phys ( _etextdata );
size = ( end - start );
padded_size = ( size + max_align - 1 );
diff --git a/gpxe/src/arch/i386/core/stack.S b/gpxe/src/arch/i386/core/stack.S
index c2d138aa..da66d239 100644
--- a/gpxe/src/arch/i386/core/stack.S
+++ b/gpxe/src/arch/i386/core/stack.S
@@ -4,7 +4,7 @@
* Internal stack
****************************************************************************
*/
- .section ".stack"
+ .section ".stack", "aw", @nobits
.align 8
.globl _stack
_stack:
diff --git a/gpxe/src/arch/i386/core/stack16.S b/gpxe/src/arch/i386/core/stack16.S
index 3380a083..d1251f06 100644
--- a/gpxe/src/arch/i386/core/stack16.S
+++ b/gpxe/src/arch/i386/core/stack16.S
@@ -4,7 +4,7 @@
* Internal stack
****************************************************************************
*/
- .section ".stack16"
+ .section ".stack16", "aw", @nobits
.align 8
.globl _stack16
_stack16:
diff --git a/gpxe/src/arch/i386/core/start32.S b/gpxe/src/arch/i386/core/start32.S
deleted file mode 100644
index 37ef5eb9..00000000
--- a/gpxe/src/arch/i386/core/start32.S
+++ /dev/null
@@ -1,325 +0,0 @@
-#include "virtaddr.h"
-
- .equ MSR_K6_EFER, 0xC0000080
- .equ EFER_LME, 0x00000100
- .equ X86_CR4_PAE, 0x00000020
- .equ CR0_PG, 0x80000000
-
-#ifdef GAS291
-#define DATA32 data32;
-#define ADDR32 addr32;
-#define LJMPI(x) ljmp x
-#else
-#define DATA32 data32
-#define ADDR32 addr32
-/* newer GAS295 require #define LJMPI(x) ljmp *x */
-#define LJMPI(x) ljmp x
-#endif
-
-/*
- * NOTE: if you write a subroutine that is called from C code (gcc/egcs),
- * then you only have to take care of %ebx, %esi, %edi and %ebp. These
- * registers must not be altered under any circumstance. All other registers
- * may be clobbered without any negative side effects. If you don't follow
- * this rule then you'll run into strange effects that only occur on some
- * gcc versions (because the register allocator may use different registers).
- *
- * All the data32 prefixes for the ljmp instructions are necessary, because
- * the assembler emits code with a relocation address of 0. This means that
- * all destinations are initially negative, which the assembler doesn't grok,
- * because for some reason negative numbers don't fit into 16 bits. The addr32
- * prefixes are there for the same reasons, because otherwise the memory
- * references are only 16 bit wide. Theoretically they are all superfluous.
- * One last note about prefixes: the data32 prefixes on all call _real_to_prot
- * instructions could be removed if the _real_to_prot function is changed to
- * deal correctly with 16 bit return addresses. I tried it, but failed.
- */
-
- .text
- .arch i386
- .code32
-
- /* This is a struct os_entry_regs */
- .globl os_regs
-os_regs: .space 56
-
-/**************************************************************************
-XSTART32 - Transfer control to the kernel just loaded
-**************************************************************************/
- .globl xstart32
-xstart32:
- /* Save the callee save registers */
- movl %ebp, os_regs + 32
- movl %esi, os_regs + 36
- movl %edi, os_regs + 40
- movl %ebx, os_regs + 44
-
- /* save the return address */
- popl %eax
- movl %eax, os_regs + 48
-
- /* save the stack pointer */
- movl %esp, os_regs + 52
-
- /* Get the new destination address */
- popl %ecx
-
- /* Store the physical address of xend on the stack */
- movl $xend32, %ebx
- addl virt_offset, %ebx
- pushl %ebx
-
- /* Store the destination address on the stack */
- pushl $PHYSICAL_CS
- pushl %ecx
-
- /* Cache virt_offset */
- movl virt_offset, %ebp
-
- /* Switch to using physical addresses */
- call _virt_to_phys
-
- /* Save the target stack pointer */
- movl %esp, os_regs + 12(%ebp)
- leal os_regs(%ebp), %esp
-
- /* Store the pointer to os_regs */
- movl %esp, os_regs_ptr(%ebp)
-
- /* Load my new registers */
- popal
- movl (-32 + 12)(%esp), %esp
-
- /* Jump to the new kernel
- * The lret switches to a flat code segment
- */
- lret
-
- .balign 4
- .globl xend32
-xend32:
- /* Fixup %eflags */
- nop
- cli
- cld
-
- /* Load %esp with &os_regs + virt_offset */
- .byte 0xbc /* movl $0, %esp */
-os_regs_ptr:
- .long 0
-
- /* Save the result registers */
- addl $32, %esp
- pushal
-
- /* Compute virt_offset */
- movl %esp, %ebp
- subl $os_regs, %ebp
-
- /* Load the stack pointer and convert it to physical address */
- movl 52(%esp), %esp
- addl %ebp, %esp
-
- /* Enable the virtual addresses */
- leal _phys_to_virt(%ebp), %eax
- call *%eax
-
- /* Restore the callee save registers */
- movl os_regs + 32, %ebp
- movl os_regs + 36, %esi
- movl os_regs + 40, %edi
- movl os_regs + 44, %ebx
- movl os_regs + 48, %edx
- movl os_regs + 52, %esp
-
- /* Get the C return value */
- movl os_regs + 28, %eax
-
- jmpl *%edx
-
-#ifdef CONFIG_X86_64
- .arch sledgehammer
-/**************************************************************************
-XSTART_lm - Transfer control to the kernel just loaded in long mode
-**************************************************************************/
- .globl xstart_lm
-xstart_lm:
- /* Save the callee save registers */
- pushl %ebp
- pushl %esi
- pushl %edi
- pushl %ebx
-
- /* Cache virt_offset && (virt_offset & 0xfffff000) */
- movl virt_offset, %ebp
- movl %ebp, %ebx
- andl $0xfffff000, %ebx
-
- /* Switch to using physical addresses */
- call _virt_to_phys
-
- /* Initialize the page tables */
- /* Level 4 */
- leal 0x23 + pgt_level3(%ebx), %eax
- leal pgt_level4(%ebx), %edi
- movl %eax, (%edi)
-
- /* Level 3 */
- leal 0x23 + pgt_level2(%ebx), %eax
- leal pgt_level3(%ebx), %edi
- movl %eax, 0x00(%edi)
- addl $4096, %eax
- movl %eax, 0x08(%edi)
- addl $4096, %eax
- movl %eax, 0x10(%edi)
- addl $4096, %eax
- movl %eax, 0x18(%edi)
-
- /* Level 2 */
- movl $0xe3, %eax
- leal pgt_level2(%ebx), %edi
- leal 16384(%edi), %esi
-pgt_level2_loop:
- movl %eax, (%edi)
- addl $8, %edi
- addl $0x200000, %eax
- cmp %esi, %edi
- jne pgt_level2_loop
-
- /* Point at the x86_64 page tables */
- leal pgt_level4(%ebx), %edi
- movl %edi, %cr3
-
-
- /* Setup for the return from 64bit mode */
- /* 64bit align the stack */
- movl %esp, %ebx /* original stack pointer + 16 */
- andl $0xfffffff8, %esp
-
- /* Save original stack pointer + 16 */
- pushl %ebx
-
- /* Save virt_offset */
- pushl %ebp
-
- /* Setup for the jmp to 64bit long mode */
- leal start_lm(%ebp), %eax
- movl %eax, 0x00 + start_lm_addr(%ebp)
- movl $LM_CODE_SEG, %eax
- movl %eax, 0x04 + start_lm_addr(%ebp)
-
- /* Setup for the jump out of 64bit long mode */
- leal end_lm(%ebp), %eax
- movl %eax, 0x00 + end_lm_addr(%ebp)
- movl $FLAT_CODE_SEG, %eax
- movl %eax, 0x04 + end_lm_addr(%ebp)
-
- /* Enable PAE mode */
- movl %cr4, %eax
- orl $X86_CR4_PAE, %eax
- movl %eax, %cr4
-
- /* Enable long mode */
- movl $MSR_K6_EFER, %ecx
- rdmsr
- orl $EFER_LME, %eax
- wrmsr
-
- /* Start paging, entering 32bit compatiblity mode */
- movl %cr0, %eax
- orl $CR0_PG, %eax
- movl %eax, %cr0
-
- /* Enter 64bit long mode */
- ljmp *start_lm_addr(%ebp)
- .code64
-start_lm:
- /* Load 64bit data segments */
- movl $LM_DATA_SEG, %eax
- movl %eax, %ds
- movl %eax, %es
- movl %eax, %ss
-
- andq $0xffffffff, %rbx
- /* Get the address to jump to */
- movl 20(%rbx), %edx
- andq $0xffffffff, %rdx
-
- /* Get the argument pointer */
- movl 24(%rbx), %ebx
- andq $0xffffffff, %rbx
-
- /* Jump to the 64bit code */
- call *%rdx
-
- /* Preserve the result */
- movl %eax, %edx
-
- /* Fixup %eflags */
- cli
- cld
-
- /* Switch to 32bit compatibility mode */
- ljmp *end_lm_addr(%rip)
-
- .code32
-end_lm:
- /* Disable paging */
- movl %cr0, %eax
- andl $~CR0_PG, %eax
- movl %eax, %cr0
-
- /* Disable long mode */
- movl $MSR_K6_EFER, %ecx
- rdmsr
- andl $~EFER_LME, %eax
- wrmsr
-
- /* Disable PAE */
- movl %cr4, %eax
- andl $~X86_CR4_PAE, %eax
- movl %eax, %cr4
-
- /* Compute virt_offset */
- popl %ebp
-
- /* Compute the original stack pointer + 16 */
- popl %ebx
- movl %ebx, %esp
-
- /* Enable the virtual addresses */
- leal _phys_to_virt(%ebp), %eax
- call *%eax
-
- /* Restore the callee save registers */
- popl %ebx
- popl %esi
- popl %edi
- popl %ebp
-
- /* Get the C return value */
- movl %edx, %eax
-
- /* Return */
- ret
-
- .arch i386
-#endif /* CONFIG_X86_64 */
-
-#ifdef CONFIG_X86_64
- .section ".bss"
- .p2align 12
- /* Include a dummy space in case we are loaded badly aligned */
- .space 4096
- /* Reserve enough space for a page table convering 4GB with 2MB pages */
-pgt_level4:
- .space 4096
-pgt_level3:
- .space 4096
-pgt_level2:
- .space 16384
-start_lm_addr:
- .space 8
-end_lm_addr:
- .space 8
-#endif
diff --git a/gpxe/src/arch/i386/core/i386_timer.c b/gpxe/src/arch/i386/core/timer2.c
index 8f90ae05..bb589ecc 100644
--- a/gpxe/src/arch/i386/core/i386_timer.c
+++ b/gpxe/src/arch/i386/core/timer2.c
@@ -12,12 +12,11 @@
*/
#include <stddef.h>
-#include <bits/timer2.h>
-#include <gpxe/timer.h>
-#include <io.h>
+#include <gpxe/timer2.h>
+#include <gpxe/io.h>
/* Timers tick over at this rate */
-#define TIMER2_TICK_RATE 1193180U
+#define TIMER2_TICKS_PER_SEC 1193180U
/* Parallel Peripheral Controller Port B */
#define PPC_PORTB 0x61
@@ -52,8 +51,7 @@
#define BINARY_COUNT 0x00
#define BCD_COUNT 0x01
-static void load_timer2(unsigned int ticks)
-{
+static void load_timer2 ( unsigned int ticks ) {
/*
* Now let's take care of PPC channel 2
*
@@ -75,15 +73,13 @@ static void load_timer2(unsigned int ticks)
outb(ticks >> 8, TIMER2_PORT);
}
-static int timer2_running(void)
-{
+static int timer2_running ( void ) {
return ((inb(PPC_PORTB) & PPCB_T2OUT) == 0);
}
-void i386_timer2_udelay(unsigned int usecs)
-{
- load_timer2((usecs * TIMER2_TICK_RATE)/USECS_IN_SEC);
- while (timer2_running())
- ;
+void timer2_udelay ( unsigned long usecs ) {
+ load_timer2 ( ( usecs * TIMER2_TICKS_PER_SEC ) / ( 1000 * 1000 ) );
+ while (timer2_running()) {
+ /* Do nothing */
+ }
}
-
diff --git a/gpxe/src/arch/i386/core/video_subr.c b/gpxe/src/arch/i386/core/video_subr.c
index bf82cc61..c821cd02 100644
--- a/gpxe/src/arch/i386/core/video_subr.c
+++ b/gpxe/src/arch/i386/core/video_subr.c
@@ -7,7 +7,7 @@
#include "stddef.h"
#include "string.h"
-#include "io.h"
+#include <gpxe/io.h>
#include "console.h"
#include <gpxe/init.h>
#include "vga.h"
diff --git a/gpxe/src/arch/i386/core/virtaddr.S b/gpxe/src/arch/i386/core/virtaddr.S
index 5d762375..cf6da4f6 100644
--- a/gpxe/src/arch/i386/core/virtaddr.S
+++ b/gpxe/src/arch/i386/core/virtaddr.S
@@ -4,7 +4,7 @@
*
*/
-#include "virtaddr.h"
+#include "librm.h"
.arch i386
.text
diff --git a/gpxe/src/arch/i386/core/x86_io.c b/gpxe/src/arch/i386/core/x86_io.c
new file mode 100644
index 00000000..424a96cc
--- /dev/null
+++ b/gpxe/src/arch/i386/core/x86_io.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <gpxe/io.h>
+#include <gpxe/x86_io.h>
+
+/** @file
+ *
+ * gPXE I/O API for x86
+ *
+ */
+
+/**
+ * Read 64-bit qword from memory-mapped device
+ *
+ * @v io_addr I/O address
+ * @ret data Value read
+ *
+ * This routine uses MMX instructions.
+ */
+static uint64_t x86_readq ( volatile uint64_t *io_addr ) {
+ uint64_t data;
+ __asm__ __volatile__ ( "pushl %%edx\n\t"
+ "pushl %%eax\n\t"
+ "movq (%1), %%mm0\n\t"
+ "movq %%mm0, (%%esp)\n\t"
+ "popl %%eax\n\t"
+ "popl %%edx\n\t"
+ "emms\n\t"
+ : "=A" ( data ) : "r" ( io_addr ) );
+ return data;
+}
+
+/**
+ * Write 64-bit qword to memory-mapped device
+ *
+ * @v data Value to write
+ * @v io_addr I/O address
+ *
+ * This routine uses MMX instructions.
+ */
+static void x86_writeq ( uint64_t data, volatile uint64_t *io_addr ) {
+ __asm__ __volatile__ ( "pushl %%edx\n\t"
+ "pushl %%eax\n\t"
+ "movq (%%esp), %%mm0\n\t"
+ "movq %%mm0, (%1)\n\t"
+ "popl %%eax\n\t"
+ "popl %%edx\n\t"
+ "emms\n\t"
+ : : "A" ( data ), "r" ( io_addr ) );
+}
+
+PROVIDE_IOAPI_INLINE ( x86, phys_to_bus );
+PROVIDE_IOAPI_INLINE ( x86, bus_to_phys );
+PROVIDE_IOAPI_INLINE ( x86, ioremap );
+PROVIDE_IOAPI_INLINE ( x86, iounmap );
+PROVIDE_IOAPI_INLINE ( x86, io_to_bus );
+PROVIDE_IOAPI_INLINE ( x86, readb );
+PROVIDE_IOAPI_INLINE ( x86, readw );
+PROVIDE_IOAPI_INLINE ( x86, readl );
+PROVIDE_IOAPI ( x86, readq, x86_readq );
+PROVIDE_IOAPI_INLINE ( x86, writeb );
+PROVIDE_IOAPI_INLINE ( x86, writew );
+PROVIDE_IOAPI_INLINE ( x86, writel );
+PROVIDE_IOAPI ( x86, writeq, x86_writeq );
+PROVIDE_IOAPI_INLINE ( x86, inb );
+PROVIDE_IOAPI_INLINE ( x86, inw );
+PROVIDE_IOAPI_INLINE ( x86, inl );
+PROVIDE_IOAPI_INLINE ( x86, outb );
+PROVIDE_IOAPI_INLINE ( x86, outw );
+PROVIDE_IOAPI_INLINE ( x86, outl );
+PROVIDE_IOAPI_INLINE ( x86, insb );
+PROVIDE_IOAPI_INLINE ( x86, insw );
+PROVIDE_IOAPI_INLINE ( x86, insl );
+PROVIDE_IOAPI_INLINE ( x86, outsb );
+PROVIDE_IOAPI_INLINE ( x86, outsw );
+PROVIDE_IOAPI_INLINE ( x86, outsl );
+PROVIDE_IOAPI_INLINE ( x86, iodelay );
+PROVIDE_IOAPI_INLINE ( x86, mb );
diff --git a/gpxe/src/arch/i386/drivers/net/undiisr.S b/gpxe/src/arch/i386/drivers/net/undiisr.S
index a6c6c381..2b31b414 100644
--- a/gpxe/src/arch/i386/drivers/net/undiisr.S
+++ b/gpxe/src/arch/i386/drivers/net/undiisr.S
@@ -10,11 +10,9 @@
.text
.arch i386
- .section ".text16", "ax", @progbits
- .section ".data16", "aw", @progbits
.code16
- .section ".text16"
+ .section ".text16", "ax", @progbits
.globl undiisr
undiisr:
@@ -75,7 +73,7 @@ exit: /* Restore registers and return */
popw %ds
iret
- .section ".data16"
+ .section ".data16", "aw", @progbits
undinet_params:
status: .word 0
funcflag: .word 0
diff --git a/gpxe/src/arch/i386/drivers/net/undinet.c b/gpxe/src/arch/i386/drivers/net/undinet.c
index 9576ad60..d6db6f7c 100644
--- a/gpxe/src/arch/i386/drivers/net/undinet.c
+++ b/gpxe/src/arch/i386/drivers/net/undinet.c
@@ -23,6 +23,7 @@
#include <biosint.h>
#include <pnpbios.h>
#include <basemem_packet.h>
+#include <gpxe/io.h>
#include <gpxe/iobuf.h>
#include <gpxe/netdevice.h>
#include <gpxe/if_ether.h>
@@ -481,8 +482,7 @@ static void undinet_poll ( struct net_device *netdev ) {
undi_isr.Frame.offset, frag_len );
if ( iob_len ( iobuf ) == len ) {
/* Whole packet received; deliver it */
- netdev_rx ( netdev, iobuf );
- iobuf = NULL;
+ netdev_rx ( netdev, iob_disown ( iobuf ) );
/* Etherboot 5.4 fails to return all packets
* under mild load; pretend it retriggered.
*/
@@ -554,7 +554,7 @@ static int undinet_open ( struct net_device *netdev ) {
DBGC ( undinic, "UNDINIC %p opened\n", undinic );
return 0;
-err:
+ err:
undinet_close ( netdev );
return rc;
}
@@ -595,10 +595,6 @@ static void undinet_close ( struct net_device *netdev ) {
/* Disable interrupt and unhook ISR */
disable_irq ( undinic->irq );
undinet_unhook_isr ( undinic->irq );
-#if 0
- enable_irq ( undinic->irq );
- send_eoi ( undinic->irq );
-#endif
DBGC ( undinic, "UNDINIC %p closed\n", undinic );
}
@@ -642,9 +638,7 @@ int undinet_probe ( struct undi_device *undi ) {
struct s_PXENV_UNDI_GET_IFACE_INFO undi_iface;
struct s_PXENV_UNDI_SHUTDOWN undi_shutdown;
struct s_PXENV_UNDI_CLEANUP undi_cleanup;
-#if 0
struct s_PXENV_STOP_UNDI stop_undi;
-#endif
int rc;
/* Allocate net device */
@@ -671,20 +665,23 @@ int undinet_probe ( struct undi_device *undi ) {
&start_undi,
sizeof ( start_undi ) ) ) != 0 )
goto err_start_undi;
- /* Bring up UNDI stack */
+ }
+ undi->flags |= UNDI_FL_STARTED;
+
+ /* Bring up UNDI stack */
+ if ( ! ( undi->flags & UNDI_FL_INITIALIZED ) ) {
memset ( &undi_startup, 0, sizeof ( undi_startup ) );
if ( ( rc = undinet_call ( undinic, PXENV_UNDI_STARTUP,
&undi_startup,
sizeof ( undi_startup ) ) ) != 0 )
- goto err_undi_startup;
-
+ goto err_undi_startup;
memset ( &undi_initialize, 0, sizeof ( undi_initialize ) );
if ( ( rc = undinet_call ( undinic, PXENV_UNDI_INITIALIZE,
&undi_initialize,
- sizeof ( undi_initialize ) ) ) != 0 )
- goto err_undi_initialize;
+ sizeof ( undi_initialize ))) != 0 )
+ goto err_undi_initialize;
}
- undi->flags |= UNDI_FL_STARTED;
+ undi->flags |= UNDI_FL_INITIALIZED;
/* Get device information */
memset ( &undi_info, 0, sizeof ( undi_info ) );
@@ -707,7 +704,7 @@ int undinet_probe ( struct undi_device *undi ) {
&undi_iface,
sizeof ( undi_iface ) ) ) != 0 )
goto err_undi_get_iface_info;
- DBGC ( undinic, "UNDINIC %p has type %s and link speed %ld\n",
+ DBGC ( undinic, "UNDINIC %p has type %s and link speed %d\n",
undinic, undi_iface.IfaceType, undi_iface.LinkSpeed );
if ( strncmp ( ( ( char * ) undi_iface.IfaceType ), "Etherboot",
sizeof ( undi_iface.IfaceType ) ) == 0 ) {
@@ -731,7 +728,6 @@ int undinet_probe ( struct undi_device *undi ) {
err_bad_irq:
err_undi_get_information:
err_undi_initialize:
-
/* Shut down UNDI stack */
memset ( &undi_shutdown, 0, sizeof ( undi_shutdown ) );
undinet_call ( undinic, PXENV_UNDI_SHUTDOWN, &undi_shutdown,
@@ -739,13 +735,13 @@ int undinet_probe ( struct undi_device *undi ) {
memset ( &undi_cleanup, 0, sizeof ( undi_cleanup ) );
undinet_call ( undinic, PXENV_UNDI_CLEANUP, &undi_cleanup,
sizeof ( undi_cleanup ) );
+ undi->flags &= ~UNDI_FL_INITIALIZED;
err_undi_startup:
-#if 0
/* Unhook UNDI stack */
memset ( &stop_undi, 0, sizeof ( stop_undi ) );
undinet_call ( undinic, PXENV_STOP_UNDI, &stop_undi,
sizeof ( stop_undi ) );
-#endif
+ undi->flags &= ~UNDI_FL_STARTED;
err_start_undi:
netdev_nullify ( netdev );
netdev_put ( netdev );
@@ -761,30 +757,33 @@ int undinet_probe ( struct undi_device *undi ) {
void undinet_remove ( struct undi_device *undi ) {
struct net_device *netdev = undi_get_drvdata ( undi );
struct undi_nic *undinic = netdev->priv;
-#if 0
struct s_PXENV_UNDI_SHUTDOWN undi_shutdown;
struct s_PXENV_UNDI_CLEANUP undi_cleanup;
struct s_PXENV_STOP_UNDI stop_undi;
-#endif
/* Unregister net device */
unregister_netdev ( netdev );
- /* Shut down UNDI stack */
-#if 0
- memset ( &undi_shutdown, 0, sizeof ( undi_shutdown ) );
- undinet_call ( undinic, PXENV_UNDI_SHUTDOWN, &undi_shutdown,
- sizeof ( undi_shutdown ) );
- memset ( &undi_cleanup, 0, sizeof ( undi_cleanup ) );
- undinet_call ( undinic, PXENV_UNDI_CLEANUP, &undi_cleanup,
- sizeof ( undi_cleanup ) );
-
- /* Unhook UNDI stack */
- memset ( &stop_undi, 0, sizeof ( stop_undi ) );
- undinet_call ( undinic, PXENV_STOP_UNDI, &stop_undi,
- sizeof ( stop_undi ) );
- undi->flags &= ~UNDI_FL_STARTED;
-#endif
+ /* If we are preparing for an OS boot, or if we cannot exit
+ * via the PXE stack, then shut down the PXE stack.
+ */
+ if ( ! ( undi->flags & UNDI_FL_KEEP_ALL ) ) {
+
+ /* Shut down UNDI stack */
+ memset ( &undi_shutdown, 0, sizeof ( undi_shutdown ) );
+ undinet_call ( undinic, PXENV_UNDI_SHUTDOWN, &undi_shutdown,
+ sizeof ( undi_shutdown ) );
+ memset ( &undi_cleanup, 0, sizeof ( undi_cleanup ) );
+ undinet_call ( undinic, PXENV_UNDI_CLEANUP, &undi_cleanup,
+ sizeof ( undi_cleanup ) );
+ undi->flags &= ~UNDI_FL_INITIALIZED;
+
+ /* Unhook UNDI stack */
+ memset ( &stop_undi, 0, sizeof ( stop_undi ) );
+ undinet_call ( undinic, PXENV_STOP_UNDI, &stop_undi,
+ sizeof ( stop_undi ) );
+ undi->flags &= ~UNDI_FL_STARTED;
+ }
/* Clear entry point */
memset ( &undinet_entry_point, 0, sizeof ( undinet_entry_point ) );
diff --git a/gpxe/src/arch/i386/drivers/net/undionly.c b/gpxe/src/arch/i386/drivers/net/undionly.c
index ee361493..4cdce677 100644
--- a/gpxe/src/arch/i386/drivers/net/undionly.c
+++ b/gpxe/src/arch/i386/drivers/net/undionly.c
@@ -20,6 +20,7 @@
#include <stdlib.h>
#include <string.h>
#include <gpxe/device.h>
+#include <gpxe/init.h>
#include <undi.h>
#include <undinet.h>
#include <undipreload.h>
@@ -107,3 +108,20 @@ struct root_device undi_root_device __root_device = {
.dev = { .name = "UNDI" },
.driver = &undi_root_driver,
};
+
+/**
+ * Prepare for exit
+ *
+ * @v flags Shutdown flags
+ */
+static void undionly_shutdown ( int flags ) {
+ /* If we are shutting down to boot an OS, clear the "keep PXE
+ * stack" flag.
+ */
+ if ( flags & SHUTDOWN_BOOT )
+ preloaded_undi.flags &= ~UNDI_FL_KEEP_ALL;
+}
+
+struct startup_fn startup_undionly __startup_fn ( STARTUP_LATE ) = {
+ .shutdown = undionly_shutdown,
+};
diff --git a/gpxe/src/arch/i386/drivers/net/undirom.c b/gpxe/src/arch/i386/drivers/net/undirom.c
index d40fcd35..e5782781 100644
--- a/gpxe/src/arch/i386/drivers/net/undirom.c
+++ b/gpxe/src/arch/i386/drivers/net/undirom.c
@@ -52,7 +52,7 @@ static int undirom_parse_pxeromid ( struct undi_rom *undirom,
sizeof ( undi_rom_id ) );
if ( undi_rom_id.Signature != UNDI_ROM_ID_SIGNATURE ) {
DBGC ( undirom, "UNDIROM %p has bad PXE ROM ID signature "
- "%08lx\n", undirom, undi_rom_id.Signature );
+ "%08x\n", undirom, undi_rom_id.Signature );
return -EINVAL;
}
@@ -94,7 +94,7 @@ static int undirom_parse_pcirheader ( struct undi_rom *undirom,
sizeof ( pcir_header ) );
if ( pcir_header.signature != PCIR_SIGNATURE ) {
DBGC ( undirom, "UNDIROM %p has bad PCI expansion header "
- "signature %08lx\n", undirom, pcir_header.signature );
+ "signature %08x\n", undirom, pcir_header.signature );
return -EINVAL;
}
diff --git a/gpxe/src/arch/i386/drivers/timer_bios.c b/gpxe/src/arch/i386/drivers/timer_bios.c
deleted file mode 100644
index f9caf8d9..00000000
--- a/gpxe/src/arch/i386/drivers/timer_bios.c
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Etherboot routines for PCBIOS firmware.
- *
- * Body of routines taken from old pcbios.S
- */
-
-#include <gpxe/init.h>
-#include <gpxe/timer.h>
-#include <stdio.h>
-#include <realmode.h>
-#include <bios.h>
-#include <bits/timer2.h>
-
-/* A bit faster actually, but we don't care. */
-#define TIMER2_TICKS_PER_SEC 18
-
-/*
- * Use direct memory access to BIOS variables, longword 0040:006C (ticks
- * today) and byte 0040:0070 (midnight crossover flag) instead of calling
- * timeofday BIOS interrupt.
- */
-
-static tick_t bios_currticks ( void ) {
- static int days = 0;
- uint32_t ticks;
- uint8_t midnight;
-
- /* Re-enable interrupts so that the timer interrupt can occur */
- __asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
- "nop\n\t"
- "nop\n\t"
- "cli\n\t" ) : : );
-
- get_real ( ticks, BDA_SEG, 0x006c );
- get_real ( midnight, BDA_SEG, 0x0070 );
-
- if ( midnight ) {
- midnight = 0;
- put_real ( midnight, BDA_SEG, 0x0070 );
- days += 0x1800b0;
- }
-
- return ( (days + ticks) * (USECS_IN_SEC / TIMER2_TICKS_PER_SEC) );
-}
-
-static int bios_ts_init(void)
-{
- DBG("BIOS timer installed\n");
- return 0;
-}
-
-struct timer bios_ts __timer ( 02 ) = {
- .init = bios_ts_init,
- .udelay = i386_timer2_udelay,
- .currticks = bios_currticks,
-};
-
diff --git a/gpxe/src/arch/i386/drivers/timer_rdtsc.c b/gpxe/src/arch/i386/drivers/timer_rdtsc.c
deleted file mode 100644
index 09b7df2f..00000000
--- a/gpxe/src/arch/i386/drivers/timer_rdtsc.c
+++ /dev/null
@@ -1,69 +0,0 @@
-
-#include <gpxe/init.h>
-#include <gpxe/timer.h>
-#include <errno.h>
-#include <stdio.h>
-#include <bits/cpu.h>
-#include <bits/timer2.h>
-#include <io.h>
-
-
-#define rdtsc(low,high) \
- __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
-
-#define rdtscll(val) \
- __asm__ __volatile__ ("rdtsc" : "=A" (val))
-
-
-/* Measure how many clocks we get in one microsecond */
-static inline uint64_t calibrate_tsc(void)
-{
-
- uint64_t rdtsc_start;
- uint64_t rdtsc_end;
-
- rdtscll(rdtsc_start);
- i386_timer2_udelay(USECS_IN_MSEC);
- rdtscll(rdtsc_end);
-
- return (rdtsc_end - rdtsc_start) / USECS_IN_MSEC;
-}
-
-static uint32_t clocks_per_usec = 0;
-
-/* We measure time in microseconds. */
-static tick_t rdtsc_currticks(void)
-{
- uint64_t clocks;
-
- /* Read the Time Stamp Counter */
- rdtscll(clocks);
-
- return clocks / clocks_per_usec;
-}
-
-static int rdtsc_ts_init(void)
-{
-
- struct cpuinfo_x86 cpu_info;
-
- get_cpuinfo(&cpu_info);
- if (cpu_info.features & X86_FEATURE_TSC) {
- clocks_per_usec= calibrate_tsc();
- if (clocks_per_usec) {
- DBG("RDTSC ticksource installed. CPU running at %ld Mhz\n",
- clocks_per_usec);
- return 0;
- }
- }
-
- DBG("RDTSC ticksource not available on this machine.\n");
- return -ENODEV;
-}
-
-struct timer rdtsc_ts __timer (01) = {
- .init = rdtsc_ts_init,
- .udelay = generic_currticks_udelay,
- .currticks = rdtsc_currticks,
-};
-
diff --git a/gpxe/src/arch/i386/firmware/pcbios/bios_console.c b/gpxe/src/arch/i386/firmware/pcbios/bios_console.c
index dcb0462a..91363772 100644
--- a/gpxe/src/arch/i386/firmware/pcbios/bios_console.c
+++ b/gpxe/src/arch/i386/firmware/pcbios/bios_console.c
@@ -193,13 +193,14 @@ static const char *ansi_input = "";
* dense range, so subtracting a constant and treating them as offsets
* into an array works efficiently.
*/
-#define BIOS_KEY_MIN 0x47
+#define BIOS_KEY_MIN 0x42
/** Offset into list of interesting BIOS scancodes */
#define BIOS_KEY(scancode) ( (scancode) - BIOS_KEY_MIN )
/** Mapping from BIOS scan codes to ANSI escape sequences */
static const char *ansi_sequences[] = {
+ [ BIOS_KEY ( 0x42 ) ] = "[19~", /* F8 (required for PXE) */
[ BIOS_KEY ( 0x47 ) ] = "[H", /* Home */
[ BIOS_KEY ( 0x48 ) ] = "[A", /* Up arrow */
[ BIOS_KEY ( 0x4b ) ] = "[D", /* Left arrow */
@@ -222,6 +223,7 @@ static const char * scancode_to_ansi_seq ( unsigned int scancode ) {
sizeof ( ansi_sequences[0] ) ) ) {
return ansi_sequences[bios_key];
}
+ DBG ( "Unrecognised BIOS scancode %02x\n", scancode );
return NULL;
}
diff --git a/gpxe/src/arch/i386/firmware/pcbios/e820mangler.S b/gpxe/src/arch/i386/firmware/pcbios/e820mangler.S
index 4fbd6563..4ba3fb14 100644
--- a/gpxe/src/arch/i386/firmware/pcbios/e820mangler.S
+++ b/gpxe/src/arch/i386/firmware/pcbios/e820mangler.S
@@ -18,9 +18,6 @@
.text
.arch i386
- .section ".text16", "ax", @progbits
- .section ".data16", "aw", @progbits
- .section ".text16.data", "aw", @progbits
.code16
#define SMAP 0x534d4150
@@ -62,11 +59,11 @@
*
****************************************************************************
*/
- .section ".data16"
+ .section ".data16", "aw", @progbits
.align 16
.globl hidemem_base
.globl hidemem_umalloc
- .globl hidemem_text
+ .globl hidemem_textdata
memory_windows:
base_memory_window: .long 0x00000000, 0x00000000 /* Start of memory */
@@ -76,7 +73,7 @@ ext_memory_window: .long 0x000a0000, 0x00000000 /* 640kB mark */
hidemem_umalloc: .long 0xffffffff, 0xffffffff /* Changes at runtime */
.long 0xffffffff, 0xffffffff /* Changes at runtime */
-hidemem_text: .long 0xffffffff, 0xffffffff /* Changes at runtime */
+hidemem_textdata: .long 0xffffffff, 0xffffffff /* Changes at runtime */
.long 0xffffffff, 0xffffffff /* Changes at runtime */
.long 0xffffffff, 0xffffffff /* End of memory */
@@ -94,7 +91,7 @@ memory_windows_end:
* %ecx:%ebx Length of windowed region
****************************************************************************
*/
- .section ".text16"
+ .section ".text16", "ax", @progbits
window_region:
/* Convert (start,len) to (start, end) */
addl %eax, %ebx
@@ -132,7 +129,7 @@ window_region:
* %ax Modified memory above 1M in 1kB blocks
****************************************************************************
*/
- .section ".text16"
+ .section ".text16", "ax", @progbits
patch_1m:
pushal
/* Convert to (start,len) format and call truncate */
@@ -162,7 +159,7 @@ patch_1m:
* %bx Modified memory above 16M in 64kB blocks
****************************************************************************
*/
- .section ".text16"
+ .section ".text16", "ax", @progbits
patch_16m:
pushal
/* Convert to (start,len) format and call truncate */
@@ -193,7 +190,7 @@ patch_16m:
* %bx Modified memory above 16MB, in 64kB blocks
****************************************************************************
*/
- .section ".text16"
+ .section ".text16", "ax", @progbits
patch_1m_16m:
call patch_1m
call patch_16m
@@ -219,7 +216,7 @@ patch_1m_16m:
*
****************************************************************************
*/
- .section ".text16"
+ .section ".text16", "ax", @progbits
get_underlying_e820:
/* If the requested region is in the cache, return it */
@@ -268,8 +265,10 @@ get_underlying_e820:
pushl %ebx
pushl %ecx
pushl %edx
+ pushl %esi /* Some implementations corrupt %esi, so we */
+ pushl %edi /* preserve %esi, %edi and %ebp to be paranoid */
+ pushl %ebp
pushw %es
- pushw %di
pushw %ds
popw %es
movw $underlying_e820_cache, %di
@@ -280,8 +279,10 @@ get_underlying_e820:
stc
pushfw
lcall *%cs:int15_vector
- popw %di
popw %es
+ popl %ebp
+ popl %edi
+ popl %esi
/* Check for error return from underlying e820 call */
jc 2f /* CF set: error */
cmpl $SMAP, %eax
@@ -304,22 +305,22 @@ get_underlying_e820:
jmp get_underlying_e820
.size get_underlying_e820, . - get_underlying_e820
- .section ".data16"
+ .section ".data16", "aw", @progbits
underlying_e820_index:
.word 0xffff /* Initialise to an invalid value */
.size underlying_e820_index, . - underlying_e820_index
- .section ".bss16"
+ .section ".bss16", "aw", @nobits
underlying_e820_ebx:
.long 0
.size underlying_e820_ebx, . - underlying_e820_ebx
- .section ".bss16"
+ .section ".bss16", "aw", @nobits
underlying_e820_cache:
.space E820MAXSIZE
.size underlying_e820_cache, . - underlying_e820_cache
- .section ".bss16"
+ .section ".bss16", "aw", @nobits
underlying_e820_cache_size:
.long 0
.size underlying_e820_cache_size, . - underlying_e820_cache_size
@@ -338,7 +339,7 @@ underlying_e820_cache_size:
*
****************************************************************************
*/
- .section ".text16"
+ .section ".text16", "ax", @progbits
get_windowed_e820:
/* Preserve registers */
@@ -413,7 +414,7 @@ get_windowed_e820:
*
****************************************************************************
*/
- .section ".text16"
+ .section ".text16", "ax", @progbits
get_nonempty_e820:
/* Record entry parameters */
@@ -458,7 +459,7 @@ get_nonempty_e820:
*
****************************************************************************
*/
- .section ".text16"
+ .section ".text16", "ax", @progbits
get_mangled_e820:
/* Get a nonempty region */
@@ -492,7 +493,7 @@ get_mangled_e820:
* INT 15,e820 handler
****************************************************************************
*/
- .section ".text16"
+ .section ".text16", "ax", @progbits
int15_e820:
pushw %ds
pushw %cs:rm_ds
@@ -506,7 +507,7 @@ int15_e820:
* INT 15,e801 handler
****************************************************************************
*/
- .section ".text16"
+ .section ".text16", "ax", @progbits
int15_e801:
/* Call previous handler */
pushfw
@@ -532,7 +533,7 @@ int15_e801:
* INT 15,88 handler
****************************************************************************
*/
- .section ".text16"
+ .section ".text16", "ax", @progbits
int15_88:
/* Call previous handler */
pushfw
@@ -553,7 +554,7 @@ int15_88:
* INT 15 handler
****************************************************************************
*/
- .section ".text16"
+ .section ".text16", "ax", @progbits
.globl int15
int15:
/* See if we want to intercept this call */
@@ -576,7 +577,7 @@ int15:
ljmp *%cs:int15_vector
.size int15, . - int15
- .section ".text16.data"
+ .section ".text16.data", "aw", @progbits
.globl int15_vector
int15_vector:
.long 0
diff --git a/gpxe/src/arch/i386/firmware/pcbios/gateA20.c b/gpxe/src/arch/i386/firmware/pcbios/gateA20.c
index a14e3416..34e3ac52 100644
--- a/gpxe/src/arch/i386/firmware/pcbios/gateA20.c
+++ b/gpxe/src/arch/i386/firmware/pcbios/gateA20.c
@@ -1,6 +1,7 @@
#include <stdio.h>
#include <realmode.h>
#include <bios.h>
+#include <gpxe/io.h>
#include <gpxe/timer.h>
#define K_RDWR 0x60 /* keyboard data & cmds (read/write) */
@@ -48,9 +49,9 @@ static void empty_8042 ( void ) {
time = currticks() + TICKS_PER_SEC; /* max wait of 1 second */
while ( ( inb ( K_CMD ) & ( K_IBUF_FUL | K_OBUF_FUL ) ) &&
currticks() < time ) {
- SLOW_DOWN_IO;
- ( void ) inb ( K_RDWR );
- SLOW_DOWN_IO;
+ iodelay();
+ ( void ) inb_p ( K_RDWR );
+ iodelay();
}
}
@@ -77,7 +78,7 @@ static int gateA20_is_set ( int retries ) {
/* Avoid false negatives */
test_pattern++;
- SLOW_DOWN_IO;
+ iodelay();
/* Always retry at least once, to avoid false negatives */
} while ( retries-- >= 0 );
@@ -145,9 +146,9 @@ void gateA20_set ( void ) {
scp_a = inb ( SCP_A );
scp_a &= ~0x01; /* Avoid triggering a reset */
scp_a |= 0x02; /* Enable A20 */
- SLOW_DOWN_IO;
+ iodelay();
outb ( scp_a, SCP_A );
- SLOW_DOWN_IO;
+ iodelay();
if ( gateA20_is_set ( A20_SCPA_RETRIES ) ) {
DBG ( "Enabled gate A20 using "
"Fast Gate A20\n" );
diff --git a/gpxe/src/arch/i386/firmware/pcbios/hidemem.c b/gpxe/src/arch/i386/firmware/pcbios/hidemem.c
index c9df7bd0..620b62e0 100644
--- a/gpxe/src/arch/i386/firmware/pcbios/hidemem.c
+++ b/gpxe/src/arch/i386/firmware/pcbios/hidemem.c
@@ -55,8 +55,8 @@ extern struct hidden_region __data16 ( hidemem_umalloc );
#define hidemem_umalloc __use_data16 ( hidemem_umalloc )
/** Hidden text memory */
-extern struct hidden_region __data16 ( hidemem_text );
-#define hidemem_text __use_data16 ( hidemem_text )
+extern struct hidden_region __data16 ( hidemem_textdata );
+#define hidemem_textdata __use_data16 ( hidemem_textdata )
/** Assembly routine in e820mangler.S */
extern void int15();
@@ -66,12 +66,12 @@ extern struct segoff __text16 ( int15_vector );
#define int15_vector __use_text16 ( int15_vector )
/* The linker defines these symbols for us */
-extern char _text[];
-extern char _end[];
-extern char _text16_size[];
-#define _text16_size ( ( unsigned int ) _text16_size )
-extern char _data16_size[];
-#define _data16_size ( ( unsigned int ) _data16_size )
+extern char _textdata[];
+extern char _etextdata[];
+extern char _text16_memsz[];
+#define _text16_memsz ( ( unsigned int ) _text16_memsz )
+extern char _data16_memsz[];
+#define _data16_memsz ( ( unsigned int ) _data16_memsz )
/**
* Hide region of memory from system memory map
@@ -110,7 +110,7 @@ void hide_basemem ( void ) {
*
*/
void hide_umalloc ( physaddr_t start, physaddr_t end ) {
- assert ( end <= virt_to_phys ( _text ) );
+ assert ( end <= virt_to_phys ( _textdata ) );
hide_region ( &hidemem_umalloc, start, end );
}
@@ -118,9 +118,9 @@ void hide_umalloc ( physaddr_t start, physaddr_t end ) {
* Hide .text and .data
*
*/
-void hide_text ( void ) {
- hide_region ( &hidemem_text, virt_to_phys ( _text ),
- virt_to_phys ( _end ) );
+void hide_textdata ( void ) {
+ hide_region ( &hidemem_textdata, virt_to_phys ( _textdata ),
+ virt_to_phys ( _etextdata ) );
}
/**
@@ -148,8 +148,8 @@ static void hide_etherboot ( void ) {
/* Initialise the hidden regions */
hide_basemem();
- hide_umalloc ( virt_to_phys ( _text ), virt_to_phys ( _text ) );
- hide_text();
+ hide_umalloc ( virt_to_phys ( _textdata ), virt_to_phys ( _textdata ) );
+ hide_textdata();
/* Some really moronic BIOSes bring up the PXE stack via the
* UNDI loader entry point and then don't bother to unload it
@@ -161,8 +161,8 @@ static void hide_etherboot ( void ) {
* We use a heuristic to guess whether or not we are being
* loaded sensibly.
*/
- rm_cs_top = ( ( ( rm_cs << 4 ) + _text16_size + 1024 - 1 ) >> 10 );
- rm_ds_top = ( ( ( rm_ds << 4 ) + _data16_size + 1024 - 1 ) >> 10 );
+ rm_cs_top = ( ( ( rm_cs << 4 ) + _text16_memsz + 1024 - 1 ) >> 10 );
+ rm_ds_top = ( ( ( rm_ds << 4 ) + _data16_memsz + 1024 - 1 ) >> 10 );
fbms = get_fbms();
if ( ( rm_cs_top < fbms ) && ( rm_ds_top < fbms ) ) {
DBG ( "Detected potentially unsafe UNDI load at CS=%04x "
diff --git a/gpxe/src/arch/i386/firmware/pcbios/memmap.c b/gpxe/src/arch/i386/firmware/pcbios/memmap.c
index 9de10a7a..ff387d93 100644
--- a/gpxe/src/arch/i386/firmware/pcbios/memmap.c
+++ b/gpxe/src/arch/i386/firmware/pcbios/memmap.c
@@ -158,7 +158,7 @@ static int meme820 ( struct memory_map *memmap ) {
uint32_t smap;
size_t size;
unsigned int flags;
- unsigned int discard_d, discard_D;
+ unsigned int discard_D;
/* Clear the E820 buffer. Do this once before starting,
* rather than on each call; some BIOSes rely on the contents
@@ -167,18 +167,24 @@ static int meme820 ( struct memory_map *memmap ) {
memset ( &e820buf, 0, sizeof ( e820buf ) );
do {
- __asm__ __volatile__ ( REAL_CODE ( "stc\n\t"
+ /* Some BIOSes corrupt %esi for fun. Guard against
+ * this by telling gcc that all non-output registers
+ * may be corrupted.
+ */
+ __asm__ __volatile__ ( REAL_CODE ( "pushl %%ebp\n\t"
+ "stc\n\t"
"int $0x15\n\t"
"pushfw\n\t"
- "popw %w0\n\t" )
- : "=r" ( flags ), "=a" ( smap ),
- "=b" ( next ), "=D" ( discard_D ),
- "=c" ( size ), "=d" ( discard_d )
+ "popw %%dx\n\t"
+ "popl %%ebp\n\t" )
+ : "=a" ( smap ), "=b" ( next ),
+ "=c" ( size ), "=d" ( flags ),
+ "=D" ( discard_D )
: "a" ( 0xe820 ), "b" ( next ),
"D" ( __from_data16 ( &e820buf ) ),
"c" ( sizeof ( e820buf ) ),
"d" ( SMAP )
- : "memory" );
+ : "esi", "memory" );
if ( smap != SMAP ) {
DBG ( "INT 15,e820 failed SMAP signature check\n" );
@@ -195,6 +201,13 @@ static int meme820 ( struct memory_map *memmap ) {
break;
}
+ /* If first region is not RAM, assume map is invalid */
+ if ( ( memmap->count == 0 ) &&
+ ( e820buf.type != E820_TYPE_RAM ) ) {
+ DBG ( "INT 15,e820 failed, first entry not RAM\n" );
+ return -EINVAL;
+ }
+
DBG ( "INT 15,e820 region [%llx,%llx) type %d",
e820buf.start, ( e820buf.start + e820buf.len ),
( int ) e820buf.type );
@@ -204,7 +217,7 @@ static int meme820 ( struct memory_map *memmap ) {
if ( e820buf.attrs & E820_ATTR_NONVOLATILE )
DBG ( ", non-volatile" );
if ( e820buf.attrs & E820_ATTR_UNKNOWN )
- DBG ( ", other [%08lx]", e820buf.attrs );
+ DBG ( ", other [%08x]", e820buf.attrs );
DBG ( ")" );
}
DBG ( "\n" );
diff --git a/gpxe/src/arch/i386/image/bzimage.c b/gpxe/src/arch/i386/image/bzimage.c
index e6fd854f..47d46ca4 100644
--- a/gpxe/src/arch/i386/image/bzimage.c
+++ b/gpxe/src/arch/i386/image/bzimage.c
@@ -400,7 +400,7 @@ static int bzimage_load_header ( struct image *image,
copy_from_user ( bzhdr, image->data, BZI_HDR_OFFSET,
sizeof ( *bzhdr ) );
if ( bzhdr->header != BZI_SIGNATURE ) {
- DBGC ( image, "bzImage %p bad signature %08lx\n",
+ DBGC ( image, "bzImage %p bad signature %08x\n",
image, bzhdr->header );
return -ENOEXEC;
}
diff --git a/gpxe/src/arch/i386/image/com32.c b/gpxe/src/arch/i386/image/com32.c
index da604625..d1b9a59f 100644
--- a/gpxe/src/arch/i386/image/com32.c
+++ b/gpxe/src/arch/i386/image/com32.c
@@ -52,7 +52,7 @@ static int com32_exec ( struct image *image ) {
int state;
uint32_t avail_mem_top;
- state = setjmp ( comboot_return );
+ state = rmsetjmp ( comboot_return );
switch ( state ) {
case 0: /* First time through; invoke COM32 program */
@@ -70,20 +70,20 @@ static int com32_exec ( struct image *image ) {
}
DBGC ( image, "COM32 %p: available memory top = 0x%x\n",
- image, (int)avail_mem_top );
+ image, avail_mem_top );
assert ( avail_mem_top != 0 );
com32_external_esp = phys_to_virt ( avail_mem_top );
/* Hook COMBOOT API interrupts */
- hook_comboot_interrupts( );
+ hook_comboot_interrupts();
- /* Temporarily de-register image, so that a "boot" command
- * doesn't throw us into an execution loop. Hold a reference
- * to avoid the image's being freed.
+ /* Unregister image, so that a "boot" command doesn't
+ * throw us into an execution loop. We never
+ * reregister ourselves; COMBOOT images expect to be
+ * removed on exit.
*/
- image_get ( image );
unregister_image ( image );
__asm__ __volatile__ (
@@ -111,25 +111,33 @@ static int com32_exec ( struct image *image ) {
/* %6 */ "r" ( COM32_START_PHYS )
:
"memory" );
+ DBGC ( image, "COM32 %p: returned\n", image );
break;
- case COMBOOT_RETURN_RUN_KERNEL:
- DBGC ( image, "COM32 %p: returned to run kernel...\n", image );
- comboot_run_kernel ( );
+ case COMBOOT_EXIT:
+ DBGC ( image, "COM32 %p: exited\n", image );
break;
- case COMBOOT_RETURN_EXIT:
+ case COMBOOT_EXIT_RUN_KERNEL:
+ DBGC ( image, "COM32 %p: exited to run kernel %p\n",
+ image, comboot_replacement_image );
+ image->replacement = comboot_replacement_image;
+ comboot_replacement_image = NULL;
+ image_autoload ( image->replacement );
break;
- }
-
- comboot_force_text_mode ( );
+ case COMBOOT_EXIT_COMMAND:
+ DBGC ( image, "COM32 %p: exited after executing command\n",
+ image );
+ break;
- DBGC ( image, "COM32 %p returned\n", image );
+ default:
+ assert ( 0 );
+ break;
+ }
- /* Re-register image and return */
- register_image ( image );
- image_put ( image );
+ unhook_comboot_interrupts();
+ comboot_force_text_mode();
return 0;
}
diff --git a/gpxe/src/arch/i386/image/comboot.c b/gpxe/src/arch/i386/image/comboot.c
index 63d02c0f..40e32185 100644
--- a/gpxe/src/arch/i386/image/comboot.c
+++ b/gpxe/src/arch/i386/image/comboot.c
@@ -133,7 +133,7 @@ static int comboot_exec ( struct image *image ) {
userptr_t seg_userptr = real_to_user ( COMBOOT_PSP_SEG, 0 );
int state;
- state = setjmp ( comboot_return );
+ state = rmsetjmp ( comboot_return );
switch ( state ) {
case 0: /* First time through; invoke COMBOOT program */
@@ -142,16 +142,16 @@ static int comboot_exec ( struct image *image ) {
comboot_init_psp ( image, seg_userptr );
/* Hook COMBOOT API interrupts */
- hook_comboot_interrupts ( );
+ hook_comboot_interrupts();
DBGC ( image, "executing 16-bit COMBOOT image at %4x:0100\n",
- COMBOOT_PSP_SEG );
+ COMBOOT_PSP_SEG );
- /* Temporarily de-register image, so that a "boot" command
- * doesn't throw us into an execution loop. Hold a reference
- * to avoid the image's being freed.
+ /* Unregister image, so that a "boot" command doesn't
+ * throw us into an execution loop. We never
+ * reregister ourselves; COMBOOT images expect to be
+ * removed on exit.
*/
- image_get ( image );
unregister_image ( image );
/* Store stack segment at 0x38 and stack pointer at 0x3A
@@ -180,26 +180,34 @@ static int comboot_exec ( struct image *image ) {
"xorw %%bp, %%bp\n\t"
"lret\n\t" )
: : "r" ( COMBOOT_PSP_SEG ) : "eax" );
+ DBGC ( image, "COMBOOT %p: returned\n", image );
break;
- case COMBOOT_RETURN_RUN_KERNEL:
- DBGC ( image, "COMBOOT %p: returned to run kernel...\n", image );
- comboot_run_kernel ( );
+ case COMBOOT_EXIT:
+ DBGC ( image, "COMBOOT %p: exited\n", image );
break;
- case COMBOOT_RETURN_EXIT:
+ case COMBOOT_EXIT_RUN_KERNEL:
+ DBGC ( image, "COMBOOT %p: exited to run kernel %p\n",
+ image, comboot_replacement_image );
+ image->replacement = comboot_replacement_image;
+ comboot_replacement_image = NULL;
+ image_autoload ( image->replacement );
break;
- }
+ case COMBOOT_EXIT_COMMAND:
+ DBGC ( image, "COMBOOT %p: exited after executing command\n",
+ image );
+ break;
- comboot_force_text_mode ( );
+ default:
+ assert ( 0 );
+ break;
+ }
- DBGC ( image, "COMBOOT %p returned\n", image );
+ unhook_comboot_interrupts();
+ comboot_force_text_mode();
- /* Re-register image and return */
- register_image ( image );
- image_put ( image );
-
return 0;
}
diff --git a/gpxe/src/arch/i386/image/multiboot.c b/gpxe/src/arch/i386/image/multiboot.c
index a4a340fd..52bb10f6 100644
--- a/gpxe/src/arch/i386/image/multiboot.c
+++ b/gpxe/src/arch/i386/image/multiboot.c
@@ -220,7 +220,7 @@ multiboot_build_module_list ( struct image *image,
/* Dump module configuration */
for ( i = 0 ; i < count ; i++ ) {
- DBGC ( image, "MULTIBOOT %p module %d is [%lx,%lx)\n",
+ DBGC ( image, "MULTIBOOT %p module %d is [%x,%x)\n",
image, i, modules[i].mod_start,
modules[i].mod_end );
}
@@ -282,11 +282,13 @@ static int multiboot_exec ( struct image *image ) {
/* Jump to OS with flat physical addressing */
DBGC ( image, "MULTIBOOT %p starting execution at %lx\n",
image, entry );
- __asm__ __volatile__ ( PHYS_CODE ( "call *%%edi\n\t" )
+ __asm__ __volatile__ ( PHYS_CODE ( "pushl %%ebp\n\t"
+ "call *%%edi\n\t"
+ "popl %%ebp\n\t" )
: : "a" ( MULTIBOOT_BOOTLOADER_MAGIC ),
"b" ( virt_to_phys ( &mbinfo ) ),
"D" ( entry )
- : "ecx", "edx", "esi", "ebp", "memory" );
+ : "ecx", "edx", "esi", "memory" );
DBGC ( image, "MULTIBOOT %p returned\n", image );
@@ -416,7 +418,7 @@ static int multiboot_load ( struct image *image ) {
image );
return rc;
}
- DBGC ( image, "MULTIBOOT %p found header with flags %08lx\n",
+ DBGC ( image, "MULTIBOOT %p found header with flags %08x\n",
image, hdr.mb.flags );
/* This is a multiboot image, valid or otherwise */
@@ -425,7 +427,7 @@ static int multiboot_load ( struct image *image ) {
/* Abort if we detect flags that we cannot support */
if ( hdr.mb.flags & MB_UNSUPPORTED_FLAGS ) {
- DBGC ( image, "MULTIBOOT %p flags %08lx not supported\n",
+ DBGC ( image, "MULTIBOOT %p flags %08x not supported\n",
image, ( hdr.mb.flags & MB_UNSUPPORTED_FLAGS ) );
return -ENOTSUP;
}
diff --git a/gpxe/src/arch/i386/image/nbi.c b/gpxe/src/arch/i386/image/nbi.c
index e6a0ab0f..a4ee4420 100644
--- a/gpxe/src/arch/i386/image/nbi.c
+++ b/gpxe/src/arch/i386/image/nbi.c
@@ -367,22 +367,6 @@ static int nbi_boot32 ( struct image *image, struct imgheader *imgheader ) {
}
/**
- * Guess boot network device
- *
- * @ret netdev Boot network device
- */
-static struct net_device * guess_boot_netdev ( void ) {
- struct net_device *boot_netdev;
-
- /* Just use the first network device */
- for_each_netdev ( boot_netdev ) {
- return boot_netdev;
- }
-
- return NULL;
-}
-
-/**
* Prepare DHCP parameter block for NBI image
*
* @v image NBI image
@@ -392,7 +376,7 @@ static int nbi_prepare_dhcp ( struct image *image ) {
struct net_device *boot_netdev;
int rc;
- boot_netdev = guess_boot_netdev();
+ boot_netdev = last_opened_netdev();
if ( ! boot_netdev ) {
DBGC ( image, "NBI %p could not identify a network device\n",
image );
diff --git a/gpxe/src/arch/i386/image/pxe_image.c b/gpxe/src/arch/i386/image/pxe_image.c
index 77fa0469..90550d83 100644
--- a/gpxe/src/arch/i386/image/pxe_image.c
+++ b/gpxe/src/arch/i386/image/pxe_image.c
@@ -42,18 +42,14 @@ struct image_type pxe_image_type __image_type ( PROBE_PXE );
* @ret rc Return status code
*/
static int pxe_exec ( struct image *image ) {
- struct net_device *netdev;
int rc;
/* Ensure that PXE stack is ready to use */
pxe_init_structures();
pxe_hook_int1a();
- /* Arbitrarily pick the first open network device to use for PXE */
- for_each_netdev ( netdev ) {
- pxe_set_netdev ( netdev );
- break;
- }
+ /* Arbitrarily pick the most recently opened network device */
+ pxe_set_netdev ( last_opened_netdev() );
/* Many things will break if pxe_netdev is NULL */
if ( ! pxe_netdev ) {
@@ -92,6 +88,12 @@ int pxe_load ( struct image *image ) {
if ( filesz > ( 0xa0000 - 0x7c00 ) )
return -ENOEXEC;
+ /* Rejecting zero-length images is also useful, since these
+ * end up looking to the user like bugs in gPXE.
+ */
+ if ( ! filesz )
+ return -ENOEXEC;
+
/* There are no signature checks for PXE; we will accept anything */
if ( ! image->type )
image->type = &pxe_image_type;
diff --git a/gpxe/src/arch/i386/include/bios.h b/gpxe/src/arch/i386/include/bios.h
index 630a898b..979a092c 100644
--- a/gpxe/src/arch/i386/include/bios.h
+++ b/gpxe/src/arch/i386/include/bios.h
@@ -5,7 +5,4 @@
#define BDA_FBMS 0x0013
#define BDA_NUM_DRIVES 0x0075
-extern unsigned long currticks ( void );
-extern void cpu_nap ( void );
-
#endif /* BIOS_H */
diff --git a/gpxe/src/arch/i386/include/biosint.h b/gpxe/src/arch/i386/include/biosint.h
index d4e34963..d365cf01 100644
--- a/gpxe/src/arch/i386/include/biosint.h
+++ b/gpxe/src/arch/i386/include/biosint.h
@@ -6,9 +6,22 @@
*
*/
+#include <realmode.h>
+
struct segoff;
-extern int hooked_bios_interrupts;
+/**
+ * Hooked interrupt count
+ *
+ * At exit, after unhooking all possible interrupts, this counter
+ * should be examined. If it is non-zero, it means that we failed to
+ * unhook at least one interrupt vector, and so must not free up the
+ * memory we are using. (Note that this also implies that we should
+ * re-hook INT 15 in order to hide ourselves from the memory map).
+ */
+extern uint16_t __text16 ( hooked_bios_interrupts );
+#define hooked_bios_interrupts __use_text16 ( hooked_bios_interrupts )
+
extern void hook_bios_interrupt ( unsigned int interrupt, unsigned int handler,
struct segoff *chain_vector );
extern int unhook_bios_interrupt ( unsigned int interrupt,
diff --git a/gpxe/src/arch/i386/include/bits/byteswap.h b/gpxe/src/arch/i386/include/bits/byteswap.h
index 54b93ab9..98418c29 100644
--- a/gpxe/src/arch/i386/include/bits/byteswap.h
+++ b/gpxe/src/arch/i386/include/bits/byteswap.h
@@ -2,7 +2,7 @@
#define ETHERBOOT_BITS_BYTESWAP_H
static inline __attribute__ ((always_inline, const)) uint16_t
-__i386_bswap_16(uint16_t x)
+__bswap_variable_16(uint16_t x)
{
__asm__("xchgb %b0,%h0\n\t"
: "=q" (x)
@@ -11,7 +11,7 @@ __i386_bswap_16(uint16_t x)
}
static inline __attribute__ ((always_inline, const)) uint32_t
-__i386_bswap_32(uint32_t x)
+__bswap_variable_32(uint32_t x)
{
__asm__("xchgb %b0,%h0\n\t"
"rorl $16,%0\n\t"
@@ -22,7 +22,7 @@ __i386_bswap_32(uint32_t x)
}
static inline __attribute__ ((always_inline, const)) uint64_t
-__i386_bswap_64(uint64_t x)
+__bswap_variable_64(uint64_t x)
{
union {
uint64_t qword;
@@ -30,47 +30,12 @@ __i386_bswap_64(uint64_t x)
} u;
u.qword = x;
- u.dword[0] = __i386_bswap_32(u.dword[0]);
- u.dword[1] = __i386_bswap_32(u.dword[1]);
+ u.dword[0] = __bswap_variable_32(u.dword[0]);
+ u.dword[1] = __bswap_variable_32(u.dword[1]);
__asm__("xchgl %0,%1"
: "=r" ( u.dword[0] ), "=r" ( u.dword[1] )
: "0" ( u.dword[0] ), "1" ( u.dword[1] ) );
return u.qword;
}
-#define __bswap_constant_16(x) \
- ((uint16_t)((((uint16_t)(x) & 0x00ff) << 8) | \
- (((uint16_t)(x) & 0xff00) >> 8)))
-
-#define __bswap_constant_32(x) \
- ((uint32_t)((((uint32_t)(x) & 0x000000ffU) << 24) | \
- (((uint32_t)(x) & 0x0000ff00U) << 8) | \
- (((uint32_t)(x) & 0x00ff0000U) >> 8) | \
- (((uint32_t)(x) & 0xff000000U) >> 24)))
-
-#define __bswap_constant_64(x) \
- ((uint64_t)((((uint64_t)(x) & 0x00000000000000ffULL) << 56) | \
- (((uint64_t)(x) & 0x000000000000ff00ULL) << 40) | \
- (((uint64_t)(x) & 0x0000000000ff0000ULL) << 24) | \
- (((uint64_t)(x) & 0x00000000ff000000ULL) << 8) | \
- (((uint64_t)(x) & 0x000000ff00000000ULL) >> 8) | \
- (((uint64_t)(x) & 0x0000ff0000000000ULL) >> 24) | \
- (((uint64_t)(x) & 0x00ff000000000000ULL) >> 40) | \
- (((uint64_t)(x) & 0xff00000000000000ULL) >> 56)))
-
-#define __bswap_16(x) \
- ((uint16_t)(__builtin_constant_p(x) ? \
- __bswap_constant_16(x) : \
- __i386_bswap_16(x)))
-
-#define __bswap_32(x) \
- ((uint32_t)(__builtin_constant_p(x) ? \
- __bswap_constant_32(x) : \
- __i386_bswap_32(x)))
-
-#define __bswap_64(x) \
- ((uint64_t)(__builtin_constant_p(x) ? \
- __bswap_constant_64(x) : \
- __i386_bswap_64(x)))
-
#endif /* ETHERBOOT_BITS_BYTESWAP_H */
diff --git a/gpxe/src/arch/i386/include/bits/compiler.h b/gpxe/src/arch/i386/include/bits/compiler.h
new file mode 100644
index 00000000..119a9a21
--- /dev/null
+++ b/gpxe/src/arch/i386/include/bits/compiler.h
@@ -0,0 +1,25 @@
+#ifndef _BITS_COMPILER_H
+#define _BITS_COMPILER_H
+
+#ifndef ASSEMBLY
+
+/** Declare a function with standard calling conventions */
+#define __asmcall __attribute__ (( cdecl, regparm(0) ))
+
+/**
+ * Declare a function with libgcc implicit linkage
+ *
+ * It seems as though gcc expects its implicit arithmetic functions to
+ * be cdecl, even if -mrtd is specified. This is somewhat
+ * inconsistent; for example, if -mregparm=3 is used then the implicit
+ * functions do become regparm(3).
+ *
+ * The implicit calls to memcpy() and memset() which gcc can generate
+ * do not seem to have this inconsistency; -mregparm and -mrtd affect
+ * them in the same way as any other function.
+ */
+#define __libgcc __attribute__ (( cdecl ))
+
+#endif /* ASSEMBLY */
+
+#endif /* _BITS_COMPILER_H */
diff --git a/gpxe/src/arch/i386/include/bits/elf.h b/gpxe/src/arch/i386/include/bits/elf.h
deleted file mode 100644
index dad9c7b8..00000000
--- a/gpxe/src/arch/i386/include/bits/elf.h
+++ /dev/null
@@ -1,91 +0,0 @@
-#ifndef I386_BITS_ELF_H
-#define I386_BITS_ELF_H
-
-#include "cpu.h"
-
-#ifdef CONFIG_X86_64
-/* ELF Defines for the 64bit version of the current architecture */
-#define EM_CURRENT_64 EM_X86_64
-#define EM_CURRENT_64_PRESENT ( \
- CPU_FEATURE_P(cpu_info.x86_capability, LM) && \
- CPU_FEATURE_P(cpu_info.x86_capability, PAE) && \
- CPU_FEATURE_P(cpu_info.x86_capability, PSE))
-
-#define ELF_CHECK_X86_64_ARCH(x) \
- (EM_CURRENT_64_PRESENT && ((x).e_machine == EM_X86_64))
-#define __unused_i386
-#else
-#define ELF_CHECK_X86_64_ARCH(x) 0
-#define __unused_i386 __unused
-#endif
-
-
-/* ELF Defines for the current architecture */
-#define EM_CURRENT EM_386
-#define ELFDATA_CURRENT ELFDATA2LSB
-
-#define ELF_CHECK_I386_ARCH(x) \
- (((x).e_machine == EM_386) || ((x).e_machine == EM_486))
-
-#define ELF_CHECK_ARCH(x) \
- ((ELF_CHECK_I386_ARCH(x) || ELF_CHECK_X86_64_ARCH(x)) && \
- ((x).e_entry <= 0xffffffffUL))
-
-#ifdef IMAGE_FREEBSD
-/*
- * FreeBSD has this rather strange "feature" of its design.
- * At some point in its evolution, FreeBSD started to rely
- * externally on private/static/debug internal symbol information.
- * That is, some of the interfaces that software uses to access
- * and work with the FreeBSD kernel are made available not
- * via the shared library symbol information (the .DYNAMIC section)
- * but rather the debug symbols. This means that any symbol, not
- * just publicly defined symbols can be (and are) used by system
- * tools to make the system work. (such as top, swapinfo, swapon,
- * etc)
- *
- * Even worse, however, is the fact that standard ELF loaders do
- * not know how to load the symbols since they are not within
- * an ELF PT_LOAD section. The kernel needs these symbols to
- * operate so the following changes/additions to the boot
- * loading of EtherBoot have been made to get the kernel to load.
- * All of the changes are within IMAGE_FREEBSD such that the
- * extra/changed code only compiles when FREEBSD support is
- * enabled.
- */
-
-/*
- * Section header for FreeBSD (debug symbol kludge!) support
- */
-typedef struct {
- Elf32_Word sh_name; /* Section name (index into the
- section header string table). */
- Elf32_Word sh_type; /* Section type. */
- Elf32_Word sh_flags; /* Section flags. */
- Elf32_Addr sh_addr; /* Address in memory image. */
- Elf32_Off sh_offset; /* Offset in file. */
- Elf32_Size sh_size; /* Size in bytes. */
- Elf32_Word sh_link; /* Index of a related section. */
- Elf32_Word sh_info; /* Depends on section type. */
- Elf32_Size sh_addralign; /* Alignment in bytes. */
- Elf32_Size sh_entsize; /* Size of each entry in section. */
-} Elf32_Shdr;
-
-/* sh_type */
-#define SHT_SYMTAB 2 /* symbol table section */
-#define SHT_STRTAB 3 /* string table section */
-
-/*
- * Module information subtypes (for the metadata that we need to build)
- */
-#define MODINFO_END 0x0000 /* End of list */
-#define MODINFO_NAME 0x0001 /* Name of module (string) */
-#define MODINFO_TYPE 0x0002 /* Type of module (string) */
-#define MODINFO_METADATA 0x8000 /* Module-specfic */
-
-#define MODINFOMD_SSYM 0x0003 /* start of symbols */
-#define MODINFOMD_ESYM 0x0004 /* end of symbols */
-
-#endif /* IMAGE_FREEBSD */
-
-#endif /* I386_BITS_ELF_H */
diff --git a/gpxe/src/arch/i386/include/bits/elf_x.h b/gpxe/src/arch/i386/include/bits/elf_x.h
deleted file mode 100644
index 86c67250..00000000
--- a/gpxe/src/arch/i386/include/bits/elf_x.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#define ARCH_ELF_CLASS ELFCLASS32
-#define ARCH_ELF_DATA ELFDATA2LSB
-#define ARCH_ELF_MACHINE_OK(x) ((x)==EM_386 || (x)==EM_486)
-typedef Elf32_Ehdr Elf_ehdr;
-typedef Elf32_Phdr Elf_phdr;
diff --git a/gpxe/src/arch/i386/include/bits/errfile.h b/gpxe/src/arch/i386/include/bits/errfile.h
index 99927c28..5ea8a318 100644
--- a/gpxe/src/arch/i386/include/bits/errfile.h
+++ b/gpxe/src/arch/i386/include/bits/errfile.h
@@ -6,13 +6,12 @@
* @{
*/
-#define ERRFILE_umalloc ( ERRFILE_ARCH | ERRFILE_CORE | 0x00000000 )
+#define ERRFILE_memtop_umalloc ( ERRFILE_ARCH | ERRFILE_CORE | 0x00000000 )
#define ERRFILE_memmap ( ERRFILE_ARCH | ERRFILE_CORE | 0x00010000 )
#define ERRFILE_pnpbios ( ERRFILE_ARCH | ERRFILE_CORE | 0x00020000 )
-#define ERRFILE_smbios ( ERRFILE_ARCH | ERRFILE_CORE | 0x00030000 )
+#define ERRFILE_bios_smbios ( ERRFILE_ARCH | ERRFILE_CORE | 0x00030000 )
#define ERRFILE_biosint ( ERRFILE_ARCH | ERRFILE_CORE | 0x00040000 )
#define ERRFILE_int13 ( ERRFILE_ARCH | ERRFILE_CORE | 0x00050000 )
-#define ERRFILE_smbios_settings ( ERRFILE_ARCH | ERRFILE_CORE | 0x00060000 )
#define ERRFILE_bootsector ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00000000 )
#define ERRFILE_bzimage ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00010000 )
@@ -24,6 +23,7 @@
#define ERRFILE_comboot ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00070000 )
#define ERRFILE_com32 ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00080000 )
#define ERRFILE_comboot_resolv ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00090000 )
+#define ERRFILE_comboot_call ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x000a0000 )
#define ERRFILE_undi ( ERRFILE_ARCH | ERRFILE_NET | 0x00000000 )
#define ERRFILE_undiload ( ERRFILE_ARCH | ERRFILE_NET | 0x00010000 )
diff --git a/gpxe/src/arch/i386/include/bits/io.h b/gpxe/src/arch/i386/include/bits/io.h
new file mode 100644
index 00000000..dd0ee444
--- /dev/null
+++ b/gpxe/src/arch/i386/include/bits/io.h
@@ -0,0 +1,12 @@
+#ifndef _BITS_IO_H
+#define _BITS_IO_H
+
+/** @file
+ *
+ * i386-specific I/O API implementations
+ *
+ */
+
+#include <gpxe/x86_io.h>
+
+#endif /* _BITS_IO_H */
diff --git a/gpxe/src/arch/i386/include/bits/nap.h b/gpxe/src/arch/i386/include/bits/nap.h
new file mode 100644
index 00000000..f8ba7a7c
--- /dev/null
+++ b/gpxe/src/arch/i386/include/bits/nap.h
@@ -0,0 +1,13 @@
+#ifndef _BITS_NAP_H
+#define _BITS_NAP_H
+
+/** @file
+ *
+ * i386-specific CPU sleeping API implementations
+ *
+ */
+
+#include <gpxe/bios_nap.h>
+#include <gpxe/efi/efix86_nap.h>
+
+#endif /* _BITS_MAP_H */
diff --git a/gpxe/src/arch/i386/include/bits/smbios.h b/gpxe/src/arch/i386/include/bits/smbios.h
new file mode 100644
index 00000000..647ea19e
--- /dev/null
+++ b/gpxe/src/arch/i386/include/bits/smbios.h
@@ -0,0 +1,12 @@
+#ifndef _BITS_SMBIOS_H
+#define _BITS_SMBIOS_H
+
+/** @file
+ *
+ * i386-specific SMBIOS API implementations
+ *
+ */
+
+#include <gpxe/bios_smbios.h>
+
+#endif /* _BITS_SMBIOS_H */
diff --git a/gpxe/src/arch/i386/include/bits/stdint.h b/gpxe/src/arch/i386/include/bits/stdint.h
index a2947cda..6ccf0971 100644
--- a/gpxe/src/arch/i386/include/bits/stdint.h
+++ b/gpxe/src/arch/i386/include/bits/stdint.h
@@ -1,18 +1,18 @@
#ifndef _BITS_STDINT_H
#define _BITS_STDINT_H
-typedef typeof(sizeof(int)) size_t;
-typedef signed long ssize_t;
+typedef unsigned int size_t;
+typedef signed int ssize_t;
typedef signed long off_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
-typedef unsigned long uint32_t;
+typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
typedef signed char int8_t;
typedef signed short int16_t;
-typedef signed long int32_t;
+typedef signed int int32_t;
typedef signed long long int64_t;
typedef unsigned long physaddr_t;
diff --git a/gpxe/src/arch/i386/include/bits/timer.h b/gpxe/src/arch/i386/include/bits/timer.h
new file mode 100644
index 00000000..99666d84
--- /dev/null
+++ b/gpxe/src/arch/i386/include/bits/timer.h
@@ -0,0 +1,13 @@
+#ifndef _BITS_TIMER_H
+#define _BITS_TIMER_H
+
+/** @file
+ *
+ * i386-specific timer API implementations
+ *
+ */
+
+#include <gpxe/bios_timer.h>
+#include <gpxe/rdtsc_timer.h>
+
+#endif /* _BITS_TIMER_H */
diff --git a/gpxe/src/arch/i386/include/bits/timer2.h b/gpxe/src/arch/i386/include/bits/timer2.h
deleted file mode 100644
index 83923b29..00000000
--- a/gpxe/src/arch/i386/include/bits/timer2.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef BITS_TIMER2_H
-#define BITS_TIMER2_H
-
-#include <stddef.h>
-
-void i386_timer2_udelay(unsigned int usecs);
-
-#endif
diff --git a/gpxe/src/arch/i386/include/bits/uaccess.h b/gpxe/src/arch/i386/include/bits/uaccess.h
index 9c6d0c21..0ecc5028 100644
--- a/gpxe/src/arch/i386/include/bits/uaccess.h
+++ b/gpxe/src/arch/i386/include/bits/uaccess.h
@@ -1,6 +1,12 @@
#ifndef _BITS_UACCESS_H
#define _BITS_UACCESS_H
-#include <realmode.h>
+/** @file
+ *
+ * i386-specific user access API implementations
+ *
+ */
+
+#include <librm.h>
#endif /* _BITS_UACCESS_H */
diff --git a/gpxe/src/arch/i386/include/bits/umalloc.h b/gpxe/src/arch/i386/include/bits/umalloc.h
new file mode 100644
index 00000000..dcbd0a6b
--- /dev/null
+++ b/gpxe/src/arch/i386/include/bits/umalloc.h
@@ -0,0 +1,12 @@
+#ifndef _BITS_UMALLOC_H
+#define _BITS_UMALLOC_H
+
+/** @file
+ *
+ * i386-specific user memory allocation API implementations
+ *
+ */
+
+#include <gpxe/memtop_umalloc.h>
+
+#endif /* _BITS_UMALLOC_H */
diff --git a/gpxe/src/arch/i386/include/comboot.h b/gpxe/src/arch/i386/include/comboot.h
index 1fc3b718..56661a80 100644
--- a/gpxe/src/arch/i386/include/comboot.h
+++ b/gpxe/src/arch/i386/include/comboot.h
@@ -58,12 +58,47 @@ typedef struct {
} com32sys_t;
typedef struct {
+ uint32_t eax; /* Offset 0 */
+ uint32_t ecx; /* Offset 4 */
+ uint32_t edx; /* Offset 8 */
+ uint32_t ebx; /* Offset 12 */
+ uint32_t esp; /* Offset 16 */
+ uint32_t ebp; /* Offset 20 */
+ uint32_t esi; /* Offset 24 */
+ uint32_t edi; /* Offset 28 */
+
+ uint32_t eip; /* Offset 32 */
+} syslinux_pm_regs;
+
+typedef struct {
+ uint16_t es; /* Offset 0 */
+ uint16_t _unused_cs; /* Offset 2 */
+ uint16_t ds; /* Offset 4 */
+ uint16_t ss; /* Offset 6 */
+ uint16_t fs; /* Offset 8 */
+ uint16_t gs; /* Offset 10 */
+
+ uint32_t eax; /* Offset 12 */
+ uint32_t ecx; /* Offset 16 */
+ uint32_t edx; /* Offset 20 */
+ uint32_t ebx; /* Offset 24 */
+ uint32_t esp; /* Offset 28 */
+ uint32_t ebp; /* Offset 32 */
+ uint32_t esi; /* Offset 36 */
+ uint32_t edi; /* Offset 40 */
+
+ uint16_t ip; /* Offset 44 */
+ uint16_t cs; /* Offset 46 */
+} syslinux_rm_regs;
+
+typedef struct {
uint32_t dest;
uint32_t src;
uint32_t len;
} comboot_shuffle_descriptor;
extern void hook_comboot_interrupts ( );
+extern void unhook_comboot_interrupts ( );
/* These are not the correct prototypes, but it doens't matter,
* as we only ever get the address of these functions;
@@ -77,20 +112,16 @@ extern void com32_cfarcall_wrapper ( );
extern int comboot_resolv ( const char *name, struct in_addr *address );
/* setjmp/longjmp context buffer used to return after loading an image */
-extern jmp_buf comboot_return;
-
-/* Command line to execute when returning via comboot_return
- * with COMBOOT_RETURN_RUN_KERNEL
- */
-extern char *comboot_kernel_cmdline;
+extern rmjmp_buf comboot_return;
-/* Execute comboot_image_cmdline */
-extern void comboot_run_kernel ( );
+/* Replacement image when exiting with COMBOOT_EXIT_RUN_KERNEL */
+extern struct image *comboot_replacement_image;
extern void *com32_external_esp;
-#define COMBOOT_RETURN_EXIT 1
-#define COMBOOT_RETURN_RUN_KERNEL 2
+#define COMBOOT_EXIT 1
+#define COMBOOT_EXIT_RUN_KERNEL 2
+#define COMBOOT_EXIT_COMMAND 3
extern void comboot_force_text_mode ( void );
diff --git a/gpxe/src/arch/i386/include/gdbmach.h b/gpxe/src/arch/i386/include/gdbmach.h
index 1a38ccd1..794dab19 100644
--- a/gpxe/src/arch/i386/include/gdbmach.h
+++ b/gpxe/src/arch/i386/include/gdbmach.h
@@ -12,7 +12,7 @@
#include <stdint.h>
-typedef uint32_t gdbreg_t;
+typedef unsigned long gdbreg_t;
/* The register snapshot, this must be in sync with interrupt handler and the
* GDB protocol. */
diff --git a/gpxe/src/include/gpxe/abft.h b/gpxe/src/arch/i386/include/gpxe/abft.h
index 1c651ef1..1c651ef1 100644
--- a/gpxe/src/include/gpxe/abft.h
+++ b/gpxe/src/arch/i386/include/gpxe/abft.h
diff --git a/gpxe/src/arch/i386/include/gpxe/bios_nap.h b/gpxe/src/arch/i386/include/gpxe/bios_nap.h
new file mode 100644
index 00000000..f1c721e9
--- /dev/null
+++ b/gpxe/src/arch/i386/include/gpxe/bios_nap.h
@@ -0,0 +1,16 @@
+#ifndef _GPXE_BIOS_NAP_H
+#define _GPXE_BIOS_NAP_H
+
+/** @file
+ *
+ * BIOS CPU sleeping
+ *
+ */
+
+#ifdef NAP_PCBIOS
+#define NAP_PREFIX_pcbios
+#else
+#define NAP_PREFIX_pcbios __pcbios_
+#endif
+
+#endif /* _GPXE_BIOS_NAP_H */
diff --git a/gpxe/src/arch/i386/include/gpxe/bios_smbios.h b/gpxe/src/arch/i386/include/gpxe/bios_smbios.h
new file mode 100644
index 00000000..0a6f277a
--- /dev/null
+++ b/gpxe/src/arch/i386/include/gpxe/bios_smbios.h
@@ -0,0 +1,16 @@
+#ifndef _GPXE_BIOS_SMBIOS_H
+#define _GPXE_BIOS_SMBIOS_H
+
+/** @file
+ *
+ * Standard PC-BIOS SMBIOS interface
+ *
+ */
+
+#ifdef SMBIOS_PCBIOS
+#define SMBIOS_PREFIX_pcbios
+#else
+#define SMBIOS_PREFIX_pcbios __pcbios_
+#endif
+
+#endif /* _GPXE_BIOS_SMBIOS_H */
diff --git a/gpxe/src/arch/i386/include/gpxe/bios_timer.h b/gpxe/src/arch/i386/include/gpxe/bios_timer.h
new file mode 100644
index 00000000..7e3caa3c
--- /dev/null
+++ b/gpxe/src/arch/i386/include/gpxe/bios_timer.h
@@ -0,0 +1,42 @@
+#ifndef _GPXE_BIOS_TIMER_H
+#define _GPXE_BIOS_TIMER_H
+
+/** @file
+ *
+ * BIOS timer
+ *
+ */
+
+#ifdef TIMER_PCBIOS
+#define TIMER_PREFIX_pcbios
+#else
+#define TIMER_PREFIX_pcbios __pcbios_
+#endif
+
+#include <gpxe/timer2.h>
+
+/**
+ * Delay for a fixed number of microseconds
+ *
+ * @v usecs Number of microseconds for which to delay
+ */
+static inline __always_inline void
+TIMER_INLINE ( pcbios, udelay ) ( unsigned long usecs ) {
+ /* BIOS timer is not high-resolution enough for udelay(), so
+ * we use timer2
+ */
+ timer2_udelay ( usecs );
+}
+
+/**
+ * Get number of ticks per second
+ *
+ * @ret ticks_per_sec Number of ticks per second
+ */
+static inline __always_inline unsigned long
+TIMER_INLINE ( pcbios, ticks_per_sec ) ( void ) {
+ /* BIOS timer ticks over at 18.2 ticks per second */
+ return 18;
+}
+
+#endif /* _GPXE_BIOS_TIMER_H */
diff --git a/gpxe/src/include/gpxe/ibft.h b/gpxe/src/arch/i386/include/gpxe/ibft.h
index 5eef547b..5eef547b 100644
--- a/gpxe/src/include/gpxe/ibft.h
+++ b/gpxe/src/arch/i386/include/gpxe/ibft.h
diff --git a/gpxe/src/arch/i386/include/gpxe/memtop_umalloc.h b/gpxe/src/arch/i386/include/gpxe/memtop_umalloc.h
new file mode 100644
index 00000000..a3cd2c01
--- /dev/null
+++ b/gpxe/src/arch/i386/include/gpxe/memtop_umalloc.h
@@ -0,0 +1,16 @@
+#ifndef _GPXE_MEMTOP_UMALLOC_H
+#define _GPXE_MEMTOP_UMALLOC_H
+
+/** @file
+ *
+ * External memory allocation
+ *
+ */
+
+#ifdef UMALLOC_MEMTOP
+#define UMALLOC_PREFIX_memtop
+#else
+#define UMALLOC_PREFIX_memtop __memtop_
+#endif
+
+#endif /* _GPXE_MEMTOP_UMALLOC_H */
diff --git a/gpxe/src/arch/i386/include/gpxe/rdtsc_timer.h b/gpxe/src/arch/i386/include/gpxe/rdtsc_timer.h
new file mode 100644
index 00000000..0e03d707
--- /dev/null
+++ b/gpxe/src/arch/i386/include/gpxe/rdtsc_timer.h
@@ -0,0 +1,37 @@
+#ifndef _GPXE_RDTSC_TIMER_H
+#define _GPXE_RDTSC_TIMER_H
+
+/** @file
+ *
+ * RDTSC timer
+ *
+ */
+
+#ifdef TIMER_RDTSC
+#define TIMER_PREFIX_rdtsc
+#else
+#define TIMER_PREFIX_rdtsc __rdtsc_
+#endif
+
+/**
+ * RDTSC values can easily overflow an unsigned long. We discard the
+ * low-order bits in order to obtain sensibly-scaled values.
+ */
+#define TSC_SHIFT 8
+
+/**
+ * Get current system time in ticks
+ *
+ * @ret ticks Current time, in ticks
+ */
+static inline __always_inline unsigned long
+TIMER_INLINE ( rdtsc, currticks ) ( void ) {
+ unsigned long ticks;
+
+ __asm__ __volatile__ ( "rdtsc\n\t"
+ "shrdl %1, %%edx, %%eax\n\t"
+ : "=a" ( ticks ) : "i" ( TSC_SHIFT ) : "edx" );
+ return ticks;
+}
+
+#endif /* _GPXE_RDTSC_TIMER_H */
diff --git a/gpxe/src/arch/i386/include/gpxe/timer2.h b/gpxe/src/arch/i386/include/gpxe/timer2.h
new file mode 100644
index 00000000..59705fa2
--- /dev/null
+++ b/gpxe/src/arch/i386/include/gpxe/timer2.h
@@ -0,0 +1,12 @@
+#ifndef _GPXE_TIMER2_H
+#define _GPXE_TIMER2_H
+
+/** @file
+ *
+ * Timer chip control
+ *
+ */
+
+extern void timer2_udelay ( unsigned long usecs );
+
+#endif /* _GPXE_TIMER2_H */
diff --git a/gpxe/src/arch/i386/include/gpxe/x86_io.h b/gpxe/src/arch/i386/include/gpxe/x86_io.h
new file mode 100644
index 00000000..b1ae3bac
--- /dev/null
+++ b/gpxe/src/arch/i386/include/gpxe/x86_io.h
@@ -0,0 +1,151 @@
+#ifndef _GPXE_X86_IO_H
+#define _GPXE_X86_IO_H
+
+/** @file
+ *
+ * gPXE I/O API for x86
+ *
+ * i386 uses direct pointer dereferences for accesses to memory-mapped
+ * I/O space, and the inX/outX instructions for accesses to
+ * port-mapped I/O space.
+ *
+ * 64-bit atomic accesses (readq() and writeq()) use MMX instructions,
+ * and will crash original Pentium and earlier CPUs. Fortunately, no
+ * hardware that requires atomic 64-bit accesses will physically fit
+ * into a machine with such an old CPU anyway.
+ */
+
+#ifdef IOAPI_X86
+#define IOAPI_PREFIX_x86
+#else
+#define IOAPI_PREFIX_x86 __x86_
+#endif
+
+/*
+ * Memory space mappings
+ *
+ */
+
+/*
+ * Physical<->Bus and Bus<->I/O address mappings
+ *
+ */
+
+static inline __always_inline unsigned long
+IOAPI_INLINE ( x86, phys_to_bus ) ( unsigned long phys_addr ) {
+ return phys_addr;
+}
+
+static inline __always_inline unsigned long
+IOAPI_INLINE ( x86, bus_to_phys ) ( unsigned long bus_addr ) {
+ return bus_addr;
+}
+
+static inline __always_inline void *
+IOAPI_INLINE ( x86, ioremap ) ( unsigned long bus_addr, size_t len __unused ) {
+ return phys_to_virt ( bus_addr );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( x86, iounmap ) ( volatile const void *io_addr __unused ) {
+ /* Nothing to do */
+}
+
+static inline __always_inline unsigned long
+IOAPI_INLINE ( x86, io_to_bus ) ( volatile const void *io_addr ) {
+ return virt_to_phys ( io_addr );
+}
+
+/*
+ * MMIO reads and writes up to 32 bits
+ *
+ */
+
+#define X86_READX( _api_func, _type ) \
+static inline __always_inline _type \
+IOAPI_INLINE ( x86, _api_func ) ( volatile _type *io_addr ) { \
+ return *io_addr; \
+}
+X86_READX ( readb, uint8_t );
+X86_READX ( readw, uint16_t );
+X86_READX ( readl, uint32_t );
+
+#define X86_WRITEX( _api_func, _type ) \
+static inline __always_inline void \
+IOAPI_INLINE ( x86, _api_func ) ( _type data, \
+ volatile _type *io_addr ) { \
+ *io_addr = data; \
+}
+X86_WRITEX ( writeb, uint8_t );
+X86_WRITEX ( writew, uint16_t );
+X86_WRITEX ( writel, uint32_t );
+
+/*
+ * PIO reads and writes up to 32 bits
+ *
+ */
+
+#define X86_INX( _insn_suffix, _type, _reg_prefix ) \
+static inline __always_inline _type \
+IOAPI_INLINE ( x86, in ## _insn_suffix ) ( volatile _type *io_addr ) { \
+ _type data; \
+ __asm__ __volatile__ ( "in" #_insn_suffix " %w1, %" _reg_prefix "0" \
+ : "=a" ( data ) : "Nd" ( io_addr ) ); \
+ return data; \
+} \
+static inline __always_inline void \
+IOAPI_INLINE ( x86, ins ## _insn_suffix ) ( volatile _type *io_addr, \
+ _type *data, \
+ unsigned int count ) { \
+ unsigned int discard_D; \
+ __asm__ __volatile__ ( "rep ins" #_insn_suffix \
+ : "=D" ( discard_D ) \
+ : "d" ( io_addr ), "c" ( count ), \
+ "0" ( data ) ); \
+}
+X86_INX ( b, uint8_t, "b" );
+X86_INX ( w, uint16_t, "w" );
+X86_INX ( l, uint32_t, "k" );
+
+#define X86_OUTX( _insn_suffix, _type, _reg_prefix ) \
+static inline __always_inline void \
+IOAPI_INLINE ( x86, out ## _insn_suffix ) ( _type data, \
+ volatile _type *io_addr ) { \
+ __asm__ __volatile__ ( "out" #_insn_suffix " %" _reg_prefix "0, %w1" \
+ : : "a" ( data ), "Nd" ( io_addr ) ); \
+} \
+static inline __always_inline void \
+IOAPI_INLINE ( x86, outs ## _insn_suffix ) ( volatile _type *io_addr, \
+ const _type *data, \
+ unsigned int count ) { \
+ unsigned int discard_S; \
+ __asm__ __volatile__ ( "rep outs" #_insn_suffix \
+ : "=S" ( discard_S ) \
+ : "d" ( io_addr ), "c" ( count ), \
+ "0" ( data ) ); \
+}
+X86_OUTX ( b, uint8_t, "b" );
+X86_OUTX ( w, uint16_t, "w" );
+X86_OUTX ( l, uint32_t, "k" );
+
+/*
+ * Slow down I/O
+ *
+ */
+
+static inline __always_inline void
+IOAPI_INLINE ( x86, iodelay ) ( void ) {
+ __asm__ __volatile__ ( "outb %al, $0x80" );
+}
+
+/*
+ * Memory barrier
+ *
+ */
+
+static inline __always_inline void
+IOAPI_INLINE ( x86, mb ) ( void ) {
+ __asm__ __volatile__ ( "lock; addl $0, 0(%%esp)" : : : "memory" );
+}
+
+#endif /* _GPXE_X86_IO_H */
diff --git a/gpxe/src/arch/i386/include/int13.h b/gpxe/src/arch/i386/include/int13.h
index 72ca97d7..bf6d0318 100644
--- a/gpxe/src/arch/i386/include/int13.h
+++ b/gpxe/src/arch/i386/include/int13.h
@@ -9,6 +9,7 @@
#include <stdint.h>
#include <gpxe/list.h>
+#include <realmode.h>
struct block_device;
diff --git a/gpxe/src/arch/i386/include/io.h b/gpxe/src/arch/i386/include/io.h
deleted file mode 100644
index c26fdf7e..00000000
--- a/gpxe/src/arch/i386/include/io.h
+++ /dev/null
@@ -1,265 +0,0 @@
-#ifndef ETHERBOOT_IO_H
-#define ETHERBOOT_IO_H
-
-#include <stdint.h>
-#include "virtaddr.h"
-
-/* virt_to_bus converts an addresss inside of etherboot [_start, _end]
- * into a memory access cards can use.
- */
-#define virt_to_bus virt_to_phys
-
-
-/* bus_to_virt reverses virt_to_bus, the address must be output
- * from virt_to_bus to be valid. This function does not work on
- * all bus addresses.
- */
-#define bus_to_virt phys_to_virt
-
-/* ioremap converts a random 32bit bus address into something
- * etherboot can access.
- */
-static inline void *ioremap(unsigned long bus_addr, unsigned long length __unused)
-{
- return bus_to_virt(bus_addr);
-}
-
-/* iounmap cleans up anything ioremap had to setup */
-static inline void iounmap(void *virt_addr __unused)
-{
- return;
-}
-
-/*
- * This file contains the definitions for the x86 IO instructions
- * inb/inw/inl/outb/outw/outl and the "string versions" of the same
- * (insb/insw/insl/outsb/outsw/outsl). You can also use "pausing"
- * versions of the single-IO instructions (inb_p/inw_p/..).
- *
- * This file is not meant to be obfuscating: it's just complicated
- * to (a) handle it all in a way that makes gcc able to optimize it
- * as well as possible and (b) trying to avoid writing the same thing
- * over and over again with slight variations and possibly making a
- * mistake somewhere.
- */
-
-/*
- * Thanks to James van Artsdalen for a better timing-fix than
- * the two short jumps: using outb's to a nonexistent port seems
- * to guarantee better timings even on fast machines.
- *
- * On the other hand, I'd like to be sure of a non-existent port:
- * I feel a bit unsafe about using 0x80 (should be safe, though)
- *
- * Linus
- */
-
-#ifdef SLOW_IO_BY_JUMPING
-#define __SLOW_DOWN_IO __asm__ __volatile__("jmp 1f\n1:\tjmp 1f\n1:")
-#else
-#define __SLOW_DOWN_IO __asm__ __volatile__("outb %al,$0x80")
-#endif
-
-#ifdef REALLY_SLOW_IO
-#define SLOW_DOWN_IO { __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; }
-#else
-#define SLOW_DOWN_IO __SLOW_DOWN_IO
-#endif
-
-/*
- * readX/writeX() are used to access memory mapped devices. On some
- * architectures the memory mapped IO stuff needs to be accessed
- * differently. On the x86 architecture, we just read/write the
- * memory location directly.
- */
-static inline __attribute__ (( always_inline )) unsigned long
-_readb ( volatile uint8_t *addr ) {
- unsigned long data = *addr;
- DBGIO ( "[%08lx] => %02lx\n", virt_to_phys ( addr ), data );
- return data;
-}
-static inline __attribute__ (( always_inline )) unsigned long
-_readw ( volatile uint16_t *addr ) {
- unsigned long data = *addr;
- DBGIO ( "[%08lx] => %04lx\n", virt_to_phys ( addr ), data );
- return data;
-}
-static inline __attribute__ (( always_inline )) unsigned long
-_readl ( volatile uint32_t *addr ) {
- unsigned long data = *addr;
- DBGIO ( "[%08lx] => %08lx\n", virt_to_phys ( addr ), data );
- return data;
-}
-#define readb( addr ) _readb ( ( volatile uint8_t * ) (addr) )
-#define readw( addr ) _readw ( ( volatile uint16_t * ) (addr) )
-#define readl( addr ) _readl ( ( volatile uint32_t * ) (addr) )
-
-static inline __attribute__ (( always_inline )) void
-_writeb ( unsigned long data, volatile uint8_t *addr ) {
- DBGIO ( "[%08lx] <= %02lx\n", virt_to_phys ( addr ), data );
- *addr = data;
-}
-static inline __attribute__ (( always_inline )) void
-_writew ( unsigned long data, volatile uint16_t *addr ) {
- DBGIO ( "[%08lx] <= %04lx\n", virt_to_phys ( addr ), data );
- *addr = data;
-}
-static inline __attribute__ (( always_inline )) void
-_writel ( unsigned long data, volatile uint32_t *addr ) {
- DBGIO ( "[%08lx] <= %08lx\n", virt_to_phys ( addr ), data );
- *addr = data;
-}
-#define writeb( b, addr ) _writeb ( (b), ( volatile uint8_t * ) (addr) )
-#define writew( b, addr ) _writew ( (b), ( volatile uint16_t * ) (addr) )
-#define writel( b, addr ) _writel ( (b), ( volatile uint32_t * ) (addr) )
-
-#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c))
-#define memcpy_toio(a,b,c) memcpy((void *)(a),(b),(c))
-
-/*
- * Force strict CPU ordering.
- * And yes, this is required on UP too when we're talking
- * to devices.
- *
- * For now, "wmb()" doesn't actually do anything, as all
- * Intel CPU's follow what Intel calls a *Processor Order*,
- * in which all writes are seen in the program order even
- * outside the CPU.
- *
- * I expect future Intel CPU's to have a weaker ordering,
- * but I'd also expect them to finally get their act together
- * and add some real memory barriers if so.
- *
- * Some non intel clones support out of order store. wmb() ceases to be a
- * nop for these.
- */
-
-#define mb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
-#define rmb() mb()
-#define wmb() mb();
-
-
-/*
- * Talk about misusing macros..
- */
-
-#define __OUT1(s,x) \
-extern void __out##s(unsigned x value, unsigned short port); \
-extern inline void __out##s(unsigned x value, unsigned short port) {
-
-#define __OUT2(s,s1,s2) \
-__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
-
-#define __OUT(s,s1,x) \
-__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "d" (port)); } \
-__OUT1(s##c,x) __OUT2(s,s1,"") : : "a" (value), "id" (port)); } \
-__OUT1(s##_p,x) __OUT2(s,s1,"w") : : "a" (value), "d" (port)); SLOW_DOWN_IO; } \
-__OUT1(s##c_p,x) __OUT2(s,s1,"") : : "a" (value), "id" (port)); SLOW_DOWN_IO; }
-
-#define __IN1(s,x) \
-extern unsigned x __in##s(unsigned short port); \
-extern inline unsigned x __in##s(unsigned short port) { unsigned x _v;
-
-#define __IN2(s,s1,s2) \
-__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
-
-#define __IN(s,s1,x,i...) \
-__IN1(s,x) __IN2(s,s1,"w") : "=a" (_v) : "d" (port) ,##i ); return _v; } \
-__IN1(s##c,x) __IN2(s,s1,"") : "=a" (_v) : "id" (port) ,##i ); return _v; } \
-__IN1(s##_p,x) __IN2(s,s1,"w") : "=a" (_v) : "d" (port) ,##i ); SLOW_DOWN_IO; return _v; } \
-__IN1(s##c_p,x) __IN2(s,s1,"") : "=a" (_v) : "id" (port) ,##i ); SLOW_DOWN_IO; return _v; }
-
-#define __INS(s) \
-extern void ins##s(unsigned short port, void * addr, unsigned long count); \
-extern inline void ins##s(unsigned short port, void * addr, unsigned long count) \
-{ __asm__ __volatile__ ("cld ; rep ; ins" #s \
-: "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
-
-#define __OUTS(s) \
-extern void outs##s(unsigned short port, const void * addr, unsigned long count); \
-extern inline void outs##s(unsigned short port, const void * addr, unsigned long count) \
-{ __asm__ __volatile__ ("cld ; rep ; outs" #s \
-: "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
-
-__IN(b,"", char)
-__IN(w,"",short)
-__IN(l,"", long)
-
-__OUT(b,"b",char)
-__OUT(w,"w",short)
-__OUT(l,,int)
-
-__INS(b)
-__INS(w)
-__INS(l)
-
-__OUTS(b)
-__OUTS(w)
-__OUTS(l)
-
-/*
- * Note that due to the way __builtin_constant_p() works, you
- * - can't use it inside a inline function (it will never be true)
- * - you don't have to worry about side effects within the __builtin..
- */
-#define outb(val,port) \
-((__builtin_constant_p((port)) && (port) < 256) ? \
- __outbc((val),(port)) : \
- __outb((val),(port)))
-
-#define inb(port) \
-((__builtin_constant_p((port)) && (port) < 256) ? \
- __inbc(port) : \
- __inb(port))
-
-#define outb_p(val,port) \
-((__builtin_constant_p((port)) && (port) < 256) ? \
- __outbc_p((val),(port)) : \
- __outb_p((val),(port)))
-
-#define inb_p(port) \
-((__builtin_constant_p((port)) && (port) < 256) ? \
- __inbc_p(port) : \
- __inb_p(port))
-
-#define outw(val,port) \
-((__builtin_constant_p((port)) && (port) < 256) ? \
- __outwc((val),(port)) : \
- __outw((val),(port)))
-
-#define inw(port) \
-((__builtin_constant_p((port)) && (port) < 256) ? \
- __inwc(port) : \
- __inw(port))
-
-#define outw_p(val,port) \
-((__builtin_constant_p((port)) && (port) < 256) ? \
- __outwc_p((val),(port)) : \
- __outw_p((val),(port)))
-
-#define inw_p(port) \
-((__builtin_constant_p((port)) && (port) < 256) ? \
- __inwc_p(port) : \
- __inw_p(port))
-
-#define outl(val,port) \
-((__builtin_constant_p((port)) && (port) < 256) ? \
- __outlc((val),(port)) : \
- __outl((val),(port)))
-
-#define inl(port) \
-((__builtin_constant_p((port)) && (port) < 256) ? \
- __inlc(port) : \
- __inl(port))
-
-#define outl_p(val,port) \
-((__builtin_constant_p((port)) && (port) < 256) ? \
- __outlc_p((val),(port)) : \
- __outl_p((val),(port)))
-
-#define inl_p(port) \
-((__builtin_constant_p((port)) && (port) < 256) ? \
- __inlc_p(port) : \
- __inl_p(port))
-
-#endif /* ETHERBOOT_IO_H */
diff --git a/gpxe/src/arch/i386/include/librm.h b/gpxe/src/arch/i386/include/librm.h
index 07a85c59..9eb2767a 100644..100755
--- a/gpxe/src/arch/i386/include/librm.h
+++ b/gpxe/src/arch/i386/include/librm.h
@@ -1,21 +1,109 @@
#ifndef LIBRM_H
#define LIBRM_H
-/* Drag in protected-mode segment selector values */
-#include "virtaddr.h"
-#include "realmode.h"
+/* Segment selectors as used in our protected-mode GDTs.
+ *
+ * Don't change these unless you really know what you're doing.
+ */
+
+#define VIRTUAL_CS 0x08
+#define VIRTUAL_DS 0x10
+#define PHYSICAL_CS 0x18
+#define PHYSICAL_DS 0x20
+#define REAL_CS 0x28
+#define REAL_DS 0x30
+#if 0
+#define LONG_CS 0x38
+#define LONG_DS 0x40
+#endif
#ifndef ASSEMBLY
-#include "stddef.h"
-#include "string.h"
+#ifdef UACCESS_LIBRM
+#define UACCESS_PREFIX_librm
+#else
+#define UACCESS_PREFIX_librm __librm_
+#endif
+
+/* Variables in librm.S */
+extern unsigned long virt_offset;
+
+/**
+ * Convert physical address to user pointer
+ *
+ * @v phys_addr Physical address
+ * @ret userptr User pointer
+ */
+static inline __always_inline userptr_t
+UACCESS_INLINE ( librm, phys_to_user ) ( unsigned long phys_addr ) {
+ return ( phys_addr - virt_offset );
+}
-/*
- * Data structures and type definitions
+/**
+ * Convert user buffer to physical address
+ *
+ * @v userptr User pointer
+ * @v offset Offset from user pointer
+ * @ret phys_addr Physical address
+ */
+static inline __always_inline unsigned long
+UACCESS_INLINE ( librm, user_to_phys ) ( userptr_t userptr, off_t offset ) {
+ return ( userptr + offset + virt_offset );
+}
+
+static inline __always_inline userptr_t
+UACCESS_INLINE ( librm, virt_to_user ) ( volatile const void *addr ) {
+ return trivial_virt_to_user ( addr );
+}
+
+static inline __always_inline void *
+UACCESS_INLINE ( librm, user_to_virt ) ( userptr_t userptr, off_t offset ) {
+ return trivial_user_to_virt ( userptr, offset );
+}
+
+static inline __always_inline userptr_t
+UACCESS_INLINE ( librm, userptr_add ) ( userptr_t userptr, off_t offset ) {
+ return trivial_userptr_add ( userptr, offset );
+}
+
+static inline __always_inline void
+UACCESS_INLINE ( librm, memcpy_user ) ( userptr_t dest, off_t dest_off,
+ userptr_t src, off_t src_off,
+ size_t len ) {
+ trivial_memcpy_user ( dest, dest_off, src, src_off, len );
+}
+
+static inline __always_inline void
+UACCESS_INLINE ( librm, memmove_user ) ( userptr_t dest, off_t dest_off,
+ userptr_t src, off_t src_off,
+ size_t len ) {
+ trivial_memmove_user ( dest, dest_off, src, src_off, len );
+}
+
+static inline __always_inline void
+UACCESS_INLINE ( librm, memset_user ) ( userptr_t buffer, off_t offset,
+ int c, size_t len ) {
+ trivial_memset_user ( buffer, offset, c, len );
+}
+
+static inline __always_inline size_t
+UACCESS_INLINE ( librm, strlen_user ) ( userptr_t buffer, off_t offset ) {
+ return trivial_strlen_user ( buffer, offset );
+}
+
+static inline __always_inline off_t
+UACCESS_INLINE ( librm, memchr_user ) ( userptr_t buffer, off_t offset,
+ int c, size_t len ) {
+ return trivial_memchr_user ( buffer, offset, c, len );
+}
+
+
+/******************************************************************************
+ *
+ * Access to variables in .data16 and .text16
*
*/
-/* Access to variables in .data16 and .text16 */
extern char *data16;
extern char *text16;
@@ -72,178 +160,6 @@ extern uint16_t __text16 ( rm_ds );
*/
extern void gateA20_set ( void );
-/*
- * librm_mgmt: functions for manipulating base memory and executing
- * real-mode code.
- *
- * Full API documentation for these functions is in realmode.h.
- *
- */
-
-/* Macro for obtaining a physical address from a segment:offset pair. */
-#define VIRTUAL(x,y) ( phys_to_virt ( ( ( x ) << 4 ) + ( y ) ) )
-
-/* Copy to/from base memory */
-static inline __attribute__ (( always_inline )) void
-copy_to_real_librm ( unsigned int dest_seg, unsigned int dest_off,
- void *src, size_t n ) {
- memcpy ( VIRTUAL ( dest_seg, dest_off ), src, n );
-}
-static inline __attribute__ (( always_inline )) void
-copy_from_real_librm ( void *dest, unsigned int src_seg,
- unsigned int src_off, size_t n ) {
- memcpy ( dest, VIRTUAL ( src_seg, src_off ), n );
-}
-#define put_real_librm( var, dest_seg, dest_off ) \
- do { \
- * ( ( typeof(var) * ) VIRTUAL ( dest_seg, dest_off ) ) = var; \
- } while ( 0 )
-#define get_real_librm( var, src_seg, src_off ) \
- do { \
- var = * ( ( typeof(var) * ) VIRTUAL ( src_seg, src_off ) ); \
- } while ( 0 )
-#define copy_to_real copy_to_real_librm
-#define copy_from_real copy_from_real_librm
-#define put_real put_real_librm
-#define get_real get_real_librm
-
-/**
- * A pointer to a user buffer
- *
- * Even though we could just use a void *, we use an intptr_t so that
- * attempts to use normal pointers show up as compiler warnings. Such
- * code is actually valid for librm, but not for libkir (i.e. under
- * KEEP_IT_REAL), so it's good to have the warnings even under librm.
- */
-typedef intptr_t userptr_t;
-
-/**
- * Add offset to user pointer
- *
- * @v ptr User pointer
- * @v offset Offset
- * @ret new_ptr New pointer value
- */
-static inline __attribute__ (( always_inline )) userptr_t
-userptr_add ( userptr_t ptr, off_t offset ) {
- return ( ptr + offset );
-}
-
-/**
- * Copy data to user buffer
- *
- * @v buffer User buffer
- * @v offset Offset within user buffer
- * @v src Source
- * @v len Length
- */
-static inline __attribute__ (( always_inline )) void
-copy_to_user ( userptr_t buffer, off_t offset, const void *src, size_t len ) {
- memcpy ( ( ( void * ) buffer + offset ), src, len );
-}
-
-/**
- * Copy data from user buffer
- *
- * @v dest Destination
- * @v buffer User buffer
- * @v offset Offset within user buffer
- * @v len Length
- */
-static inline __attribute__ (( always_inline )) void
-copy_from_user ( void *dest, userptr_t buffer, off_t offset, size_t len ) {
- memcpy ( dest, ( ( void * ) buffer + offset ), len );
-}
-
-/**
- * Copy data between user buffers
- *
- * @v dest Destination user buffer
- * @v dest_off Offset within destination buffer
- * @v src Source user buffer
- * @v src_off Offset within source buffer
- * @v len Length
- */
-static inline __attribute__ (( always_inline )) void
-memcpy_user ( userptr_t dest, off_t dest_off, userptr_t src, off_t src_off,
- size_t len ) {
- memcpy ( ( ( void * ) dest + dest_off ), ( ( void * ) src + src_off ),
- len );
-}
-
-/**
- * Copy data between user buffers, allowing for overlap
- *
- * @v dest Destination user buffer
- * @v dest_off Offset within destination buffer
- * @v src Source user buffer
- * @v src_off Offset within source buffer
- * @v len Length
- */
-static inline __attribute__ (( always_inline )) void
-memmove_user ( userptr_t dest, off_t dest_off, userptr_t src, off_t src_off,
- size_t len ) {
- memmove ( ( ( void * ) dest + dest_off ), ( ( void * ) src + src_off ),
- len );
-}
-
-/**
- * Fill user buffer with a constant byte
- *
- * @v buffer User buffer
- * @v offset Offset within buffer
- * @v c Constant byte with which to fill
- * @v len Length
- */
-static inline __attribute__ (( always_inline )) void
-memset_user ( userptr_t buffer, off_t offset, int c, size_t len ) {
- memset ( ( ( void * ) buffer + offset ), c, len );
-}
-
-/**
- * Find length of NUL-terminated string in user buffer
- *
- * @v buffer User buffer
- * @v offset Offset within buffer
- * @ret len Length of string (excluding NUL)
- */
-static inline __attribute__ (( always_inline )) size_t
-strlen_user ( userptr_t buffer, off_t offset ) {
- return strlen ( ( void * ) buffer + offset );
-}
-
-/**
- * Find character in user buffer
- *
- * @v buffer User buffer
- * @v offset Starting offset within buffer
- * @v c Character to search for
- * @v len Length of user buffer
- * @ret offset Offset of character, or <0 if not found
- */
-static inline __attribute__ (( always_inline )) off_t
-memchr_user ( userptr_t buffer, off_t offset, int c, size_t len ) {
- void *found;
-
- found = memchr ( ( ( void * ) buffer + offset ), c, len );
- return ( found ? ( found - ( void * ) buffer ) : -1 );
-}
-
-/**
- * Convert virtual address to user buffer
- *
- * @v virtual Virtual address
- * @ret buffer User buffer
- *
- * This constructs a user buffer from an ordinary pointer. Use it
- * when you need to pass a pointer to an internal buffer to a function
- * that expects a @c userptr_t.
- */
-static inline __attribute__ (( always_inline )) userptr_t
-virt_to_user ( void * virtual ) {
- return ( ( intptr_t ) virtual );
-}
-
/**
* Convert segment:offset address to user buffer
*
@@ -251,32 +167,9 @@ virt_to_user ( void * virtual ) {
* @v offset Real-mode offset
* @ret buffer User buffer
*/
-static inline __attribute__ (( always_inline )) userptr_t
+static inline __always_inline userptr_t
real_to_user ( unsigned int segment, unsigned int offset ) {
- return virt_to_user ( VIRTUAL ( segment, offset ) );
-}
-
-/**
- * Convert physical address to user buffer
- *
- * @v physical Physical address
- * @ret buffer User buffer
- */
-static inline __attribute__ (( always_inline )) userptr_t
-phys_to_user ( physaddr_t physical ) {
- return virt_to_user ( phys_to_virt ( physical ) );
-}
-
-/**
- * Convert user buffer to physical address
- *
- * @v buffer User buffer
- * @v offset Offset within user buffer
- * @ret physical Physical address
- */
-static inline __attribute__ (( always_inline )) physaddr_t
-user_to_phys ( userptr_t buffer, off_t offset ) {
- return virt_to_phys ( ( void * ) buffer + offset );
+ return ( phys_to_user ( ( segment << 4 ) + offset ) );
}
extern uint16_t copy_user_to_rm_stack ( userptr_t data, size_t size );
diff --git a/gpxe/src/arch/i386/include/pci_io.h b/gpxe/src/arch/i386/include/pci_io.h
deleted file mode 100644
index 4888d557..00000000
--- a/gpxe/src/arch/i386/include/pci_io.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef _PCI_IO_H
-#define _PCI_IO_H
-
-#include <pcibios.h>
-#include <pcidirect.h>
-
-/** @file
- *
- * i386 PCI configuration space access
- *
- * We have two methods of PCI configuration space access: the PCI BIOS
- * and direct Type 1 accesses. Selecting between them is via the
- * compile-time switch -DCONFIG_PCI_DIRECT.
- *
- */
-
-#if CONFIG_PCI_DIRECT
-#define pci_max_bus pcidirect_max_bus
-#define pci_read_config_byte pcidirect_read_config_byte
-#define pci_read_config_word pcidirect_read_config_word
-#define pci_read_config_dword pcidirect_read_config_dword
-#define pci_write_config_byte pcidirect_write_config_byte
-#define pci_write_config_word pcidirect_write_config_word
-#define pci_write_config_dword pcidirect_write_config_dword
-#else /* CONFIG_PCI_DIRECT */
-#define pci_max_bus pcibios_max_bus
-#define pci_read_config_byte pcibios_read_config_byte
-#define pci_read_config_word pcibios_read_config_word
-#define pci_read_config_dword pcibios_read_config_dword
-#define pci_write_config_byte pcibios_write_config_byte
-#define pci_write_config_word pcibios_write_config_word
-#define pci_write_config_dword pcibios_write_config_dword
-#endif /* CONFIG_PCI_DIRECT */
-
-#endif /* _PCI_IO_H */
diff --git a/gpxe/src/include/pxe.h b/gpxe/src/arch/i386/include/pxe.h
index 6d332ac7..6d332ac7 100644
--- a/gpxe/src/include/pxe.h
+++ b/gpxe/src/arch/i386/include/pxe.h
diff --git a/gpxe/src/arch/i386/include/pxe_addr.h b/gpxe/src/arch/i386/include/pxe_addr.h
deleted file mode 100644
index 954551e8..00000000
--- a/gpxe/src/arch/i386/include/pxe_addr.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Architecture-specific portion of pxe.h for Etherboot
- *
- * This file has to define the types SEGOFF16_t, SEGDESC_t and
- * SEGSEL_t for use in other PXE structures. See pxe.h for details.
- */
-
-#ifndef PXE_ADDR_H
-#define PXE_ADDR_H
-
-#define IS_NULL_SEGOFF16(x) ( ( (x).segment == 0 ) && ( (x).offset == 0 ) )
-#define SEGOFF16_TO_PTR(x) ( VIRTUAL( (x).segment, (x).offset ) )
-#define PTR_TO_SEGOFF16(ptr,segoff16) \
- (segoff16).segment = SEGMENT(ptr); \
- (segoff16).offset = OFFSET(ptr);
-
-#endif /* PXE_ADDR_H */
diff --git a/gpxe/src/include/pxe_api.h b/gpxe/src/arch/i386/include/pxe_api.h
index b3d4bca8..b3d4bca8 100644
--- a/gpxe/src/include/pxe_api.h
+++ b/gpxe/src/arch/i386/include/pxe_api.h
diff --git a/gpxe/src/arch/i386/include/pxe_call.h b/gpxe/src/arch/i386/include/pxe_call.h
index 7a38d314..2f3ea15a 100644
--- a/gpxe/src/arch/i386/include/pxe_call.h
+++ b/gpxe/src/arch/i386/include/pxe_call.h
@@ -30,6 +30,6 @@ extern void pxe_hook_int1a ( void );
extern int pxe_unhook_int1a ( void );
extern void pxe_init_structures ( void );
extern int pxe_start_nbp ( void );
-extern __cdecl void pxe_api_call ( struct i386_all_regs *ix86 );
+extern __asmcall void pxe_api_call ( struct i386_all_regs *ix86 );
#endif /* _PXE_CALL_H */
diff --git a/gpxe/src/include/pxe_types.h b/gpxe/src/arch/i386/include/pxe_types.h
index e31af062..dd9092ef 100644
--- a/gpxe/src/include/pxe_types.h
+++ b/gpxe/src/arch/i386/include/pxe_types.h
@@ -7,9 +7,8 @@
*
*/
-#include "stdint.h"
-#include "pxe_addr.h" /* Architecture-specific PXE definitions */
-#include "errno.h" /* PXE status codes */
+#include <stdint.h>
+#include <errno.h> /* PXE status codes */
/** @addtogroup pxe Preboot eXecution Environment (PXE) API
* @{
diff --git a/gpxe/src/arch/i386/include/realmode.h b/gpxe/src/arch/i386/include/realmode.h
index 5d3ddf50..26e6dd77 100644
--- a/gpxe/src/arch/i386/include/realmode.h
+++ b/gpxe/src/arch/i386/include/realmode.h
@@ -1,45 +1,15 @@
#ifndef REALMODE_H
#define REALMODE_H
-#ifndef ASSEMBLY
-
-#include "stdint.h"
-#include "registers.h"
-#include "io.h"
+#include <stdint.h>
+#include <registers.h>
+#include <gpxe/uaccess.h>
/*
* Data structures and type definitions
*
*/
-/* Segment:offset structure. Note that the order within the structure
- * is offset:segment.
- */
-struct segoff {
- uint16_t offset;
- uint16_t segment;
-} __attribute__ (( packed ));
-
-typedef struct segoff segoff_t;
-
-/* Macro hackery needed to stringify bits of inline assembly */
-#define RM_XSTR(x) #x
-#define RM_STR(x) RM_XSTR(x)
-
-/* Drag in the selected real-mode transition library header */
-#ifdef KEEP_IT_REAL
-#include "libkir.h"
-#else
-#include "librm.h"
-#endif
-
-/*
- * The API to some functions is identical between librm and libkir, so
- * they are documented here, even though the prototypes are in librm.h
- * and libkir.h.
- *
- */
-
/*
* Declaration of variables in .data16
*
@@ -92,24 +62,53 @@ typedef struct segoff segoff_t;
* assembler output to make sure that it's doing the right thing.
*/
-/*
- * void copy_to_real ( uint16_t dest_seg, uint16_t dest_off,
- * void *src, size_t n )
- * void copy_from_real ( void *dest, uint16_t src_seg, uint16_t src_off,
- * size_t n )
+/**
+ * Copy data to base memory
*
- * These functions can be used to copy data to and from arbitrary
- * locations in base memory.
+ * @v dest_seg Destination segment
+ * @v dest_off Destination offset
+ * @v src Source
+ * @v len Length
*/
+static inline __always_inline void
+copy_to_real ( unsigned int dest_seg, unsigned int dest_off,
+ void *src, size_t n ) {
+ copy_to_user ( real_to_user ( dest_seg, dest_off ), 0, src, n );
+}
-/*
- * put_real ( variable, uint16_t dest_seg, uint16_t dest_off )
- * get_real ( variable, uint16_t src_seg, uint16_t src_off )
+/**
+ * Copy data to base memory
+ *
+ * @v dest Destination
+ * @v src_seg Source segment
+ * @v src_off Source offset
+ * @v len Length
+ */
+static inline __always_inline void
+copy_from_real ( void *dest, unsigned int src_seg,
+ unsigned int src_off, size_t n ) {
+ copy_from_user ( dest, real_to_user ( src_seg, src_off ), 0, n );
+}
+
+/**
+ * Write a single variable to base memory
*
- * These macros can be used to read or write single variables to and
- * from arbitrary locations in base memory. "variable" must be a
- * variable of either 1, 2 or 4 bytes in length.
+ * @v var Variable to write
+ * @v dest_seg Destination segment
+ * @v dest_off Destination offset
*/
+#define put_real( var, dest_seg, dest_off ) \
+ copy_to_real ( (dest_seg), (dest_off), &(var), sizeof (var) )
+
+/**
+ * Read a single variable from base memory
+ *
+ * @v var Variable to read
+ * @v src_seg Source segment
+ * @v src_off Source offset
+ */
+#define get_real( var, src_seg, src_off ) \
+ copy_from_real ( &(var), (src_seg), (src_off), sizeof (var) )
/*
* REAL_CODE ( asm_code_str )
@@ -123,6 +122,4 @@ typedef struct segoff segoff_t;
*
*/
-#endif /* ASSEMBLY */
-
#endif /* REALMODE_H */
diff --git a/gpxe/src/arch/i386/include/registers.h b/gpxe/src/arch/i386/include/registers.h
index 2b9b2b43..e68fa85a 100644
--- a/gpxe/src/arch/i386/include/registers.h
+++ b/gpxe/src/arch/i386/include/registers.h
@@ -10,8 +10,7 @@
*
*/
-#include "compiler.h" /* for doxygen */
-#include "stdint.h"
+#include <stdint.h>
/**
* A 16-bit general register.
@@ -184,4 +183,14 @@ struct i386_all_regs {
#define SF ( 1 << 7 )
#define OF ( 1 << 11 )
+/* Segment:offset structure. Note that the order within the structure
+ * is offset:segment.
+ */
+struct segoff {
+ uint16_t offset;
+ uint16_t segment;
+} PACKED;
+
+typedef struct segoff segoff_t;
+
#endif /* REGISTERS_H */
diff --git a/gpxe/src/arch/i386/include/setjmp.h b/gpxe/src/arch/i386/include/setjmp.h
index bb0a100d..c18d03e1 100644
--- a/gpxe/src/arch/i386/include/setjmp.h
+++ b/gpxe/src/arch/i386/include/setjmp.h
@@ -1,12 +1,38 @@
#ifndef ETHERBOOT_SETJMP_H
#define ETHERBOOT_SETJMP_H
+#include <stdint.h>
+#include <realmode.h>
-/* Define a type for use by setjmp and longjmp */
-#define JBLEN 6
-typedef unsigned long jmp_buf[JBLEN];
+/** A jump buffer */
+typedef struct {
+ uint32_t retaddr;
+ uint32_t ebx;
+ uint32_t esp;
+ uint32_t ebp;
+ uint32_t esi;
+ uint32_t edi;
+} jmp_buf[1];
-extern int __cdecl setjmp (jmp_buf env);
-extern void __cdecl longjmp (jmp_buf env, int val);
+/** A real-mode-extended jump buffer */
+typedef struct {
+ jmp_buf env;
+ uint16_t rm_ss;
+ uint16_t rm_sp;
+} rmjmp_buf[1];
+
+extern int __asmcall setjmp ( jmp_buf env );
+extern void __asmcall longjmp ( jmp_buf env, int val );
+
+#define rmsetjmp( _env ) ( { \
+ (_env)->rm_ss = rm_ss; \
+ (_env)->rm_sp = rm_sp; \
+ setjmp ( (_env)->env ); } ) \
+
+#define rmlongjmp( _env, _val ) do { \
+ rm_ss = (_env)->rm_ss; \
+ rm_sp = (_env)->rm_sp; \
+ longjmp ( (_env)->env, (_val) ); \
+ } while ( 0 )
#endif /* ETHERBOOT_SETJMP_H */
diff --git a/gpxe/src/arch/i386/include/smbios.h b/gpxe/src/arch/i386/include/smbios.h
deleted file mode 100644
index f2736dc3..00000000
--- a/gpxe/src/arch/i386/include/smbios.h
+++ /dev/null
@@ -1,60 +0,0 @@
-#ifndef _SMBIOS_H
-#define _SMBIOS_H
-
-/** @file
- *
- * System Management BIOS
- */
-
-#include <stdint.h>
-
-/** An SMBIOS structure header */
-struct smbios_header {
- /** Type */
- uint8_t type;
- /** Length */
- uint8_t len;
- /** Handle */
- uint16_t handle;
-} __attribute__ (( packed ));
-
-/** SMBIOS structure descriptor */
-struct smbios_structure {
- /** Copy of SMBIOS structure header */
- struct smbios_header header;
- /** Offset of structure within SMBIOS */
- size_t offset;
- /** Length of strings section */
- size_t strings_len;
-};
-
-/** SMBIOS system information structure */
-struct smbios_system_information {
- /** SMBIOS structure header */
- struct smbios_header header;
- /** Manufacturer string */
- uint8_t manufacturer;
- /** Product string */
- uint8_t product;
- /** Version string */
- uint8_t version;
- /** Serial number string */
- uint8_t serial;
- /** UUID */
- uint8_t uuid[16];
- /** Wake-up type */
- uint8_t wakeup;
-} __attribute__ (( packed ));
-
-/** SMBIOS system information structure type */
-#define SMBIOS_TYPE_SYSTEM_INFORMATION 1
-
-extern int find_smbios_structure ( unsigned int type,
- struct smbios_structure *structure );
-extern int read_smbios_structure ( struct smbios_structure *structure,
- void *data, size_t len );
-extern int read_smbios_string ( struct smbios_structure *structure,
- unsigned int index,
- void *data, size_t len );
-
-#endif /* _SMBIOS_H */
diff --git a/gpxe/src/arch/i386/include/undi.h b/gpxe/src/arch/i386/include/undi.h
index 9936e17f..c6253d0a 100644
--- a/gpxe/src/arch/i386/include/undi.h
+++ b/gpxe/src/arch/i386/include/undi.h
@@ -24,10 +24,6 @@ struct undi_device {
SEGOFF16_t ppxe;
/** Entry point */
SEGOFF16_t entry;
- /** Return stack */
- UINT16_t return_stack[3];
- /** Return type */
- UINT16_t return_type;
/** Free base memory after load */
UINT16_t fbms;
/** Free base memory prior to load */
@@ -99,4 +95,10 @@ static inline void * undi_get_drvdata ( struct undi_device *undi ) {
/** UNDI flag: START_UNDI has been called */
#define UNDI_FL_STARTED 0x0001
+/** UNDI flag: UNDI_STARTUP and UNDI_INITIALIZE have been called */
+#define UNDI_FL_INITIALIZED 0x0002
+
+/** UNDI flag: keep stack resident */
+#define UNDI_FL_KEEP_ALL 0x0004
+
#endif /* _UNDI_H */
diff --git a/gpxe/src/arch/i386/include/virtaddr.h b/gpxe/src/arch/i386/include/virtaddr.h
deleted file mode 100644
index f2ffa2a1..00000000
--- a/gpxe/src/arch/i386/include/virtaddr.h
+++ /dev/null
@@ -1,105 +0,0 @@
-#ifndef VIRTADDR_H
-#define VIRTADDR_H
-
-/* Segment selectors as used in our protected-mode GDTs.
- *
- * Don't change these unless you really know what you're doing.
- */
-
-#define VIRTUAL_CS 0x08
-#define VIRTUAL_DS 0x10
-#define PHYSICAL_CS 0x18
-#define PHYSICAL_DS 0x20
-#define REAL_CS 0x28
-#define REAL_DS 0x30
-#if 0
-#define LONG_CS 0x38
-#define LONG_DS 0x40
-#endif
-
-#ifndef ASSEMBLY
-
-#include "stdint.h"
-#include "string.h"
-
-#ifndef KEEP_IT_REAL
-
-/*
- * Without -DKEEP_IT_REAL, we are in 32-bit protected mode with a
- * fixed link address but an unknown physical start address. Our GDT
- * sets up code and data segments with an offset of virt_offset, so
- * that link-time addresses can still work.
- *
- */
-
-/* C-callable function prototypes */
-
-extern void relocate_to ( uint32_t new_phys_addr );
-
-/* Variables in virtaddr.S */
-extern unsigned long virt_offset;
-
-/*
- * Convert between virtual and physical addresses
- *
- */
-static inline unsigned long virt_to_phys ( volatile const void *virt_addr ) {
- return ( ( unsigned long ) virt_addr ) + virt_offset;
-}
-
-static inline void * phys_to_virt ( unsigned long phys_addr ) {
- return ( void * ) ( phys_addr - virt_offset );
-}
-
-static inline void copy_to_phys ( physaddr_t dest, const void *src,
- size_t len ) {
- memcpy ( phys_to_virt ( dest ), src, len );
-}
-
-static inline void copy_from_phys ( void *dest, physaddr_t src, size_t len ) {
- memcpy ( dest, phys_to_virt ( src ), len );
-}
-
-static inline void copy_phys_to_phys ( physaddr_t dest, physaddr_t src,
- size_t len ) {
- memcpy ( phys_to_virt ( dest ), phys_to_virt ( src ), len );
-}
-
-#else /* KEEP_IT_REAL */
-
-/*
- * With -DKEEP_IT_REAL, we are in 16-bit real mode with fixed link
- * addresses and a segmented memory model. We have separate code and
- * data segments.
- *
- * Because we may be called in 16-bit protected mode (damn PXE spec),
- * we cannot simply assume that physical = segment * 16 + offset.
- * Instead, we have to look up the physical start address of the
- * segment in the !PXE structure. We have to assume that
- * virt_to_phys() is called only on pointers within the data segment,
- * because nothing passes segment information to us.
- *
- * We don't implement phys_to_virt at all, because there will be many
- * addresses that simply cannot be reached via a virtual address when
- * the virtual address space is limited to 64kB!
- */
-
-static inline unsigned long virt_to_phys ( volatile const void *virt_addr ) {
- /* Cheat: just for now, do the segment*16+offset calculation */
- uint16_t ds;
-
- __asm__ ( "movw %%ds, %%ax" : "=a" ( ds ) : );
- return ( 16 * ds + ( ( unsigned long ) virt_addr ) );
-}
-
-/* Define it as a deprecated function so that we get compile-time
- * warnings, rather than just the link-time errors.
- */
-extern void * phys_to_virt ( unsigned long phys_addr )
- __attribute__ ((deprecated));
-
-#endif /* KEEP_IT_REAL */
-
-#endif /* ASSEMBLY */
-
-#endif /* VIRTADDR_H */
diff --git a/gpxe/src/core/abft.c b/gpxe/src/arch/i386/interface/pcbios/abft.c
index af28bbcf..af28bbcf 100644
--- a/gpxe/src/core/abft.c
+++ b/gpxe/src/arch/i386/interface/pcbios/abft.c
diff --git a/gpxe/src/usr/aoeboot.c b/gpxe/src/arch/i386/interface/pcbios/aoeboot.c
index f0e481bd..6e1e51cb 100644
--- a/gpxe/src/usr/aoeboot.c
+++ b/gpxe/src/arch/i386/interface/pcbios/aoeboot.c
@@ -6,27 +6,11 @@
#include <gpxe/ata.h>
#include <gpxe/netdevice.h>
#include <gpxe/settings.h>
+#include <gpxe/sanboot.h>
#include <gpxe/abft.h>
#include <int13.h>
-#include <usr/aoeboot.h>
-/**
- * Guess boot network device
- *
- * @ret netdev Boot network device
- */
-static struct net_device * guess_boot_netdev ( void ) {
- struct net_device *boot_netdev;
-
- /* Just use the first network device */
- for_each_netdev ( boot_netdev ) {
- return boot_netdev;
- }
-
- return NULL;
-}
-
-int aoeboot ( const char *root_path ) {
+static int aoeboot ( const char *root_path ) {
struct ata_device ata;
struct int13_drive drive;
int rc;
@@ -37,7 +21,7 @@ int aoeboot ( const char *root_path ) {
printf ( "AoE booting from %s\n", root_path );
/* FIXME: ugly, ugly hack */
- struct net_device *netdev = guess_boot_netdev();
+ struct net_device *netdev = last_opened_netdev();
if ( ( rc = aoe_attach ( &ata, netdev, root_path ) ) != 0 ) {
printf ( "Could not attach AoE device: %s\n",
@@ -71,3 +55,8 @@ int aoeboot ( const char *root_path ) {
error_attach:
return rc;
}
+
+struct sanboot_protocol aoe_sanboot_protocol __sanboot_protocol = {
+ .prefix = "aoe:",
+ .boot = aoeboot,
+};
diff --git a/gpxe/src/arch/i386/interface/pcbios/bios_nap.c b/gpxe/src/arch/i386/interface/pcbios/bios_nap.c
new file mode 100644
index 00000000..2f4a0513
--- /dev/null
+++ b/gpxe/src/arch/i386/interface/pcbios/bios_nap.c
@@ -0,0 +1,14 @@
+#include <gpxe/nap.h>
+#include <realmode.h>
+
+/**
+ * Save power by halting the CPU until the next interrupt
+ *
+ */
+static void bios_cpu_nap ( void ) {
+ __asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
+ "hlt\n\t"
+ "cli\n\t" ) : : );
+}
+
+PROVIDE_NAP ( pcbios, cpu_nap, bios_cpu_nap );
diff --git a/gpxe/src/arch/i386/interface/pcbios/bios_smbios.c b/gpxe/src/arch/i386/interface/pcbios/bios_smbios.c
new file mode 100644
index 00000000..efaaef0d
--- /dev/null
+++ b/gpxe/src/arch/i386/interface/pcbios/bios_smbios.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <gpxe/uaccess.h>
+#include <gpxe/smbios.h>
+#include <realmode.h>
+#include <pnpbios.h>
+
+/** @file
+ *
+ * System Management BIOS
+ *
+ */
+
+/**
+ * Find SMBIOS
+ *
+ * @v smbios SMBIOS entry point descriptor structure to fill in
+ * @ret rc Return status code
+ */
+static int bios_find_smbios ( struct smbios *smbios ) {
+ union {
+ struct smbios_entry entry;
+ uint8_t bytes[256]; /* 256 is maximum length possible */
+ } u;
+ static unsigned int offset = 0;
+ size_t len;
+ unsigned int i;
+ uint8_t sum;
+
+ /* Try to find SMBIOS */
+ for ( ; offset < 0x10000 ; offset += 0x10 ) {
+
+ /* Read start of header and verify signature */
+ copy_from_real ( &u.entry, BIOS_SEG, offset,
+ sizeof ( u.entry ));
+ if ( u.entry.signature != SMBIOS_SIGNATURE )
+ continue;
+
+ /* Read whole header and verify checksum */
+ len = u.entry.len;
+ copy_from_real ( &u.bytes, BIOS_SEG, offset, len );
+ for ( i = 0 , sum = 0 ; i < len ; i++ ) {
+ sum += u.bytes[i];
+ }
+ if ( sum != 0 ) {
+ DBG ( "SMBIOS at %04x:%04x has bad checksum %02x\n",
+ BIOS_SEG, offset, sum );
+ continue;
+ }
+
+ /* Fill result structure */
+ DBG ( "Found SMBIOS v%d.%d entry point at %04x:%04x\n",
+ u.entry.major, u.entry.minor, BIOS_SEG, offset );
+ smbios->address = phys_to_user ( u.entry.smbios_address );
+ smbios->len = u.entry.smbios_len;
+ smbios->count = u.entry.smbios_count;
+ return 0;
+ }
+
+ DBG ( "No SMBIOS found\n" );
+ return -ENODEV;
+}
+
+PROVIDE_SMBIOS ( pcbios, find_smbios, bios_find_smbios );
diff --git a/gpxe/src/arch/i386/interface/pcbios/bios_timer.c b/gpxe/src/arch/i386/interface/pcbios/bios_timer.c
new file mode 100644
index 00000000..0b475ea3
--- /dev/null
+++ b/gpxe/src/arch/i386/interface/pcbios/bios_timer.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/** @file
+ *
+ * BIOS timer
+ *
+ */
+
+#include <gpxe/timer.h>
+#include <realmode.h>
+#include <bios.h>
+
+/**
+ * Get current system time in ticks
+ *
+ * @ret ticks Current time, in ticks
+ *
+ * Use direct memory access to BIOS variables, longword 0040:006C
+ * (ticks today) and byte 0040:0070 (midnight crossover flag) instead
+ * of calling timeofday BIOS interrupt.
+ */
+static unsigned long bios_currticks ( void ) {
+ static int days = 0;
+ uint32_t ticks;
+ uint8_t midnight;
+
+ /* Re-enable interrupts so that the timer interrupt can occur */
+ __asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "cli\n\t" ) : : );
+
+ get_real ( ticks, BDA_SEG, 0x006c );
+ get_real ( midnight, BDA_SEG, 0x0070 );
+
+ if ( midnight ) {
+ midnight = 0;
+ put_real ( midnight, BDA_SEG, 0x0070 );
+ days += 0x1800b0;
+ }
+
+ return ( days + ticks );
+}
+
+PROVIDE_TIMER_INLINE ( pcbios, udelay );
+PROVIDE_TIMER ( pcbios, currticks, bios_currticks );
+PROVIDE_TIMER_INLINE ( pcbios, ticks_per_sec );
diff --git a/gpxe/src/arch/i386/interface/pcbios/biosint.c b/gpxe/src/arch/i386/interface/pcbios/biosint.c
index 8ef2d7ab..1306f918 100644
--- a/gpxe/src/arch/i386/interface/pcbios/biosint.c
+++ b/gpxe/src/arch/i386/interface/pcbios/biosint.c
@@ -8,17 +8,6 @@
*/
/**
- * Hooked interrupt count
- *
- * At exit, after unhooking all possible interrupts, this counter
- * should be examined. If it is non-zero, it means that we failed to
- * unhook at least one interrupt vector, and so must not free up the
- * memory we are using. (Note that this also implies that we should
- * re-hook INT 15 in order to hide ourselves from the memory map).
- */
-int hooked_bios_interrupts = 0;
-
-/**
* Hook INT vector
*
* @v interrupt INT number
diff --git a/gpxe/src/core/ibft.c b/gpxe/src/arch/i386/interface/pcbios/ibft.c
index ffa65964..ffa65964 100644
--- a/gpxe/src/core/ibft.c
+++ b/gpxe/src/arch/i386/interface/pcbios/ibft.c
diff --git a/gpxe/src/arch/i386/interface/pcbios/int13.c b/gpxe/src/arch/i386/interface/pcbios/int13.c
index 6f61e4a1..2e9de5cb 100644
--- a/gpxe/src/arch/i386/interface/pcbios/int13.c
+++ b/gpxe/src/arch/i386/interface/pcbios/int13.c
@@ -144,7 +144,7 @@ static int int13_rw_sectors ( struct int13_drive *drive,
static int int13_read_sectors ( struct int13_drive *drive,
struct i386_all_regs *ix86 ) {
DBG ( "Read: " );
- return int13_rw_sectors ( drive, ix86, drive->blockdev->read );
+ return int13_rw_sectors ( drive, ix86, drive->blockdev->op->read );
}
/**
@@ -163,7 +163,7 @@ static int int13_read_sectors ( struct int13_drive *drive,
static int int13_write_sectors ( struct int13_drive *drive,
struct i386_all_regs *ix86 ) {
DBG ( "Write: " );
- return int13_rw_sectors ( drive, ix86, drive->blockdev->write );
+ return int13_rw_sectors ( drive, ix86, drive->blockdev->op->write );
}
/**
@@ -275,7 +275,7 @@ static int int13_extended_rw ( struct int13_drive *drive,
static int int13_extended_read ( struct int13_drive *drive,
struct i386_all_regs *ix86 ) {
DBG ( "Extended read: " );
- return int13_extended_rw ( drive, ix86, drive->blockdev->read );
+ return int13_extended_rw ( drive, ix86, drive->blockdev->op->read );
}
/**
@@ -288,7 +288,7 @@ static int int13_extended_read ( struct int13_drive *drive,
static int int13_extended_write ( struct int13_drive *drive,
struct i386_all_regs *ix86 ) {
DBG ( "Extended write: " );
- return int13_extended_rw ( drive, ix86, drive->blockdev->write );
+ return int13_extended_rw ( drive, ix86, drive->blockdev->op->write );
}
/**
@@ -322,7 +322,7 @@ static int int13_get_extended_parameters ( struct int13_drive *drive,
* INT 13 handler
*
*/
-static __cdecl void int13 ( struct i386_all_regs *ix86 ) {
+static __asmcall void int13 ( struct i386_all_regs *ix86 ) {
int command = ix86->regs.ah;
unsigned int bios_drive = ix86->regs.dl;
struct int13_drive *drive;
@@ -488,8 +488,8 @@ static void guess_int13_geometry ( struct int13_drive *drive ) {
/* Scan through partition table and modify guesses for heads
* and sectors_per_track if we find any used partitions.
*/
- if ( drive->blockdev->read ( drive->blockdev, 0, 1,
- virt_to_user ( &mbr ) ) == 0 ) {
+ if ( drive->blockdev->op->read ( drive->blockdev, 0, 1,
+ virt_to_user ( &mbr ) ) == 0 ) {
for ( i = 0 ; i < 4 ; i++ ) {
partition = &mbr.partitions[i];
if ( ! partition->type )
diff --git a/gpxe/src/usr/iscsiboot.c b/gpxe/src/arch/i386/interface/pcbios/iscsiboot.c
index 84d77c45..02aec4ba 100644
--- a/gpxe/src/usr/iscsiboot.c
+++ b/gpxe/src/arch/i386/interface/pcbios/iscsiboot.c
@@ -9,9 +9,9 @@
#include <gpxe/netdevice.h>
#include <gpxe/ibft.h>
#include <gpxe/init.h>
+#include <gpxe/sanboot.h>
#include <int13.h>
#include <usr/autoboot.h>
-#include <usr/iscsiboot.h>
struct setting keep_san_setting __setting = {
.name = "keep-san",
@@ -20,23 +20,7 @@ struct setting keep_san_setting __setting = {
.type = &setting_type_int8,
};
-/**
- * Guess boot network device
- *
- * @ret netdev Boot network device
- */
-static struct net_device * guess_boot_netdev ( void ) {
- struct net_device *boot_netdev;
-
- /* Just use the first network device */
- for_each_netdev ( boot_netdev ) {
- return boot_netdev;
- }
-
- return NULL;
-}
-
-int iscsiboot ( const char *root_path ) {
+static int iscsiboot ( const char *root_path ) {
struct scsi_device *scsi;
struct int13_drive *drive;
int keep_san;
@@ -69,7 +53,7 @@ int iscsiboot ( const char *root_path ) {
drive->blockdev = &scsi->blockdev;
/* FIXME: ugly, ugly hack */
- struct net_device *netdev = guess_boot_netdev();
+ struct net_device *netdev = last_opened_netdev();
struct iscsi_session *iscsi =
container_of ( scsi->backend, struct iscsi_session, refcnt );
ibft_fill_data ( netdev, iscsi );
@@ -100,3 +84,8 @@ int iscsiboot ( const char *root_path ) {
err_alloc_scsi:
return rc;
}
+
+struct sanboot_protocol iscsi_sanboot_protocol __sanboot_protocol = {
+ .prefix = "iscsi:",
+ .boot = iscsiboot,
+};
diff --git a/gpxe/src/arch/i386/core/umalloc.c b/gpxe/src/arch/i386/interface/pcbios/memtop_umalloc.c
index 3990488c..744d8e30 100644
--- a/gpxe/src/arch/i386/core/umalloc.c
+++ b/gpxe/src/arch/i386/interface/pcbios/memtop_umalloc.c
@@ -36,9 +36,6 @@
/** Equivalent of NOWHERE for user pointers */
#define UNOWHERE ( ~UNULL )
-/** Start of Etherboot text, as defined by the linker */
-extern char _text[];
-
/** An external memory block */
struct external_memory {
/** Size of this memory block (excluding this header) */
@@ -95,7 +92,7 @@ static int init_eheap ( void ) {
}
}
- if ( ! top ) {
+ if ( ! heap_size ) {
DBG ( "No external heap available\n" );
return -ENOMEM;
}
@@ -135,16 +132,16 @@ static void ecollect_free ( void ) {
* Calling realloc() with a new size of zero is a valid way to free a
* memory block.
*/
-userptr_t urealloc ( userptr_t ptr, size_t new_size ) {
+static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) {
struct external_memory extmem;
userptr_t new = ptr;
size_t align;
int rc;
/* Initialise external memory allocator if necessary */
- if ( ! top ) {
+ if ( bottom == top ) {
if ( ( rc = init_eheap() ) != 0 )
- return rc;
+ return UNULL;
}
/* Get block properties into extmem */
@@ -200,25 +197,4 @@ userptr_t urealloc ( userptr_t ptr, size_t new_size ) {
return ( new_size ? new : UNOWHERE );
}
-/**
- * Allocate external memory
- *
- * @v size Requested size
- * @ret ptr Memory, or UNULL
- *
- * Memory is guaranteed to be aligned to a page boundary.
- */
-userptr_t umalloc ( size_t size ) {
- return urealloc ( UNULL, size );
-}
-
-/**
- * Free external memory
- *
- * @v ptr Memory allocated by umalloc(), or UNULL
- *
- * If @c ptr is UNULL, no action is taken.
- */
-void ufree ( userptr_t ptr ) {
- urealloc ( ptr, 0 );
-}
+PROVIDE_UMALLOC ( memtop, urealloc, memtop_urealloc );
diff --git a/gpxe/src/arch/i386/core/pcibios.c b/gpxe/src/arch/i386/interface/pcbios/pcibios.c
index 1c93e4be..81b4fd3c 100644
--- a/gpxe/src/arch/i386/core/pcibios.c
+++ b/gpxe/src/arch/i386/interface/pcbios/pcibios.c
@@ -18,7 +18,6 @@
#include <stdint.h>
#include <gpxe/pci.h>
-#include <pcibios.h>
#include <realmode.h>
/** @file
@@ -32,7 +31,7 @@
*
* @ret max_bus Maximum bus number
*/
-int pcibios_max_bus ( void ) {
+static int pcibios_max_bus ( void ) {
int discard_a, discard_D;
uint8_t max_bus;
@@ -104,3 +103,11 @@ int pcibios_write ( struct pci_device *pci, uint32_t command, uint32_t value ){
return ( ( status >> 8 ) & 0xff );
}
+
+PROVIDE_PCIAPI ( pcbios, pci_max_bus, pcibios_max_bus );
+PROVIDE_PCIAPI_INLINE ( pcbios, pci_read_config_byte );
+PROVIDE_PCIAPI_INLINE ( pcbios, pci_read_config_word );
+PROVIDE_PCIAPI_INLINE ( pcbios, pci_read_config_dword );
+PROVIDE_PCIAPI_INLINE ( pcbios, pci_write_config_byte );
+PROVIDE_PCIAPI_INLINE ( pcbios, pci_write_config_word );
+PROVIDE_PCIAPI_INLINE ( pcbios, pci_write_config_dword );
diff --git a/gpxe/src/arch/i386/interface/pxe/pxe_call.c b/gpxe/src/arch/i386/interface/pxe/pxe_call.c
index 7122c4eb..04aaf3b2 100644
--- a/gpxe/src/arch/i386/interface/pxe/pxe_call.c
+++ b/gpxe/src/arch/i386/interface/pxe/pxe_call.c
@@ -119,7 +119,7 @@ static PXENV_EXIT_t pxenv_unknown ( struct s_PXENV_UNKNOWN *pxenv_unknown ) {
* @v es:di Address of PXE parameter block
* @ret ax PXE exit code
*/
-__cdecl void pxe_api_call ( struct i386_all_regs *ix86 ) {
+__asmcall void pxe_api_call ( struct i386_all_regs *ix86 ) {
int opcode = ix86->regs.bx;
userptr_t parameters = real_to_user ( ix86->segs.es, ix86->regs.di );
size_t param_len;
@@ -339,7 +339,7 @@ __cdecl void pxe_api_call ( struct i386_all_regs *ix86 ) {
* @v es:di Address of PXE parameter block
* @ret ax PXE exit code
*/
-__cdecl void pxe_loader_call ( struct i386_all_regs *ix86 ) {
+__asmcall void pxe_loader_call ( struct i386_all_regs *ix86 ) {
userptr_t uparams = real_to_user ( ix86->segs.es, ix86->regs.di );
struct s_UNDI_LOADER params;
PXENV_EXIT_t ret;
diff --git a/gpxe/src/arch/i386/interface/pxe/pxe_entry.S b/gpxe/src/arch/i386/interface/pxe/pxe_entry.S
index e5d327a5..68b7374f 100644
--- a/gpxe/src/arch/i386/interface/pxe/pxe_entry.S
+++ b/gpxe/src/arch/i386/interface/pxe/pxe_entry.S
@@ -18,15 +18,12 @@
*/
.arch i386
- .section ".text16", "awx", @progbits
- .section ".text16.data", "aw", @progbits
- .section ".data16", "aw", @progbits
/****************************************************************************
* !PXE structure
****************************************************************************
*/
- .section ".text16.data"
+ .section ".text16.data", "aw", @progbits
.globl ppxe
.align 16
ppxe:
@@ -44,10 +41,10 @@ ppxe:
.byte SegDescCnt /* SegDescCnt */
.word 0 /* FirstSelector */
pxe_segments:
- .word 0, 0, 0, _data16_size /* Stack */
- .word 0, 0, 0, _data16_size /* UNDIData */
- .word 0, 0, 0, _text16_size /* UNDICode */
- .word 0, 0, 0, _text16_size /* UNDICodeWrite */
+ .word 0, 0, 0, _data16_memsz /* Stack */
+ .word 0, 0, 0, _data16_memsz /* UNDIData */
+ .word 0, 0, 0, _text16_memsz /* UNDICode */
+ .word 0, 0, 0, _text16_memsz /* UNDICodeWrite */
.word 0, 0, 0, 0 /* BC_Data */
.word 0, 0, 0, 0 /* BC_Code */
.word 0, 0, 0, 0 /* BC_CodeWrite */
@@ -56,7 +53,7 @@ pxe_segments:
.size ppxe, . - ppxe
/* Define undiheader=0 as a weak symbol for non-ROM builds */
- .section ".weak"
+ .section ".weak", "a", @nobits
.weak undiheader
undiheader:
@@ -64,7 +61,7 @@ undiheader:
* PXENV+ structure
****************************************************************************
*/
- .section ".text16.data"
+ .section ".text16.data", "aw", @progbits
.globl pxenv
.align 16
pxenv:
@@ -76,15 +73,15 @@ pxenv:
.long 0 /* PMEntry */
.word 0 /* PMSelector */
.word 0 /* StackSeg */
- .word _data16_size /* StackSize */
+ .word _data16_memsz /* StackSize */
.word 0 /* BC_CodeSeg */
.word 0 /* BC_CodeSize */
.word 0 /* BC_DataSeg */
.word 0 /* BC_DataSize */
.word 0 /* UNDIDataSeg */
- .word _data16_size /* UNDIDataSize */
+ .word _data16_memsz /* UNDIDataSize */
.word 0 /* UNDICodeSeg */
- .word _text16_size /* UNDICodeSize */
+ .word _text16_memsz /* UNDICodeSize */
.word ppxe, 0 /* PXEPtr */
.equ pxenv_length, . - pxenv
.size pxenv, . - pxenv
@@ -108,12 +105,12 @@ pxenv:
* somebody at Wyse has difficulty distinguishing between the
* words "may" and "must"...
*/
- .section ".text16.null"
+ .section ".text16.null", "ax", @progbits
.code16
pxenv_null_entry:
jmp pxenv_entry
- .section ".text16"
+ .section ".text16", "ax", @progbits
.code16
pxenv_entry:
pushl $pxe_api_call
@@ -137,7 +134,7 @@ pxenv_entry:
* none
****************************************************************************
*/
- .section ".text16"
+ .section ".text16", "ax", @progbits
.code16
pxe_entry:
pxe_entry_sp:
@@ -186,7 +183,7 @@ pxe_entry_common:
* none
****************************************************************************
*/
- .section ".text16"
+ .section ".text16", "ax", @progbits
.code16
.globl pxe_int_1a
pxe_int_1a:
@@ -205,6 +202,6 @@ pxe_int_1a:
popfw
ljmp *%cs:pxe_int_1a_vector
- .section ".text16.data"
+ .section ".text16.data", "aw", @progbits
.globl pxe_int_1a_vector
pxe_int_1a_vector: .long 0
diff --git a/gpxe/src/interface/pxe/pxe_errors.c b/gpxe/src/arch/i386/interface/pxe/pxe_errors.c
index f884ef8a..f884ef8a 100644
--- a/gpxe/src/interface/pxe/pxe_errors.c
+++ b/gpxe/src/arch/i386/interface/pxe/pxe_errors.c
diff --git a/gpxe/src/interface/pxe/pxe_file.c b/gpxe/src/arch/i386/interface/pxe/pxe_file.c
index 41674588..41674588 100644
--- a/gpxe/src/interface/pxe/pxe_file.c
+++ b/gpxe/src/arch/i386/interface/pxe/pxe_file.c
diff --git a/gpxe/src/interface/pxe/pxe_loader.c b/gpxe/src/arch/i386/interface/pxe/pxe_loader.c
index d228a36d..d228a36d 100644
--- a/gpxe/src/interface/pxe/pxe_loader.c
+++ b/gpxe/src/arch/i386/interface/pxe/pxe_loader.c
diff --git a/gpxe/src/interface/pxe/pxe_preboot.c b/gpxe/src/arch/i386/interface/pxe/pxe_preboot.c
index 8220d1f2..193abc3d 100644
--- a/gpxe/src/interface/pxe/pxe_preboot.c
+++ b/gpxe/src/arch/i386/interface/pxe/pxe_preboot.c
@@ -82,7 +82,7 @@ struct pxe_dhcp_packet_creator {
static struct pxe_dhcp_packet_creator pxe_dhcp_packet_creators[] = {
[CACHED_INFO_DHCPDISCOVER] = { create_fakedhcpdiscover },
[CACHED_INFO_DHCPACK] = { create_fakedhcpack },
- [CACHED_INFO_BINL] = { create_fakeproxydhcpack },
+ [CACHED_INFO_BINL] = { create_fakepxebsack },
};
/* The case in which the caller doesn't supply a buffer is really
diff --git a/gpxe/src/interface/pxe/pxe_tftp.c b/gpxe/src/arch/i386/interface/pxe/pxe_tftp.c
index f5e76206..715a0b61 100644
--- a/gpxe/src/interface/pxe/pxe_tftp.c
+++ b/gpxe/src/arch/i386/interface/pxe/pxe_tftp.c
@@ -113,12 +113,6 @@ static int pxe_tftp_xfer_deliver_iob ( struct xfer_interface *xfer __unused,
/* Calculate new buffer position */
pxe_tftp.offset += len;
- /* Mildly ugly hack; assume that the first non-zero seek
- * indicates the block size.
- */
- if ( pxe_tftp.blksize == 0 )
- pxe_tftp.blksize = pxe_tftp.offset;
-
/* Record maximum offset as the file size */
if ( pxe_tftp.max_offset < pxe_tftp.offset )
pxe_tftp.max_offset = pxe_tftp.offset;
@@ -265,10 +259,12 @@ PXENV_EXIT_t pxenv_tftp_open ( struct s_PXENV_TFTP_OPEN *tftp_open ) {
/* Wait for OACK to arrive so that we have the block size */
while ( ( ( rc = pxe_tftp.rc ) == -EINPROGRESS ) &&
- ( pxe_tftp.blksize == 0 ) ) {
+ ( pxe_tftp.max_offset == 0 ) ) {
step();
}
+ pxe_tftp.blksize = xfer_window ( &pxe_tftp.xfer );
tftp_open->PacketSize = pxe_tftp.blksize;
+ DBG ( " blksize=%d", tftp_open->PacketSize );
/* EINPROGRESS is normal; we don't wait for the whole transfer */
if ( rc == -EINPROGRESS )
@@ -485,7 +481,7 @@ PXENV_EXIT_t pxenv_tftp_read_file ( struct s_PXENV_TFTP_READ_FILE
*tftp_read_file ) {
int rc;
- DBG ( "PXENV_TFTP_READ_FILE to %08lx+%lx", tftp_read_file->Buffer,
+ DBG ( "PXENV_TFTP_READ_FILE to %08x+%x", tftp_read_file->Buffer,
tftp_read_file->BufferSize );
/* Open TFTP file */
@@ -571,6 +567,7 @@ PXENV_EXIT_t pxenv_tftp_get_fsize ( struct s_PXENV_TFTP_GET_FSIZE
step();
}
tftp_get_fsize->FileSize = pxe_tftp.max_offset;
+ DBG ( " fsize=%d", tftp_get_fsize->FileSize );
/* EINPROGRESS is normal; we don't wait for the whole transfer */
if ( rc == -EINPROGRESS )
diff --git a/gpxe/src/interface/pxe/pxe_udp.c b/gpxe/src/arch/i386/interface/pxe/pxe_udp.c
index 033b1ad9..033b1ad9 100644
--- a/gpxe/src/interface/pxe/pxe_udp.c
+++ b/gpxe/src/arch/i386/interface/pxe/pxe_udp.c
diff --git a/gpxe/src/interface/pxe/pxe_undi.c b/gpxe/src/arch/i386/interface/pxe/pxe_undi.c
index 5d06f2d8..4e4a3da0 100644
--- a/gpxe/src/interface/pxe/pxe_undi.c
+++ b/gpxe/src/arch/i386/interface/pxe/pxe_undi.c
@@ -199,9 +199,10 @@ PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT
struct DataBlk *datablk;
struct io_buffer *iobuf;
struct net_protocol *net_protocol;
+ struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol;
char destaddr[MAX_LL_ADDR_LEN];
const void *ll_dest;
- size_t ll_hlen = pxe_netdev->ll_protocol->ll_header_len;
+ size_t ll_hlen = ll_protocol->ll_header_len;
size_t len;
unsigned int i;
int rc;
@@ -259,17 +260,17 @@ PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT
copy_from_real ( destaddr,
undi_transmit->DestAddr.segment,
undi_transmit->DestAddr.offset,
- pxe_netdev->ll_protocol->ll_addr_len );
+ ll_protocol->ll_addr_len );
ll_dest = destaddr;
} else {
DBG ( " BCAST" );
- ll_dest = pxe_netdev->ll_protocol->ll_broadcast;
+ ll_dest = ll_protocol->ll_broadcast;
}
/* Add link-layer header */
- if ( ( rc = pxe_netdev->ll_protocol->push ( iobuf, pxe_netdev,
- net_protocol,
- ll_dest )) != 0 ){
+ if ( ( rc = ll_protocol->push ( iobuf, ll_dest,
+ pxe_netdev->ll_addr,
+ net_protocol->net_proto ))!=0){
free_iob ( iobuf );
undi_transmit->Status = PXENV_STATUS ( rc );
return PXENV_EXIT_FAILURE;
@@ -391,10 +392,10 @@ PXENV_EXIT_t pxenv_undi_get_statistics ( struct s_PXENV_UNDI_GET_STATISTICS
*undi_get_statistics ) {
DBG ( "PXENV_UNDI_GET_STATISTICS" );
- undi_get_statistics->XmtGoodFrames = pxe_netdev->stats.tx_ok;
- undi_get_statistics->RcvGoodFrames = pxe_netdev->stats.rx_ok;
- undi_get_statistics->RcvCRCErrors = pxe_netdev->stats.rx_err;
- undi_get_statistics->RcvResourceErrors = pxe_netdev->stats.rx_err;
+ undi_get_statistics->XmtGoodFrames = pxe_netdev->tx_stats.good;
+ undi_get_statistics->RcvGoodFrames = pxe_netdev->rx_stats.good;
+ undi_get_statistics->RcvCRCErrors = pxe_netdev->rx_stats.bad;
+ undi_get_statistics->RcvResourceErrors = pxe_netdev->rx_stats.bad;
undi_get_statistics->Status = PXENV_STATUS_SUCCESS;
return PXENV_EXIT_SUCCESS;
@@ -408,7 +409,8 @@ PXENV_EXIT_t pxenv_undi_clear_statistics ( struct s_PXENV_UNDI_CLEAR_STATISTICS
*undi_clear_statistics ) {
DBG ( "PXENV_UNDI_CLEAR_STATISTICS" );
- memset ( &pxe_netdev->stats, 0, sizeof ( pxe_netdev->stats ) );
+ memset ( &pxe_netdev->tx_stats, 0, sizeof ( pxe_netdev->tx_stats ) );
+ memset ( &pxe_netdev->rx_stats, 0, sizeof ( pxe_netdev->rx_stats ) );
undi_clear_statistics->Status = PXENV_STATUS_SUCCESS;
return PXENV_EXIT_SUCCESS;
@@ -545,6 +547,7 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) {
struct io_buffer *iobuf;
size_t len;
struct ll_protocol *ll_protocol;
+ const void *ll_dest;
const void *ll_source;
uint16_t net_proto;
size_t ll_hlen;
@@ -625,9 +628,8 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) {
/* Strip link-layer header */
ll_protocol = pxe_netdev->ll_protocol;
- if ( ( rc = ll_protocol->pull ( iobuf, pxe_netdev,
- &net_proto,
- &ll_source ) ) != 0 ) {
+ if ( ( rc = ll_protocol->pull ( iobuf, &ll_dest, &ll_source,
+ &net_proto ) ) != 0 ) {
/* Assume unknown net_proto and no ll_source */
net_proto = 0;
ll_source = NULL;
diff --git a/gpxe/src/arch/i386/interface/syslinux/com32_call.c b/gpxe/src/arch/i386/interface/syslinux/com32_call.c
index 586730cf..4a782dce 100644
--- a/gpxe/src/arch/i386/interface/syslinux/com32_call.c
+++ b/gpxe/src/arch/i386/interface/syslinux/com32_call.c
@@ -41,7 +41,7 @@ uint16_t __bss16 ( com32_saved_sp );
/**
* Interrupt call helper
*/
-void __cdecl com32_intcall ( uint8_t interrupt, physaddr_t inregs_phys, physaddr_t outregs_phys ) {
+void __asmcall com32_intcall ( uint8_t interrupt, physaddr_t inregs_phys, physaddr_t outregs_phys ) {
memcpy_user ( virt_to_user( &com32_regs ), 0,
phys_to_user ( inregs_phys ), 0,
@@ -111,7 +111,7 @@ void __cdecl com32_intcall ( uint8_t interrupt, physaddr_t inregs_phys, physaddr
/**
* Farcall helper
*/
-void __cdecl com32_farcall ( uint32_t proc, physaddr_t inregs_phys, physaddr_t outregs_phys ) {
+void __asmcall com32_farcall ( uint32_t proc, physaddr_t inregs_phys, physaddr_t outregs_phys ) {
memcpy_user ( virt_to_user( &com32_regs ), 0,
phys_to_user ( inregs_phys ), 0,
@@ -170,7 +170,7 @@ void __cdecl com32_farcall ( uint32_t proc, physaddr_t inregs_phys, physaddr_t o
/**
* CDECL farcall helper
*/
-int __cdecl com32_cfarcall ( uint32_t proc, physaddr_t stack, size_t stacksz ) {
+int __asmcall com32_cfarcall ( uint32_t proc, physaddr_t stack, size_t stacksz ) {
int32_t eax;
copy_user_to_rm_stack ( phys_to_user ( stack ), stacksz );
diff --git a/gpxe/src/arch/i386/interface/syslinux/comboot_call.c b/gpxe/src/arch/i386/interface/syslinux/comboot_call.c
index 5a400ede..bf6c4c66 100644
--- a/gpxe/src/arch/i386/interface/syslinux/comboot_call.c
+++ b/gpxe/src/arch/i386/interface/syslinux/comboot_call.c
@@ -35,6 +35,8 @@
#include <gpxe/process.h>
#include <gpxe/serial.h>
#include <gpxe/init.h>
+#include <gpxe/image.h>
+#include <usr/imgmgmt.h>
/** The "SYSLINUX" version string */
static char __data16_array ( syslinux_version, [] ) = "gPXE " VERSION;
@@ -51,6 +53,14 @@ static char __data16_array ( syslinux_configuration_file, [] ) = "";
static uint8_t __data16 ( comboot_feature_flags ) = COMBOOT_FEATURE_IDLE_LOOP;
#define comboot_feature_flags __use_data16 ( comboot_feature_flags )
+typedef union {
+ syslinux_pm_regs pm; syslinux_rm_regs rm;
+} syslinux_regs;
+
+/** Initial register values for INT 22h AX=1Ah and 1Bh */
+static syslinux_regs __text16 ( comboot_initial_regs );
+#define comboot_initial_regs __use_text16 ( comboot_initial_regs )
+
static struct segoff __text16 ( int20_vector );
#define int20_vector __use_text16 ( int20_vector )
@@ -65,12 +75,10 @@ extern void int21_wrapper ( void );
extern void int22_wrapper ( void );
/* setjmp/longjmp context buffer used to return after loading an image */
-jmp_buf comboot_return;
+rmjmp_buf comboot_return;
-/* Command line to execute when returning via comboot_return
- * with COMBOOT_RETURN_RUN_KERNEL
- */
-char *comboot_kernel_cmdline;
+/* Replacement image when exiting with COMBOOT_EXIT_RUN_KERNEL */
+struct image *comboot_replacement_image;
/* Mode flags set by INT 22h AX=0017h */
static uint16_t comboot_graphics_mode = 0;
@@ -154,79 +162,101 @@ void comboot_force_text_mode ( void ) {
/**
- * Run the kernel specified in comboot_kernel_cmdline
+ * Fetch kernel and optional initrd
*/
-void comboot_run_kernel ( )
-{
- char *initrd;
-
- comboot_force_text_mode ( );
-
- DBG ( "COMBOOT: executing image '%s'\n", comboot_kernel_cmdline );
+static int comboot_fetch_kernel ( char *kernel_file, char *cmdline ) {
+ struct image *kernel = NULL;
+ struct image *initrd = NULL;
+ char *initrd_file;
+ int rc;
/* Find initrd= parameter, if any */
- if ( ( initrd = strstr ( comboot_kernel_cmdline, "initrd=" ) ) ) {
- char old_char = '\0';
- char *initrd_end = strchr( initrd, ' ' );
-
- /* Replace space after end of parameter
- * with a nul terminator if this is not
- * the last parameter
- */
- if ( initrd_end ) {
- old_char = *initrd_end;
- *initrd_end = '\0';
- }
+ if ( ( initrd_file = strstr ( cmdline, "initrd=" ) ) != NULL ) {
+ char *initrd_end;
- /* Replace = with space to get 'initrd filename'
- * command suitable for system()
- */
- initrd[6] = ' ';
+ /* skip "initrd=" */
+ initrd_file += 7;
- DBG( "COMBOOT: loading initrd '%s'\n", initrd );
+ /* Find terminating space, if any, and replace with NUL */
+ initrd_end = strchr ( initrd_file, ' ' );
+ if ( initrd_end )
+ *initrd_end = '\0';
- system ( initrd );
+ DBG ( "COMBOOT: fetching initrd '%s'\n", initrd_file );
- /* Restore space after parameter */
- if ( initrd_end ) {
- *initrd_end = old_char;
+ /* Allocate and fetch initrd */
+ initrd = alloc_image();
+ if ( ! initrd ) {
+ DBG ( "COMBOOT: could not allocate initrd\n" );
+ rc = -ENOMEM;
+ goto out;
+ }
+ if ( ( rc = imgfetch ( initrd, initrd_file,
+ register_image ) ) != 0 ) {
+ DBG ( "COMBOOT: could not fetch initrd: %s\n",
+ strerror ( rc ) );
+ goto out;
}
- /* Restore = */
- initrd[6] = '=';
+ /* Restore space after initrd name, if applicable */
+ if ( initrd_end )
+ *initrd_end = ' ';
}
- /* Load kernel */
- DBG ( "COMBOOT: loading kernel '%s'\n", comboot_kernel_cmdline );
- system ( comboot_kernel_cmdline );
-
- free ( comboot_kernel_cmdline );
+ DBG ( "COMBOOT: fetching kernel '%s'\n", kernel_file );
- /* Boot */
- system ( "boot" );
+ /* Allocate and fetch kernel */
+ kernel = alloc_image();
+ if ( ! kernel ) {
+ DBG ( "COMBOOT: could not allocate kernel\n" );
+ rc = -ENOMEM;
+ goto out;
+ }
+ if ( ( rc = imgfetch ( kernel, kernel_file,
+ register_image ) ) != 0 ) {
+ DBG ( "COMBOOT: could not fetch kernel: %s\n",
+ strerror ( rc ) );
+ goto out;
+ }
+ if ( ( rc = image_set_cmdline ( kernel, cmdline ) ) != 0 ) {
+ DBG ( "COMBOOT: could not set kernel command line: %s\n",
+ strerror ( rc ) );
+ goto out;
+ }
- DBG ( "COMBOOT: back from executing command\n" );
+ /* Store kernel as replacement image */
+ assert ( comboot_replacement_image == NULL );
+ comboot_replacement_image = image_get ( kernel );
+
+ out:
+ /* Drop image references unconditionally; either we want to
+ * discard them, or they have been registered and we should
+ * drop out local reference.
+ */
+ image_put ( kernel );
+ image_put ( initrd );
+ return rc;
}
/**
* Terminate program interrupt handler
*/
-static __cdecl void int20 ( struct i386_all_regs *ix86 __unused ) {
- longjmp ( comboot_return, COMBOOT_RETURN_EXIT );
+static __asmcall void int20 ( struct i386_all_regs *ix86 __unused ) {
+ rmlongjmp ( comboot_return, COMBOOT_EXIT );
}
/**
* DOS-compatible API
*/
-static __cdecl void int21 ( struct i386_all_regs *ix86 ) {
+static __asmcall void int21 ( struct i386_all_regs *ix86 ) {
ix86->flags |= CF;
switch ( ix86->regs.ah ) {
case 0x00:
case 0x4C: /* Terminate program */
- longjmp ( comboot_return, COMBOOT_RETURN_EXIT );
+ rmlongjmp ( comboot_return, COMBOOT_EXIT );
break;
case 0x01: /* Get Key with Echo */
@@ -287,14 +317,14 @@ static __cdecl void int21 ( struct i386_all_regs *ix86 ) {
/**
* SYSLINUX API
*/
-static __cdecl void int22 ( struct i386_all_regs *ix86 ) {
+static __asmcall void int22 ( struct i386_all_regs *ix86 ) {
ix86->flags |= CF;
switch ( ix86->regs.ax ) {
case 0x0001: /* Get Version */
/* Number of INT 22h API functions available */
- ix86->regs.ax = 0x0018;
+ ix86->regs.ax = 0x001B;
/* SYSLINUX version number */
ix86->regs.ch = 0; /* major */
@@ -323,17 +353,15 @@ static __cdecl void int22 ( struct i386_all_regs *ix86 ) {
char cmd[len + 1];
copy_from_user ( cmd, cmd_u, 0, len + 1 );
DBG ( "COMBOOT: executing command '%s'\n", cmd );
-
- comboot_kernel_cmdline = strdup ( cmd );
-
- DBG ( "COMBOOT: returning to run image...\n" );
- longjmp ( comboot_return, COMBOOT_RETURN_RUN_KERNEL );
+ system ( cmd );
+ DBG ( "COMBOOT: exiting after executing command...\n" );
+ rmlongjmp ( comboot_return, COMBOOT_EXIT_COMMAND );
}
break;
case 0x0004: /* Run default command */
/* FIXME: just exit for now */
- longjmp ( comboot_return, COMBOOT_RETURN_EXIT );
+ rmlongjmp ( comboot_return, COMBOOT_EXIT_COMMAND );
break;
case 0x0005: /* Force text mode */
@@ -518,21 +546,21 @@ static __cdecl void int22 ( struct i386_all_regs *ix86 ) {
userptr_t cmd_u = real_to_user ( ix86->segs.es, ix86->regs.bx );
int file_len = strlen_user ( file_u, 0 );
int cmd_len = strlen_user ( cmd_u, 0 );
- char file[file_len + 1 + cmd_len + 7 + 1];
+ char file[file_len + 1];
char cmd[cmd_len + 1];
- memcpy( file, "kernel ", 7 );
- copy_from_user ( file + 7, file_u, 0, file_len + 1 );
+ copy_from_user ( file, file_u, 0, file_len + 1 );
copy_from_user ( cmd, cmd_u, 0, cmd_len + 1 );
- strcat ( file, " " );
- strcat ( file, cmd );
-
- DBG ( "COMBOOT: run kernel image '%s'\n", file );
- comboot_kernel_cmdline = strdup ( file );
-
- DBG ( "COMBOOT: returning to run image...\n" );
- longjmp ( comboot_return, COMBOOT_RETURN_RUN_KERNEL );
+ DBG ( "COMBOOT: run kernel %s %s\n", file, cmd );
+ comboot_fetch_kernel ( file, cmd );
+ /* Technically, we should return if we
+ * couldn't load the kernel, but it's not safe
+ * to do that since we have just overwritten
+ * part of the COMBOOT program's memory space.
+ */
+ DBG ( "COMBOOT: exiting to run kernel...\n" );
+ rmlongjmp ( comboot_return, COMBOOT_EXIT_RUN_KERNEL );
}
break;
@@ -549,6 +577,58 @@ static __cdecl void int22 ( struct i386_all_regs *ix86 ) {
ix86->flags &= ~CF;
break;
+ case 0x001B: /* Cleanup, shuffle and boot to real mode */
+ if ( ix86->regs.cx > COMBOOT_MAX_SHUFFLE_DESCRIPTORS )
+ break;
+
+ /* Perform final cleanup */
+ shutdown ( SHUTDOWN_BOOT );
+
+ /* Perform sequence of copies */
+ shuffle ( ix86->segs.es, ix86->regs.di, ix86->regs.cx );
+
+ /* Copy initial register values to .text16 */
+ memcpy_user ( real_to_user ( rm_cs, (unsigned) __from_text16 ( &comboot_initial_regs ) ), 0,
+ real_to_user ( ix86->segs.ds, ix86->regs.si ), 0,
+ sizeof(syslinux_rm_regs) );
+
+ /* Load initial register values */
+ __asm__ __volatile__ (
+ REAL_CODE (
+ /* Point SS:SP at the register value structure */
+ "pushw %%cs\n\t"
+ "popw %%ss\n\t"
+ "movw $comboot_initial_regs, %%sp\n\t"
+
+ /* Segment registers */
+ "popw %%es\n\t"
+ "popw %%ax\n\t" /* Skip CS */
+ "popw %%ds\n\t"
+ "popw %%ax\n\t" /* Skip SS for now */
+ "popw %%fs\n\t"
+ "popw %%gs\n\t"
+
+ /* GP registers */
+ "popl %%eax\n\t"
+ "popl %%ecx\n\t"
+ "popl %%edx\n\t"
+ "popl %%ebx\n\t"
+ "popl %%ebp\n\t" /* Skip ESP for now */
+ "popl %%ebp\n\t"
+ "popl %%esi\n\t"
+ "popl %%edi\n\t"
+
+ /* Load correct SS:ESP */
+ "movw $(comboot_initial_regs + 6), %%sp\n\t"
+ "popw %%ss\n\t"
+ "movl %%cs:(comboot_initial_regs + 28), %%esp\n\t"
+
+ "ljmp *%%cs:(comboot_initial_regs + 44)\n\t"
+ )
+ : : );
+
+ break;
+
default:
DBG ( "COMBOOT unknown int22 function %04x\n", ix86->regs.ax );
break;
@@ -596,3 +676,18 @@ void hook_comboot_interrupts ( ) {
hook_bios_interrupt ( 0x22, ( unsigned int ) int22_wrapper,
&int22_vector );
}
+
+/**
+ * Unhook BIOS interrupts related to COMBOOT API (INT 20h, 21h, 22h)
+ */
+void unhook_comboot_interrupts ( ) {
+
+ unhook_bios_interrupt ( 0x20, ( unsigned int ) int20_wrapper,
+ &int20_vector );
+
+ unhook_bios_interrupt ( 0x21, ( unsigned int ) int21_wrapper,
+ &int21_vector );
+
+ unhook_bios_interrupt ( 0x22, ( unsigned int ) int22_wrapper,
+ &int22_vector );
+}
diff --git a/gpxe/src/arch/i386/prefix/boot1a.S b/gpxe/src/arch/i386/prefix/boot1a.S
new file mode 100644
index 00000000..557462f1
--- /dev/null
+++ b/gpxe/src/arch/i386/prefix/boot1a.S
@@ -0,0 +1,410 @@
+# This code is no longer used in Etherboot. It is not maintained and
+# may not work.
+
+
+#
+# Copyright (c) 1998 Robert Nordier
+# All rights reserved.
+# Very small bootrom changes by Luigi Rizzo
+# <comment author="Luigi Rizzo">
+# I recently had the problem of downloading the etherboot code
+# from a hard disk partition instead of a floppy, and noticed that
+# floppyload.S does not do the job. With a bit of hacking to
+# the FreeBSD's boot1.s code, I managed to obtain a boot sector
+# which works both for floppies and hard disks -- basically you
+# do something like
+#
+# cat boot1a bin32/<yourcard>.lzrom > /dev/ad0s4
+#
+# (or whatever is the HD partition you are using, I am using slice
+# 4 on FreeBSD) and you are up and running.
+# Then with "fdisk" you have to mark your partition as having type "1"
+# (which is listed as DOS-- but basically it must be something matching
+# the variable PRT_BSD in the assembly source below).
+# </comment>
+#
+# Redistribution and use in source and binary forms are freely
+# permitted provided that the above copyright notice and this
+# paragraph and the following disclaimer are duplicated in all
+# such forms.
+#
+# This software is provided "AS IS" and without any express or
+# implied warranties, including, without limitation, the implied
+# warranties of merchantability and fitness for a particular
+# purpose.
+#
+# Makefile:
+#boot1a: boot1a.out
+# objcopy -S -O binary boot1a.out boot1a
+#
+#boot1a.out: boot1a.o
+# ld -nostdlib -static -N -e start -Ttext 0x7c00 -o boot1a.out boot1a.o
+#
+#boot1a.o: boot1a.s
+# as --defsym FLAGS=0x80 boot1a.s -o boot1a.o
+#
+#
+
+# $FreeBSD: src/sys/boot/i386/boot2/boot1.s,v 1.10.2.2 2000/07/07 21:12:32 jhb Exp $
+
+# Memory Locations
+ .set MEM_REL,0x700 # Relocation address
+ .set MEM_ARG,0x900 # Arguments
+ .set MEM_ORG,0x7c00 # Origin
+ .set MEM_BUF,0x8c00 # Load area
+ .set MEM_BTX,0x9000 # BTX start
+ .set MEM_JMP,0x9010 # BTX entry point
+ .set MEM_USR,0xa000 # Client start
+ .set BDA_BOOT,0x472 # Boot howto flag
+
+# Partition Constants
+ .set PRT_OFF,0x1be # Partition offset
+ .set PRT_NUM,0x4 # Partitions
+ .set PRT_BSD,0x1 # Partition type
+
+# Flag Bits
+ .set FL_PACKET,0x80 # Packet mode
+
+# Misc. Constants
+ .set SIZ_PAG,0x1000 # Page size
+ .set SIZ_SEC,0x200 # Sector size
+
+ .globl start
+ .globl xread
+ .code16
+
+start: jmp main # Start recognizably
+
+ .org 0x4,0x90
+#
+# Trampoline used by boot2 to call read to read data from the disk via
+# the BIOS. Call with:
+#
+# %cx:%ax - long - LBA to read in
+# %es:(%bx) - caddr_t - buffer to read data into
+# %dl - byte - drive to read from
+# %dh - byte - num sectors to read
+#
+
+xread: push %ss # Address
+ pop %ds # data
+#
+# Setup an EDD disk packet and pass it to read
+#
+xread.1: # Starting
+ pushl $0x0 # absolute
+ push %cx # block
+ push %ax # number
+ push %es # Address of
+ push %bx # transfer buffer
+ xor %ax,%ax # Number of
+ movb %dh,%al # blocks to
+ push %ax # transfer
+ push $0x10 # Size of packet
+ mov %sp,%bp # Packet pointer
+ callw read # Read from disk
+ lea 0x10(%bp),%sp # Clear stack
+ lret # To far caller
+#
+# Load the rest of boot2 and BTX up, copy the parts to the right locations,
+# and start it all up.
+#
+
+#
+# Setup the segment registers to flat addressing (segment 0) and setup the
+# stack to end just below the start of our code.
+#
+main: cld # String ops inc
+ xor %cx,%cx # Zero
+ mov %cx,%es # Address
+ mov %cx,%ds # data
+ mov %cx,%ss # Set up
+ mov $start,%sp # stack
+#
+# Relocate ourself to MEM_REL. Since %cx == 0, the inc %ch sets
+# %cx == 0x100.
+#
+ mov %sp,%si # Source
+ mov $MEM_REL,%di # Destination
+ incb %ch # Word count
+ rep # Copy
+ movsw # code
+#
+# If we are on a hard drive, then load the MBR and look for the first
+# FreeBSD slice. We use the fake partition entry below that points to
+# the MBR when we call nread. The first pass looks for the first active
+# FreeBSD slice. The second pass looks for the first non-active FreeBSD
+# slice if the first one fails.
+#
+ mov $part4,%si # Partition
+ cmpb $0x80,%dl # Hard drive?
+ jb main.4 # No
+ movb $0x1,%dh # Block count
+ callw nread # Read MBR
+ mov $0x1,%cx # Two passes
+main.1: mov $MEM_BUF+PRT_OFF,%si # Partition table
+ movb $0x1,%dh # Partition
+main.2: cmpb $PRT_BSD,0x4(%si) # Our partition type?
+ jne main.3 # No
+ jcxz main.5 # If second pass
+ testb $0x80,(%si) # Active?
+ jnz main.5 # Yes
+main.3: add $0x10,%si # Next entry
+ incb %dh # Partition
+ cmpb $0x1+PRT_NUM,%dh # In table?
+ jb main.2 # Yes
+ dec %cx # Do two
+ jcxz main.1 # passes
+#
+# If we get here, we didn't find any FreeBSD slices at all, so print an
+# error message and die.
+#
+booterror: mov $msg_part,%si # Message
+ jmp error # Error
+#
+# Floppies use partition 0 of drive 0.
+#
+main.4: xor %dx,%dx # Partition:drive
+#
+# Ok, we have a slice and drive in %dx now, so use that to locate and load
+# boot2. %si references the start of the slice we are looking for, so go
+# ahead and load up the first 16 sectors (boot1 + boot2) from that. When
+# we read it in, we conveniently use 0x8c00 as our transfer buffer. Thus,
+# boot1 ends up at 0x8c00, and boot2 starts at 0x8c00 + 0x200 = 0x8e00.
+# The first part of boot2 is the disklabel, which is 0x200 bytes long.
+# The second part is BTX, which is thus loaded into 0x9000, which is where
+# it also runs from. The boot2.bin binary starts right after the end of
+# BTX, so we have to figure out where the start of it is and then move the
+# binary to 0xb000. Normally, BTX clients start at MEM_USR, or 0xa000, but
+# when we use btxld create boot2, we use an entry point of 0x1000. That
+# entry point is relative to MEM_USR; thus boot2.bin starts at 0xb000.
+#
+main.5: mov %dx,MEM_ARG # Save args
+ movb $0x2,%dh # Sector count
+ mov $0x7e00, %bx
+ callw nreadbx # Read disk
+ movb $0x40,%dh # Sector count
+ movb %dh, %al
+ callw puthex
+ mov $0x7e00, %bx
+ callw nreadbx # Read disk
+ push %si
+ mov $msg_r1,%si
+ callw putstr
+ pop %si
+ lcall $0x800,$0 # enter the rom code
+ int $0x19
+
+msg_r1: .asciz " done\r\n"
+
+.if 0
+ mov $MEM_BTX,%bx # BTX
+ mov 0xa(%bx),%si # Get BTX length and set
+ add %bx,%si # %si to start of boot2.bin
+ mov $MEM_USR+SIZ_PAG,%di # Client page 1
+ mov $MEM_BTX+0xe*SIZ_SEC,%cx # Byte
+ sub %si,%cx # count
+ rep # Relocate
+ movsb # client
+ sub %di,%cx # Byte count
+ xorb %al,%al # Zero assumed bss from
+ rep # the end of boot2.bin
+ stosb # up to 0x10000
+ callw seta20 # Enable A20
+ jmp start+MEM_JMP-MEM_ORG # Start BTX
+#
+# Enable A20 so we can access memory above 1 meg.
+#
+seta20: cli # Disable interrupts
+seta20.1: inb $0x64,%al # Get status
+ testb $0x2,%al # Busy?
+ jnz seta20.1 # Yes
+ movb $0xd1,%al # Command: Write
+ outb %al,$0x64 # output port
+seta20.2: inb $0x64,%al # Get status
+ testb $0x2,%al # Busy?
+ jnz seta20.2 # Yes
+ movb $0xdf,%al # Enable
+ outb %al,$0x60 # A20
+ sti # Enable interrupts
+ retw # To caller
+.endif
+#
+# Trampoline used to call read from within boot1.
+#
+nread: mov $MEM_BUF,%bx # Transfer buffer
+nreadbx: # same but address is in bx
+ mov 0x8(%si),%ax # Get
+ mov 0xa(%si),%cx # LBA
+ push %bx
+ push %ax
+ callw putword
+ pop %ax
+ pop %bx
+ push %cs # Read from
+ callw xread.1 # disk
+ jnc return # If success, return
+ mov $msg_read,%si # Otherwise, set the error
+ # message and fall through to
+ # the error routine
+#
+# Print out the error message pointed to by %ds:(%si) followed
+# by a prompt, wait for a keypress, and then reboot the machine.
+#
+error: callw putstr # Display message
+ mov $prompt,%si # Display
+ callw putstr # prompt
+ xorb %ah,%ah # BIOS: Get
+ int $0x16 # keypress
+ movw $0x1234, BDA_BOOT # Do a warm boot
+ ljmp $0xffff,$0x0 # reboot the machine
+#
+# Display a null-terminated string using the BIOS output.
+#
+putstr.0: call putchar
+putstr: lodsb # Get char
+ testb %al,%al # End of string?
+ jne putstr.0 # No
+ retw
+
+putword: push %ax
+ movb $'.', %al
+ callw putchar
+ movb %ah, %al
+ callw puthex
+ pop %ax
+puthex: push %ax
+ shr $4, %al
+ callw putdigit
+ pop %ax
+putdigit:
+ andb $0xf, %al
+ addb $0x30, %al
+ cmpb $0x39, %al
+ jbe putchar
+ addb $7, %al
+putchar: push %ax
+ mov $0x7,%bx
+ movb $0xe,%ah
+ int $0x10
+ pop %ax
+ retw
+
+#
+# Overused return code. ereturn is used to return an error from the
+# read function. Since we assume putstr succeeds, we (ab)use the
+# same code when we return from putstr.
+#
+ereturn: movb $0x1,%ah # Invalid
+ stc # argument
+return: retw # To caller
+#
+# Reads sectors from the disk. If EDD is enabled, then check if it is
+# installed and use it if it is. If it is not installed or not enabled, then
+# fall back to using CHS. Since we use a LBA, if we are using CHS, we have to
+# fetch the drive parameters from the BIOS and divide it out ourselves.
+# Call with:
+#
+# %dl - byte - drive number
+# stack - 10 bytes - EDD Packet
+#
+read: push %dx # Save
+ movb $0x8,%ah # BIOS: Get drive
+ int $0x13 # parameters
+ movb %dh,%ch # Max head number
+ pop %dx # Restore
+ jc return # If error
+ andb $0x3f,%cl # Sectors per track
+ jz ereturn # If zero
+ cli # Disable interrupts
+ mov 0x8(%bp),%eax # Get LBA
+ push %dx # Save
+ movzbl %cl,%ebx # Divide by
+ xor %edx,%edx # sectors
+ div %ebx # per track
+ movb %ch,%bl # Max head number
+ movb %dl,%ch # Sector number
+ inc %bx # Divide by
+ xorb %dl,%dl # number
+ div %ebx # of heads
+ movb %dl,%bh # Head number
+ pop %dx # Restore
+ cmpl $0x3ff,%eax # Cylinder number supportable?
+ sti # Enable interrupts
+ ja read.7 # No, try EDD
+ xchgb %al,%ah # Set up cylinder
+ rorb $0x2,%al # number
+ orb %ch,%al # Merge
+ inc %ax # sector
+ xchg %ax,%cx # number
+ movb %bh,%dh # Head number
+ subb %ah,%al # Sectors this track
+ mov 0x2(%bp),%ah # Blocks to read
+ cmpb %ah,%al # To read
+ jb read.2 # this
+ movb %ah,%al # track
+read.2: mov $0x5,%di # Try count
+read.3: les 0x4(%bp),%bx # Transfer buffer
+ push %ax # Save
+ movb $0x2,%ah # BIOS: Read
+ int $0x13 # from disk
+ pop %bx # Restore
+ jnc read.4 # If success
+ dec %di # Retry?
+ jz read.6 # No
+ xorb %ah,%ah # BIOS: Reset
+ int $0x13 # disk system
+ xchg %bx,%ax # Block count
+ jmp read.3 # Continue
+read.4: movzbw %bl,%ax # Sectors read
+ add %ax,0x8(%bp) # Adjust
+ jnc read.5 # LBA,
+ incw 0xa(%bp) # transfer
+read.5: shlb %bl # buffer
+ add %bl,0x5(%bp) # pointer,
+ sub %al,0x2(%bp) # block count
+ ja read # If not done
+read.6: retw # To caller
+read.7: testb $FL_PACKET,%cs:MEM_REL+flags-start # LBA support enabled?
+ jz ereturn # No, so return an error
+ mov $0x55aa,%bx # Magic
+ push %dx # Save
+ movb $0x41,%ah # BIOS: Check
+ int $0x13 # extensions present
+ pop %dx # Restore
+ jc return # If error, return an error
+ cmp $0xaa55,%bx # Magic?
+ jne ereturn # No, so return an error
+ testb $0x1,%cl # Packet interface?
+ jz ereturn # No, so return an error
+ mov %bp,%si # Disk packet
+ movb $0x42,%ah # BIOS: Extended
+ int $0x13 # read
+ retw # To caller
+
+# Messages
+
+msg_read: .asciz "Rd"
+msg_part: .asciz "Boot"
+
+prompt: .asciz " err\r\n"
+
+flags: .byte FLAGS # Flags
+
+ .org PRT_OFF,0x90
+
+# Partition table
+
+ .fill 0x30,0x1,0x0
+part4: .byte 0x80
+ .byte 0x00 # start head
+ .byte 0x01 # start sector (6 bits) + start cyl (2 bit)
+ .byte 0x00 # start cyl (low 8 bits)
+ .byte 0x1 # part.type
+ .byte 0xff # end head
+ .byte 0xff # end sect (6) + end_cyl(2)
+ .byte 0xff # end cyl
+ .byte 0x00, 0x00, 0x00, 0x00 # explicit start
+ .byte 0x50, 0xc3, 0x00, 0x00 # 50000 sectors long, bleh
+
+ .word 0xaa55 # Magic number
diff --git a/gpxe/src/arch/i386/prefix/dskprefix.S b/gpxe/src/arch/i386/prefix/dskprefix.S
index cdc43b37..0156812a 100644
--- a/gpxe/src/arch/i386/prefix/dskprefix.S
+++ b/gpxe/src/arch/i386/prefix/dskprefix.S
@@ -144,8 +144,8 @@ got_sectors:
/* Jump to loaded copy */
ljmp $SYSSEG, $start_runtime
-endseg: .word SYSSEG + _load_size_pgh
- .section ".zinfo.fixup", "a" /* Compressor fixup information */
+endseg: .word SYSSEG + _filesz_pgh
+ .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
.ascii "SUBW"
.long endseg
.long 16
@@ -353,6 +353,7 @@ msg1end:
.word 0xAA55
start_runtime:
+ /* Install gPXE */
call install
/* Set up real-mode stack */
@@ -368,7 +369,10 @@ start_runtime:
pushl $main
pushw %cs
call prot_call
- popl %eax /* discard */
+ popl %ecx /* discard */
+
+ /* Uninstall gPXE */
+ call uninstall
/* Boot next device */
int $0x18
diff --git a/gpxe/src/arch/i386/prefix/hdprefix.S b/gpxe/src/arch/i386/prefix/hdprefix.S
index 56fcb36d..086d7f45 100644
--- a/gpxe/src/arch/i386/prefix/hdprefix.S
+++ b/gpxe/src/arch/i386/prefix/hdprefix.S
@@ -63,9 +63,9 @@ max_sector:
max_head:
.byte 0
load_length:
- .long _load_size_sect
+ .long _filesz_sect
- .section ".zinfo.fixup", "a" /* Compressor fixup information */
+ .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
.ascii "SUBL"
.long load_length
.long 512
@@ -82,6 +82,7 @@ load_failed:
.byte 0x55, 0xaa
start_image:
+ /* Install gPXE */
call install
/* Set up real-mode stack */
@@ -97,7 +98,10 @@ start_image:
pushl $main
pushw %cs
call prot_call
- popl %eax /* discard */
+ popl %ecx /* discard */
+
+ /* Uninstall gPXE */
+ call uninstall
/* Boot next device */
int $0x18
diff --git a/gpxe/src/arch/i386/prefix/kkpxeprefix.S b/gpxe/src/arch/i386/prefix/kkpxeprefix.S
new file mode 100644
index 00000000..e0bea0cd
--- /dev/null
+++ b/gpxe/src/arch/i386/prefix/kkpxeprefix.S
@@ -0,0 +1,8 @@
+/*****************************************************************************
+ * PXE prefix that keeps the whole PXE stack present
+ *****************************************************************************
+ */
+
+#define PXELOADER_KEEP_UNDI
+#define PXELOADER_KEEP_PXE
+#include "pxeprefix.S"
diff --git a/gpxe/src/arch/i386/prefix/libprefix.S b/gpxe/src/arch/i386/prefix/libprefix.S
index ae2a491f..42189135 100644
--- a/gpxe/src/arch/i386/prefix/libprefix.S
+++ b/gpxe/src/arch/i386/prefix/libprefix.S
@@ -18,8 +18,6 @@
*/
.arch i386
- .section ".prefix.lib", "awx", @progbits
- .section ".data16", "aw", @progbits
/**
* High memory temporary load address
@@ -53,7 +51,7 @@
* %ds:di : next character in output buffer (if applicable)
*****************************************************************************
*/
- .section ".prefix.lib"
+ .section ".prefix.lib", "awx", @progbits
.code16
.globl print_character
print_character:
@@ -93,7 +91,7 @@ print_character:
* %ds:di : next character in output buffer (if applicable)
*****************************************************************************
*/
- .section ".prefix.lib"
+ .section ".prefix.lib", "awx", @progbits
.code16
.globl print_message
print_message:
@@ -123,7 +121,7 @@ print_message:
* %ds:di : next character in output buffer (if applicable)
*****************************************************************************
*/
- .section ".prefix.lib"
+ .section ".prefix.lib", "awx", @progbits
.code16
.globl print_hex_dword
print_hex_dword:
@@ -171,7 +169,7 @@ print_hex_nibble:
* %ds:di : next character in output buffer (if applicable)
*****************************************************************************
*/
- .section ".prefix.lib"
+ .section ".prefix.lib", "awx", @progbits
.code16
.globl print_pci_busdevfn
print_pci_busdevfn:
@@ -181,14 +179,14 @@ print_pci_busdevfn:
xchgb %al, %ah
call print_hex_byte
/* Print ":" */
- movb $':', %al
+ movb $( ':' ), %al
call print_character
/* Print device */
movb %ah, %al
shrb $3, %al
call print_hex_byte
/* Print "." */
- movb $'.', %al
+ movb $( '.' ), %al
call print_character
/* Print function */
movb %ah, %al
@@ -199,6 +197,39 @@ print_pci_busdevfn:
ret
.size print_pci_busdevfn, . - print_pci_busdevfn
+/*****************************************************************************
+ * Utility function: clear current line
+ *
+ * Parameters:
+ * %ds:di : output buffer (or %di=0 to print to console)
+ * Returns:
+ * %ds:di : next character in output buffer (if applicable)
+ *****************************************************************************
+ */
+ .section ".prefix.lib", "awx", @progbits
+ .code16
+ .globl print_kill_line
+print_kill_line:
+ /* Preserve registers */
+ pushw %ax
+ pushw %cx
+ /* Print CR */
+ movb $( '\r' ), %al
+ call print_character
+ /* Print 79 spaces */
+ movb $( ' ' ), %al
+ movw $79, %cx
+1: call print_character
+ loop 1b
+ /* Print CR */
+ movb $( '\r' ), %al
+ call print_character
+ /* Restore registers and return */
+ popw %cx
+ popw %ax
+ ret
+ .size print_kill_line, . - print_kill_line
+
/****************************************************************************
* pm_call (real-mode near call)
*
@@ -223,7 +254,7 @@ print_pci_busdevfn:
#ifndef KEEP_IT_REAL
/* GDT for protected-mode calls */
- .section ".prefix.lib"
+ .section ".prefix.lib", "awx", @progbits
.align 16
pm_call_vars:
gdt:
@@ -246,7 +277,7 @@ gdt_end:
.equ gdt_length, . - gdt
.size gdt, . - gdt
- .section ".prefix.lib"
+ .section ".prefix.lib", "awx", @progbits
.align 16
pm_saved_gdt:
.long 0, 0
@@ -255,7 +286,7 @@ pm_saved_gdt:
.equ pm_call_vars_size, . - pm_call_vars
#define PM_CALL_VAR(x) ( -pm_call_vars_size + ( (x) - pm_call_vars ) )
- .section ".prefix.lib"
+ .section ".prefix.lib", "awx", @progbits
.code16
pm_call:
/* Preserve registers, flags, and RM return point */
@@ -308,7 +339,7 @@ pm_call:
/* Switch CPU to protected mode and load up segment registers */
pushl %eax
cli
- lgdt PM_CALL_VAR(gdt)(%bp)
+ data32 lgdt PM_CALL_VAR(gdt)(%bp)
movl %cr0, %eax
orb $CR0_PE, %al
movl %eax, %cr0
@@ -344,7 +375,7 @@ pm_call:
popw %es
popw %fs
popw %gs
- lgdt PM_CALL_VAR(pm_saved_gdt)(%bp)
+ data32 lgdt PM_CALL_VAR(pm_saved_gdt)(%bp)
popfl
movw %bp, %sp
popw %bp
@@ -378,7 +409,7 @@ set_seg_base:
* None
****************************************************************************
*/
- .section ".prefix.lib"
+ .section ".prefix.lib", "awx", @progbits
.code16
copy_bytes:
pushl %ecx
@@ -403,7 +434,7 @@ copy_bytes:
* none
****************************************************************************
*/
- .section ".prefix.lib"
+ .section ".prefix.lib", "awx", @progbits
.code16
install_block:
@@ -500,35 +531,93 @@ install_block:
* none
****************************************************************************
*/
- .section ".prefix.lib"
+ .section ".prefix.lib", "awx", @progbits
.code16
.globl alloc_basemem
alloc_basemem:
+ /* Preserve registers */
+ pushw %fs
+
/* FBMS => %ax as segment address */
- movw $0x40, %ax
- movw %ax, %fs
+ pushw $0x40
+ popw %fs
movw %fs:0x13, %ax
shlw $6, %ax
- /* .data16 segment address */
- subw $_data16_size_pgh, %ax
+ /* Calculate .data16 segment address */
+ subw $_data16_memsz_pgh, %ax
pushw %ax
- /* .text16 segment address */
- subw $_text16_size_pgh, %ax
+ /* Calculate .text16 segment address */
+ subw $_text16_memsz_pgh, %ax
pushw %ax
/* Update FBMS */
shrw $6, %ax
movw %ax, %fs:0x13
- /* Return */
+ /* Retrieve .text16 and .data16 segment addresses */
popw %ax
popw %bx
+
+ /* Restore registers and return */
+ popw %fs
ret
.size alloc_basemem, . - alloc_basemem
/****************************************************************************
+ * free_basemem (real-mode near call)
+ *
+ * Free space allocated with alloc_basemem.
+ *
+ * Parameters:
+ * %ax : .text16 segment address
+ * %bx : .data16 segment address
+ * Returns:
+ * %ax : 0 if successfully freed
+ * Corrupts:
+ * none
+ ****************************************************************************
+ */
+ .section ".text16", "ax", @progbits
+ .code16
+ .globl free_basemem
+free_basemem:
+ /* Preserve registers */
+ pushw %fs
+
+ /* Check FBMS counter */
+ pushw %ax
+ shrw $6, %ax
+ pushw $0x40
+ popw %fs
+ cmpw %ax, %fs:0x13
+ popw %ax
+ jne 1f
+
+ /* Check hooked interrupt count */
+ cmpw $0, %cs:hooked_bios_interrupts
+ jne 1f
+
+ /* OK to free memory */
+ addw $_text16_memsz_pgh, %ax
+ addw $_data16_memsz_pgh, %ax
+ shrw $6, %ax
+ movw %ax, %fs:0x13
+ xorw %ax, %ax
+
+1: /* Restore registers and return */
+ popw %fs
+ ret
+ .size free_basemem, . - free_basemem
+
+ .section ".text16.data", "aw", @progbits
+ .globl hooked_bios_interrupts
+hooked_bios_interrupts:
+ .word 0
+ .size hooked_bios_interrupts, . - hooked_bios_interrupts
+
+/****************************************************************************
* install (real-mode near call)
*
* Install all text and data segments.
@@ -542,7 +631,7 @@ alloc_basemem:
* none
****************************************************************************
*/
- .section ".prefix.lib"
+ .section ".prefix.lib", "awx", @progbits
.code16
.globl install
install:
@@ -577,7 +666,7 @@ install:
* none
****************************************************************************
*/
- .section ".prefix.lib"
+ .section ".prefix.lib", "awx", @progbits
.code16
.globl install_prealloc
install_prealloc:
@@ -594,19 +683,19 @@ install_prealloc:
jnz 1f
movw %cs, %si
shll $4, %esi
-1: addl $_payload_offset, %esi
+1: addl $_payload_lma, %esi
/* Install .text16 and .data16 */
pushl %edi
movzwl %ax, %edi
shll $4, %edi
- movl $_text16_size, %ecx
+ movl $_text16_memsz, %ecx
movl %ecx, %edx
call install_block /* .text16 */
movzwl %bx, %edi
shll $4, %edi
- movl $_data16_progbits_size, %ecx
- movl $_data16_size, %edx
+ movl $_data16_filesz, %ecx
+ movl $_data16_memsz, %edx
call install_block /* .data16 */
popl %edi
@@ -622,8 +711,8 @@ install_prealloc:
* prior to reading the E820 memory map and relocating
* properly.
*/
- movl $_textdata_progbits_size, %ecx
- movl $_textdata_size, %edx
+ movl $_textdata_filesz, %ecx
+ movl $_textdata_memsz, %edx
call install_block
/* Initialise librm at current location */
@@ -659,7 +748,7 @@ install_prealloc:
.size install_prealloc, . - install_prealloc
/* Vectors for far calls to .text16 functions */
- .section ".data16"
+ .section ".data16", "aw", @progbits
#ifdef KEEP_IT_REAL
init_libkir_vector:
.word init_libkir
@@ -676,30 +765,53 @@ prot_call_vector:
.size prot_call_vector, . - prot_call_vector
#endif
+/****************************************************************************
+ * uninstall (real-mode near call)
+ *
+ * Uninstall all text and data segments.
+ *
+ * Parameters:
+ * %ax : .text16 segment address
+ * %bx : .data16 segment address
+ * Returns:
+ * none
+ * Corrupts:
+ * none
+ ****************************************************************************
+ */
+ .section ".text16", "ax", @progbits
+ .code16
+ .globl uninstall
+uninstall:
+ call free_basemem
+ ret
+ .size uninstall, . - uninstall
+
+
/* File split information for the compressor */
#if COMPRESS
- .section ".zinfo", "a"
+ .section ".zinfo", "a", @progbits
.ascii "COPY"
- .long _prefix_load_offset
- .long _prefix_progbits_size
+ .long _prefix_lma
+ .long _prefix_filesz
.long _max_align
.ascii "PACK"
- .long _text16_load_offset
- .long _text16_progbits_size
+ .long _text16_lma
+ .long _text16_filesz
.long _max_align
.ascii "PACK"
- .long _data16_load_offset
- .long _data16_progbits_size
+ .long _data16_lma
+ .long _data16_filesz
.long _max_align
.ascii "PACK"
- .long _textdata_load_offset
- .long _textdata_progbits_size
+ .long _textdata_lma
+ .long _textdata_filesz
.long _max_align
#else /* COMPRESS */
- .section ".zinfo", "a"
+ .section ".zinfo", "a", @progbits
.ascii "COPY"
- .long _prefix_load_offset
- .long _load_size
+ .long _prefix_lma
+ .long _filesz
.long _max_align
#endif /* COMPRESS */
diff --git a/gpxe/src/arch/i386/prefix/lkrnprefix.S b/gpxe/src/arch/i386/prefix/lkrnprefix.S
index c1e92f57..094263d2 100644
--- a/gpxe/src/arch/i386/prefix/lkrnprefix.S
+++ b/gpxe/src/arch/i386/prefix/lkrnprefix.S
@@ -92,9 +92,9 @@ setup_sects:
root_flags:
.word 0
syssize:
- .long _load_size_pgh - PREFIXPGH
+ .long _filesz_pgh - PREFIXPGH
- .section ".zinfo.fixup", "a" /* Compressor fixup information */
+ .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
.ascii "SUBL"
.long syssize
.long 16
@@ -189,6 +189,7 @@ run_gpxe:
movw %ax, %ss
movw $0x7c00, %sp
+ /* Install gPXE */
call install
/* Set up real-mode stack */
@@ -204,7 +205,10 @@ run_gpxe:
pushl $main
pushw %cs
call prot_call
- popl %eax /* discard */
+ popl %ecx /* discard */
+
+ /* Uninstall gPXE */
+ call uninstall
/* Boot next device */
int $0x18
diff --git a/gpxe/src/arch/i386/prefix/nbiprefix.S b/gpxe/src/arch/i386/prefix/nbiprefix.S
index d4904b73..4fb4acb1 100644
--- a/gpxe/src/arch/i386/prefix/nbiprefix.S
+++ b/gpxe/src/arch/i386/prefix/nbiprefix.S
@@ -1,9 +1,7 @@
.text
.arch i386
- .section ".prefix", "ax", @progbits
- .section ".prefix.data", "aw", @progbits
.code16
- .section ".prefix"
+ .section ".prefix", "ax", @progbits
.org 0
nbi_header:
@@ -32,11 +30,11 @@ segment_header:
.byte 0
.byte 0x04 /* Last segment */
.long 0x00007e00
-imglen: .long _load_size - 512
-memlen: .long _load_size - 512
+imglen: .long _filesz - 512
+memlen: .long _filesz - 512
.size segment_header, . - segment_header
- .section ".zinfo.fixup", "a" /* Compressor fixup information */
+ .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
.ascii "SUBL"
.long imglen
.long 1
@@ -52,7 +50,7 @@ memlen: .long _load_size - 512
*****************************************************************************
*/
entry:
- /* Install low and high memory regions */
+ /* Install gPXE */
call install
/* Jump to .text16 segment */
@@ -64,7 +62,10 @@ entry:
pushl $main
pushw %cs
call prot_call
- popl %eax /* discard */
+ popl %ecx /* discard */
+
+ /* Uninstall gPXE */
+ call uninstall
/* Reboot system */
int $0x19
diff --git a/gpxe/src/arch/i386/prefix/pxeprefix.S b/gpxe/src/arch/i386/prefix/pxeprefix.S
index 302f8e5d..ee0f4d94 100644
--- a/gpxe/src/arch/i386/prefix/pxeprefix.S
+++ b/gpxe/src/arch/i386/prefix/pxeprefix.S
@@ -2,57 +2,60 @@
#define PXENV_UNDI_GET_NIC_TYPE 0x0012
#define PXENV_STOP_UNDI 0x0015
#define PXENV_UNLOAD_STACK 0x0070
-
+
.text
.arch i386
.org 0
- .section ".prefix", "ax", @progbits
- .section ".prefix.data", "aw", @progbits
.code16
#include <undi.h>
+#define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) )
+
/*****************************************************************************
* Entry point: set operating context, print welcome message
*****************************************************************************
*/
- .section ".prefix"
- /* Set up our non-stack segment registers */
+ .section ".prefix", "ax", @progbits
jmp $0x7c0, $1f
-1: pushfl
- /* %ax here is the default return type... */
- movw $5, %ax /* Keep PXE+UNDI */
+1:
+ /* Preserve registers for possible return to PXE */
+ pushfl
pushal
- pushw %ds
- pushw %es
- pushw %fs
pushw %gs
+ pushw %fs
+ pushw %es
+ pushw %ds
+
+ /* Store magic word on PXE stack and remember PXE %ss:esp */
+ pushl $STACK_MAGIC
+ movw %ss, %cs:pxe_ss
+ movl %esp, %cs:pxe_esp
+ movw %sp, %bp
+ movl (10*4+4*2+4)(%bp),%ebp /* !PXE address */
+
+ /* Set up %ds */
movw %cs, %ax
movw %ax, %ds
-
- movw $0x40, %ax /* BIOS data segment access */
- movw %ax, %fs
-
- pushw %fs:0x13
/* Record PXENV+ and !PXE nominal addresses */
- movw %es, pxenv_segment
+ movw %es, pxenv_segment /* PXENV+ address */
movw %bx, pxenv_offset
- movw %sp, %bp
- movw %ss, return_stack_segment
- movl %esp, return_stack_offset
- movl 50(%bp), %eax
- movl %eax, ppxe_segoff /* !PXE address */
+ movl %ebp, ppxe_segoff /* !PXE address */
+ /* Set up %es and %fs */
+ movw %ax, %es
+ movw $0x40, %ax /* BIOS data segment access */
+ movw %ax, %fs
/* Set up stack just below 0x7c00 */
xorw %ax, %ax
movw %ax, %ss
- movw $0x7c00, %sp
+ movl $0x7c00, %esp
/* Clear direction flag, for the sake of sanity */
cld
/* Print welcome message */
movw $10f, %si
xorw %di, %di
call print_message
- .section ".prefix.data"
+ .section ".prefix.data", "aw", @progbits
10: .asciz "PXE->EB:"
.previous
@@ -80,10 +83,10 @@ detect_pxenv:
movw $10f, %si
call print_message
call print_segoff
- movb $',', %al
+ movb $( ',' ), %al
call print_character
jmp 99f
- .section ".prefix.data"
+ .section ".prefix.data", "aw", @progbits
10: .asciz " PXENV+ at "
.previous
@@ -118,10 +121,10 @@ detect_ppxe:
movw $10f, %si
call print_message
call print_segoff
- movb $',', %al
+ movb $( ',' ), %al
call print_character
jmp 99f
- .section ".prefix.data"
+ .section ".prefix.data", "aw", @progbits
10: .asciz " !PXE at "
.previous
@@ -144,7 +147,7 @@ check_have_stack:
movw $10f, %si
call print_message
jmp finished
- .section ".prefix.data"
+ .section ".prefix.data", "aw", @progbits
10: .asciz " No PXE stack found!\n"
.previous
99:
@@ -182,7 +185,7 @@ print_structure_information:
call print_message
les entry_segoff, %bx
call print_segoff
- .section ".prefix.data"
+ .section ".prefix.data", "aw", @progbits
10: .asciz " entry point at "
.previous
/* Print UNDI code segment */
@@ -190,7 +193,7 @@ print_structure_information:
call print_message
les undi_code_segoff, %bx
call print_segoff
- .section ".prefix.data"
+ .section ".prefix.data", "aw", @progbits
10: .asciz "\n UNDI code segment "
.previous
/* Print UNDI data segment */
@@ -198,7 +201,7 @@ print_structure_information:
call print_message
les undi_data_segoff, %bx
call print_segoff
- .section ".prefix.data"
+ .section ".prefix.data", "aw", @progbits
10: .asciz ", data segment "
.previous
/* Print UNDI memory usage */
@@ -206,13 +209,13 @@ print_structure_information:
call print_message
movw undi_fbms_start, %ax
call print_word
- movb $'-', %al
+ movb $( '-' ), %al
call print_character
movw undi_fbms_end, %ax
call print_word
movw $20f, %si
call print_message
- .section ".prefix.data"
+ .section ".prefix.data", "aw", @progbits
10: .asciz " ("
20: .asciz "kB)\n"
.previous
@@ -246,7 +249,7 @@ pci_physical_device:
movb $0x0a, %al
call print_character
jmp 99f
- .section ".prefix.data"
+ .section ".prefix.data", "aw", @progbits
10: .asciz " UNDI device is PCI "
.previous
@@ -254,7 +257,7 @@ no_physical_device:
/* No device found, or device type not understood */
movw $10f, %si
call print_message
- .section ".prefix.data"
+ .section ".prefix.data", "aw", @progbits
10: .asciz " Unable to determine UNDI physical device\n"
.previous
@@ -264,7 +267,7 @@ no_physical_device:
* Leave NIC in a safe state
*****************************************************************************
*/
-#ifndef PXELOADER_KEEP_UNDI
+#ifndef PXELOADER_KEEP_PXE
shutdown_nic:
/* Issue PXENV_UNDI_SHUTDOWN */
movw $PXENV_UNDI_SHUTDOWN, %bx
@@ -272,11 +275,6 @@ shutdown_nic:
jnc 1f
call print_pxe_error
1:
-
-/*****************************************************************************
- * Unload PXE base code
- *****************************************************************************
- */
unload_base_code:
/* Issue PXENV_UNLOAD_STACK */
movw $PXENV_UNLOAD_STACK, %bx
@@ -289,12 +287,14 @@ unload_base_code:
movw %fs:(0x13), %bx
call free_basemem
99:
+ andw $~( UNDI_FL_INITIALIZED | UNDI_FL_KEEP_ALL ), flags
+#endif /* PXELOADER_KEEP_PXE */
/*****************************************************************************
* Unload UNDI driver
*****************************************************************************
*/
-
+#ifndef PXELOADER_KEEP_UNDI
unload_undi:
/* Issue PXENV_STOP_UNDI */
movw $PXENV_STOP_UNDI, %bx
@@ -309,6 +309,7 @@ unload_undi:
/* Clear UNDI_FL_STARTED */
andw $~UNDI_FL_STARTED, flags
99:
+#endif /* PXELOADER_KEEP_UNDI */
/*****************************************************************************
* Print remaining free base memory
@@ -321,19 +322,18 @@ print_free_basemem:
call print_word
movw $20f, %si
call print_message
- .section ".prefix.data"
+ .section ".prefix.data", "aw", @progbits
10: .asciz " "
20: .asciz "kB free base memory after PXE unload\n"
.previous
-#endif /* PXELOADER_KEEP_UNDI */
/*****************************************************************************
* Exit point
*****************************************************************************
*/
finished:
- jmp run_etherboot
-
+ jmp run_gpxe
+
/*****************************************************************************
* Subroutine: print segment:offset address
*
@@ -350,7 +350,7 @@ print_segoff:
/* Print "<segment>:offset" */
movw %es, %ax
call print_hex_word
- movb $':', %al
+ movb $( ':' ), %al
call print_character
movw %bx, %ax
call print_hex_word
@@ -517,7 +517,7 @@ print_pxe_error:
call print_message
popw %si
ret
- .section ".prefix.data"
+ .section ".prefix.data", "aw", @progbits
10: .asciz " UNDI API call "
20: .asciz " failed: status code "
30: .asciz "\n"
@@ -527,6 +527,10 @@ print_pxe_error:
* PXE data structures
*****************************************************************************
*/
+ .section ".prefix.data"
+
+pxe_ss: .word 0
+pxe_esp: .long 0
pxe_parameter_structure: .fill 20
@@ -554,12 +558,6 @@ entry_segoff:
entry_offset: .word 0
entry_segment: .word 0
-return_stack_segoff:
-return_stack_offset: .long 0
-return_stack_segment: .word 0
-
-return_type: .word 0 /* Default: unload PXE and boot next */
-
undi_fbms_start: .word 0
undi_fbms_end: .word 0
@@ -569,16 +567,18 @@ isapnp_read_port: .word UNDI_NO_ISAPNP_READ_PORT
pci_vendor: .word 0
pci_device: .word 0
-flags: .word UNDI_FL_STARTED
+flags:
+ .word ( UNDI_FL_INITIALIZED | UNDI_FL_STARTED | UNDI_FL_KEEP_ALL )
.equ undi_device_size, ( . - undi_device )
/*****************************************************************************
- * Run Etherboot main code
+ * Run gPXE main code
*****************************************************************************
- */
-run_etherboot:
- /* Install Etherboot */
+ */
+ .section ".prefix"
+run_gpxe:
+ /* Install gPXE */
call install
/* Set up real-mode stack */
@@ -594,6 +594,10 @@ run_etherboot:
rep movsb
#endif
+ /* Retrieve PXE %ss:esp */
+ movw pxe_ss, %di
+ movl pxe_esp, %ebp
+
/* Jump to .text16 segment with %ds pointing to .data16 */
movw %bx, %ds
pushw %ax
@@ -605,29 +609,30 @@ run_etherboot:
pushl $main
pushw %cs
call prot_call
- popl %eax /* discard */
+ popl %ecx /* discard */
-#ifdef PXELOADER_KEEP_UNDI
- /* Boot next device */
- movw $0x40, %ax
- movw %ax, %fs
- movw $preloaded_undi,%bx
-
- cli
- movw %ss:return_type-undi_device(%bx),%ax
- lssl %ss:return_stack_segoff-undi_device(%bx), %esp
- movw %sp,%bp
- movw %ax,38(%bp) /* Overwrite return AX value */
- popw %fs:0x13 /* 0 */
- popw %gs /* 2 */
- popw %fs /* 4 */
- popw %es /* 6 */
- popw %ds /* 8 */
- popal /* 10, 14, 18, 22, 26, 30, 34, 38 */
- popfl /* 42 */
- lret /* 46 */
-#else
- int $0x18
-#endif
+ /* Uninstall gPXE */
+ call uninstall
+
+ /* Restore PXE stack */
+ movw %di, %ss
+ movl %ebp, %esp
+
+ /* Check PXE stack magic */
+ popl %eax
+ cmpl $STACK_MAGIC, %eax
+ jne 1f
+ /* PXE stack OK: return to caller */
+ popw %ds
+ popw %es
+ popw %fs
+ popw %gs
+ popal
+ popfl
+ xorw %ax, %ax /* Return success */
+ lret
+
+1: /* PXE stack corrupt or removed: use INT 18 */
+ int $0x18
.previous
diff --git a/gpxe/src/arch/i386/prefix/romprefix.S b/gpxe/src/arch/i386/prefix/romprefix.S
index 92a931cd..7d532375 100644
--- a/gpxe/src/arch/i386/prefix/romprefix.S
+++ b/gpxe/src/arch/i386/prefix/romprefix.S
@@ -14,6 +14,7 @@
#define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) )
#define PNP_GET_BBS_VERSION 0x60
#define PMM_ALLOCATE 0x0000
+#define PMM_DEALLOCATE 0x0002
/* ROM banner timeout. Based on the configurable BANNER_TIMEOUT in
* config.h, but converted to a number of (18Hz) timer ticks, and
@@ -30,7 +31,7 @@
.org 0x00
romheader:
.word 0xAA55 /* BIOS extension signature */
-romheader_size: .byte _load_size_sect /* Size in 512-byte blocks */
+romheader_size: .byte _filesz_sect /* Size in 512-byte blocks */
jmp init /* Initialisation vector */
checksum:
.byte 0
@@ -42,7 +43,7 @@ checksum:
.word pnpheader
.size romheader, . - romheader
- .section ".zinfo.fixup", "a" /* Compressor fixup information */
+ .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
.ascii "SUBB"
.long romheader_size
.long 512
@@ -58,18 +59,18 @@ pciheader:
.byte 0x03 /* PCI data structure revision */
.byte 0x02, 0x00, 0x00 /* Class code */
pciheader_image_length:
- .word _load_size_sect /* Image length */
+ .word _filesz_sect /* Image length */
.word 0x0001 /* Revision level */
.byte 0x00 /* Code type */
.byte 0x80 /* Last image indicator */
pciheader_runtime_length:
- .word _load_size_sect /* Maximum run-time image length */
+ .word _filesz_sect /* Maximum run-time image length */
.word 0x0000 /* Configuration utility code header */
.word 0x0000 /* DMTF CLP entry point */
.equ pciheader_len, . - pciheader
.size pciheader, . - pciheader
- .section ".zinfo.fixup", "a" /* Compressor fixup information */
+ .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
.ascii "SUBW"
.long pciheader_image_length
.long 512
@@ -109,12 +110,12 @@ mfgstr:
/* Product string
*
- * Defaults to "gPXE". If the ROM image is writable at initialisation
- * time, it will be filled in to include the PCI bus:dev.fn number of
- * the card as well.
+ * Defaults to PRODUCT_SHORT_NAME. If the ROM image is writable at
+ * initialisation time, it will be filled in to include the PCI
+ * bus:dev.fn number of the card as well.
*/
prodstr:
- .ascii "gPXE"
+ .ascii PRODUCT_SHORT_NAME
prodstr_separator:
.byte 0
.ascii "(PCI "
@@ -130,9 +131,9 @@ undiheader:
.byte 0 /* Structure revision */
.byte 0,1,2 /* PXE version: 2.1.0 */
.word undiloader /* Offset to loader routine */
- .word _data16_size /* Stack segment size */
- .word _data16_size /* Data segment size */
- .word _text16_size /* Code segment size */
+ .word _data16_memsz /* Stack segment size */
+ .word _data16_memsz /* Data segment size */
+ .word _text16_memsz /* Code segment size */
.ascii "PCIR" /* Bus type */
.equ undiheader_len, . - undiheader
.size undiheader, . - undiheader
@@ -174,10 +175,10 @@ init:
/* Fill in product name string, if possible */
movw $prodstr_pci_id, %di
call print_pci_busdevfn
- movb $' ', prodstr_separator
+ movb $( ' ' ), prodstr_separator
/* Print segment address */
- movb $' ', %al
+ movb $( ' ' ), %al
xorw %di, %di
call print_character
movw %cs, %ax
@@ -190,26 +191,48 @@ init:
stc
movw $0xb101, %ax
int $0x1a
- jc 1f
+ jc no_pci3
cmpl $PCI_SIGNATURE, %edx
- jne 1f
+ jne no_pci3
testb %ah, %ah
- jnz 1f
+ jnz no_pci3
movw $init_message_pci, %si
xorw %di, %di
call print_message
movb %bh, %al
call print_hex_nibble
- movb $'.', %al
+ movb $( '.' ), %al
call print_character
movb %bl, %al
call print_hex_byte
cmpb $3, %bh
- jae 2f
-1: /* PCI <3.0: set %gs (runtime segment) = %cs (init-time segment) */
+ jb no_pci3
+ /* PCI >=3.0: leave %gs as-is if sane */
+ movw %gs, %ax
+ cmpw $0xa000, %ax /* Insane if %gs < 0xa000 */
+ jb pci3_insane
+ movw %cs, %bx /* Sane if %cs == %gs */
+ cmpw %bx, %ax
+ je 1f
+ movzbw romheader_size, %cx /* Sane if %cs+len <= %gs */
+ shlw $5, %cx
+ addw %cx, %bx
+ cmpw %bx, %ax
+ jae 1f
+ movw %cs, %bx /* Sane if %gs+len <= %cs */
+ addw %cx, %ax
+ cmpw %bx, %ax
+ jbe 1f
+pci3_insane: /* PCI 3.0 with insane %gs value: print error and ignore %gs */
+ movb $( '!' ), %al
+ call print_character
+ movw %gs, %ax
+ call print_hex_word
+no_pci3:
+ /* PCI <3.0: set %gs (runtime segment) = %cs (init-time segment) */
pushw %cs
popw %gs
-2: popl %edi
+1: popl %edi
popl %edx
popl %ebx
@@ -268,21 +291,52 @@ pmm_scan:
movw $init_message_pmm, %si
xorw %di, %di
call print_message
- /* Try to allocate 2MB block via PMM */
+ /* We have PMM and so a 1kB stack: preserve upper register halves */
+ pushal
+ /* Calculate required allocation size in %esi */
+ movzbl romheader_size, %eax
+ shll $9, %eax
+ addl $_textdata_memsz, %eax
+ orw $0xffff, %ax /* Ensure allocation size is at least 64kB */
+ bsrl %eax, %ecx
+ subw $15, %cx /* Round up and convert to 64kB count */
+ movw $1, %si
+ shlw %cl, %si
+pmm_loop:
+ /* Try to allocate block via PMM */
pushw $0x0006 /* Aligned, extended memory */
pushl $0xffffffff /* No handle */
- pushl $( 0x00200000 / 16 ) /* 2MB in paragraphs */
+ movzwl %si, %eax
+ shll $12, %eax
+ pushl %eax /* Allocation size in paragraphs */
pushw $PMM_ALLOCATE
lcall *%es:7
addw $12, %sp
+ /* Abort if allocation fails */
+ testw %dx, %dx /* %ax==0 even on success, since align>=64kB */
+ jz pmm_fail
+ /* If block has A20==1, free block and try again with twice
+ * the allocation size (and hence alignment).
+ */
+ testw $0x0010, %dx
+ jz got_pmm
+ pushw %dx
+ pushw $0
+ pushw $PMM_DEALLOCATE
+ lcall *%es:7
+ addw $6, %sp
+ addw %si, %si
+ jmp pmm_loop
+got_pmm: /* PMM allocation succeeded */
+ movw %dx, ( image_source + 2 )
movw %dx, %ax
xorw %di, %di
call print_hex_word
- movw %dx, ( image_source + 2 )
- testw %dx, %dx /* %ax==0 even on success, since align=2MB */
- jz no_pmm
- /* PMM allocation succeeded: copy ROM to PMM block */
- pushal /* PMM presence implies 1kB stack */
+ movb $( '@' ), %al
+ call print_character
+ movw %si, %ax
+ call print_hex_byte
+ /* Copy ROM to PMM block */
xorw %ax, %ax
movw %ax, %es
movl image_source, %edi
@@ -291,24 +345,28 @@ pmm_scan:
shll $9, %ecx
addr32 rep movsb /* PMM presence implies flat real mode */
movl %edi, decompress_to
- /* Shrink ROM and update checksum */
+ /* Shrink ROM */
+ movb $_prefix_memsz_sect, romheader_size
+pmm_fail:
+ /* Restore upper register halves */
+ popal
+no_pmm:
+
+ /* Update checksum */
xorw %bx, %bx
xorw %si, %si
- movw $_prefix_size_sect, %cx
- movb %cl, romheader_size
+ movzbw romheader_size, %cx
shlw $9, %cx
1: lodsb
addb %al, %bl
loop 1b
subb %bl, checksum
- popal
-no_pmm:
/* Copy self to option ROM space. Required for PCI3.0, which
* loads us to a temporary location in low memory. Will be a
* no-op for lower PCI versions.
*/
- movb $' ', %al
+ movb $( ' ' ), %al
xorw %di, %di
call print_character
movw %gs, %ax
@@ -324,23 +382,28 @@ no_pmm:
movw $init_message_prompt, %si
xorw %di, %di
call print_message
+ movw $prodstr, %si
+ call print_message
+ movw $init_message_dots, %si
+ call print_message
/* Wait for Ctrl-B */
movw $0xff02, %bx
call wait_for_key
/* Clear prompt */
pushf
- movw $clear_message, %si
xorw %di, %di
+ call print_kill_line
+ movw $init_message_done, %si
call print_message
popf
- jnz 1f
+ jnz 2f
/* Ctrl-B was pressed: invoke gPXE. The keypress will be
* picked up by the initial shell prompt, and we will drop
* into a shell.
*/
pushw %cs
call exec
-1:
+2:
/* Restore registers */
popw %gs
popw %fs
@@ -353,7 +416,26 @@ no_pmm:
lret
.size init, . - init
+/*
+ * Note to hardware vendors:
+ *
+ * If you wish to brand this boot ROM, please do so by defining the
+ * strings PRODUCT_NAME and PRODUCT_SHORT_NAME in config/general.h.
+ *
+ * While nothing in the GPL prevents you from removing all references
+ * to gPXE or http://etherboot.org, we prefer you not to do so.
+ *
+ * If you have an OEM-mandated branding requirement that cannot be
+ * satisfied simply by defining PRODUCT_NAME and PRODUCT_SHORT_NAME,
+ * please contact us.
+ *
+ * [ Including an ASCII NUL in PRODUCT_NAME is considered to be
+ * bypassing the spirit of this request! ]
+ */
init_message:
+ .ascii "\n"
+ .ascii PRODUCT_NAME
+ .ascii "\n"
.asciz "gPXE (http://etherboot.org) - "
.size init_message, . - init_message
init_message_pci:
@@ -372,11 +454,14 @@ init_message_int19:
.asciz " INT19"
.size init_message_int19, . - init_message_int19
init_message_prompt:
- .asciz "\nPress Ctrl-B to configure gPXE..."
+ .asciz "\nPress Ctrl-B to configure "
.size init_message_prompt, . - init_message_prompt
-clear_message:
- .asciz "\r \n\n"
- .size clear_message, . - clear_message
+init_message_dots:
+ .asciz "..."
+ .size init_message_dots, . - init_message_dots
+init_message_done:
+ .asciz "\n\n"
+ .size init_message_done, . - init_message_done
/* ROM image location
*
@@ -429,14 +514,15 @@ int19_entry:
call print_message
movw $int19_message_dots, %si
call print_message
- movw $0xdf42, %bx
+ movw $0xdf4e, %bx
call wait_for_key
pushf
- movw $clear_message, %si
xorw %di, %di
+ call print_kill_line
+ movw $int19_message_done, %si
call print_message
popf
- jnz 1f
+ jz 1f
/* Leave keypress in buffer and start gPXE. The keypress will
* cause the usual initial Ctrl-B prompt to be skipped.
*/
@@ -455,11 +541,14 @@ orig_int19:
.size orig_int19, . - orig_int19
int19_message_prompt:
- .asciz "Press B to boot from "
+ .asciz "Press N to skip booting from "
.size int19_message_prompt, . - int19_message_prompt
int19_message_dots:
.asciz "..."
.size int19_message_dots, . - int19_message_dots
+int19_message_done:
+ .asciz "\n\n"
+ .size int19_message_done, . - int19_message_done
/* Execute as a boot device
*
@@ -504,8 +593,11 @@ exec: /* Set %ds = %cs */
pushl $main
pushw %cs
call prot_call
- /* No need to clean up stack; we are about to reload %ss:sp */
-
+ popl %ecx /* discard */
+
+ /* Uninstall gPXE */
+ call uninstall
+
/* Restore BIOS stack */
movw %dx, %ss
movw %bp, %sp
diff --git a/gpxe/src/arch/i386/scripts/i386.lds b/gpxe/src/arch/i386/scripts/i386.lds
index 729ad30a..8a0c6733 100644
--- a/gpxe/src/arch/i386/scripts/i386.lds
+++ b/gpxe/src/arch/i386/scripts/i386.lds
@@ -5,15 +5,9 @@
*
*/
-OUTPUT_FORMAT ( "elf32-i386", "elf32-i386", "elf32-i386" )
-OUTPUT_ARCH ( i386 )
-ENTRY ( _entry )
-
SECTIONS {
- /* All sections in the resulting file have consecutive load
- * addresses, but may have individual link addresses depending on
- * the memory model being used.
+ /* Each section starts at a virtual address of zero.
*
* We guarantee alignment of virtual addresses to any alignment
* specified by the constituent object files (e.g. via
@@ -31,254 +25,185 @@ SECTIONS {
*/
/*
- * Weak symbols that need zero values if not otherwise defined
- */
-
- . = 0;
- .weak : AT ( 0 ) {
- *(.weak)
- }
- _assert = ASSERT ( ( . == 0 ), ".weak is non-zero length" );
-
- /*
* The prefix
+ *
*/
- _prefix_link_addr = 0;
- . = _prefix_link_addr;
- _prefix = .;
-
- .prefix : AT ( _prefix_load_offset + __prefix ) {
- __prefix = .;
- _entry = .;
+ .prefix 0x0 : AT ( _prefix_lma ) {
+ _prefix = .;
*(.prefix)
*(.prefix.*)
- _eprefix_progbits = .;
+ _mprefix = .;
+ } .bss.prefix (NOLOAD) : AT ( _end_lma ) {
+ _eprefix = .;
}
-
- _eprefix = .;
+ _prefix_filesz = ABSOLUTE ( _mprefix - _prefix );
+ _prefix_memsz = ABSOLUTE ( _eprefix - _prefix );
/*
- * The 16-bit sections, if present
+ * The 16-bit (real-mode) code section
+ *
*/
- _text16_link_addr = 0;
- . = _text16_link_addr;
- _text16 = .;
-
- /* We need to allow code at the NULL address in .text16 */
-
- .text16 : AT ( _text16_load_offset + __text16 ) {
- __text16 = .;
+ .text16 0x0 : AT ( _text16_lma ) {
+ _text16 = .;
*(.text16.null)
- . += 1; /* Prevent NULL being valid */
+ . += 1; /* Prevent NULL being valid */
*(.text16)
*(.text16.*)
- _etext16_progbits = .;
- } = 0x9090
-
- _etext16 = .;
-
- _data16_link_addr = 0;
- . = _data16_link_addr;
- _data16 = .;
+ _mtext16 = .;
+ } .bss.text16 (NOLOAD) : AT ( _end_lma ) {
+ _etext16 = .;
+ }
+ _text16_filesz = ABSOLUTE ( _mtext16 - _text16 );
+ _text16_memsz = ABSOLUTE ( _etext16 - _text16 );
- . += 1; /* Prevent NULL being valid */
+ /*
+ * The 16-bit (real-mode) data section
+ *
+ */
- .rodata16 : AT ( _data16_load_offset + __rodata16 ) {
- __rodata16 = .;
+ .data16 0x0 : AT ( _data16_lma ) {
+ _data16 = .;
+ . += 1; /* Prevent NULL being valid */
*(.rodata16)
*(.rodata16.*)
- }
- .data16 : AT ( _data16_load_offset + __data16 ) {
- __data16 = .;
*(.data16)
*(.data16.*)
- _edata16_progbits = .;
- }
- .bss16 : AT ( _data16_load_offset + __bss16 ) {
- __bss16 = .;
- _bss16 = .;
+ _mdata16 = .;
+ } .bss.data16 (NOLOAD) : AT ( _end_lma ) {
*(.bss16)
*(.bss16.*)
- _ebss16 = .;
- }
- .stack16 : AT ( _data16_load_offset + __stack16 ) {
- __stack16 = .;
*(.stack16)
*(.stack16.*)
+ _edata16 = .;
}
-
- _edata16 = .;
+ _data16_filesz = ABSOLUTE ( _mdata16 - _data16 );
+ _data16_memsz = ABSOLUTE ( _edata16 - _data16 );
/*
* The 32-bit sections
+ *
*/
- _textdata_link_addr = 0;
- . = _textdata_link_addr;
- _textdata = .;
-
- _text = .;
-
- . += 1; /* Prevent NULL being valid */
-
- .text : AT ( _textdata_load_offset + __text ) {
- __text = .;
+ .textdata 0x0 : AT ( _textdata_lma ) {
+ _textdata = .;
*(.text.null_trap)
+ . += 1; /* Prevent NULL being valid */
*(.text)
*(.text.*)
- } = 0x9090
-
- _etext = .;
-
- _data = .;
-
- .rodata : AT ( _textdata_load_offset + __rodata ) {
- __rodata = .;
*(.rodata)
*(.rodata.*)
- }
- .data : AT ( _textdata_load_offset + __data ) {
- __data = .;
*(.data)
*(.data.*)
*(SORT(.tbl.*)) /* Various tables. See include/tables.h */
- _etextdata_progbits = .;
- }
- .bss : AT ( _textdata_load_offset + __bss ) {
- __bss = .;
- _bss = .;
+ _mtextdata = .;
+ } .bss.textdata (NOLOAD) : AT ( _end_lma ) {
*(.bss)
*(.bss.*)
*(COMMON)
- _ebss = .;
- }
- .stack : AT ( _textdata_load_offset + __stack ) {
- __stack = .;
*(.stack)
*(.stack.*)
+ _etextdata = .;
}
-
- _edata = .;
-
- _etextdata = .;
-
- _end = .;
+ _textdata_filesz = ABSOLUTE ( _mtextdata - _textdata );
+ _textdata_memsz = ABSOLUTE ( _etextdata - _textdata );
/*
* Compressor information block
+ *
*/
- _zinfo_link_addr = 0;
- . = _zinfo_link_addr;
- _zinfo = .;
-
- .zinfo : AT ( _zinfo_load_offset + __zinfo ) {
- __zinfo = .;
- _entry = .;
+ .zinfo 0x0 : AT ( _zinfo_lma ) {
+ _zinfo = .;
*(.zinfo)
*(.zinfo.*)
- _ezinfo_progbits = .;
+ _mzinfo = .;
+ } .bss.zinfo (NOLOAD) : AT ( _end_lma ) {
+ _ezinfo = .;
}
-
- _ezinfo = .;
+ _zinfo_filesz = ABSOLUTE ( _mzinfo - _zinfo );
+ _zinfo_memsz = ABSOLUTE ( _ezinfo - _zinfo );
+
+ /*
+ * Weak symbols that need zero values if not otherwise defined
+ *
+ */
+
+ .weak 0x0 : AT ( _end_lma ) {
+ _weak = .;
+ *(.weak)
+ _eweak = .;
+ }
+ _assert = ASSERT ( ( _weak == _eweak ), ".weak is non-zero length" );
/*
* Dispose of the comment and note sections to make the link map
* easier to read
+ *
*/
/DISCARD/ : {
*(.comment)
+ *(.comment.*)
*(.note)
+ *(.note.*)
+ *(.eh_frame)
+ *(.eh_frame.*)
+ *(.rel)
+ *(.rel.*)
}
/*
- * Load address calculations. The slightly obscure nature of the
- * calculations is because ALIGN(x) can only operate on the
- * location counter.
+ * Load address calculations. In older versions of ld, ALIGN()
+ * can operate only on the location counter, so we use that.
+ *
*/
- _max_align = 16;
- _load_addr = 0;
-
- . = _load_addr;
-
- . -= _prefix_link_addr;
- _prefix_load_offset = ALIGN ( _max_align );
- _prefix_load_addr = _prefix_link_addr + _prefix_load_offset;
- _prefix_size = _eprefix - _prefix;
- _prefix_progbits_size = _eprefix_progbits - _prefix;
- . = _prefix_load_addr + _prefix_progbits_size;
-
- . -= _text16_link_addr;
- _text16_load_offset = ALIGN ( _max_align );
- _text16_load_addr = _text16_link_addr + _text16_load_offset;
- _text16_size = _etext16 - _text16;
- _text16_progbits_size = _etext16_progbits - _text16;
- . = _text16_load_addr + _text16_progbits_size;
+ PROVIDE ( _max_align = 16 );
+ . = 0;
- . -= _data16_link_addr;
- _data16_load_offset = ALIGN ( _max_align );
- _data16_load_addr = _data16_link_addr + _data16_load_offset;
- _data16_size = _edata16 - _data16;
- _data16_progbits_size = _edata16_progbits - _data16;
- . = _data16_load_addr + _data16_progbits_size;
+ . = ALIGN ( _max_align );
+ _prefix_lma = .;
+ . += _prefix_filesz;
- . -= _textdata_link_addr;
- _textdata_load_offset = ALIGN ( _max_align );
- _textdata_load_addr = _textdata_link_addr + _textdata_load_offset;
- _textdata_size = _etextdata - _textdata;
- _textdata_progbits_size = _etextdata_progbits - _textdata;
- . = _textdata_load_addr + _textdata_progbits_size;
+ . = ALIGN ( _max_align );
+ _payload_lma = .;
+ _text16_lma = .;
+ . += _text16_filesz;
- _load_size = . - _load_addr;
+ . = ALIGN ( _max_align );
+ _data16_lma = .;
+ . += _data16_filesz;
- . -= _zinfo_link_addr;
- _zinfo_load_offset = ALIGN ( _max_align );
- _zinfo_load_addr = _zinfo_link_addr + _zinfo_load_offset;
- _zinfo_size = _ezinfo - _zinfo;
- _zinfo_progbits_size = _ezinfo_progbits - _zinfo;
- . = _zinfo_load_addr + _zinfo_progbits_size;
+ . = ALIGN ( _max_align );
+ _textdata_lma = .;
+ . += _textdata_filesz;
- _payload_offset = _text16_load_offset;
+ _filesz = .; /* Do not include zinfo block in file size */
- /*
- * Alignment checks. ALIGN() can only operate on the location
- * counter, so we set the location counter to each value we want
- * to check.
- */
-
- . = _prefix_load_addr - _prefix_link_addr;
- _assert = ASSERT ( ( . == ALIGN ( _max_align ) ),
- "_prefix is badly aligned" );
-
- . = _text16_load_addr - _text16_link_addr;
- _assert = ASSERT ( ( . == ALIGN ( _max_align ) ),
- "_text16 is badly aligned" );
+ . = ALIGN ( _max_align );
+ _zinfo_lma = .;
+ . += _zinfo_filesz;
- . = _data16_load_addr - _data16_link_addr;
- _assert = ASSERT ( ( . == ALIGN ( _max_align ) ),
- "_data16 is badly aligned" );
-
- . = _textdata_load_addr - _textdata_link_addr;
- _assert = ASSERT ( ( . == ALIGN ( _max_align ) ),
- "_text is badly aligned" );
+ . = ALIGN ( _max_align );
+ _end_lma = .;
/*
* Values calculated to save code from doing it
+ *
*/
- _prefix_size_pgh = ( ( _prefix_size + 15 ) / 16 );
- _prefix_size_sect = ( ( _prefix_size + 511 ) / 512 );
- _text16_size_pgh = ( ( _text16_size + 15 ) / 16 );
- _data16_size_pgh = ( ( _data16_size + 15 ) / 16 );
+ _prefix_memsz_pgh = ( ( _prefix_memsz + 15 ) / 16 );
+ _prefix_memsz_sect = ( ( _prefix_memsz + 511 ) / 512 );
+ _text16_memsz_pgh = ( ( _text16_memsz + 15 ) / 16 );
+ _data16_memsz_pgh = ( ( _data16_memsz + 15 ) / 16 );
/*
- * Load sizes in paragraphs and sectors. Note that wherever the
- * _load_size variables are used, there must be a corresponding
+ * File size in paragraphs and sectors. Note that wherever the
+ * _filesz variables are used, there must be a corresponding
* .zinfo.fixup section.
+ *
*/
- _load_size_pgh = ( ( _load_size + 15 ) / 16 );
- _load_size_sect = ( ( _load_size + 511 ) / 512 );
+ _filesz_pgh = ( ( _filesz + 15 ) / 16 );
+ _filesz_sect = ( ( _filesz + 511 ) / 512 );
}
diff --git a/gpxe/src/arch/i386/transitions/librm.S b/gpxe/src/arch/i386/transitions/librm.S
index ff4b1d97..8cf1f7f5 100644..100755
--- a/gpxe/src/arch/i386/transitions/librm.S
+++ b/gpxe/src/arch/i386/transitions/librm.S
@@ -19,9 +19,6 @@
#define SIZEOF_I386_ALL_REGS ( SIZEOF_REAL_MODE_REGS + SIZEOF_I386_FLAGS )
.arch i386
- .section ".text16", "ax", @progbits
- .section ".text16.data", "aw", @progbits
- .section ".data16", "aw", @progbits
/****************************************************************************
* Global descriptor table
@@ -47,7 +44,7 @@
#else
#define RM_LIMIT_16_19__AVL__SIZE__GRANULARITY 0x00
#endif
- .section ".data16"
+ .section ".data16", "aw", @progbits
.align 16
gdt:
gdtr: /* The first GDT entry is unused, the GDTR can fit here. */
@@ -99,7 +96,7 @@ gdt_end:
* %edi : Physical base of protected-mode code (virt_offset)
****************************************************************************
*/
- .section ".text16"
+ .section ".text16", "ax", @progbits
.code16
.globl init_librm
init_librm:
@@ -149,7 +146,7 @@ init_librm:
popl %eax
lret
- .section ".text16"
+ .section ".text16", "ax", @progbits
.code16
.weak idt_init
set_seg_base:
@@ -177,7 +174,7 @@ idt_init: /* Reuse the return opcode here */
*
****************************************************************************
*/
- .section ".text16"
+ .section ".text16", "ax", @progbits
.code16
real_to_prot:
/* Make sure we have our data segment available */
@@ -203,13 +200,13 @@ real_to_prot:
/* Switch to protected mode */
cli
- data32 lgdt gdtr
- data32 lidt idtr
+ data32 lgdt gdtr
+ data32 lidt idtr
movl %cr0, %eax
orb $CR0_PE, %al
movl %eax, %cr0
data32 ljmp $VIRTUAL_CS, $1f
- .section ".text"
+ .section ".text", "ax", @progbits
.code32
1:
/* Set up protected-mode data segments and stack pointer */
@@ -240,7 +237,7 @@ real_to_prot:
ret
/* Default IDTR with no interrupts */
- .section ".data16"
+ .section ".data16", "aw", @progbits
.weak idtr
idtr:
rm_idtr:
@@ -266,7 +263,7 @@ rm_idtr:
*
****************************************************************************
*/
- .section ".text"
+ .section ".text", "ax", @progbits
.code32
prot_to_real:
/* Add return address to data to be moved to RM stack */
@@ -296,7 +293,7 @@ prot_to_real:
movw %ax, %gs
movw %ax, %ss
ljmp $REAL_CS, $1f
- .section ".text16"
+ .section ".text16", "ax", @progbits
.code16
1:
/* Switch to real mode */
@@ -316,7 +313,7 @@ p2r_jump_target:
movl %edx, %esp
/* Reset IDTR to the real-mode defaults */
- lidt rm_idtr
+ data32 lidt rm_idtr
/* Return to real-mode address */
data32 ret
@@ -328,13 +325,13 @@ p2r_jump_target:
* rather than .data16 because code needs to be able to locate
* the data segment.
*/
- .section ".data16"
+ .section ".data16", "aw", @progbits
p2r_jump_vector:
.word p2r_jump_target
.globl rm_cs
rm_cs: .word 0
.globl rm_ds
- .section ".text16.data"
+ .section ".text16.data", "aw", @progbits
rm_ds: .word 0
/****************************************************************************
@@ -378,7 +375,7 @@ rm_ds: .word 0
#define PC_OFFSET_FUNCTION ( PC_OFFSET_RETADDR + 4 )
#define PC_OFFSET_END ( PC_OFFSET_FUNCTION + 4 )
- .section ".text16"
+ .section ".text16", "ax", @progbits
.code16
.globl prot_call
prot_call:
@@ -403,7 +400,7 @@ prot_call:
movl $PC_OFFSET_END, %ecx
pushl $1f
jmp real_to_prot
- .section ".text"
+ .section ".text", "ax", @progbits
.code32
1:
/* Set up environment expected by C code */
@@ -419,13 +416,13 @@ prot_call:
movl $PC_OFFSET_END, %ecx
pushl $1f
jmp prot_to_real
- .section ".text16"
+ .section ".text16", "ax", @progbits
.code16
1:
/* Reload GDT and IDT, restore registers and flags and return */
movw %sp, %bp
- lgdt (%bp)
- lidt 8(%bp)
+ data32 lgdt (%bp)
+ data32 lidt 8(%bp)
addw $20, %sp /* also skip %cs and %ss */
popw %ds
popw %es
@@ -475,7 +472,7 @@ prot_call:
#define RC_OFFSET_FUNCTION ( RC_OFFSET_RETADDR + 4 )
#define RC_OFFSET_END ( RC_OFFSET_FUNCTION + 4 )
- .section ".text"
+ .section ".text", "ax", @progbits
.code32
.globl real_call
real_call:
@@ -487,7 +484,7 @@ real_call:
movl $( RC_OFFSET_RETADDR + 4 /* function pointer copy */ ), %ecx
pushl $1f
jmp prot_to_real
- .section ".text16"
+ .section ".text16", "ax", @progbits
.code16
1:
/* Call real-mode function */
@@ -503,7 +500,7 @@ real_call:
movl $RC_OFFSET_RETADDR, %ecx
pushl $1f
jmp real_to_prot
- .section ".text"
+ .section ".text", "ax", @progbits
.code32
1:
/* Restore registers and return */
@@ -514,7 +511,7 @@ real_call:
/* Function vector, used because "call xx(%sp)" is not a valid
* 16-bit expression.
*/
- .section ".data16"
+ .section ".data16", "aw", @progbits
rc_function: .word 0, 0
/****************************************************************************
@@ -551,7 +548,7 @@ rc_function: .word 0, 0
* to us.
****************************************************************************
*/
- .section ".data"
+ .section ".data", "aw", @progbits
.globl rm_sp
rm_sp: .word 0
.globl rm_ss
@@ -567,13 +564,13 @@ pm_esp: .long _estack
****************************************************************************
*/
/* Internal copies, created by init_librm (which runs in real mode) */
- .section ".data16"
+ .section ".data16", "aw", @progbits
_virt_offset: .long 0
_text16: .long 0
_data16: .long 0
/* Externally-visible copies, created by real_to_prot */
- .section ".data"
+ .section ".data", "aw", @progbits
.globl virt_offset
virt_offset: .long 0
.globl text16
diff --git a/gpxe/src/arch/i386/transitions/librm_mgmt.c b/gpxe/src/arch/i386/transitions/librm_mgmt.c
index 59b2eabc..50569f8e 100644..100755
--- a/gpxe/src/arch/i386/transitions/librm_mgmt.c
+++ b/gpxe/src/arch/i386/transitions/librm_mgmt.c
@@ -1,45 +1,56 @@
-/*
- * librm: a library for interfacing to real-mode code
- *
- * Michael Brown <mbrown@fensystems.co.uk>
- *
- */
-
-#include <stdint.h>
-#include <librm.h>
-
-/*
- * This file provides functions for managing librm.
- *
- */
-
-/**
- * Allocate space on the real-mode stack and copy data there from a
- * user buffer
- *
- * @v data User buffer
- * @v size Size of stack data
- * @ret sp New value of real-mode stack pointer
- */
-uint16_t copy_user_to_rm_stack ( userptr_t data, size_t size ) {
- userptr_t rm_stack;
- rm_sp -= size;
- rm_stack = real_to_user ( rm_ss, rm_sp );
- memcpy_user ( rm_stack, 0, data, 0, size );
- return rm_sp;
-};
-
-/**
- * Deallocate space on the real-mode stack, optionally copying back
- * data to a user buffer.
- *
- * @v data User buffer
- * @v size Size of stack data
- */
-void remove_user_from_rm_stack ( userptr_t data, size_t size ) {
- if ( data ) {
- userptr_t rm_stack = real_to_user ( rm_ss, rm_sp );
- memcpy_user ( rm_stack, 0, data, 0, size );
- }
- rm_sp += size;
-};
+/*
+ * librm: a library for interfacing to real-mode code
+ *
+ * Michael Brown <mbrown@fensystems.co.uk>
+ *
+ */
+
+#include <stdint.h>
+#include <realmode.h>
+
+/*
+ * This file provides functions for managing librm.
+ *
+ */
+
+/**
+ * Allocate space on the real-mode stack and copy data there from a
+ * user buffer
+ *
+ * @v data User buffer
+ * @v size Size of stack data
+ * @ret sp New value of real-mode stack pointer
+ */
+uint16_t copy_user_to_rm_stack ( userptr_t data, size_t size ) {
+ userptr_t rm_stack;
+ rm_sp -= size;
+ rm_stack = real_to_user ( rm_ss, rm_sp );
+ memcpy_user ( rm_stack, 0, data, 0, size );
+ return rm_sp;
+};
+
+/**
+ * Deallocate space on the real-mode stack, optionally copying back
+ * data to a user buffer.
+ *
+ * @v data User buffer
+ * @v size Size of stack data
+ */
+void remove_user_from_rm_stack ( userptr_t data, size_t size ) {
+ if ( data ) {
+ userptr_t rm_stack = real_to_user ( rm_ss, rm_sp );
+ memcpy_user ( rm_stack, 0, data, 0, size );
+ }
+ rm_sp += size;
+};
+
+PROVIDE_UACCESS_INLINE ( librm, phys_to_user );
+PROVIDE_UACCESS_INLINE ( librm, user_to_phys );
+PROVIDE_UACCESS_INLINE ( librm, virt_to_user );
+PROVIDE_UACCESS_INLINE ( librm, user_to_virt );
+PROVIDE_UACCESS_INLINE ( librm, userptr_add );
+PROVIDE_UACCESS_INLINE ( librm, memcpy_user );
+PROVIDE_UACCESS_INLINE ( librm, memmove_user );
+PROVIDE_UACCESS_INLINE ( librm, memset_user );
+PROVIDE_UACCESS_INLINE ( librm, strlen_user );
+PROVIDE_UACCESS_INLINE ( librm, memchr_user );
diff --git a/gpxe/src/arch/x86/Makefile b/gpxe/src/arch/x86/Makefile
new file mode 100644
index 00000000..a7c4bc0e
--- /dev/null
+++ b/gpxe/src/arch/x86/Makefile
@@ -0,0 +1,9 @@
+# Include common x86 headers
+#
+CFLAGS += -Iarch/x86/include
+
+# x86-specific directories containing source files
+#
+SRCDIRS += arch/x86/core
+SRCDIRS += arch/x86/interface/efi
+SRCDIRS += arch/x86/prefix
diff --git a/gpxe/src/arch/x86/Makefile.efi b/gpxe/src/arch/x86/Makefile.efi
new file mode 100644
index 00000000..bef8d59d
--- /dev/null
+++ b/gpxe/src/arch/x86/Makefile.efi
@@ -0,0 +1,28 @@
+# -*- makefile -*- : Force emacs to use Makefile mode
+
+# The EFI linker script
+#
+LDSCRIPT = arch/x86/scripts/efi.lds
+
+# Retain relocation information for elf2efi
+#
+LDFLAGS += -q -S
+
+# Media types.
+#
+NON_AUTO_MEDIA += efi
+NON_AUTO_MEDIA += efidrv
+
+# Rules for building EFI files
+#
+$(BIN)/%.efi : $(BIN)/%.efi.tmp $(ELF2EFI)
+ $(QM)$(ECHO) " [FINISH] $@"
+ $(Q)$(ELF2EFI) --subsystem=10 $< $@
+
+$(BIN)/%.efidrv : $(BIN)/%.efidrv.tmp $(ELF2EFI)
+ $(QM)$(ECHO) " [FINISH] $@"
+ $(Q)$(ELF2EFI) --subsystem=11 $< $@
+
+$(BIN)/%.efirom : $(BIN)/%.efidrv $(EFIROM)
+ $(QM)$(ECHO) " [FINISH] $@"
+ $(Q)$(EFIROM) -v $(TGT_PCI_VENDOR) -d $(TGT_PCI_DEVICE) $< $@
diff --git a/gpxe/src/arch/i386/core/pcidirect.c b/gpxe/src/arch/x86/core/pcidirect.c
index 2ed8c2ad..db17215e 100644
--- a/gpxe/src/arch/i386/core/pcidirect.c
+++ b/gpxe/src/arch/x86/core/pcidirect.c
@@ -16,8 +16,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <gpxe/io.h>
#include <gpxe/pci.h>
-#include <pcidirect.h>
/** @file
*
@@ -36,3 +36,10 @@ void pcidirect_prepare ( struct pci_device *pci, int where ) {
( where & ~3 ) ), PCIDIRECT_CONFIG_ADDRESS );
}
+PROVIDE_PCIAPI_INLINE ( direct, pci_max_bus );
+PROVIDE_PCIAPI_INLINE ( direct, pci_read_config_byte );
+PROVIDE_PCIAPI_INLINE ( direct, pci_read_config_word );
+PROVIDE_PCIAPI_INLINE ( direct, pci_read_config_dword );
+PROVIDE_PCIAPI_INLINE ( direct, pci_write_config_byte );
+PROVIDE_PCIAPI_INLINE ( direct, pci_write_config_word );
+PROVIDE_PCIAPI_INLINE ( direct, pci_write_config_dword );
diff --git a/gpxe/src/arch/i386/core/i386_string.c b/gpxe/src/arch/x86/core/x86_string.c
index 9917363a..c0224c7a 100644
--- a/gpxe/src/arch/i386/core/i386_string.c
+++ b/gpxe/src/arch/x86/core/x86_string.c
@@ -32,9 +32,7 @@
* @v len Length
* @ret dest Destination address
*/
-__attribute__ (( regparm ( 3 ) )) void * __memcpy ( void *dest,
- const void *src,
- size_t len ) {
+void * __memcpy ( void *dest, const void *src, size_t len ) {
void *edi = dest;
const void *esi = src;
int discard_ecx;
diff --git a/gpxe/src/arch/x86/include/bits/pci_io.h b/gpxe/src/arch/x86/include/bits/pci_io.h
new file mode 100644
index 00000000..0fbb439d
--- /dev/null
+++ b/gpxe/src/arch/x86/include/bits/pci_io.h
@@ -0,0 +1,13 @@
+#ifndef _BITS_PCI_IO_H
+#define _BITS_PCI_IO_H
+
+/** @file
+ *
+ * i386-specific PCI I/O API implementations
+ *
+ */
+
+#include <gpxe/pcibios.h>
+#include <gpxe/pcidirect.h>
+
+#endif /* _BITS_PCI_IO_H */
diff --git a/gpxe/src/arch/i386/include/bits/string.h b/gpxe/src/arch/x86/include/bits/string.h
index c05a7df8..42ddeddf 100644
--- a/gpxe/src/arch/i386/include/bits/string.h
+++ b/gpxe/src/arch/x86/include/bits/string.h
@@ -23,9 +23,7 @@
#define __HAVE_ARCH_MEMCPY
-extern __attribute__ (( regparm ( 3 ) )) void * __memcpy ( void *dest,
- const void *src,
- size_t len );
+extern void * __memcpy ( void *dest, const void *src, size_t len );
#if 0
static inline __attribute__ (( always_inline )) void *
diff --git a/gpxe/src/arch/x86/include/gpxe/efi/efix86_nap.h b/gpxe/src/arch/x86/include/gpxe/efi/efix86_nap.h
new file mode 100644
index 00000000..91424c54
--- /dev/null
+++ b/gpxe/src/arch/x86/include/gpxe/efi/efix86_nap.h
@@ -0,0 +1,16 @@
+#ifndef _GPXE_EFIX86_NAP_H
+#define _GPXE_EFIX86_NAP_H
+
+/** @file
+ *
+ * EFI CPU sleeping
+ *
+ */
+
+#ifdef NAP_EFIX86
+#define NAP_PREFIX_efix86
+#else
+#define NAP_PREFIX_efix86 __efix86_
+#endif
+
+#endif /* _GPXE_EFIX86_NAP_H */
diff --git a/gpxe/src/arch/i386/include/pcibios.h b/gpxe/src/arch/x86/include/gpxe/pcibios.h
index 3d08d135..b86f5abd 100644
--- a/gpxe/src/arch/i386/include/pcibios.h
+++ b/gpxe/src/arch/x86/include/gpxe/pcibios.h
@@ -1,5 +1,5 @@
-#ifndef _PCIBIOS_H
-#define _PCIBIOS_H
+#ifndef _GPXE_PCIBIOS_H
+#define _GPXE_PCIBIOS_H
#include <stdint.h>
@@ -9,6 +9,12 @@
*
*/
+#ifdef PCIAPI_PCBIOS
+#define PCIAPI_PREFIX_pcbios
+#else
+#define PCIAPI_PREFIX_pcbios __pcbios_
+#endif
+
struct pci_device;
#define PCIBIOS_INSTALLATION_CHECK 0xb1010000
@@ -19,7 +25,6 @@ struct pci_device;
#define PCIBIOS_WRITE_CONFIG_WORD 0xb10c0000
#define PCIBIOS_WRITE_CONFIG_DWORD 0xb10d0000
-extern int pcibios_max_bus ( void );
extern int pcibios_read ( struct pci_device *pci, uint32_t command,
uint32_t *value );
extern int pcibios_write ( struct pci_device *pci, uint32_t command,
@@ -33,9 +38,10 @@ extern int pcibios_write ( struct pci_device *pci, uint32_t command,
* @v value Value read
* @ret rc Return status code
*/
-static inline __attribute__ (( always_inline )) int
-pcibios_read_config_byte ( struct pci_device *pci, unsigned int where,
- uint8_t *value ) {
+static inline __always_inline int
+PCIAPI_INLINE ( pcbios, pci_read_config_byte ) ( struct pci_device *pci,
+ unsigned int where,
+ uint8_t *value ) {
uint32_t tmp;
int rc;
@@ -52,9 +58,10 @@ pcibios_read_config_byte ( struct pci_device *pci, unsigned int where,
* @v value Value read
* @ret rc Return status code
*/
-static inline __attribute__ (( always_inline )) int
-pcibios_read_config_word ( struct pci_device *pci, unsigned int where,
- uint16_t *value ) {
+static inline __always_inline int
+PCIAPI_INLINE ( pcbios, pci_read_config_word ) ( struct pci_device *pci,
+ unsigned int where,
+ uint16_t *value ) {
uint32_t tmp;
int rc;
@@ -71,9 +78,10 @@ pcibios_read_config_word ( struct pci_device *pci, unsigned int where,
* @v value Value read
* @ret rc Return status code
*/
-static inline __attribute__ (( always_inline )) int
-pcibios_read_config_dword ( struct pci_device *pci, unsigned int where,
- uint32_t *value ) {
+static inline __always_inline int
+PCIAPI_INLINE ( pcbios, pci_read_config_dword ) ( struct pci_device *pci,
+ unsigned int where,
+ uint32_t *value ) {
return pcibios_read ( pci, PCIBIOS_READ_CONFIG_DWORD | where, value );
}
@@ -85,9 +93,10 @@ pcibios_read_config_dword ( struct pci_device *pci, unsigned int where,
* @v value Value to be written
* @ret rc Return status code
*/
-static inline __attribute__ (( always_inline )) int
-pcibios_write_config_byte ( struct pci_device *pci, unsigned int where,
- uint8_t value ) {
+static inline __always_inline int
+PCIAPI_INLINE ( pcbios, pci_write_config_byte ) ( struct pci_device *pci,
+ unsigned int where,
+ uint8_t value ) {
return pcibios_write ( pci, PCIBIOS_WRITE_CONFIG_BYTE | where, value );
}
@@ -99,9 +108,10 @@ pcibios_write_config_byte ( struct pci_device *pci, unsigned int where,
* @v value Value to be written
* @ret rc Return status code
*/
-static inline __attribute__ (( always_inline )) int
-pcibios_write_config_word ( struct pci_device *pci, unsigned int where,
- uint16_t value ) {
+static inline __always_inline int
+PCIAPI_INLINE ( pcbios, pci_write_config_word ) ( struct pci_device *pci,
+ unsigned int where,
+ uint16_t value ) {
return pcibios_write ( pci, PCIBIOS_WRITE_CONFIG_WORD | where, value );
}
@@ -113,10 +123,11 @@ pcibios_write_config_word ( struct pci_device *pci, unsigned int where,
* @v value Value to be written
* @ret rc Return status code
*/
-static inline __attribute__ (( always_inline )) int
-pcibios_write_config_dword ( struct pci_device *pci, unsigned int where,
- uint32_t value ) {
+static inline __always_inline int
+PCIAPI_INLINE ( pcbios, pci_write_config_dword ) ( struct pci_device *pci,
+ unsigned int where,
+ uint32_t value ) {
return pcibios_write ( pci, PCIBIOS_WRITE_CONFIG_DWORD | where, value);
}
-#endif /* _PCIBIOS_H */
+#endif /* _GPXE_PCIBIOS_H */
diff --git a/gpxe/src/arch/i386/include/pcidirect.h b/gpxe/src/arch/x86/include/gpxe/pcidirect.h
index 4e2e9d12..fe433c6f 100644
--- a/gpxe/src/arch/i386/include/pcidirect.h
+++ b/gpxe/src/arch/x86/include/gpxe/pcidirect.h
@@ -2,7 +2,13 @@
#define _PCIDIRECT_H
#include <stdint.h>
-#include <io.h>
+#include <gpxe/io.h>
+
+#ifdef PCIAPI_DIRECT
+#define PCIAPI_PREFIX_direct
+#else
+#define PCIAPI_PREFIX_direct __direct_
+#endif
/** @file
*
@@ -22,7 +28,8 @@ extern void pcidirect_prepare ( struct pci_device *pci, int where );
*
* @ret max_bus Maximum bus number
*/
-static inline int pcidirect_max_bus ( void ) {
+static inline __always_inline int
+PCIAPI_INLINE ( direct, pci_max_bus ) ( void ) {
/* No way to work this out via Type 1 accesses */
return 0xff;
}
@@ -35,9 +42,10 @@ static inline int pcidirect_max_bus ( void ) {
* @v value Value read
* @ret rc Return status code
*/
-static inline __attribute__ (( always_inline )) int
-pcidirect_read_config_byte ( struct pci_device *pci, unsigned int where,
- uint8_t *value ) {
+static inline __always_inline int
+PCIAPI_INLINE ( direct, pci_read_config_byte ) ( struct pci_device *pci,
+ unsigned int where,
+ uint8_t *value ) {
pcidirect_prepare ( pci, where );
*value = inb ( PCIDIRECT_CONFIG_DATA + ( where & 3 ) );
return 0;
@@ -51,9 +59,10 @@ pcidirect_read_config_byte ( struct pci_device *pci, unsigned int where,
* @v value Value read
* @ret rc Return status code
*/
-static inline __attribute__ (( always_inline )) int
-pcidirect_read_config_word ( struct pci_device *pci, unsigned int where,
- uint16_t *value ) {
+static inline __always_inline int
+PCIAPI_INLINE ( direct, pci_read_config_word ) ( struct pci_device *pci,
+ unsigned int where,
+ uint16_t *value ) {
pcidirect_prepare ( pci, where );
*value = inw ( PCIDIRECT_CONFIG_DATA + ( where & 2 ) );
return 0;
@@ -67,9 +76,10 @@ pcidirect_read_config_word ( struct pci_device *pci, unsigned int where,
* @v value Value read
* @ret rc Return status code
*/
-static inline __attribute__ (( always_inline )) int
-pcidirect_read_config_dword ( struct pci_device *pci, unsigned int where,
- uint32_t *value ) {
+static inline __always_inline int
+PCIAPI_INLINE ( direct, pci_read_config_dword ) ( struct pci_device *pci,
+ unsigned int where,
+ uint32_t *value ) {
pcidirect_prepare ( pci, where );
*value = inl ( PCIDIRECT_CONFIG_DATA );
return 0;
@@ -83,9 +93,10 @@ pcidirect_read_config_dword ( struct pci_device *pci, unsigned int where,
* @v value Value to be written
* @ret rc Return status code
*/
-static inline __attribute__ (( always_inline )) int
-pcidirect_write_config_byte ( struct pci_device *pci, unsigned int where,
- uint8_t value ) {
+static inline __always_inline int
+PCIAPI_INLINE ( direct, pci_write_config_byte ) ( struct pci_device *pci,
+ unsigned int where,
+ uint8_t value ) {
pcidirect_prepare ( pci, where );
outb ( value, PCIDIRECT_CONFIG_DATA + ( where & 3 ) );
return 0;
@@ -99,9 +110,10 @@ pcidirect_write_config_byte ( struct pci_device *pci, unsigned int where,
* @v value Value to be written
* @ret rc Return status code
*/
-static inline __attribute__ (( always_inline )) int
-pcidirect_write_config_word ( struct pci_device *pci, unsigned int where,
- uint16_t value ) {
+static inline __always_inline int
+PCIAPI_INLINE ( direct, pci_write_config_word ) ( struct pci_device *pci,
+ unsigned int where,
+ uint16_t value ) {
pcidirect_prepare ( pci, where );
outw ( value, PCIDIRECT_CONFIG_DATA + ( where & 2 ) );
return 0;
@@ -115,9 +127,10 @@ pcidirect_write_config_word ( struct pci_device *pci, unsigned int where,
* @v value Value to be written
* @ret rc Return status code
*/
-static inline __attribute__ (( always_inline )) int
-pcidirect_write_config_dword ( struct pci_device *pci, unsigned int where,
- uint32_t value ) {
+static inline __always_inline int
+PCIAPI_INLINE ( direct, pci_write_config_dword ) ( struct pci_device *pci,
+ unsigned int where,
+ uint32_t value ) {
pcidirect_prepare ( pci, where );
outl ( value, PCIDIRECT_CONFIG_DATA );
return 0;
diff --git a/gpxe/src/arch/x86/interface/efi/efix86_nap.c b/gpxe/src/arch/x86/interface/efi/efix86_nap.c
new file mode 100644
index 00000000..45e99a68
--- /dev/null
+++ b/gpxe/src/arch/x86/interface/efi/efix86_nap.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <gpxe/nap.h>
+#include <gpxe/efi/efi.h>
+
+/** @file
+ *
+ * gPXE CPU sleeping API for EFI
+ *
+ */
+
+/**
+ * Sleep until next interrupt
+ *
+ */
+static void efix86_cpu_nap ( void ) {
+ /*
+ * I can't find any EFI API that allows us to put the CPU to
+ * sleep. The CpuSleep() function is defined in CpuLib.h, but
+ * isn't part of any exposed protocol so we have no way to
+ * call it.
+ *
+ * The EFI shell doesn't seem to bother sleeping the CPU; it
+ * just sits there idly burning power.
+ *
+ */
+ __asm__ __volatile__ ( "hlt" );
+}
+
+PROVIDE_NAP ( efix86, cpu_nap, efix86_cpu_nap );
diff --git a/gpxe/src/arch/x86/prefix/efidrvprefix.c b/gpxe/src/arch/x86/prefix/efidrvprefix.c
new file mode 100644
index 00000000..5f631588
--- /dev/null
+++ b/gpxe/src/arch/x86/prefix/efidrvprefix.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdlib.h>
+#include <gpxe/init.h>
+#include <gpxe/efi/efi.h>
+
+/**
+ * EFI entry point
+ *
+ * @v image_handle Image handle
+ * @v systab System table
+ * @ret efirc EFI return status code
+ */
+EFI_STATUS EFIAPI _start ( EFI_HANDLE image_handle,
+ EFI_SYSTEM_TABLE *systab ) {
+ EFI_STATUS efirc;
+
+ /* Initialise EFI environment */
+ if ( ( efirc = efi_init ( image_handle, systab ) ) != 0 )
+ return efirc;
+
+ /* Initialise gPXE environment */
+ initialise();
+ startup();
+
+ /* Install SNP driver and return */
+ return RC_TO_EFIRC ( efi_snp_install () );
+}
diff --git a/gpxe/src/arch/x86/prefix/efiprefix.c b/gpxe/src/arch/x86/prefix/efiprefix.c
new file mode 100644
index 00000000..b05b744d
--- /dev/null
+++ b/gpxe/src/arch/x86/prefix/efiprefix.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdlib.h>
+#include <gpxe/efi/efi.h>
+
+/**
+ * EFI entry point
+ *
+ * @v image_handle Image handle
+ * @v systab System table
+ * @ret efirc EFI return status code
+ */
+EFI_STATUS EFIAPI _start ( EFI_HANDLE image_handle,
+ EFI_SYSTEM_TABLE *systab ) {
+ EFI_STATUS efirc;
+
+ /* Initialise EFI environment */
+ if ( ( efirc = efi_init ( image_handle, systab ) ) != 0 )
+ return efirc;
+
+ /* Call to main() */
+ return RC_TO_EFIRC ( main () );
+}
diff --git a/gpxe/src/arch/x86/scripts/efi.lds b/gpxe/src/arch/x86/scripts/efi.lds
new file mode 100644
index 00000000..aac31056
--- /dev/null
+++ b/gpxe/src/arch/x86/scripts/efi.lds
@@ -0,0 +1,105 @@
+/* -*- sh -*- */
+
+/*
+ * Linker script for EFI images
+ *
+ */
+
+ENTRY ( _start )
+
+SECTIONS {
+
+ /* The file starts at a virtual address of zero, and sections are
+ * contiguous. Each section is aligned to at least _max_align,
+ * which defaults to 32. Load addresses are equal to virtual
+ * addresses.
+ */
+
+ _max_align = 32;
+
+ /* Allow plenty of space for file headers */
+ . = 0x1000;
+
+ /*
+ * The text section
+ *
+ */
+
+ . = ALIGN ( _max_align );
+ .text : {
+ _text = .;
+ *(.text)
+ *(.text.*)
+ _etext = .;
+ }
+
+ /*
+ * The rodata section
+ *
+ */
+
+ . = ALIGN ( _max_align );
+ .rodata : {
+ _rodata = .;
+ *(.rodata)
+ *(.rodata.*)
+ _erodata = .;
+ }
+
+ /*
+ * The data section
+ *
+ */
+
+ . = ALIGN ( _max_align );
+ .data : {
+ _data = .;
+ *(.data)
+ *(.data.*)
+ *(SORT(.tbl.*)) /* Various tables. See include/tables.h */
+ _edata = .;
+ }
+
+ /*
+ * The bss section
+ *
+ */
+
+ . = ALIGN ( _max_align );
+ .bss : {
+ _bss = .;
+ *(.bss)
+ *(.bss.*)
+ *(COMMON)
+ _ebss = .;
+ }
+
+ /*
+ * Weak symbols that need zero values if not otherwise defined
+ *
+ */
+
+ .weak 0x0 : {
+ _weak = .;
+ *(.weak)
+ _eweak = .;
+ }
+ _assert = ASSERT ( ( _weak == _eweak ), ".weak is non-zero length" );
+
+ /*
+ * Dispose of the comment and note sections to make the link map
+ * easier to read
+ *
+ */
+
+ /DISCARD/ : {
+ *(.comment)
+ *(.comment.*)
+ *(.note)
+ *(.note.*)
+ *(.eh_frame)
+ *(.eh_frame.*)
+ *(.rel)
+ *(.rel.*)
+ }
+}
diff --git a/gpxe/src/arch/x86_64/Makefile b/gpxe/src/arch/x86_64/Makefile
new file mode 100644
index 00000000..d2c2ff53
--- /dev/null
+++ b/gpxe/src/arch/x86_64/Makefile
@@ -0,0 +1,41 @@
+# Code size reduction.
+#
+CFLAGS += -fstrength-reduce -fomit-frame-pointer
+
+# Code size reduction. gcc3 needs a different syntax to gcc2 if you
+# want to avoid spurious warnings.
+#
+CFLAGS += -falign-jumps=1 -falign-loops=1 -falign-functions=1
+
+# Use %rip-relative addressing wherever possible.
+#
+CFLAGS += -fpie
+
+# Force 64-bit code
+#
+CFLAGS += -m64
+ASFLAGS += --64
+LDFLAGS += -m elf_x86_64
+
+# EFI requires -fshort-wchar, and nothing else currently uses wchar_t
+#
+CFLAGS += -fshort-wchar
+
+# We need to undefine the default macro "i386" when compiling .S
+# files, otherwise ".arch i386" translates to ".arch 1"...
+#
+CFLAGS += -Ui386
+
+# x86_64-specific directories containing source files
+#
+SRCDIRS += arch/x86_64/prefix
+
+# Include common x86 Makefile
+#
+MAKEDEPS += arch/x86/Makefile
+include arch/x86/Makefile
+
+# Include platform-specific Makefile
+#
+MAKEDEPS += arch/x86_64/Makefile.$(PLATFORM)
+include arch/x86_64/Makefile.$(PLATFORM)
diff --git a/gpxe/src/arch/x86_64/Makefile.efi b/gpxe/src/arch/x86_64/Makefile.efi
new file mode 100644
index 00000000..26b71278
--- /dev/null
+++ b/gpxe/src/arch/x86_64/Makefile.efi
@@ -0,0 +1,14 @@
+# -*- makefile -*- : Force emacs to use Makefile mode
+
+# EFI probably doesn't guarantee us a red zone, so let's not rely on it.
+#
+CFLAGS += -mno-red-zone
+
+# Specify EFI image builder
+#
+ELF2EFI = $(ELF2EFI64)
+
+# Include generic EFI Makefile
+#
+MAKEDEPS += arch/x86/Makefile.efi
+include arch/x86/Makefile.efi
diff --git a/gpxe/src/arch/x86_64/include/bits/byteswap.h b/gpxe/src/arch/x86_64/include/bits/byteswap.h
new file mode 100644
index 00000000..9ed85e8f
--- /dev/null
+++ b/gpxe/src/arch/x86_64/include/bits/byteswap.h
@@ -0,0 +1,22 @@
+#ifndef _BITS_BYTESWAP_H
+#define _BITS_BYTESWAP_H
+
+static inline __attribute__ (( always_inline, const )) uint16_t
+__bswap_variable_16 ( uint16_t x ) {
+ __asm__ ( "xchgb %b0,%h0" : "=Q" ( x ) : "0" ( x ) );
+ return x;
+}
+
+static inline __attribute__ (( always_inline, const )) uint32_t
+__bswap_variable_32 ( uint32_t x ) {
+ __asm__ ( "bswapl %k0" : "=r" ( x ) : "0" ( x ) );
+ return x;
+}
+
+static inline __attribute__ (( always_inline, const )) uint64_t
+__bswap_variable_64 ( uint64_t x ) {
+ __asm__ ( "bswapq %q0" : "=r" ( x ) : "0" ( x ) );
+ return x;
+}
+
+#endif /* _BITS_BYTESWAP_H */
diff --git a/gpxe/src/arch/x86_64/include/bits/compiler.h b/gpxe/src/arch/x86_64/include/bits/compiler.h
new file mode 100644
index 00000000..51a7eaae
--- /dev/null
+++ b/gpxe/src/arch/x86_64/include/bits/compiler.h
@@ -0,0 +1,14 @@
+#ifndef _BITS_COMPILER_H
+#define _BITS_COMPILER_H
+
+#ifndef ASSEMBLY
+
+/** Declare a function with standard calling conventions */
+#define __asmcall __attribute__ (( regparm(0) ))
+
+/** Declare a function with libgcc implicit linkage */
+#define __libgcc
+
+#endif /* ASSEMBLY */
+
+#endif /* _BITS_COMPILER_H */
diff --git a/gpxe/src/arch/x86_64/include/bits/endian.h b/gpxe/src/arch/x86_64/include/bits/endian.h
new file mode 100644
index 00000000..413e702d
--- /dev/null
+++ b/gpxe/src/arch/x86_64/include/bits/endian.h
@@ -0,0 +1,6 @@
+#ifndef ETHERBOOT_BITS_ENDIAN_H
+#define ETHERBOOT_BITS_ENDIAN_H
+
+#define __BYTE_ORDER __LITTLE_ENDIAN
+
+#endif /* ETHERBOOT_BITS_ENDIAN_H */
diff --git a/gpxe/src/arch/x86_64/include/bits/errfile.h b/gpxe/src/arch/x86_64/include/bits/errfile.h
new file mode 100644
index 00000000..dcda26ba
--- /dev/null
+++ b/gpxe/src/arch/x86_64/include/bits/errfile.h
@@ -0,0 +1,11 @@
+#ifndef _BITS_ERRFILE_H
+#define _BITS_ERRFILE_H
+
+/**
+ * @addtogroup errfile Error file identifiers
+ * @{
+ */
+
+/** @} */
+
+#endif /* _BITS_ERRFILE_H */
diff --git a/gpxe/src/arch/x86_64/include/bits/io.h b/gpxe/src/arch/x86_64/include/bits/io.h
new file mode 100644
index 00000000..921fdcc0
--- /dev/null
+++ b/gpxe/src/arch/x86_64/include/bits/io.h
@@ -0,0 +1,10 @@
+#ifndef _BITS_IO_H
+#define _BITS_IO_H
+
+/** @file
+ *
+ * x86_64-specific I/O API implementations
+ *
+ */
+
+#endif /* _BITS_IO_H */
diff --git a/gpxe/src/arch/x86_64/include/bits/nap.h b/gpxe/src/arch/x86_64/include/bits/nap.h
new file mode 100644
index 00000000..0a0c8a24
--- /dev/null
+++ b/gpxe/src/arch/x86_64/include/bits/nap.h
@@ -0,0 +1,12 @@
+#ifndef _BITS_NAP_H
+#define _BITS_NAP_H
+
+/** @file
+ *
+ * x86_64-specific CPU sleeping API implementations
+ *
+ */
+
+#include <gpxe/efi/efix86_nap.h>
+
+#endif /* _BITS_MAP_H */
diff --git a/gpxe/src/arch/x86_64/include/bits/smbios.h b/gpxe/src/arch/x86_64/include/bits/smbios.h
new file mode 100644
index 00000000..2f0118d0
--- /dev/null
+++ b/gpxe/src/arch/x86_64/include/bits/smbios.h
@@ -0,0 +1,10 @@
+#ifndef _BITS_SMBIOS_H
+#define _BITS_SMBIOS_H
+
+/** @file
+ *
+ * i386-specific SMBIOS API implementations
+ *
+ */
+
+#endif /* _BITS_SMBIOS_H */
diff --git a/gpxe/src/arch/x86_64/include/bits/stdint.h b/gpxe/src/arch/x86_64/include/bits/stdint.h
new file mode 100644
index 00000000..23bae9c4
--- /dev/null
+++ b/gpxe/src/arch/x86_64/include/bits/stdint.h
@@ -0,0 +1,21 @@
+#ifndef _BITS_STDINT_H
+#define _BITS_STDINT_H
+
+typedef unsigned long size_t;
+typedef signed long ssize_t;
+typedef signed long off_t;
+
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+
+typedef signed char int8_t;
+typedef signed short int16_t;
+typedef signed int int32_t;
+typedef signed long long int64_t;
+
+typedef unsigned long physaddr_t;
+typedef unsigned long intptr_t;
+
+#endif /* _BITS_STDINT_H */
diff --git a/gpxe/src/arch/x86_64/include/bits/timer.h b/gpxe/src/arch/x86_64/include/bits/timer.h
new file mode 100644
index 00000000..dfa6c270
--- /dev/null
+++ b/gpxe/src/arch/x86_64/include/bits/timer.h
@@ -0,0 +1,10 @@
+#ifndef _BITS_TIMER_H
+#define _BITS_TIMER_H
+
+/** @file
+ *
+ * x86_64-specific timer API implementations
+ *
+ */
+
+#endif /* _BITS_TIMER_H */
diff --git a/gpxe/src/arch/x86_64/include/bits/uaccess.h b/gpxe/src/arch/x86_64/include/bits/uaccess.h
new file mode 100644
index 00000000..45582924
--- /dev/null
+++ b/gpxe/src/arch/x86_64/include/bits/uaccess.h
@@ -0,0 +1,10 @@
+#ifndef _BITS_UACCESS_H
+#define _BITS_UACCESS_H
+
+/** @file
+ *
+ * x86_64-specific user access API implementations
+ *
+ */
+
+#endif /* _BITS_UACCESS_H */
diff --git a/gpxe/src/arch/x86_64/include/bits/umalloc.h b/gpxe/src/arch/x86_64/include/bits/umalloc.h
new file mode 100644
index 00000000..12bf949d
--- /dev/null
+++ b/gpxe/src/arch/x86_64/include/bits/umalloc.h
@@ -0,0 +1,10 @@
+#ifndef _BITS_UMALLOC_H
+#define _BITS_UMALLOC_H
+
+/** @file
+ *
+ * x86_64-specific user memory allocation API implementations
+ *
+ */
+
+#endif /* _BITS_UMALLOC_H */
diff --git a/gpxe/src/arch/x86_64/include/gdbmach.h b/gpxe/src/arch/x86_64/include/gdbmach.h
new file mode 100644
index 00000000..fcf8e94e
--- /dev/null
+++ b/gpxe/src/arch/x86_64/include/gdbmach.h
@@ -0,0 +1,51 @@
+#ifndef GDBMACH_H
+#define GDBMACH_H
+
+/** @file
+ *
+ * GDB architecture specifics
+ *
+ * This file declares functions for manipulating the machine state and
+ * debugging context.
+ *
+ */
+
+#include <stdint.h>
+
+typedef unsigned long gdbreg_t;
+
+/* The register snapshot, this must be in sync with interrupt handler and the
+ * GDB protocol. */
+enum {
+ // STUB: don't expect this to work!
+ GDBMACH_EIP,
+ GDBMACH_EFLAGS,
+ GDBMACH_NREGS,
+ GDBMACH_SIZEOF_REGS = GDBMACH_NREGS * sizeof ( gdbreg_t )
+};
+
+/* Breakpoint types */
+enum {
+ GDBMACH_BPMEM,
+ GDBMACH_BPHW,
+ GDBMACH_WATCH,
+ GDBMACH_RWATCH,
+ GDBMACH_AWATCH,
+};
+
+static inline void gdbmach_set_pc ( gdbreg_t *regs, gdbreg_t pc ) {
+ regs [ GDBMACH_EIP ] = pc;
+}
+
+static inline void gdbmach_set_single_step ( gdbreg_t *regs, int step ) {
+ regs [ GDBMACH_EFLAGS ] &= ~( 1 << 8 ); /* Trace Flag (TF) */
+ regs [ GDBMACH_EFLAGS ] |= ( step << 8 );
+}
+
+static inline void gdbmach_breakpoint ( void ) {
+ __asm__ __volatile__ ( "int $3\n" );
+}
+
+extern int gdbmach_set_breakpoint ( int type, unsigned long addr, size_t len, int enable );
+
+#endif /* GDBMACH_H */
diff --git a/gpxe/src/arch/x86_64/include/limits.h b/gpxe/src/arch/x86_64/include/limits.h
new file mode 100644
index 00000000..8cf87b47
--- /dev/null
+++ b/gpxe/src/arch/x86_64/include/limits.h
@@ -0,0 +1,59 @@
+#ifndef LIMITS_H
+#define LIMITS_H 1
+
+/* Number of bits in a `char' */
+#define CHAR_BIT 8
+
+/* Minimum and maximum values a `signed char' can hold */
+#define SCHAR_MIN (-128)
+#define SCHAR_MAX 127
+
+/* Maximum value an `unsigned char' can hold. (Minimum is 0.) */
+#define UCHAR_MAX 255
+
+/* Minimum and maximum values a `char' can hold */
+#define CHAR_MIN SCHAR_MIN
+#define CHAR_MAX SCHAR_MAX
+
+/* Minimum and maximum values a `signed short int' can hold */
+#define SHRT_MIN (-32768)
+#define SHRT_MAX 32767
+
+/* Maximum value an `unsigned short' can hold. (Minimum is 0.) */
+#define USHRT_MAX 65535
+
+
+/* Minimum and maximum values a `signed int' can hold */
+#define INT_MIN (-INT_MAX - 1)
+#define INT_MAX 2147483647
+
+/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
+#define UINT_MAX 4294967295U
+
+
+/* Minimum and maximum values a `signed int' can hold */
+#define INT_MAX 2147483647
+#define INT_MIN (-INT_MAX - 1)
+
+
+/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
+#define UINT_MAX 4294967295U
+
+
+/* Minimum and maximum values a `signed long' can hold */
+#define LONG_MAX 9223372036854775807L
+#define LONG_MIN (-LONG_MAX - 1L)
+
+/* Maximum value an `unsigned long' can hold. (Minimum is 0.) */
+#define ULONG_MAX 18446744073709551615UL
+
+/* Minimum and maximum values a `signed long long' can hold */
+#define LLONG_MAX 9223372036854775807LL
+#define LLONG_MIN (-LONG_MAX - 1LL)
+
+
+/* Maximum value an `unsigned long long' can hold. (Minimum is 0.) */
+#define ULLONG_MAX 18446744073709551615ULL
+
+
+#endif /* LIMITS_H */
diff --git a/gpxe/src/config.h b/gpxe/src/config.h
deleted file mode 100644
index 603604ab..00000000
--- a/gpxe/src/config.h
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * This file defines the configuration for Etherboot.
- *
- * The build system splits this file into several individual header
- * files of the form config/%.h, so that changing one option doesn't
- * necessitate a rebuild of every single object. For this reason, it
- * is important to maintain the strict formatting in this file.
- *
- */
-
-/* @BEGIN general.h
- *
- * Console configuration
- *
- * These options specify the console types that Etherboot will use for
- * interaction with the user.
- *
- */
-
-#define CONSOLE_FIRMWARE /* Default BIOS console */
-#undef CONSOLE_SERIAL /* Serial port */
-#undef CONSOLE_DIRECT_VGA /* Direct access to VGA card */
-#undef CONSOLE_BTEXT /* Who knows what this does? */
-#undef CONSOLE_PC_KBD /* Direct access to PC keyboard */
-
-/* @END general.h */
-
-/* @BEGIN serial.h
- *
- * Serial port configuration
- *
- * These options affect the operation of the serial console. They
- * take effect only if the serial console is included using the
- * CONSOLE_SERIAL option.
- *
- */
-
-#define COMCONSOLE 0x3f8 /* I/O port address */
-
-/* Keep settings from a previous user of the serial port (e.g. lilo or
- * LinuxBIOS), ignoring COMSPEED, COMDATA, COMPARITY and COMSTOP.
- */
-#undef COMPRESERVE
-
-#ifndef COMPRESERVE
-#define COMSPEED 115200 /* Baud rate */
-#define COMDATA 8 /* Data bits */
-#define COMPARITY 0 /* Parity: 0=None, 1=Odd, 2=Even */
-#define COMSTOP 1 /* Stop bits */
-#endif
-
-/* @END serial.h */
-
-/* @BEGIN general.h
- *
- * Timer configuration
- *
- */
-#define TIMER_BIOS /* 18Hz BIOS timer */
-#define TIMER_RDTSC /* CPU TimeStamp Counter timer */
-#define BANNER_TIMEOUT 20 /* Tenths of a second for which the shell
- banner should appear */
-
-/* @END general.h */
-
-/* @BEGIN isa.h
- *
- * ISA probe address configuration
- *
- * You can override the list of addresses that will be probed by any
- * ISA drivers.
- *
- */
-#undef ISA_PROBE_ADDRS /* e.g. 0x200, 0x300 */
-#undef ISA_PROBE_ONLY /* Do not probe any other addresses */
-
-/* @END isa.h */
-
-/* @BEGIN general.h
- *
- * Network protocols
- *
- */
-
-#define NET_PROTO_IPV4 /* IPv4 protocol */
-
-/* @END general.h */
-
-/* @BEGIN general.h
- *
- * Download protocols
- *
- */
-
-#define DOWNLOAD_PROTO_TFTP /* Trivial File Transfer Protocol */
-#define DOWNLOAD_PROTO_NFS /* Network File System */
-#define DOWNLOAD_PROTO_HTTP /* Hypertext Transfer Protocol */
-#define DOWNLOAD_PROTO_HTTPS /* Secure Hypertext Transfer Protocol */
-#define DOWNLOAD_PROTO_FTP /* File Transfer Protocol */
-#undef DOWNLOAD_PROTO_TFTM /* Multicast Trivial File Transfer Protocol */
-#undef DOWNLOAD_PROTO_SLAM /* Scalable Local Area Multicast */
-#undef DOWNLOAD_PROTO_FSP /* FSP? */
-
-/* @END general.h */
-
-/* @BEGIN general.h
- *
- * Name resolution modules
- *
- */
-
-#define DNS_RESOLVER /* DNS resolver */
-#undef NMB_RESOLVER /* NMB resolver */
-
-/* @END general.h */
-
-/* @BEGIN general.h
- *
- * Image types
- *
- * Etherboot supports various image formats. Select whichever ones
- * you want to use.
- *
- */
-#undef IMAGE_NBI /* NBI image support */
-#define IMAGE_ELF /* ELF image support */
-#undef IMAGE_FREEBSD /* FreeBSD kernel image support */
-#define IMAGE_MULTIBOOT /* MultiBoot image support */
-#undef IMAGE_AOUT /* a.out image support */
-#undef IMAGE_WINCE /* WinCE image support */
-#define IMAGE_PXE /* PXE image support */
-#define IMAGE_SCRIPT /* gPXE script image support */
-#define IMAGE_BZIMAGE /* Linux bzImage image support */
-#define IMAGE_COMBOOT /* SYSLINUX COMBOOT image support */
-
-/* @END general.h */
-
-/* @BEGIN general.h
- *
- * Command-line commands to include
- *
- */
-#define AUTOBOOT_CMD /* Automatic booting */
-#define NVO_CMD /* Non-volatile option storage commands */
-#define CONFIG_CMD /* Option configuration console */
-#define IFMGMT_CMD /* Interface management commands */
-#define ROUTE_CMD /* Routing table management commands */
-#define IMAGE_CMD /* Image management commands */
-#define DHCP_CMD /* DHCP management commands */
-#define SANBOOT_CMD /* SAN boot commands */
-
-/* @END general.h */
-
-/* @BEGIN general.h
- *
- * Obscure configuration options
- *
- * You probably don't need to touch these.
- *
- */
-
-#undef BUILD_SERIAL /* Include an automatic build serial
- * number. Add "bs" to the list of
- * make targets. For example:
- * "make bin/rtl8139.dsk bs" */
-#undef BUILD_ID /* Include a custom build ID string,
- * e.g "test-foo" */
-#undef NULL_TRAP /* Attempt to catch NULL function calls */
-#undef GDBSERIAL /* Remote GDB debugging over serial */
-#undef GDBUDP /* Remote GDB debugging over UDP
- * (both may be set) */
-
-/* @END general.h */
-
-/* @TRYSOURCE config-local.h */
diff --git a/gpxe/src/config/.gitignore b/gpxe/src/config/.gitignore
index 499ae122..8e94f32f 100644
--- a/gpxe/src/config/.gitignore
+++ b/gpxe/src/config/.gitignore
@@ -1,2 +1 @@
-*.h
.buildserial.*
diff --git a/gpxe/src/config/console.h b/gpxe/src/config/console.h
new file mode 100644
index 00000000..b4ea1dda
--- /dev/null
+++ b/gpxe/src/config/console.h
@@ -0,0 +1,21 @@
+#ifndef CONFIG_CONSOLE_H
+#define CONFIG_CONSOLE_H
+
+/** @file
+ *
+ * Console configuration
+ *
+ * These options specify the console types that Etherboot will use for
+ * interaction with the user.
+ *
+ */
+
+#include <config/defaults.h>
+
+//#define CONSOLE_PCBIOS /* Default BIOS console */
+//#define CONSOLE_SERIAL /* Serial port */
+//#define CONSOLE_DIRECT_VGA /* Direct access to VGA card */
+//#define CONSOLE_BTEXT /* Who knows what this does? */
+//#define CONSOLE_PC_KBD /* Direct access to PC keyboard */
+
+#endif /* CONFIG_CONSOLE_H */
diff --git a/gpxe/src/config/defaults.h b/gpxe/src/config/defaults.h
new file mode 100644
index 00000000..1f55ef3c
--- /dev/null
+++ b/gpxe/src/config/defaults.h
@@ -0,0 +1,8 @@
+#ifndef CONFIG_DEFAULTS_H
+#define CONFIG_DEFAULTS_H
+
+#define CONFIG_DEFAULTS(_platform) <config/defaults/_platform.h>
+
+#include CONFIG_DEFAULTS(PLATFORM)
+
+#endif /* CONFIG_DEFAULTS_H */
diff --git a/gpxe/src/config/defaults/efi.h b/gpxe/src/config/defaults/efi.h
new file mode 100644
index 00000000..fe38fd03
--- /dev/null
+++ b/gpxe/src/config/defaults/efi.h
@@ -0,0 +1,21 @@
+#ifndef CONFIG_DEFAULTS_EFI_H
+#define CONFIG_DEFAULTS_EFI_H
+
+/** @file
+ *
+ * Configuration defaults for EFI
+ *
+ */
+
+#define UACCESS_EFI
+#define IOAPI_EFI
+#define PCIAPI_EFI
+#define CONSOLE_EFI
+#define TIMER_EFI
+#define NAP_EFIX86
+#define UMALLOC_EFI
+#define SMBIOS_EFI
+
+#define IMAGE_EFI /* EFI image support */
+
+#endif /* CONFIG_DEFAULTS_EFI_H */
diff --git a/gpxe/src/config/defaults/pcbios.h b/gpxe/src/config/defaults/pcbios.h
new file mode 100644
index 00000000..4359e1a4
--- /dev/null
+++ b/gpxe/src/config/defaults/pcbios.h
@@ -0,0 +1,29 @@
+#ifndef CONFIG_DEFAULTS_PCBIOS_H
+#define CONFIG_DEFAULTS_PCBIOS_H
+
+/** @file
+ *
+ * Configuration defaults for PCBIOS
+ *
+ */
+
+#define UACCESS_LIBRM
+#define IOAPI_X86
+#define PCIAPI_PCBIOS
+#define TIMER_PCBIOS
+#define CONSOLE_PCBIOS
+#define NAP_PCBIOS
+#define UMALLOC_MEMTOP
+#define SMBIOS_PCBIOS
+
+#define IMAGE_ELF /* ELF image support */
+#define IMAGE_MULTIBOOT /* MultiBoot image support */
+#define IMAGE_PXE /* PXE image support */
+#define IMAGE_SCRIPT /* gPXE script image support */
+#define IMAGE_BZIMAGE /* Linux bzImage image support */
+#define IMAGE_COMBOOT /* SYSLINUX COMBOOT image support */
+
+#define SANBOOT_PROTO_ISCSI /* iSCSI protocol */
+#define SANBOOT_PROTO_AOE /* AoE protocol */
+
+#endif /* CONFIG_DEFAULTS_PCBIOS_H */
diff --git a/gpxe/src/config/general.h b/gpxe/src/config/general.h
new file mode 100644
index 00000000..a3d563c2
--- /dev/null
+++ b/gpxe/src/config/general.h
@@ -0,0 +1,123 @@
+#ifndef CONFIG_GENERAL_H
+#define CONFIG_GENERAL_H
+
+/** @file
+ *
+ * General configuration
+ *
+ */
+
+#include <config/defaults.h>
+
+/*
+ * Branding
+ *
+ * Vendors may use these strings to add their own branding to gPXE.
+ * PRODUCT_NAME is displayed prior to any gPXE branding in startup
+ * messages, and PRODUCT_SHORT_NAME is used where a brief product
+ * label is required (e.g. in BIOS boot selection menus).
+ *
+ * To minimise end-user confusion, it's probably a good idea to either
+ * make PRODUCT_SHORT_NAME a substring of PRODUCT_NAME or leave it as
+ * "gPXE".
+ *
+ */
+#define PRODUCT_NAME ""
+#define PRODUCT_SHORT_NAME "gPXE"
+
+/*
+ * Timer configuration
+ *
+ */
+#define BANNER_TIMEOUT 20 /* Tenths of a second for which the shell
+ banner should appear */
+
+/*
+ * Network protocols
+ *
+ */
+
+#define NET_PROTO_IPV4 /* IPv4 protocol */
+
+/*
+ * Download protocols
+ *
+ */
+
+#define DOWNLOAD_PROTO_TFTP /* Trivial File Transfer Protocol */
+#define DOWNLOAD_PROTO_NFS /* Network File System */
+#define DOWNLOAD_PROTO_HTTP /* Hypertext Transfer Protocol */
+#define DOWNLOAD_PROTO_HTTPS /* Secure Hypertext Transfer Protocol */
+#define DOWNLOAD_PROTO_FTP /* File Transfer Protocol */
+#undef DOWNLOAD_PROTO_TFTM /* Multicast Trivial File Transfer Protocol */
+#undef DOWNLOAD_PROTO_SLAM /* Scalable Local Area Multicast */
+#undef DOWNLOAD_PROTO_FSP /* FSP? */
+
+/*
+ * SAN boot protocols
+ *
+ */
+
+//#undef SANBOOT_PROTO_ISCSI /* iSCSI protocol */
+//#undef SANBOOT_PROTO_AOE /* AoE protocol */
+
+/*
+ * Name resolution modules
+ *
+ */
+
+#define DNS_RESOLVER /* DNS resolver */
+#undef NMB_RESOLVER /* NMB resolver */
+
+/*
+ * Image types
+ *
+ * Etherboot supports various image formats. Select whichever ones
+ * you want to use.
+ *
+ */
+//#define IMAGE_NBI /* NBI image support */
+//#define IMAGE_ELF /* ELF image support */
+//#define IMAGE_FREEBSD /* FreeBSD kernel image support */
+//#define IMAGE_MULTIBOOT /* MultiBoot image support */
+//#define IMAGE_AOUT /* a.out image support */
+//#define IMAGE_WINCE /* WinCE image support */
+//#define IMAGE_PXE /* PXE image support */
+//#define IMAGE_SCRIPT /* gPXE script image support */
+//#define IMAGE_BZIMAGE /* Linux bzImage image support */
+//#define IMAGE_COMBOOT /* SYSLINUX COMBOOT image support */
+//#define IMAGE_EFI /* EFI image support */
+
+/*
+ * Command-line commands to include
+ *
+ */
+#define AUTOBOOT_CMD /* Automatic booting */
+#define NVO_CMD /* Non-volatile option storage commands */
+#define CONFIG_CMD /* Option configuration console */
+#define IFMGMT_CMD /* Interface management commands */
+#define ROUTE_CMD /* Routing table management commands */
+#define IMAGE_CMD /* Image management commands */
+#define DHCP_CMD /* DHCP management commands */
+#define SANBOOT_CMD /* SAN boot commands */
+#define LOGIN_CMD /* Login command */
+
+/*
+ * Obscure configuration options
+ *
+ * You probably don't need to touch these.
+ *
+ */
+
+#undef BUILD_SERIAL /* Include an automatic build serial
+ * number. Add "bs" to the list of
+ * make targets. For example:
+ * "make bin/rtl8139.dsk bs" */
+#undef BUILD_ID /* Include a custom build ID string,
+ * e.g "test-foo" */
+#undef NULL_TRAP /* Attempt to catch NULL function calls */
+#undef GDBSERIAL /* Remote GDB debugging over serial */
+#undef GDBUDP /* Remote GDB debugging over UDP
+ * (both may be set) */
+
+#endif /* CONFIG_GENERAL_H */
diff --git a/gpxe/src/config/ioapi.h b/gpxe/src/config/ioapi.h
new file mode 100644
index 00000000..7726a0f0
--- /dev/null
+++ b/gpxe/src/config/ioapi.h
@@ -0,0 +1,15 @@
+#ifndef CONFIG_IOAPI_H
+#define CONFIG_IOAPI_H
+
+/** @file
+ *
+ * I/O API configuration
+ *
+ */
+
+#include <config/defaults.h>
+
+//#undef PCIAPI_PCBIOS /* Access via PCI BIOS */
+//#define PCIAPI_DIRECT /* Direct access via Type 1 accesses */
+
+#endif /* CONFIG_IOAPI_H */
diff --git a/gpxe/src/config/isa.h b/gpxe/src/config/isa.h
new file mode 100644
index 00000000..523be1c0
--- /dev/null
+++ b/gpxe/src/config/isa.h
@@ -0,0 +1,15 @@
+#ifndef CONFIG_ISA_H
+#define CONFIG_ISA_H
+
+/** @file
+ *
+ * ISA probe address configuration
+ *
+ * You can override the list of addresses that will be probed by any
+ * ISA drivers.
+ *
+ */
+#undef ISA_PROBE_ADDRS /* e.g. 0x200, 0x300 */
+#undef ISA_PROBE_ONLY /* Do not probe any other addresses */
+
+#endif /* CONFIG_ISA_H */
diff --git a/gpxe/src/config/nap.h b/gpxe/src/config/nap.h
new file mode 100644
index 00000000..8648d925
--- /dev/null
+++ b/gpxe/src/config/nap.h
@@ -0,0 +1,15 @@
+#ifndef CONFIG_NAP_H
+#define CONFIG_NAP_H
+
+/** @file
+ *
+ * CPU sleeping
+ *
+ */
+
+#include <config/defaults.h>
+
+//#undef NAP_PCBIOS
+//#define NAP_NULL
+
+#endif /* CONFIG_NAP_H */
diff --git a/gpxe/src/config/serial.h b/gpxe/src/config/serial.h
new file mode 100644
index 00000000..984a7a9c
--- /dev/null
+++ b/gpxe/src/config/serial.h
@@ -0,0 +1,28 @@
+#ifndef CONFIG_SERIAL_H
+#define CONFIG_SERIAL_H
+
+/** @file
+ *
+ * Serial port configuration
+ *
+ * These options affect the operation of the serial console. They
+ * take effect only if the serial console is included using the
+ * CONSOLE_SERIAL option.
+ *
+ */
+
+#define COMCONSOLE 0x3f8 /* I/O port address */
+
+/* Keep settings from a previous user of the serial port (e.g. lilo or
+ * LinuxBIOS), ignoring COMSPEED, COMDATA, COMPARITY and COMSTOP.
+ */
+#undef COMPRESERVE
+
+#ifndef COMPRESERVE
+#define COMSPEED 115200 /* Baud rate */
+#define COMDATA 8 /* Data bits */
+#define COMPARITY 0 /* Parity: 0=None, 1=Odd, 2=Even */
+#define COMSTOP 1 /* Stop bits */
+#endif
+
+#endif /* CONFIG_SERIAL_H */
diff --git a/gpxe/src/config/timer.h b/gpxe/src/config/timer.h
new file mode 100644
index 00000000..7c3f3521
--- /dev/null
+++ b/gpxe/src/config/timer.h
@@ -0,0 +1,15 @@
+#ifndef CONFIG_TIMER_H
+#define CONFIG_TIMER_H
+
+/** @file
+ *
+ * Timer configuration.
+ *
+ */
+
+#include <config/defaults.h>
+
+//#undef TIMER_PCBIOS
+//#define TIMER_RDTSC
+
+#endif /* CONFIG_TIMER_H */
diff --git a/gpxe/src/config/umalloc.h b/gpxe/src/config/umalloc.h
new file mode 100644
index 00000000..de4019e5
--- /dev/null
+++ b/gpxe/src/config/umalloc.h
@@ -0,0 +1,12 @@
+#ifndef CONFIG_UMALLOC_H
+#define CONFIG_UMALLOC_H
+
+/** @file
+ *
+ * User memory allocation API configuration
+ *
+ */
+
+#include <config/defaults.h>
+
+#endif /* CONFIG_UMALLOC_H */
diff --git a/gpxe/src/core/base64.c b/gpxe/src/core/base64.c
new file mode 100644
index 00000000..e54821e3
--- /dev/null
+++ b/gpxe/src/core/base64.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <gpxe/base64.h>
+
+/** @file
+ *
+ * Base64 encoding
+ *
+ */
+
+static const char base64[64] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+/**
+ * Base64-encode a string
+ *
+ * @v raw Raw string
+ * @v encoded Buffer for encoded string
+ *
+ * The buffer must be the correct length for the encoded string. Use
+ * something like
+ *
+ * char buf[ base64_encoded_len ( strlen ( raw ) ) + 1 ];
+ *
+ * (the +1 is for the terminating NUL) to provide a buffer of the
+ * correct size.
+ */
+void base64_encode ( const char *raw, char *encoded ) {
+ const uint8_t *raw_bytes = ( ( const uint8_t * ) raw );
+ uint8_t *encoded_bytes = ( ( uint8_t * ) encoded );
+ size_t raw_bit_len = ( 8 * strlen ( raw ) );
+ unsigned int bit;
+ unsigned int tmp;
+
+ for ( bit = 0 ; bit < raw_bit_len ; bit += 6 ) {
+ tmp = ( ( raw_bytes[ bit / 8 ] << ( bit % 8 ) ) |
+ ( raw_bytes[ bit / 8 + 1 ] >> ( 8 - ( bit % 8 ) ) ) );
+ tmp = ( ( tmp >> 2 ) & 0x3f );
+ *(encoded_bytes++) = base64[tmp];
+ }
+ for ( ; ( bit % 8 ) != 0 ; bit += 6 )
+ *(encoded_bytes++) = '=';
+ *(encoded_bytes++) = '\0';
+
+ DBG ( "Base64-encoded \"%s\" as \"%s\"\n", raw, encoded );
+ assert ( strlen ( encoded ) == base64_encoded_len ( strlen ( raw ) ) );
+}
diff --git a/gpxe/src/core/config.c b/gpxe/src/core/config.c
index b5624fae..bd0d66ec 100644
--- a/gpxe/src/core/config.c
+++ b/gpxe/src/core/config.c
@@ -5,7 +5,8 @@
* your option) any later version.
*/
-#include "config/general.h"
+#include <config/general.h>
+#include <config/console.h>
/*
* Build ID string calculations
@@ -38,19 +39,9 @@
/*
* Drag in all requested console types
*
- * CONSOLE_DUAL sets both CONSOLE_FIRMWARE and CONSOLE_SERIAL for
- * legacy compatibility.
- *
*/
-#ifdef CONSOLE_DUAL
-#undef CONSOLE_FIRMWARE
-#define CONSOLE_FIRMWARE 1
-#undef CONSOLE_SERIAL
-#define CONSOLE_SERIAL 1
-#endif
-
-#ifdef CONSOLE_FIRMWARE
+#ifdef CONSOLE_PCBIOS
REQUIRE_OBJECT ( bios_console );
#endif
#ifdef CONSOLE_SERIAL
@@ -68,15 +59,8 @@ REQUIRE_OBJECT ( pc_kbd );
#ifdef CONSOLE_SYSLOG
REQUIRE_OBJECT ( syslog );
#endif
-
-/*
- * Drag in all requested timers
- */
-#ifdef TIMER_BIOS
-REQUIRE_OBJECT ( timer_bios );
-#endif
-#ifdef TIMER_RDTSC
-REQUIRE_OBJECT ( timer_rdtsc );
+#ifdef CONSOLE_EFI
+REQUIRE_OBJECT ( efi_console );
#endif
/*
@@ -114,6 +98,17 @@ REQUIRE_OBJECT ( slam );
#endif
/*
+ * Drag in all requested SAN boot protocols
+ *
+ */
+#ifdef SANBOOT_PROTO_ISCSI
+REQUIRE_OBJECT ( iscsiboot );
+#endif
+#ifdef SANBOOT_PROTO_AOE
+REQUIRE_OBJECT ( aoeboot );
+#endif
+
+/*
* Drag in all requested resolvers
*
*/
@@ -166,6 +161,9 @@ REQUIRE_OBJECT ( com32_call );
REQUIRE_OBJECT ( com32_wrapper );
REQUIRE_OBJECT ( comboot_resolv );
#endif
+#ifdef IMAGE_EFI
+REQUIRE_OBJECT ( efi_image );
+#endif
/*
* Drag in all requested commands
@@ -195,6 +193,9 @@ REQUIRE_OBJECT ( dhcp_cmd );
#ifdef SANBOOT_CMD
REQUIRE_OBJECT ( sanboot_cmd );
#endif
+#ifdef LOGIN_CMD
+REQUIRE_OBJECT ( login_cmd );
+#endif
/*
* Drag in miscellaneous objects
@@ -220,3 +221,4 @@ REQUIRE_OBJECT ( gdbstub_cmd );
*
*/
REQUIRE_OBJECT ( device );
+REQUIRE_OBJECT ( embedded );
diff --git a/gpxe/src/core/console.c b/gpxe/src/core/console.c
index 653f689d..c9773f71 100644
--- a/gpxe/src/core/console.c
+++ b/gpxe/src/core/console.c
@@ -1,11 +1,10 @@
#include "stddef.h"
#include "console.h"
#include <gpxe/process.h>
+#include <gpxe/nap.h>
/** @file */
-#include "bios.h"
-
static struct console_driver console_drivers[0]
__table_start ( struct console_driver, console );
static struct console_driver console_drivers_end[0]
@@ -82,9 +81,6 @@ static struct console_driver * has_input ( void ) {
*
* The character read will not be echoed back to any console.
*
- * @bug We need a cleaner way to pick up cpu_nap(). It makes a
- * real-mode call, and so we don't want to use it with LinuxBIOS.
- *
*/
int getchar ( void ) {
struct console_driver *console;
diff --git a/gpxe/src/core/cwuri.c b/gpxe/src/core/cwuri.c
index c7f01386..81fd900e 100644
--- a/gpxe/src/core/cwuri.c
+++ b/gpxe/src/core/cwuri.c
@@ -36,6 +36,9 @@ struct uri *cwuri = NULL;
* @v uri New working URI, or NULL
*/
void churi ( struct uri *uri ) {
+ struct uri *new_uri;
+
+ new_uri = resolve_uri ( cwuri, uri );
uri_put ( cwuri );
- cwuri = uri_get ( uri );
+ cwuri = new_uri;
}
diff --git a/gpxe/src/core/debug.c b/gpxe/src/core/debug.c
index 09830420..500a7ac0 100644
--- a/gpxe/src/core/debug.c
+++ b/gpxe/src/core/debug.c
@@ -1,7 +1,7 @@
#include <stdio.h>
#include <stdint.h>
#include <stdarg.h>
-#include <io.h>
+#include <gpxe/io.h>
#include <console.h>
void pause ( void ) {
@@ -106,12 +106,12 @@ int check_region ( void *region, size_t len ) {
virt_to_phys ( region + len ) );
}
in_corruption = 1;
- printf ( "--- offset %#lx ", offset );
+ printf ( "--- offset %#x ", offset );
} else if ( ( in_corruption != 0 ) &&
( test == GUARD_SYMBOL ) ) {
/* End of corruption */
in_corruption = 0;
- printf ( "to offset %#lx", offset );
+ printf ( "to offset %#x", offset );
}
}
diff --git a/gpxe/src/core/gdbudp.c b/gpxe/src/core/gdbudp.c
index c49a1bca..26feb38a 100644
--- a/gpxe/src/core/gdbudp.c
+++ b/gpxe/src/core/gdbudp.c
@@ -19,7 +19,6 @@
#include <stdio.h>
#include <string.h>
#include <byteswap.h>
-#include <bios.h>
#include <gpxe/iobuf.h>
#include <gpxe/in.h>
#include <gpxe/if_arp.h>
@@ -27,6 +26,7 @@
#include <gpxe/ip.h>
#include <gpxe/udp.h>
#include <gpxe/netdevice.h>
+#include <gpxe/nap.h>
#include <gpxe/gdbstub.h>
#include <gpxe/gdbudp.h>
diff --git a/gpxe/src/core/getkey.c b/gpxe/src/core/getkey.c
index 1551cf37..787c9027 100644
--- a/gpxe/src/core/getkey.c
+++ b/gpxe/src/core/getkey.c
@@ -16,6 +16,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <ctype.h>
#include <console.h>
#include <gpxe/process.h>
#include <gpxe/keys.h>
@@ -59,21 +60,22 @@ static int getchar_timeout ( unsigned long timeout ) {
*/
int getkey ( void ) {
int character;
- int key;
+ unsigned int n = 0;
character = getchar();
if ( character != ESC )
return character;
- key = 0;
while ( ( character = getchar_timeout ( GETKEY_TIMEOUT ) ) >= 0 ) {
if ( character == '[' )
continue;
- if ( ! key )
- key = KEY_ANSI ( character );
+ if ( isdigit ( character ) ) {
+ n = ( ( n * 10 ) + ( character - '0' ) );
+ continue;
+ }
if ( character >= 0x40 )
- break;
+ return KEY_ANSI ( n, character );
}
- return ( key ? key : ESC );
+ return ESC;
}
diff --git a/gpxe/src/core/image.c b/gpxe/src/core/image.c
index 440a68c9..277d09a9 100644
--- a/gpxe/src/core/image.c
+++ b/gpxe/src/core/image.c
@@ -53,6 +53,7 @@ static void free_image ( struct refcnt *refcnt ) {
uri_put ( image->uri );
ufree ( image->data );
+ image_put ( image->replacement );
free ( image );
DBGC ( image, "IMAGE %p freed\n", image );
}
@@ -142,9 +143,9 @@ int register_image ( struct image *image ) {
* @v image Executable/loadable image
*/
void unregister_image ( struct image *image ) {
+ DBGC ( image, "IMAGE %p unregistered\n", image );
list_del ( &image->list );
image_put ( image );
- DBGC ( image, "IMAGE %p unregistered\n", image );
}
/**
@@ -237,6 +238,7 @@ int image_autoload ( struct image *image ) {
* @ret rc Return status code
*/
int image_exec ( struct image *image ) {
+ struct image *replacement;
struct uri *old_cwuri;
int rc;
@@ -257,18 +259,39 @@ int image_exec ( struct image *image ) {
old_cwuri = uri_get ( cwuri );
churi ( image->uri );
+ /* Take out a temporary reference to the image. This allows
+ * the image to unregister itself if necessary, without
+ * automatically freeing itself.
+ */
+ image_get ( image );
+
/* Try executing the image */
if ( ( rc = image->type->exec ( image ) ) != 0 ) {
DBGC ( image, "IMAGE %p could not execute: %s\n",
image, strerror ( rc ) );
- goto done;
+ /* Do not return yet; we still have clean-up to do */
}
- done:
+ /* Pick up replacement image before we drop the original
+ * image's temporary reference.
+ */
+ replacement = image->replacement;
+
+ /* Drop temporary reference to the original image */
+ image_put ( image );
+
/* Reset current working directory */
churi ( old_cwuri );
uri_put ( old_cwuri );
+ /* Tail-recurse into replacement image, if one exists */
+ if ( replacement ) {
+ DBGC ( image, "IMAGE %p replacing self with IMAGE %p\n",
+ image, replacement );
+ if ( ( rc = image_exec ( replacement ) ) != 0 )
+ return rc;
+ }
+
return rc;
}
diff --git a/gpxe/src/core/main.c b/gpxe/src/core/main.c
index d5892261..8d360c42 100644
--- a/gpxe/src/core/main.c
+++ b/gpxe/src/core/main.c
@@ -19,7 +19,9 @@ Literature dealing with the network protocols:
#include <gpxe/features.h>
#include <gpxe/shell.h>
#include <gpxe/shell_banner.h>
+#include <gpxe/image.h>
#include <usr/autoboot.h>
+#include <config/general.h>
#define NORMAL "\033[0m"
#define BOLD "\033[1m"
@@ -33,14 +35,29 @@ static struct feature features_end[0] __table_end ( struct feature, features );
*
* @ret rc Return status code
*/
-__cdecl int main ( void ) {
+__asmcall int main ( void ) {
struct feature *feature;
+ struct image *image;
+
+ /* Some devices take an unreasonably long time to initialise */
+ printf ( PRODUCT_SHORT_NAME " initialising devices...\n" );
initialise();
startup();
- /* Print welcome banner */
- printf ( NORMAL "\n\n\n" BOLD "gPXE " VERSION
+ /*
+ * Print welcome banner
+ *
+ *
+ * If you wish to brand this build of gPXE, please do so by
+ * defining the string PRODUCT_NAME in config/general.h.
+ *
+ * While nothing in the GPL prevents you from removing all
+ * references to gPXE or http://etherboot.org, we prefer you
+ * not to do so.
+ *
+ */
+ printf ( NORMAL "\n\n" PRODUCT_NAME "\n" BOLD "gPXE " VERSION
NORMAL " -- Open Source Boot Firmware -- "
CYAN "http://etherboot.org" NORMAL "\n"
"Features:" );
@@ -53,11 +70,16 @@ __cdecl int main ( void ) {
/* User wants shell; just give them a shell */
shell();
} else {
- /* User doesn't want shell; try booting. If booting
- * fails, offer a second chance to enter the shell for
- * diagnostics.
+ /* User doesn't want shell; load and execute the first
+ * image. If booting fails (i.e. if the image
+ * returns, or fails to execute), offer a second
+ * chance to enter the shell for diagnostics.
*/
- autoboot();
+ for_each_image ( image ) {
+ image_exec ( image );
+ break;
+ }
+
if ( shell_banner() )
shell();
}
diff --git a/gpxe/src/core/malloc.c b/gpxe/src/core/malloc.c
index 2d892f42..db7f1bed 100644
--- a/gpxe/src/core/malloc.c
+++ b/gpxe/src/core/malloc.c
@@ -20,7 +20,7 @@
#include <stdint.h>
#include <string.h>
#include <strings.h>
-#include <io.h>
+#include <gpxe/io.h>
#include <gpxe/list.h>
#include <gpxe/init.h>
#include <gpxe/malloc.h>
diff --git a/gpxe/src/core/monojob.c b/gpxe/src/core/monojob.c
index 2c91e132..657bfd7a 100644
--- a/gpxe/src/core/monojob.c
+++ b/gpxe/src/core/monojob.c
@@ -63,7 +63,8 @@ struct job_interface monojob = {
int monojob_wait ( const char *string ) {
int key;
int rc;
- tick_t last_progress_dot;
+ unsigned long last_progress_dot;
+ unsigned long elapsed;
printf ( "%s.", string );
monojob_rc = -EINPROGRESS;
@@ -81,7 +82,8 @@ int monojob_wait ( const char *string ) {
break;
}
}
- if ( ( currticks() - last_progress_dot ) > TICKS_PER_SEC ) {
+ elapsed = ( currticks() - last_progress_dot );
+ if ( elapsed >= TICKS_PER_SEC ) {
printf ( "." );
last_progress_dot = currticks();
}
@@ -89,6 +91,7 @@ int monojob_wait ( const char *string ) {
rc = monojob_rc;
done:
+ job_done ( &monojob, rc );
if ( rc ) {
printf ( " %s\n", strerror ( rc ) );
} else {
diff --git a/gpxe/src/core/null_nap.c b/gpxe/src/core/null_nap.c
new file mode 100644
index 00000000..a3b01eb1
--- /dev/null
+++ b/gpxe/src/core/null_nap.c
@@ -0,0 +1,3 @@
+#include <gpxe/nap.h>
+
+PROVIDE_NAP_INLINE ( null, cpu_nap );
diff --git a/gpxe/src/core/nvo.c b/gpxe/src/core/nvo.c
index 13078022..e5c07d98 100644
--- a/gpxe/src/core/nvo.c
+++ b/gpxe/src/core/nvo.c
@@ -203,7 +203,7 @@ void nvo_init ( struct nvo_block *nvo, struct nvs_device *nvs,
nvo->nvs = nvs;
nvo->fragments = fragments;
settings_init ( &nvo->settings, &nvo_settings_operations, refcnt,
- "nvo" );
+ "nvo", 0 );
}
/**
diff --git a/gpxe/src/core/pc_kbd.c b/gpxe/src/core/pc_kbd.c
index d43357fe..799c8beb 100644
--- a/gpxe/src/core/pc_kbd.c
+++ b/gpxe/src/core/pc_kbd.c
@@ -10,7 +10,7 @@
* yhlu@tyan.com
*/
-#include "io.h"
+#include <gpxe/io.h>
#include "console.h"
static char key_map[][128] = {
diff --git a/gpxe/src/core/process.c b/gpxe/src/core/process.c
index cf931acf..6a687140 100644
--- a/gpxe/src/core/process.c
+++ b/gpxe/src/core/process.c
@@ -79,7 +79,9 @@ void step ( void ) {
list_for_each_entry ( process, &run_queue, list ) {
list_del ( &process->list );
list_add_tail ( &process->list, &run_queue );
+ DBGC2 ( process, "PROCESS %p executing\n", process );
process->step ( process );
+ DBGC2 ( process, "PROCESS %p finished executing\n", process );
break;
}
}
diff --git a/gpxe/src/core/serial.c b/gpxe/src/core/serial.c
index 97640f93..5b3be39c 100644
--- a/gpxe/src/core/serial.c
+++ b/gpxe/src/core/serial.c
@@ -13,7 +13,7 @@
#include "stddef.h"
#include <gpxe/init.h>
-#include "io.h"
+#include <gpxe/io.h>
#include <unistd.h>
#include <gpxe/serial.h>
#include "config/serial.h"
diff --git a/gpxe/src/core/settings.c b/gpxe/src/core/settings.c
index 3e9eb18a..f34eb664 100644
--- a/gpxe/src/core/settings.c
+++ b/gpxe/src/core/settings.c
@@ -183,12 +183,17 @@ static void reprioritise_settings ( struct settings *settings ) {
* @ret rc Return status code
*/
int register_settings ( struct settings *settings, struct settings *parent ) {
+ struct settings *old_settings;
/* NULL parent => add to settings root */
assert ( settings != NULL );
if ( parent == NULL )
parent = &settings_root;
+ /* Remove any existing settings with the same name */
+ if ( ( old_settings = find_child_settings ( parent, settings->name ) ))
+ unregister_settings ( old_settings );
+
/* Add to list of settings */
ref_get ( settings->refcnt );
ref_get ( parent->refcnt );
@@ -279,7 +284,7 @@ struct settings * find_settings ( const char *name ) {
/**
* Store value of setting
*
- * @v settings Settings block
+ * @v settings Settings block, or NULL
* @v setting Setting to store
* @v data Setting data, or NULL to clear setting
* @v len Length of setting data
@@ -289,9 +294,9 @@ int store_setting ( struct settings *settings, struct setting *setting,
const void *data, size_t len ) {
int rc;
- /* Sanity check */
+ /* NULL settings implies storing into the global settings root */
if ( ! settings )
- return -ENODEV;
+ settings = &settings_root;
/* Store setting */
if ( ( rc = settings->op->store ( settings, setting,
@@ -333,6 +338,9 @@ int fetch_setting ( struct settings *settings, struct setting *setting,
struct settings *child;
int ret;
+ /* Avoid returning uninitialised data on error */
+ memset ( data, 0, len );
+
/* NULL settings implies starting at the global settings root */
if ( ! settings )
settings = &settings_root;
@@ -387,6 +395,38 @@ int fetch_string_setting ( struct settings *settings, struct setting *setting,
}
/**
+ * Fetch value of string setting
+ *
+ * @v settings Settings block, or NULL to search all blocks
+ * @v setting Setting to fetch
+ * @v data Buffer to allocate and fill with setting string data
+ * @ret len Length of string setting, or negative error
+ *
+ * The resulting string is guaranteed to be correctly NUL-terminated.
+ * The returned length will be the length of the underlying setting
+ * data. The caller is responsible for eventually freeing the
+ * allocated buffer.
+ */
+int fetch_string_setting_copy ( struct settings *settings,
+ struct setting *setting,
+ char **data ) {
+ int len;
+ int check_len;
+
+ len = fetch_setting_len ( settings, setting );
+ if ( len < 0 )
+ return len;
+
+ *data = malloc ( len + 1 );
+ if ( ! *data )
+ return -ENOMEM;
+
+ fetch_string_setting ( settings, setting, *data, ( len + 1 ) );
+ assert ( check_len == len );
+ return len;
+}
+
+/**
* Fetch value of IPv4 address setting
*
* @v settings Settings block, or NULL to search all blocks
@@ -417,20 +457,23 @@ int fetch_ipv4_setting ( struct settings *settings, struct setting *setting,
int fetch_int_setting ( struct settings *settings, struct setting *setting,
long *value ) {
union {
- long value;
uint8_t u8[ sizeof ( long ) ];
int8_t s8[ sizeof ( long ) ];
} buf;
int len;
int i;
- buf.value = 0;
+ /* Avoid returning uninitialised data on error */
+ *value = 0;
+
+ /* Fetch raw (network-ordered, variable-length) setting */
len = fetch_setting ( settings, setting, &buf, sizeof ( buf ) );
if ( len < 0 )
return len;
if ( len > ( int ) sizeof ( buf ) )
return -ERANGE;
+ /* Convert to host-ordered signed long */
*value = ( ( buf.s8[0] >= 0 ) ? 0 : -1L );
for ( i = 0 ; i < len ; i++ ) {
*value = ( ( *value << 8 ) | buf.u8[i] );
@@ -452,10 +495,15 @@ int fetch_uint_setting ( struct settings *settings, struct setting *setting,
long svalue;
int len;
+ /* Avoid returning uninitialised data on error */
+ *value = 0;
+
+ /* Fetch as a signed long */
len = fetch_int_setting ( settings, setting, &svalue );
if ( len < 0 )
return len;
+ /* Mask off sign-extended bits */
*value = ( svalue & ( -1UL >> ( sizeof ( long ) - len ) ) );
return len;
@@ -469,7 +517,7 @@ int fetch_uint_setting ( struct settings *settings, struct setting *setting,
* @ret value Setting value, or zero
*/
long fetch_intz_setting ( struct settings *settings, struct setting *setting ){
- long value = 0;
+ long value;
fetch_int_setting ( settings, setting, &value );
return value;
@@ -484,7 +532,7 @@ long fetch_intz_setting ( struct settings *settings, struct setting *setting ){
*/
unsigned long fetch_uintz_setting ( struct settings *settings,
struct setting *setting ) {
- unsigned long value = 0;
+ unsigned long value;
fetch_uint_setting ( settings, setting, &value );
return value;
@@ -655,6 +703,7 @@ static int parse_setting_name ( const char *name, struct settings **settings,
}
tmp++;
}
+ setting->tag |= (*settings)->tag_magic;
}
/* Identify setting type, if specified */
@@ -776,12 +825,15 @@ static int storef_uristring ( struct settings *settings,
static int fetchf_uristring ( struct settings *settings,
struct setting *setting,
char *buf, size_t len ) {
- size_t raw_len;
+ ssize_t raw_len;
/* We need to always retrieve the full raw string to know the
* length of the encoded string.
*/
raw_len = fetch_setting ( settings, setting, NULL, 0 );
+ if ( raw_len < 0 )
+ return raw_len;
+
{
char raw_buf[ raw_len + 1 ];
diff --git a/gpxe/src/core/timer.c b/gpxe/src/core/timer.c
index 4e047ea7..d71e3da1 100644
--- a/gpxe/src/core/timer.c
+++ b/gpxe/src/core/timer.c
@@ -1,7 +1,5 @@
/*
- * core/timer.c
- *
- * Copyright (C) 2007 Alexey Zaytsev <alexey.zaytsev@gmail.com>
+ * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -18,96 +16,25 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <stddef.h>
-#include <assert.h>
-#include <gpxe/timer.h>
-
-static struct timer ts_table[0]
- __table_start ( struct timer, timers );
-static struct timer ts_table_end[0]
- __table_end ( struct timer, timers );
-
-/*
- * This function may be used in custom timer driver.
- *
- * This udelay implementation works well if you've got a
- * fast currticks().
- */
-void generic_currticks_udelay ( unsigned int usecs ) {
- tick_t start;
- tick_t elapsed;
-
- start = currticks();
- do {
- /* xxx: Relax the cpu some way. */
- elapsed = ( currticks() - start );
- } while ( elapsed < usecs );
-}
-
-/**
- * Identify timer source
- *
- * @ret timer Timer source
- */
-static struct timer * timer ( void ) {
- static struct timer *ts = NULL;
-
- /* If we have a timer, use it */
- if ( ts )
- return ts;
-
- /* Scan for a usable timer */
- for ( ts = ts_table ; ts < ts_table_end ; ts++ ) {
- if ( ts->init() == 0 )
- return ts;
- }
-
- /* No timer found; we cannot continue */
- assert ( 0 );
- while ( 1 ) {};
-}
-
-/**
- * Read current time
- *
- * @ret ticks Current time, in ticks
- */
-tick_t currticks ( void ) {
- tick_t ct;
-
- ct = timer()->currticks();
- DBG ( "currticks: %ld.%06ld seconds\n",
- ct / USECS_IN_SEC, ct % USECS_IN_SEC );
-
- return ct;
-}
-
-/**
- * Delay
- *
- * @v usecs Time to delay, in microseconds
- */
-void udelay ( unsigned int usecs ) {
- timer()->udelay ( usecs );
-}
+#include <unistd.h>
/**
- * Delay
+ * Delay for a fixed number of milliseconds
*
- * @v msecs Time to delay, in milliseconds
+ * @v msecs Number of milliseconds for which to delay
*/
-void mdelay ( unsigned int msecs ) {
+void mdelay ( unsigned long msecs ) {
while ( msecs-- )
- udelay ( USECS_IN_MSEC );
+ udelay ( 1000 );
}
/**
- * Delay
+ * Delay for a fixed number of seconds
*
- * @v secs Time to delay, in seconds
+ * @v secs Number of seconds for which to delay
*/
unsigned int sleep ( unsigned int secs ) {
while ( secs-- )
- mdelay ( MSECS_IN_SEC );
+ mdelay ( 1000 );
return 0;
}
diff --git a/gpxe/src/core/uri.c b/gpxe/src/core/uri.c
index cf2b071d..7bb46da0 100644
--- a/gpxe/src/core/uri.c
+++ b/gpxe/src/core/uri.c
@@ -92,8 +92,12 @@ struct uri * parse_uri ( const char *uri_string ) {
uri->fragment = tmp;
}
- /* Identify absolute/relative URI */
- if ( ( tmp = strchr ( raw, ':' ) ) ) {
+ /* Identify absolute/relative URI. We ignore schemes that are
+ * apparently only a single character long, since otherwise we
+ * misinterpret a DOS-style path name ("C:\path\to\file") as a
+ * URI with scheme="C",opaque="\path\to\file".
+ */
+ if ( ( tmp = strchr ( raw, ':' ) ) && ( tmp > ( raw + 1 ) ) ) {
/* Absolute URI: identify hierarchical/opaque */
uri->scheme = raw;
*(tmp++) = '\0';
diff --git a/gpxe/src/core/uuid.c b/gpxe/src/core/uuid.c
index c6e7f5d5..a3a82c68 100644
--- a/gpxe/src/core/uuid.c
+++ b/gpxe/src/core/uuid.c
@@ -36,7 +36,7 @@
char * uuid_ntoa ( union uuid *uuid ) {
static char buf[37]; /* "00000000-0000-0000-0000-000000000000" */
- sprintf ( buf, "%08lx-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
+ sprintf ( buf, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
be32_to_cpu ( uuid->canonical.a ),
be16_to_cpu ( uuid->canonical.b ),
be16_to_cpu ( uuid->canonical.c ),
diff --git a/gpxe/src/core/xfer.c b/gpxe/src/core/xfer.c
index 14c77d64..9ed19da2 100644
--- a/gpxe/src/core/xfer.c
+++ b/gpxe/src/core/xfer.c
@@ -28,6 +28,14 @@
*/
/**
+ * Dummy transfer metadata
+ *
+ * This gets passed to xfer_interface::deliver_iob() and equivalents
+ * when no metadata is available.
+ */
+static struct xfer_metadata dummy_metadata;
+
+/**
* Close data transfer interface
*
* @v xfer Data transfer interface
@@ -159,7 +167,6 @@ int xfer_deliver_iob_meta ( struct xfer_interface *xfer,
*/
int xfer_deliver_iob ( struct xfer_interface *xfer,
struct io_buffer *iobuf ) {
- static struct xfer_metadata dummy_metadata;
return xfer_deliver_iob_meta ( xfer, iobuf, &dummy_metadata );
}
@@ -366,7 +373,7 @@ int xfer_deliver_as_iob ( struct xfer_interface *xfer,
return -ENOMEM;
memcpy ( iob_put ( iobuf, len ), data, len );
- return xfer->op->deliver_iob ( xfer, iobuf, NULL );
+ return xfer->op->deliver_iob ( xfer, iobuf, &dummy_metadata );
}
/**
diff --git a/gpxe/src/crypto/asn1.c b/gpxe/src/crypto/asn1.c
index 0a69162a..25e7495b 100644
--- a/gpxe/src/crypto/asn1.c
+++ b/gpxe/src/crypto/asn1.c
@@ -32,7 +32,7 @@
*
* @v cursor ASN.1 object cursor
* @v type Expected type
- * @ret len Length of object body, or -1 on error
+ * @ret len Length of object body, or negative error
*
* The object cursor will be updated to point to the start of the
* object body (i.e. the first byte following the length byte(s)), and
@@ -44,29 +44,32 @@
* the cursor will be invalidated and a negative value will be
* returned.
*/
-static int asn1_start_object ( struct asn1_cursor *cursor,
+static int asn1_start ( struct asn1_cursor *cursor,
unsigned int type ) {
unsigned int len_len;
unsigned int len;
+ int rc;
/* Sanity check */
if ( cursor->len < 2 /* Tag byte and first length byte */ ) {
if ( cursor->len )
DBGC ( cursor, "ASN1 %p too short\n", cursor );
+ rc = -EINVAL;
goto notfound;
}
/* Check the tag byte */
- if ( cursor->data[0] != type ) {
+ if ( *( ( uint8_t * ) cursor->data ) != type ) {
DBGC ( cursor, "ASN1 %p type mismatch (expected %d, got %d)\n",
- cursor, type, cursor->data[0] );
+ cursor, type, *( ( uint8_t * ) cursor->data ) );
+ rc = -ENXIO;
goto notfound;
}
cursor->data++;
cursor->len--;
/* Extract length of the length field and sanity check */
- len_len = cursor->data[0];
+ len_len = *( ( uint8_t * ) cursor->data );
if ( len_len & 0x80 ) {
len_len = ( len_len & 0x7f );
cursor->data++;
@@ -77,19 +80,21 @@ static int asn1_start_object ( struct asn1_cursor *cursor,
if ( cursor->len < len_len ) {
DBGC ( cursor, "ASN1 %p bad length field length %d (max "
"%zd)\n", cursor, len_len, cursor->len );
+ rc = -EINVAL;
goto notfound;
}
/* Extract the length and sanity check */
for ( len = 0 ; len_len ; len_len-- ) {
len <<= 8;
- len |= cursor->data[0];
+ len |= *( ( uint8_t * ) cursor->data );
cursor->data++;
cursor->len--;
}
if ( cursor->len < len ) {
DBGC ( cursor, "ASN1 %p bad length %d (max %zd)\n",
cursor, len, cursor->len );
+ rc = -EINVAL;
goto notfound;
}
@@ -98,7 +103,7 @@ static int asn1_start_object ( struct asn1_cursor *cursor,
notfound:
cursor->data = NULL;
cursor->len = 0;
- return -1;
+ return rc;
}
/**
@@ -112,12 +117,12 @@ static int asn1_start_object ( struct asn1_cursor *cursor,
* current ASN.1 object. If any error occurs, the object cursor will
* be invalidated.
*/
-int asn1_enter_object ( struct asn1_cursor *cursor, unsigned int type ) {
+int asn1_enter ( struct asn1_cursor *cursor, unsigned int type ) {
int len;
- len = asn1_start_object ( cursor, type );
+ len = asn1_start ( cursor, type );
if ( len < 0 )
- return -ENOENT;
+ return len;
cursor->len = len;
DBGC ( cursor, "ASN1 %p entered object type %02x (len %x)\n",
@@ -137,12 +142,12 @@ int asn1_enter_object ( struct asn1_cursor *cursor, unsigned int type ) {
* object. If any error occurs, the object cursor will be
* invalidated.
*/
-int asn1_skip_object ( struct asn1_cursor *cursor, unsigned int type ) {
+int asn1_skip ( struct asn1_cursor *cursor, unsigned int type ) {
int len;
- len = asn1_start_object ( cursor, type );
+ len = asn1_start ( cursor, type );
if ( len < 0 )
- return -ENOENT;
+ return len;
cursor->data += len;
cursor->len -= len;
diff --git a/gpxe/src/crypto/axtls/axtls_asn1.c b/gpxe/src/crypto/axtls/axtls_asn1.c
deleted file mode 100644
index 74411c70..00000000
--- a/gpxe/src/crypto/axtls/axtls_asn1.c
+++ /dev/null
@@ -1,867 +0,0 @@
-/*
- * Copyright(C) 2006 Cameron Rich
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/**
- * @file asn1.c
- *
- * Some primitive asn methods for extraction rsa modulus information. It also
- * is used for retrieving information from X.509 certificates.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include "crypto.h"
-
-#define SIG_OID_PREFIX_SIZE 8
-
-#define SIG_TYPE_MD2 0x02
-#define SIG_TYPE_MD5 0x04
-#define SIG_TYPE_SHA1 0x05
-
-/* Must be an RSA algorithm with either SHA1 or MD5 for verifying to work */
-static const uint8_t sig_oid_prefix[SIG_OID_PREFIX_SIZE] =
-{
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01
-};
-
-/* CN, O, OU */
-static const uint8_t g_dn_types[] = { 3, 10, 11 };
-
-static int get_asn1_length(const uint8_t *buf, int *offset)
-{
- int len, i;
-
- if (!(buf[*offset] & 0x80)) /* short form */
- {
- len = buf[(*offset)++];
- }
- else /* long form */
- {
- int length_bytes = buf[(*offset)++]&0x7f;
- len = 0;
- for (i = 0; i < length_bytes; i++)
- {
- len <<= 8;
- len += buf[(*offset)++];
- }
- }
-
- return len;
-}
-
-/**
- * Skip the ASN1.1 object type and its length. Get ready to read the object's
- * data.
- */
-int asn1_next_obj(const uint8_t *buf, int *offset, int obj_type)
-{
- if (buf[*offset] != obj_type)
- return X509_NOT_OK;
- (*offset)++;
- return get_asn1_length(buf, offset);
-}
-
-/**
- * Skip over an ASN.1 object type completely. Get ready to read the next
- * object.
- */
-int asn1_skip_obj(const uint8_t *buf, int *offset, int obj_type)
-{
- int len;
-
- if (buf[*offset] != obj_type)
- return X509_NOT_OK;
- (*offset)++;
- len = get_asn1_length(buf, offset);
- *offset += len;
- return 0;
-}
-
-/**
- * Read an integer value for ASN.1 data
- * Note: This function allocates memory which must be freed by the user.
- */
-int asn1_get_int(const uint8_t *buf, int *offset, uint8_t **object)
-{
- int len;
-
- if ((len = asn1_next_obj(buf, offset, ASN1_INTEGER)) < 0)
- goto end_int_array;
-
- *object = (uint8_t *)malloc(len);
- memcpy(*object, &buf[*offset], len);
- *offset += len;
-
-end_int_array:
- return len;
-}
-
-#if 0
-
-/**
- * Get all the RSA private key specifics from an ASN.1 encoded file
- */
-int asn1_get_private_key(const uint8_t *buf, int len, RSA_CTX **rsa_ctx)
-{
- int offset = 7;
- uint8_t *modulus, *priv_exp, *pub_exp;
- int mod_len, priv_len, pub_len;
-#ifdef CONFIG_BIGINT_CRT
- uint8_t *p, *q, *dP, *dQ, *qInv;
- int p_len, q_len, dP_len, dQ_len, qInv_len;
-#endif
-
- /* not in der format */
- if (buf[0] != ASN1_SEQUENCE) /* basic sanity check */
- {
-#ifdef CONFIG_SSL_FULL_MODE
- printf("Error: This is not a valid ASN.1 file\n");
-#endif
- return X509_INVALID_PRIV_KEY;
- }
-
- /* initialise the RNG */
- RNG_initialize(buf, len);
-
- mod_len = asn1_get_int(buf, &offset, &modulus);
- pub_len = asn1_get_int(buf, &offset, &pub_exp);
- priv_len = asn1_get_int(buf, &offset, &priv_exp);
-
- if (mod_len <= 0 || pub_len <= 0 || priv_len <= 0)
- return X509_INVALID_PRIV_KEY;
-
-#ifdef CONFIG_BIGINT_CRT
- p_len = asn1_get_int(buf, &offset, &p);
- q_len = asn1_get_int(buf, &offset, &q);
- dP_len = asn1_get_int(buf, &offset, &dP);
- dQ_len = asn1_get_int(buf, &offset, &dQ);
- qInv_len = asn1_get_int(buf, &offset, &qInv);
-
- if (p_len <= 0 || q_len <= 0 || dP_len <= 0 || dQ_len <= 0 || qInv_len <= 0)
- return X509_INVALID_PRIV_KEY;
-
- RSA_priv_key_new(rsa_ctx,
- modulus, mod_len, pub_exp, pub_len, priv_exp, priv_len,
- p, p_len, q, p_len, dP, dP_len, dQ, dQ_len, qInv, qInv_len);
-
- free(p);
- free(q);
- free(dP);
- free(dQ);
- free(qInv);
-#else
- RSA_priv_key_new(rsa_ctx,
- modulus, mod_len, pub_exp, pub_len, priv_exp, priv_len);
-#endif
-
- free(modulus);
- free(priv_exp);
- free(pub_exp);
- return X509_OK;
-}
-
-/**
- * Get the time of a certificate. Ignore hours/minutes/seconds.
- */
-static int asn1_get_utc_time(const uint8_t *buf, int *offset, time_t *t)
-{
- int ret = X509_NOT_OK, len, t_offset;
- struct tm tm;
-
- if (buf[(*offset)++] != ASN1_UTC_TIME)
- goto end_utc_time;
- len = get_asn1_length(buf, offset);
- t_offset = *offset;
-
- memset(&tm, 0, sizeof(struct tm));
- tm.tm_year = (buf[t_offset] - '0')*10 + (buf[t_offset+1] - '0');
-
- if (tm.tm_year <= 50) /* 1951-2050 thing */
- {
- tm.tm_year += 100;
- }
-
- tm.tm_mon = (buf[t_offset+2] - '0')*10 + (buf[t_offset+3] - '0') - 1;
- tm.tm_mday = (buf[t_offset+4] - '0')*10 + (buf[t_offset+5] - '0');
- *t = mktime(&tm);
- *offset += len;
- ret = X509_OK;
-
-end_utc_time:
- return ret;
-}
-
-/**
- * Get the version type of a certificate (which we don't actually care about)
- */
-static int asn1_version(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)
-{
- int ret = X509_NOT_OK;
-
- (*offset) += 2; /* get past explicit tag */
- if (asn1_skip_obj(cert, offset, ASN1_INTEGER))
- goto end_version;
-
- ret = X509_OK;
-end_version:
- return ret;
-}
-
-/**
- * Retrieve the notbefore and notafter certificate times.
- */
-static int asn1_validity(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)
-{
- return (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 ||
- asn1_get_utc_time(cert, offset, &x509_ctx->not_before) ||
- asn1_get_utc_time(cert, offset, &x509_ctx->not_after));
-}
-
-/**
- * Get the components of a distinguished name
- */
-static int asn1_get_oid_x520(const uint8_t *buf, int *offset)
-{
- int dn_type = 0;
- int len;
-
- if ((len = asn1_next_obj(buf, offset, ASN1_OID)) < 0)
- goto end_oid;
-
- /* expect a sequence of 2.5.4.[x] where x is a one of distinguished name
- components we are interested in. */
- if (len == 3 && buf[(*offset)++] == 0x55 && buf[(*offset)++] == 0x04)
- dn_type = buf[(*offset)++];
- else
- {
- *offset += len; /* skip over it */
- }
-
-end_oid:
- return dn_type;
-}
-
-/**
- * Obtain an ASN.1 printable string type.
- */
-static int asn1_get_printable_str(const uint8_t *buf, int *offset, char **str)
-{
- int len = X509_NOT_OK;
-
- /* some certs have this awful crud in them for some reason */
- if (buf[*offset] != ASN1_PRINTABLE_STR &&
- buf[*offset] != ASN1_TELETEX_STR && buf[*offset] != ASN1_IA5_STR)
- goto end_pnt_str;
-
- (*offset)++;
- len = get_asn1_length(buf, offset);
- *str = (char *)malloc(len+1); /* allow for null */
- memcpy(*str, &buf[*offset], len);
- (*str)[len] = 0; /* null terminate */
- *offset += len;
-end_pnt_str:
- return len;
-}
-
-/**
- * Get the subject name (or the issuer) of a certificate.
- */
-static int asn1_name(const uint8_t *cert, int *offset, char *dn[])
-{
- int ret = X509_NOT_OK;
- int dn_type;
- char *tmp = NULL;
-
- if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0)
- goto end_name;
-
- while (asn1_next_obj(cert, offset, ASN1_SET) >= 0)
- {
- int i, found = 0;
-
- if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 ||
- (dn_type = asn1_get_oid_x520(cert, offset)) < 0)
- goto end_name;
-
- if (asn1_get_printable_str(cert, offset, &tmp) < 0)
- {
- free(tmp);
- goto end_name;
- }
-
- /* find the distinguished named type */
- for (i = 0; i < X509_NUM_DN_TYPES; i++)
- {
- if (dn_type == g_dn_types[i])
- {
- if (dn[i] == NULL)
- {
- dn[i] = tmp;
- found = 1;
- break;
- }
- }
- }
-
- if (found == 0) /* not found so get rid of it */
- {
- free(tmp);
- }
- }
-
- ret = X509_OK;
-end_name:
- return ret;
-}
-
-/**
- * Read the modulus and public exponent of a certificate.
- */
-static int asn1_public_key(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)
-{
- int ret = X509_NOT_OK, mod_len, pub_len;
- uint8_t *modulus, *pub_exp;
-
- if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 ||
- asn1_skip_obj(cert, offset, ASN1_SEQUENCE) ||
- asn1_next_obj(cert, offset, ASN1_BIT_STRING) < 0)
- goto end_pub_key;
-
- (*offset)++;
-
- if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0)
- goto end_pub_key;
-
- mod_len = asn1_get_int(cert, offset, &modulus);
- pub_len = asn1_get_int(cert, offset, &pub_exp);
-
- RSA_pub_key_new(&x509_ctx->rsa_ctx, modulus, mod_len, pub_exp, pub_len);
-
- free(modulus);
- free(pub_exp);
- ret = X509_OK;
-
-end_pub_key:
- return ret;
-}
-
-#ifdef CONFIG_SSL_CERT_VERIFICATION
-/**
- * Read the signature of the certificate.
- */
-static int asn1_signature(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)
-{
- int ret = X509_NOT_OK;
-
- if (cert[(*offset)++] != ASN1_BIT_STRING)
- goto end_sig;
-
- x509_ctx->sig_len = get_asn1_length(cert, offset);
- x509_ctx->signature = (uint8_t *)malloc(x509_ctx->sig_len);
- memcpy(x509_ctx->signature, &cert[*offset], x509_ctx->sig_len);
- *offset += x509_ctx->sig_len;
- ret = X509_OK;
-
-end_sig:
- return ret;
-}
-
-/*
- * Compare 2 distinguished name components for equality
- * @return 0 if a match
- */
-static int asn1_compare_dn_comp(const char *dn1, const char *dn2)
-{
- int ret = 1;
-
- if ((dn1 && dn2 == NULL) || (dn1 == NULL && dn2)) goto err_no_match;
-
- ret = (dn1 && dn2) ? strcmp(dn1, dn2) : 0;
-
-err_no_match:
- return ret;
-}
-
-/**
- * Clean up all of the CA certificates.
- */
-void remove_ca_certs(CA_CERT_CTX *ca_cert_ctx)
-{
- int i = 0;
-
- while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i])
- {
- x509_free(ca_cert_ctx->cert[i]);
- ca_cert_ctx->cert[i++] = NULL;
- }
-
- free(ca_cert_ctx);
-}
-
-/*
- * Compare 2 distinguished names for equality
- * @return 0 if a match
- */
-static int asn1_compare_dn(char * const dn1[], char * const dn2[])
-{
- int i;
-
- for (i = 0; i < X509_NUM_DN_TYPES; i++)
- {
- if (asn1_compare_dn_comp(dn1[i], dn2[i]))
- {
- return 1;
- }
- }
-
- return 0; /* all good */
-}
-
-/**
- * Retrieve the signature from a certificate.
- */
-const uint8_t *x509_get_signature(const uint8_t *asn1_sig, int *len)
-{
- int offset = 0;
- const uint8_t *ptr = NULL;
-
- if (asn1_next_obj(asn1_sig, &offset, ASN1_SEQUENCE) < 0 ||
- asn1_skip_obj(asn1_sig, &offset, ASN1_SEQUENCE))
- goto end_get_sig;
-
- if (asn1_sig[offset++] != ASN1_OCTET_STRING)
- goto end_get_sig;
- *len = get_asn1_length(asn1_sig, &offset);
- ptr = &asn1_sig[offset]; /* all ok */
-
-end_get_sig:
- return ptr;
-}
-
-#endif
-
-/**
- * Read the signature type of the certificate. We only support RSA-MD5 and
- * RSA-SHA1 signature types.
- */
-static int asn1_signature_type(const uint8_t *cert,
- int *offset, X509_CTX *x509_ctx)
-{
- int ret = X509_NOT_OK, len;
-
- if (cert[(*offset)++] != ASN1_OID)
- goto end_check_sig;
-
- len = get_asn1_length(cert, offset);
-
- if (memcmp(sig_oid_prefix, &cert[*offset], SIG_OID_PREFIX_SIZE))
- goto end_check_sig; /* unrecognised cert type */
-
- x509_ctx->sig_type = cert[*offset + SIG_OID_PREFIX_SIZE];
-
- *offset += len;
- if (asn1_skip_obj(cert, offset, ASN1_NULL))
- goto end_check_sig;
- ret = X509_OK;
-
-end_check_sig:
- return ret;
-}
-
-/**
- * Construct a new x509 object.
- * @return 0 if ok. < 0 if there was a problem.
- */
-int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx)
-{
- int begin_tbs, end_tbs;
- int ret = X509_NOT_OK, offset = 0, cert_size = 0;
- X509_CTX *x509_ctx;
- BI_CTX *bi_ctx;
-
- *ctx = (X509_CTX *)calloc(1, sizeof(X509_CTX));
- x509_ctx = *ctx;
-
- /* get the certificate size */
- asn1_skip_obj(cert, &cert_size, ASN1_SEQUENCE);
-
- if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
- goto end_cert;
-
- begin_tbs = offset; /* start of the tbs */
- end_tbs = begin_tbs; /* work out the end of the tbs */
- asn1_skip_obj(cert, &end_tbs, ASN1_SEQUENCE);
-
- if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
- goto end_cert;
-
- if (cert[offset] == ASN1_EXPLICIT_TAG) /* optional version */
- {
- if (asn1_version(cert, &offset, x509_ctx))
- goto end_cert;
- }
-
- if (asn1_skip_obj(cert, &offset, ASN1_INTEGER) || /* serial number */
- asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
- goto end_cert;
-
- /* make sure the signature is ok */
- if (asn1_signature_type(cert, &offset, x509_ctx))
- {
- ret = X509_VFY_ERROR_UNSUPPORTED_DIGEST;
- goto end_cert;
- }
-
- if (asn1_name(cert, &offset, x509_ctx->ca_cert_dn) ||
- asn1_validity(cert, &offset, x509_ctx) ||
- asn1_name(cert, &offset, x509_ctx->cert_dn) ||
- asn1_public_key(cert, &offset, x509_ctx))
- goto end_cert;
-
- bi_ctx = x509_ctx->rsa_ctx->bi_ctx;
-
-#ifdef CONFIG_SSL_CERT_VERIFICATION /* only care if doing verification */
- /* use the appropriate signature algorithm (either SHA1 or MD5) */
- if (x509_ctx->sig_type == SIG_TYPE_MD5)
- {
- MD5_CTX md5_ctx;
- uint8_t md5_dgst[MD5_SIZE];
- MD5Init(&md5_ctx);
- MD5Update(&md5_ctx, &cert[begin_tbs], end_tbs-begin_tbs);
- MD5Final(&md5_ctx, md5_dgst);
- x509_ctx->digest = bi_import(bi_ctx, md5_dgst, MD5_SIZE);
- }
- else if (x509_ctx->sig_type == SIG_TYPE_SHA1)
- {
- SHA1_CTX sha_ctx;
- uint8_t sha_dgst[SHA1_SIZE];
- SHA1Init(&sha_ctx);
- SHA1Update(&sha_ctx, &cert[begin_tbs], end_tbs-begin_tbs);
- SHA1Final(&sha_ctx, sha_dgst);
- x509_ctx->digest = bi_import(bi_ctx, sha_dgst, SHA1_SIZE);
- }
-
- offset = end_tbs; /* skip the v3 data */
- if (asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) ||
- asn1_signature(cert, &offset, x509_ctx))
- goto end_cert;
-#endif
-
- if (len)
- {
- *len = cert_size;
- }
-
- ret = X509_OK;
-end_cert:
-
-#ifdef CONFIG_SSL_FULL_MODE
- if (ret)
- {
- printf("Error: Invalid X509 ASN.1 file\n");
- }
-#endif
-
- return ret;
-}
-
-/**
- * Free an X.509 object's resources.
- */
-void x509_free(X509_CTX *x509_ctx)
-{
- X509_CTX *next;
- int i;
-
- if (x509_ctx == NULL) /* if already null, then don't bother */
- return;
-
- for (i = 0; i < X509_NUM_DN_TYPES; i++)
- {
- free(x509_ctx->ca_cert_dn[i]);
- free(x509_ctx->cert_dn[i]);
- }
-
- free(x509_ctx->signature);
-
-#ifdef CONFIG_SSL_CERT_VERIFICATION
- if (x509_ctx->digest)
- {
- bi_free(x509_ctx->rsa_ctx->bi_ctx, x509_ctx->digest);
- }
-#endif
-
- RSA_free(x509_ctx->rsa_ctx);
-
- next = x509_ctx->next;
- free(x509_ctx);
- x509_free(next); /* clear the chain */
-}
-
-#ifdef CONFIG_SSL_CERT_VERIFICATION
-/**
- * Do some basic checks on the certificate chain.
- *
- * Certificate verification consists of a number of checks:
- * - A root certificate exists in the certificate store.
- * - The date of the certificate is after the start date.
- * - The date of the certificate is before the finish date.
- * - The certificate chain is valid.
- * - That the certificate(s) are not self-signed.
- * - The signature of the certificate is valid.
- */
-int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert)
-{
- int ret = X509_OK, i = 0;
- bigint *cert_sig;
- X509_CTX *next_cert = NULL;
- BI_CTX *ctx;
- bigint *mod, *expn;
- struct timeval tv;
- int match_ca_cert = 0;
-
- if (cert == NULL || ca_cert_ctx == NULL)
- {
- ret = X509_VFY_ERROR_NO_TRUSTED_CERT;
- goto end_verify;
- }
-
- /* last cert in the chain - look for a trusted cert */
- if (cert->next == NULL)
- {
- while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i])
- {
- if (asn1_compare_dn(cert->ca_cert_dn,
- ca_cert_ctx->cert[i]->cert_dn) == 0)
- {
- match_ca_cert = 1;
- break;
- }
-
- i++;
- }
-
- if (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i])
- {
- next_cert = ca_cert_ctx->cert[i];
- }
- else /* trusted cert not found */
- {
- ret = X509_VFY_ERROR_NO_TRUSTED_CERT;
- goto end_verify;
- }
- }
- else
- {
- next_cert = cert->next;
- }
-
- gettimeofday(&tv, NULL);
-
- /* check the not before date */
- if (tv.tv_sec < cert->not_before)
- {
- ret = X509_VFY_ERROR_NOT_YET_VALID;
- goto end_verify;
- }
-
- /* check the not after date */
- if (tv.tv_sec > cert->not_after)
- {
- ret = X509_VFY_ERROR_EXPIRED;
- goto end_verify;
- }
-
- /* check the chain integrity */
- if (asn1_compare_dn(cert->ca_cert_dn, next_cert->cert_dn))
- {
- ret = X509_VFY_ERROR_INVALID_CHAIN;
- goto end_verify;
- }
-
- /* check for self-signing */
- if (!match_ca_cert && asn1_compare_dn(cert->ca_cert_dn, cert->cert_dn) == 0)
- {
- ret = X509_VFY_ERROR_SELF_SIGNED;
- goto end_verify;
- }
-
- /* check the signature */
- ctx = cert->rsa_ctx->bi_ctx;
- mod = next_cert->rsa_ctx->m;
- expn = next_cert->rsa_ctx->e;
- cert_sig = RSA_sign_verify(ctx, cert->signature, cert->sig_len,
- bi_clone(ctx, mod), bi_clone(ctx, expn));
-
- if (cert_sig)
- {
- ret = cert->digest ? /* check the signature */
- bi_compare(cert_sig, cert->digest) :
- X509_VFY_ERROR_UNSUPPORTED_DIGEST;
- bi_free(ctx, cert_sig);
-
- if (ret)
- goto end_verify;
- }
- else
- {
- ret = X509_VFY_ERROR_BAD_SIGNATURE;
- goto end_verify;
- }
-
- /* go down the certificate chain using recursion. */
- if (ret == 0 && cert->next)
- {
- ret = x509_verify(ca_cert_ctx, next_cert);
- }
-
-end_verify:
- return ret;
-}
-#endif
-
-#if defined (CONFIG_SSL_FULL_MODE)
-/**
- * Used for diagnostics.
- */
-void x509_print(CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert)
-{
- if (cert == NULL)
- return;
-
- printf("---------------- CERT DEBUG ----------------\n");
- printf("* CA Cert Distinguished Name\n");
- if (cert->ca_cert_dn[X509_COMMON_NAME])
- {
- printf("Common Name (CN):\t%s\n", cert->ca_cert_dn[X509_COMMON_NAME]);
- }
-
- if (cert->ca_cert_dn[X509_ORGANIZATION])
- {
- printf("Organization (O):\t%s\n", cert->ca_cert_dn[X509_ORGANIZATION]);
- }
-
- if (cert->ca_cert_dn[X509_ORGANIZATIONAL_TYPE])
- {
- printf("Organizational Unit (OU): %s\n",
- cert->ca_cert_dn[X509_ORGANIZATIONAL_TYPE]);
- }
-
- printf("* Cert Distinguished Name\n");
- if (cert->cert_dn[X509_COMMON_NAME])
- {
- printf("Common Name (CN):\t%s\n", cert->cert_dn[X509_COMMON_NAME]);
- }
-
- if (cert->cert_dn[X509_ORGANIZATION])
- {
- printf("Organization (O):\t%s\n", cert->cert_dn[X509_ORGANIZATION]);
- }
-
- if (cert->cert_dn[X509_ORGANIZATIONAL_TYPE])
- {
- printf("Organizational Unit (OU): %s\n",
- cert->cert_dn[X509_ORGANIZATIONAL_TYPE]);
- }
-
- printf("Not Before:\t\t%s", ctime(&cert->not_before));
- printf("Not After:\t\t%s", ctime(&cert->not_after));
- printf("RSA bitsize:\t\t%d\n", cert->rsa_ctx->num_octets*8);
- printf("Sig Type:\t\t");
- switch (cert->sig_type)
- {
- case SIG_TYPE_MD5:
- printf("MD5\n");
- break;
- case SIG_TYPE_SHA1:
- printf("SHA1\n");
- break;
- case SIG_TYPE_MD2:
- printf("MD2\n");
- break;
- default:
- printf("Unrecognized: %d\n", cert->sig_type);
- break;
- }
-
- printf("Verify:\t\t\t");
-
- if (ca_cert_ctx)
- {
- x509_display_error(x509_verify(ca_cert_ctx, cert));
- }
-
- printf("\n");
-#if 0
- print_blob("Signature", cert->signature, cert->sig_len);
- bi_print("Modulus", cert->rsa_ctx->m);
- bi_print("Pub Exp", cert->rsa_ctx->e);
-#endif
-
- if (ca_cert_ctx)
- {
- x509_print(ca_cert_ctx, cert->next);
- }
-}
-
-void x509_display_error(int error)
-{
- switch (error)
- {
- case X509_NOT_OK:
- printf("X509 not ok");
- break;
-
- case X509_VFY_ERROR_NO_TRUSTED_CERT:
- printf("No trusted cert is available");
- break;
-
- case X509_VFY_ERROR_BAD_SIGNATURE:
- printf("Bad signature");
- break;
-
- case X509_VFY_ERROR_NOT_YET_VALID:
- printf("Cert is not yet valid");
- break;
-
- case X509_VFY_ERROR_EXPIRED:
- printf("Cert has expired");
- break;
-
- case X509_VFY_ERROR_SELF_SIGNED:
- printf("Cert is self-signed");
- break;
-
- case X509_VFY_ERROR_INVALID_CHAIN:
- printf("Chain is invalid (check order of certs)");
- break;
-
- case X509_VFY_ERROR_UNSUPPORTED_DIGEST:
- printf("Unsupported digest");
- break;
-
- case X509_INVALID_PRIV_KEY:
- printf("Invalid private key");
- break;
- }
-}
-#endif /* CONFIG_SSL_FULL_MODE */
-
-#endif
diff --git a/gpxe/src/crypto/cryptoLayer.h b/gpxe/src/crypto/cryptoLayer.h
deleted file mode 100644
index 28ce97bc..00000000
--- a/gpxe/src/crypto/cryptoLayer.h
+++ /dev/null
@@ -1,120 +0,0 @@
-#ifndef _MATRIXSSL_CRYPTOLAYER_H
-#define _MATRIXSSL_CRYPTOLAYER_H
-
-/** @file
- *
- * Compatibility layer for MatrixSSL
- *
- */
-
-#include <stdint.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <assert.h>
-#include <byteswap.h>
-#include <gpxe/bitops.h>
-#include <gpxe/crypto.h>
-
-/* Drag in pscrypto.h */
-typedef uint64_t ulong64;
-typedef void psPool_t;
-#define SMALL_CODE
-#define USE_INT64
-#define USE_RSA
-#define USE_RSA_PUBLIC_ENCRYPT
-#define CRYPT
-#include "matrixssl/pscrypto.h"
-#define SMALL_CODE
-#undef CLEAN_STACK
-
-#define sslAssert( ... ) assert ( __VA_ARGS__ )
-
-static inline __attribute__ (( always_inline )) void * __malloc
-psMalloc ( psPool_t *pool __unused, size_t len ) {
- return malloc ( len );
-}
-
-static inline __attribute__ (( always_inline )) void *
-psRealloc ( void *ptr, size_t len ) {
- return realloc ( ptr, len );
-}
-
-static inline __attribute__ (( always_inline )) void psFree ( void *ptr ) {
- free ( ptr );
-}
-
-#define matrixStrDebugMsg( ... ) DBG ( __VA_ARGS__ )
-#define matrixIntDebugMsg( ... ) DBG ( __VA_ARGS__ )
-
-/* Use our standard cpu_to_leXX etc. macros */
-
-#undef LOAD32L
-#define LOAD32L( cpu32, ptr ) do { \
- uint32_t *le32 = ( ( uint32_t * ) ptr ); \
- cpu32 = le32_to_cpu ( *le32 ); \
- } while ( 0 )
-
-#undef LOAD32H
-#define LOAD32H( cpu32, ptr ) do { \
- uint32_t *be32 = ( ( uint32_t * ) ptr ); \
- cpu32 = be32_to_cpu ( *be32 ); \
- } while ( 0 )
-
-#undef LOAD64L
-#define LOAD64L( cpu64, ptr ) do { \
- uint64_t *le64 = ( ( uint64_t * ) ptr ); \
- cpu64 = le64_to_cpu ( *le64 ); \
- } while ( 0 )
-
-#undef LOAD64H
-#define LOAD64H( cpu64, ptr ) do { \
- uint64_t *be64 = ( ( uint64_t * ) ptr ); \
- cpu64 = be64_to_cpu ( *be64 ); \
- } while ( 0 )
-
-#undef STORE32L
-#define STORE32L( cpu32, ptr ) do { \
- uint32_t *le32 = ( ( uint32_t * ) ptr ); \
- *le32 = cpu_to_le32 ( cpu32 ); \
- } while ( 0 )
-
-#undef STORE32H
-#define STORE32H( cpu32, ptr ) do { \
- uint32_t *be32 = ( ( uint32_t * ) ptr ); \
- *be32 = cpu_to_be32 ( cpu32 ); \
- } while ( 0 )
-
-#undef STORE64L
-#define STORE64L( cpu64, ptr ) do { \
- uint64_t *le64 = ( ( uint64_t * ) ptr ); \
- *le64 = cpu_to_le64 ( cpu64 ); \
- } while ( 0 )
-
-#undef STORE64H
-#define STORE64H( cpu64, ptr ) do { \
- uint64_t *be64 = ( ( uint64_t * ) ptr ); \
- *be64 = cpu_to_be64 ( cpu64 ); \
- } while ( 0 )
-
-/* Use rolXX etc. from bitops.h */
-
-#undef ROL
-#define ROL( data, rotation ) rol32 ( (data), (rotation) )
-#undef ROLc
-#define ROLc( data, rotation ) rol32 ( (data), (rotation) )
-#undef ROR
-#define ROR( data, rotation ) ror32 ( (data), (rotation) )
-#undef RORc
-#define RORc( data, rotation ) ror32 ( (data), (rotation) )
-#undef ROL64
-#define ROL64( data, rotation ) rol64 ( (data), (rotation) )
-#undef ROL64c
-#define ROL64c( data, rotation ) rol64 ( (data), (rotation) )
-#undef ROR64
-#define ROR64( data, rotation ) ror64 ( (data), (rotation) )
-#undef ROR64c
-#define ROR64c( data, rotation ) ror64 ( (data), (rotation) )
-
-#endif /* _MATRIXSSL_CRYPTOLAYER_H */
diff --git a/gpxe/src/crypto/framework.c b/gpxe/src/crypto/framework.c
deleted file mode 100644
index 0da2cbe3..00000000
--- a/gpxe/src/crypto/framework.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/* mcb - this file breaks the build process; temporarily deactivating */
-#if 0
-
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#include "ssl.h"
-
-int main(int argc, char *argv[])
-{
- SSL_t ssl;
- int sockfd, portno, rc;
- struct sockaddr_in serv_addr;
- struct hostent *server;
-
- portno = 443;
- sockfd = socket(AF_INET,SOCK_STREAM,0);
- if(sockfd<0){
- fprintf(stderr,"Error creating socket\n");
- exit(sockfd);
- }
-
- server = gethostbyname(argv[1]);
- if(server==NULL){
- fprintf(stderr,"Error looking up host %s\n",argv[1]);
- exit(1);
- }
-
- /**
- *matrixSslOpen()
- *matrixSslReadKeys()
- **/
- printf("Calling CreateSSLHello()\n");
- rc = CreateSSLHello(&ssl);
- printf("Finished calling CreateSSLHello()\n");
-
- bzero((char *) &serv_addr, sizeof(serv_addr));
- serv_addr.sin_family = AF_INET;
- bcopy((char *)server->h_addr,(char *)&serv_addr.sin_addr.s_addr,server->h_length);
- serv_addr.sin_port = htons(portno);
- if(connect(sockfd,(struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0){
- fprintf(stderr,"ERROR connecting to server\n");
- exit(1);
- }
-
- PrintSSLPacket(&ssl);
-
- printf("Write ssl.buffer\n");
- write(sockfd,ssl.buffer,ssl.length);
- printf("Finished writing\n");
- ssl.length = read(sockfd,ssl.buffer,ssl.max_size);
- ReadSSLHello(&ssl);
-
- /**
- *matrixSslNewSession()
- *matrixSslSetCetValidator()
- *encodeSslHandshake()
-
- *write handshake buffer
-
- *readSslResponse() <-+
- |
- *read return code |-- similar/same function??
- |
- *sslEncode() |
- *sslDecode() <-------+
-
- *encodeSslCloseAlert()
-
- *write close alert buffer
- **/
- close(sockfd);
-
- /**
- *sslClose()
- * -free connection
- * -free keys
- * -close pki interface
- **/
-
- return 0;
-}
-
-#endif
diff --git a/gpxe/src/crypto/matrixssl/mpi.h b/gpxe/src/crypto/matrixssl/mpi.h
deleted file mode 100644
index bb2c9c57..00000000
--- a/gpxe/src/crypto/matrixssl/mpi.h
+++ /dev/null
@@ -1,487 +0,0 @@
-/*
- * mpi.h
- * Release $Name$
- *
- * multiple-precision integer library
- */
-/*
- * Copyright (c) PeerSec Networks, 2002-2006. All Rights Reserved.
- * The latest version of this code is available at http://www.matrixssl.org
- *
- * This software is open source; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This General Public License does NOT permit incorporating this software
- * into proprietary programs. If you are unable to comply with the GPL, a
- * commercial license for this software may be purchased from PeerSec Networks
- * at http://www.peersec.com
- *
- * This program is distributed in WITHOUT ANY WARRANTY; without even the
- * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * http://www.gnu.org/copyleft/gpl.html
- */
-/******************************************************************************/
-
-#ifndef _h_MPI
-#define _h_MPI
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <limits.h>
-
-#undef MIN
-#define MIN(x,y) ((x)<(y)?(x):(y))
-#undef MAX
-#define MAX(x,y) ((x)>(y)?(x):(y))
-
-#ifdef __cplusplus
-extern "C" {
-
-
-/*
- C++ compilers don't like assigning void * to mp_digit *
- */
-#define OPT_CAST(x) (x *)
-
-#else
-
-/*
- C on the other hand doesn't care
- */
-#define OPT_CAST(x)
-
-#endif /* __cplusplus */
-
-/******************************************************************************/
-/*
- some default configurations.
-
- A "mp_digit" must be able to hold DIGIT_BIT + 1 bits
- A "mp_word" must be able to hold 2*DIGIT_BIT + 1 bits
-
- At the very least a mp_digit must be able to hold 7 bits
- [any size beyond that is ok provided it doesn't overflow the data type]
- */
-#ifdef MP_8BIT
- typedef unsigned char mp_digit;
- typedef unsigned short mp_word;
-#elif defined(MP_16BIT)
- typedef unsigned short mp_digit;
- typedef unsigned long mp_word;
-#elif defined(MP_64BIT)
-/*
- for GCC only on supported platforms
- */
- #ifndef CRYPT
- typedef unsigned long long ulong64;
- typedef signed long long long64;
- #endif /* CRYPT */
-
- typedef ulong64 mp_digit;
- typedef unsigned long mp_word __attribute__ ((mode(TI)));
-
- #define DIGIT_BIT 60
-#else /* MP_8BIT */
-/*
- this is the default case, 28-bit digits
- */
- #ifndef CRYPT
- #if defined(_MSC_VER) || defined(__BORLANDC__)
- typedef unsigned __int64 ulong64;
- typedef signed __int64 long64;
- #else
- typedef unsigned long long ulong64;
- typedef signed long long long64;
- #endif
- #endif /* CRYPT */
-
- typedef unsigned long mp_digit;
- typedef ulong64 mp_word;
-
- #ifdef MP_31BIT
-/*
- this is an extension that uses 31-bit digits
- */
- #define DIGIT_BIT 31
- #else /* MP_31BIT */
-/*
- default case is 28-bit digits, defines MP_28BIT as a handy macro to test
- */
- #define DIGIT_BIT 28
- #define MP_28BIT
- #endif /* MP_31BIT */
-#endif /* MP_8BIT */
-
-/*
- otherwise the bits per digit is calculated automatically from the size of
- a mp_digit
- */
-#ifndef DIGIT_BIT
- #define DIGIT_BIT ((int32)((CHAR_BIT * sizeof(mp_digit) - 1))) /* bits per digit */
-#endif /* DIGIT_BIT */
-
-#define MP_DIGIT_BIT DIGIT_BIT
-#define MP_MASK ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit)1))
-#define MP_DIGIT_MAX MP_MASK
-
-/******************************************************************************/
-/*
- equalities
- */
-#define MP_LT -1 /* less than */
-#define MP_EQ 0 /* equal to */
-#define MP_GT 1 /* greater than */
-
-#define MP_ZPOS 0 /* positive integer */
-#define MP_NEG 1 /* negative */
-
-#define MP_OKAY 0 /* ok result */
-#define MP_MEM -2 /* out of mem */
-#define MP_VAL -3 /* invalid input */
-#define MP_RANGE MP_VAL
-
-#define MP_YES 1 /* yes response */
-#define MP_NO 0 /* no response */
-
-typedef int32 mp_err;
-
-/******************************************************************************/
-/*
- various build options
- */
-#define MP_PREC 64 /* default digits of precision */
-
-/*
- define this to use lower memory usage routines (exptmods mostly)
- */
-#define MP_LOW_MEM
-
-/*
- size of comba arrays, should be at least
- 2 * 2**(BITS_PER_WORD - BITS_PER_DIGIT*2)
- */
-#define MP_WARRAY (1 << (sizeof(mp_word) * CHAR_BIT - 2 * DIGIT_BIT + 1))
-
-typedef struct {
- int32 used, alloc, sign;
- mp_digit *dp;
-} mp_int;
-
-#define USED(m) ((m)->used)
-#define DIGIT(m,k) ((m)->dp[(k)])
-#define SIGN(m) ((m)->sign)
-
-/******************************************************************************/
-/*
- init and deinit bignum functions
- */
-
-/*
- init a bignum
- */
-extern int32 mp_init(psPool_t *pool, mp_int *a);
-
-/*
- free a bignum
- */
-extern void mp_clear(mp_int *a);
-
-/*
- init a series of arguments
- */
-extern int32 _mp_init_multi(psPool_t *pool, mp_int *mp0, mp_int *mp1, mp_int *mp2,
- mp_int *mp3, mp_int *mp4, mp_int *mp5, mp_int *mp6,
- mp_int *mp7);
-
-/*
- clear a series of arguments
- */
-extern void _mp_clear_multi(mp_int *mp0, mp_int *mp1, mp_int *mp2, mp_int *mp3,
- mp_int *mp4, mp_int *mp5, mp_int *mp6, mp_int *mp7);
-
-/*
- exchange two ints
- */
-extern void mp_exch(mp_int *a, mp_int *b);
-
-/*
- shrink ram required for a bignum
- */
-extern int32 mp_shrink(mp_int *a);
-
-/*
- grow an int32 to a given size
- */
-extern int32 mp_grow(mp_int *a, int32 size);
-
-/*
- init to a given number of digits
- */
-extern int32 mp_init_size(psPool_t *pool, mp_int *a, int32 size);
-
-/******************************************************************************/
-/*
- Basic Manipulations
- */
-#define mp_iszero(a) (((a)->used == 0) ? MP_YES : MP_NO)
-#define mp_iseven(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 0)) ? MP_YES : MP_NO)
-#define mp_isodd(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? MP_YES : MP_NO)
-
-extern int32 mp_add_d (mp_int * a, mp_digit b, mp_int * c);
-extern int32 mp_sub_d (mp_int * a, mp_digit b, mp_int * c);
-/*
- set to zero
- */
-extern void mp_zero(mp_int *a);
-
-/*
- set to a digit
- */
-extern void mp_set(mp_int *a, mp_digit b);
-
-/*
- copy, b = a
- */
-extern int32 mp_copy(mp_int *a, mp_int *b);
-
-/*
- inits and copies, a = b
- */
-extern int32 mp_init_copy(psPool_t *pool, mp_int *a, mp_int *b);
-
-/*
- trim unused digits
- */
-extern void mp_clamp(mp_int *a);
-
-/******************************************************************************/
-/*
- digit manipulation
-*/
-
-/*
- right shift by "b" digits
- */
-extern void mp_rshd(mp_int *a, int32 b);
-
-/*
- left shift by "b" digits
- */
-extern int32 mp_lshd(mp_int *a, int32 b);
-
-/*
- c = a / 2**b
- */
-extern int32 mp_div_2d(psPool_t *pool, mp_int *a, int32 b, mp_int *c, mp_int *d);
-
-/*
- b = a/2
- */
-extern int32 mp_div_2(mp_int *a, mp_int *b);
-
-/*
- c = a * 2**b
- */
-extern int32 mp_mul_2d(mp_int *a, int32 b, mp_int *c);
-
-/*
- c = a mod 2**d
- */
-extern int32 mp_mod_2d(mp_int *a, int32 b, mp_int *c);
-
-/*
- computes a = 2**b
- */
-extern int32 mp_2expt(mp_int *a, int32 b);
-
-/******************************************************************************/
-/*
- Basic arithmetic
- */
-
-/*
- b = |a|
- */
-extern int32 mp_abs(mp_int *a, mp_int *b);
-
-/*
- compare a to b
- */
-extern int32 mp_cmp(mp_int *a, mp_int *b);
-
-/*
- compare |a| to |b|
- */
-extern int32 mp_cmp_mag(mp_int *a, mp_int *b);
-
-/*
- c = a + b
- */
-extern int32 mp_add(mp_int *a, mp_int *b, mp_int *c);
-
-/*
- c = a - b
- */
-extern int32 mp_sub(mp_int *a, mp_int *b, mp_int *c);
-
-/*
- c = a * b
- b = a*a
- */
-/* STEVE - moved mp_mul out of SLOW case */
-extern int32 mp_mul(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c);
-#ifdef USE_SMALL_WORD
-extern int32 mp_sqr(psPool_t *pool, mp_int *a, mp_int *b);
-#endif
-
-/*
- a/b => cb + d == a
- */
-extern int32 mp_div(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c, mp_int *d);
-
-/*
- c = a mod b, 0 <= c < b
- */
-extern int32 mp_mod(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c);
-
-/******************************************************************************/
-/*
- single digit functions
- */
-
-/*
- compare against a single digit
- */
-extern int32 mp_cmp_d(mp_int *a, mp_digit b);
-
-/*
- c = a * b
- */
-extern int32 mp_mul_d(mp_int *a, mp_digit b, mp_int *c);
-
-/******************************************************************************/
-/*
- number theory
- */
-
-/*
- d = a + b (mod c)
- */
-extern int32 mp_addmod(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c, mp_int *d);
-
-/*
- d = a * b (mod c)
- */
-extern int32 mp_mulmod(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c, mp_int *d);
-
-/*
- c = 1/a (mod b)
- */
-#ifdef USE_SMALL_WORD
-extern int32 mp_invmod(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c);
-#endif
-
-/*
- setups the montgomery reduction
- */
-extern int32 mp_montgomery_setup(mp_int *a, mp_digit *mp);
-
-/*
- computes a = B**n mod b without division or multiplication useful for
- normalizing numbers in a Montgomery system.
- */
-extern int32 mp_montgomery_calc_normalization(mp_int *a, mp_int *b);
-
-/*
- computes x/R == x (mod N) via Montgomery Reduction
- */
-#ifdef USE_SMALL_WORD
-extern int32 mp_montgomery_reduce(mp_int *a, mp_int *m, mp_digit mp);
-#endif
-
-/*
- d = a**b (mod c)
- */
-/* TODO - we never define this */
-extern int32 mp_exptmod(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c, mp_int *d);
-
-/******************************************************************************/
-/*
- If we're using 1024 or 2048 bit keys and 28 bit digits, we only need the
- fast_ versions of these functions, removing the others to save space.
- Otherwise, we include the slow versions as well and which version to use
- is done at runtime.
-*/
-#ifdef USE_SMALL_WORD
-extern int32 s_mp_mul_digs(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c,
- int32 digs);
-extern int32 s_mp_sqr(psPool_t *pool, mp_int *a, mp_int *b);
-#else
-#define mp_montgomery_reduce fast_mp_montgomery_reduce
-#define mp_sqr fast_s_mp_sqr
-#if STEVE
-#define mp_mul(P, A, B, C) fast_s_mp_mul_digs(P, A, B, C, (A)->used + (B)->used + 1)
-#endif
-#define s_mp_mul_digs fast_s_mp_mul_digs
-#define mp_invmod fast_mp_invmod
-#endif
-
-/******************************************************************************/
-/*
- radix conversion
- */
-extern int32 mp_count_bits(mp_int *a);
-
-extern int32 mp_unsigned_bin_size(mp_int *a);
-extern int32 mp_read_unsigned_bin(mp_int *a, unsigned char *b, int32 c);
-extern int32 mp_to_unsigned_bin(psPool_t *pool, mp_int *a, unsigned char *b);
-
-extern int32 mp_signed_bin_size(mp_int *a);
-
-/*
- lowlevel functions, do not call!
- */
-#if STEVE
-#ifdef USE_SMALL_WORD
-#define s_mp_mul(P, A, B, C) s_mp_mul_digs(P, A, B, C, (A)->used + (B)->used + 1)
-#else
-#define s_mp_mul(P, A, B, C) sslAssert();
-#endif
-#endif /* STEVE */
-/* define this in all cases for now STEVE */
-#define s_mp_mul(P, A, B, C) s_mp_mul_digs(P, A, B, C, (A)->used + (B)->used + 1)
-
-
-/*
- b = a*2
- */
-extern int32 mp_mul_2(mp_int *a, mp_int *b);
-
-extern int32 s_mp_add(mp_int *a, mp_int *b, mp_int *c);
-extern int32 s_mp_sub(mp_int *a, mp_int *b, mp_int *c);
-
-extern int32 fast_s_mp_mul_digs(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c,
- int32 digs);
-extern int32 fast_s_mp_sqr(psPool_t *pool, mp_int *a, mp_int *b);
-
-extern int32 fast_mp_invmod(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c);
-extern int32 fast_mp_montgomery_reduce(mp_int *a, mp_int *m, mp_digit mp);
-
-extern void bn_reverse(unsigned char *s, int32 len);
-
-
-#ifdef __cplusplus
- }
-#endif /* __cplusplus */
-
-#endif /* _h_MPI */
-
diff --git a/gpxe/src/crypto/matrixssl/pscrypto.h b/gpxe/src/crypto/matrixssl/pscrypto.h
deleted file mode 100644
index 4d684327..00000000
--- a/gpxe/src/crypto/matrixssl/pscrypto.h
+++ /dev/null
@@ -1,661 +0,0 @@
-/*
- * pscrypto.h
- * Release $Name$
- *
- * Internal definitions for PeerSec Networks MatrixSSL cryptography provider
- */
-/*
- * Copyright (c) PeerSec Networks, 2002-2006. All Rights Reserved.
- * The latest version of this code is available at http://www.matrixssl.org
- *
- * This software is open source; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This General Public License does NOT permit incorporating this software
- * into proprietary programs. If you are unable to comply with the GPL, a
- * commercial license for this software may be purchased from PeerSec Networks
- * at http://www.peersec.com
- *
- * This program is distributed in WITHOUT ANY WARRANTY; without even the
- * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * http://www.gnu.org/copyleft/gpl.html
- */
-/******************************************************************************/
-
-#ifndef _h_PSCRYPTO
-#define _h_PSCRYPTO
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- PeerSec crypto-specific defines.
- */
-#define SMALL_CODE
-#define CLEAN_STACK
-/*
- If Native 64 bit integers are not supported, we must set the 16 bit flag
- to produce 32 bit mp_words in mpi.h
- We must also include the slow MPI functions because the fast ones only
- work with larger (28 bit) digit sizes.
-*/
-#ifndef USE_INT64
-#define MP_16BIT
-#define USE_SMALL_WORD
-#endif /* USE_INT64 */
-
-/******************************************************************************/
-
-#ifdef USE_RSA
-
-#include "mpi.h"
-
-#if LINUX
- #define _stat stat
-#endif
-
-/* this is the "32-bit at least" data type
- * Re-define it to suit your platform but it must be at least 32-bits
- */
-typedef unsigned long ulong32;
-
-/*
- Primary RSA Key struct. Define here for crypto
-*/
-typedef struct {
- mp_int e, d, N, qP, dP, dQ, p, q;
- int32 size; /* Size of the key in bytes */
- int32 optimized; /* 1 for optimized */
-} sslRsaKey_t;
-
-#endif /* USE_RSA */
-
-
-/*
- * Private
- */
-extern int32 ps_base64_decode(const unsigned char *in, uint32 len,
- unsigned char *out, uint32 *outlen);
-
-/*
- * Memory routines
- */
-extern void psZeromem(void *dst, size_t len);
-extern void psBurnStack(unsigned long len);
-
-
-/* max size of either a cipher/hash block or symmetric key [largest of the two] */
-#define MAXBLOCKSIZE 24
-
-/* ch1-01-1 */
-/* error codes [will be expanded in future releases] */
-enum {
- CRYPT_OK=0, /* Result OK */
- CRYPT_ERROR, /* Generic Error */
- CRYPT_NOP, /* Not a failure but no operation was performed */
-
- CRYPT_INVALID_KEYSIZE, /* Invalid key size given */
- CRYPT_INVALID_ROUNDS, /* Invalid number of rounds */
- CRYPT_FAIL_TESTVECTOR, /* Algorithm failed test vectors */
-
- CRYPT_BUFFER_OVERFLOW, /* Not enough space for output */
- CRYPT_INVALID_PACKET, /* Invalid input packet given */
-
- CRYPT_INVALID_PRNGSIZE, /* Invalid number of bits for a PRNG */
- CRYPT_ERROR_READPRNG, /* Could not read enough from PRNG */
-
- CRYPT_INVALID_CIPHER, /* Invalid cipher specified */
- CRYPT_INVALID_HASH, /* Invalid hash specified */
- CRYPT_INVALID_PRNG, /* Invalid PRNG specified */
-
- CRYPT_MEM, /* Out of memory */
-
- CRYPT_PK_TYPE_MISMATCH, /* Not equivalent types of PK keys */
- CRYPT_PK_NOT_PRIVATE, /* Requires a private PK key */
-
- CRYPT_INVALID_ARG, /* Generic invalid argument */
- CRYPT_FILE_NOTFOUND, /* File Not Found */
-
- CRYPT_PK_INVALID_TYPE, /* Invalid type of PK key */
- CRYPT_PK_INVALID_SYSTEM, /* Invalid PK system specified */
- CRYPT_PK_DUP, /* Duplicate key already in key ring */
- CRYPT_PK_NOT_FOUND, /* Key not found in keyring */
- CRYPT_PK_INVALID_SIZE, /* Invalid size input for PK parameters */
-
- CRYPT_INVALID_PRIME_SIZE /* Invalid size of prime requested */
-};
-
-/******************************************************************************/
-/*
- hash defines
- */
-struct sha1_state {
-#ifdef USE_INT64
- ulong64 length;
-#else
- ulong32 lengthHi;
- ulong32 lengthLo;
-#endif /* USE_INT64 */
- ulong32 state[5], curlen;
- unsigned char buf[64];
-};
-
-struct md5_state {
-#ifdef USE_INT64
- ulong64 length;
-#else
- ulong32 lengthHi;
- ulong32 lengthLo;
-#endif /* USE_INT64 */
- ulong32 state[4], curlen;
- unsigned char buf[64];
-};
-
-#ifdef USE_MD2
-struct md2_state {
- unsigned char chksum[16], X[48], buf[16];
- unsigned long curlen;
-};
-#endif /* USE_MD2 */
-
-#ifdef USE_SHA256
-struct sha256_state {
- ulong64 length;
- ulong32 state[8], curlen;
- unsigned char buf[64];
-};
-#endif /* USE_SHA256 */
-
-typedef union {
- struct sha1_state sha1;
- struct md5_state md5;
-#ifdef USE_MD2
- struct md2_state md2;
-#endif /* USE_MD2 */
-#ifdef USE_SHA256
- struct sha256_state sha256;
-#endif
-} hash_state;
-
-typedef hash_state sslSha1Context_t;
-typedef hash_state sslMd5Context_t;
-#ifdef USE_MD2
-typedef hash_state sslMd2Context_t;
-#endif /* USE_MD2 */
-#ifdef USE_SHA256
-typedef hash_state sslSha256Context_t;
-#endif /* USE_SHA256 */
-
-typedef struct {
- unsigned char pad[64];
- union {
- sslMd5Context_t md5;
- sslSha1Context_t sha1;
- } u;
-} sslHmacContext_t;
-
-/******************************************************************************/
-/*
- RC4
- */
-#ifdef USE_ARC4
-typedef struct {
- unsigned char state[256];
- uint32 byteCount;
- unsigned char x;
- unsigned char y;
-} rc4_key;
-#endif /* USE_ARC4 */
-
-#define SSL_DES3_KEY_LEN 24
-#define SSL_DES3_IV_LEN 8
-#ifdef USE_3DES
-
-typedef struct {
- ulong32 ek[3][32], dk[3][32];
-} des3_key;
-
-/*
- A block cipher CBC structure
- */
-typedef struct {
- int32 blocklen;
- unsigned char IV[8];
- des3_key key;
- int32 explicitIV; /* 1 if yes */
-} des3_CBC;
-
-extern int32 des3_setup(const unsigned char *key, int32 keylen, int32 num_rounds,
- des3_CBC *skey);
-extern void des3_ecb_encrypt(const unsigned char *pt, unsigned char *ct,
- des3_CBC *key);
-extern void des3_ecb_decrypt(const unsigned char *ct, unsigned char *pt,
- des3_CBC *key);
-extern int32 des3_keysize(int32 *desired_keysize);
-
-extern int32 des_setup(const unsigned char *key, int32 keylen, int32 num_rounds,
- des3_CBC *skey);
-extern void des_ecb_encrypt(const unsigned char *pt, unsigned char *ct,
- des3_CBC *key);
-extern void des_ecb_decrypt(const unsigned char *ct, unsigned char *pt,
- des3_CBC *key);
-
-#endif /* USE_3DES */
-
-
-typedef union {
-#ifdef USE_ARC4
- rc4_key arc4;
-#endif
-#ifdef USE_3DES
- des3_CBC des3;
-#endif
-} sslCipherContext_t;
-
-
-/*
- Controls endianess and size of registers. Leave uncommented to get
- platform neutral [slower] code detect x86-32 machines somewhat
- */
-#if (defined(_MSC_VER) && defined(WIN32)) || (defined(__GNUC__) && (defined(__DJGPP__) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__i386__)))
- #define ENDIAN_LITTLE
- #define ENDIAN_32BITWORD
-#endif
-
-
-/* #define ENDIAN_LITTLE */
-/* #define ENDIAN_BIG */
-
-/* #define ENDIAN_32BITWORD */
-/* #define ENDIAN_64BITWORD */
-
-#if (defined(ENDIAN_BIG) || defined(ENDIAN_LITTLE)) && !(defined(ENDIAN_32BITWORD) || defined(ENDIAN_64BITWORD))
- #error You must specify a word size as well as endianess
-#endif
-
-#if !(defined(ENDIAN_BIG) || defined(ENDIAN_LITTLE))
- #define ENDIAN_NEUTRAL
-#endif
-
-/*
- helper macros
- */
-#if defined (ENDIAN_NEUTRAL)
-
-#define STORE32L(x, y) \
- { (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
- (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
-
-#define LOAD32L(x, y) \
- { x = ((unsigned long)((y)[3] & 255)<<24) | \
- ((unsigned long)((y)[2] & 255)<<16) | \
- ((unsigned long)((y)[1] & 255)<<8) | \
- ((unsigned long)((y)[0] & 255)); }
-
-#define STORE64L(x, y) \
- { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255); \
- (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255); \
- (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
- (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
-
-#define LOAD64L(x, y) \
- { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48)| \
- (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32)| \
- (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16)| \
- (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); }
-
-#define STORE32H(x, y) \
- { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \
- (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); }
-
-#define LOAD32H(x, y) \
- { x = ((unsigned long)((y)[0] & 255)<<24) | \
- ((unsigned long)((y)[1] & 255)<<16) | \
- ((unsigned long)((y)[2] & 255)<<8) | \
- ((unsigned long)((y)[3] & 255)); }
-
-#define STORE64H(x, y) \
- { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
- (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
- (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
- (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
-
-#define LOAD64H(x, y) \
- { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48) | \
- (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32) | \
- (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16) | \
- (((ulong64)((y)[6] & 255))<<8)|(((ulong64)((y)[7] & 255))); }
-
-#endif /* ENDIAN_NEUTRAL */
-
-#ifdef ENDIAN_LITTLE
-
-#define STORE32H(x, y) \
- { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \
- (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); }
-
-#define LOAD32H(x, y) \
- { x = ((unsigned long)((y)[0] & 255)<<24) | \
- ((unsigned long)((y)[1] & 255)<<16) | \
- ((unsigned long)((y)[2] & 255)<<8) | \
- ((unsigned long)((y)[3] & 255)); }
-
-#define STORE64H(x, y) \
- { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
- (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
- (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
- (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
-
-#define LOAD64H(x, y) \
- { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48) | \
- (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32) | \
- (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16) | \
- (((ulong64)((y)[6] & 255))<<8)|(((ulong64)((y)[7] & 255))); }
-
-#ifdef ENDIAN_32BITWORD
-
-#define STORE32L(x, y) \
- { unsigned long __t = (x); memcpy(y, &__t, 4); }
-
-#define LOAD32L(x, y) \
- memcpy(&(x), y, 4);
-
-#define STORE64L(x, y) \
- { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255); \
- (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255); \
- (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
- (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
-
-#define LOAD64L(x, y) \
- { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48)| \
- (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32)| \
- (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16)| \
- (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); }
-
-#else /* 64-bit words then */
-
-#define STORE32L(x, y) \
- { unsigned long __t = (x); memcpy(y, &__t, 4); }
-
-#define LOAD32L(x, y) \
- { memcpy(&(x), y, 4); x &= 0xFFFFFFFF; }
-
-#define STORE64L(x, y) \
- { ulong64 __t = (x); memcpy(y, &__t, 8); }
-
-#define LOAD64L(x, y) \
- { memcpy(&(x), y, 8); }
-
-#endif /* ENDIAN_64BITWORD */
-#endif /* ENDIAN_LITTLE */
-
-#ifdef ENDIAN_BIG
-#define STORE32L(x, y) \
- { (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
- (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
-
-#define LOAD32L(x, y) \
- { x = ((unsigned long)((y)[3] & 255)<<24) | \
- ((unsigned long)((y)[2] & 255)<<16) | \
- ((unsigned long)((y)[1] & 255)<<8) | \
- ((unsigned long)((y)[0] & 255)); }
-
-#define STORE64L(x, y) \
- { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255); \
- (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255); \
- (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
- (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
-
-#define LOAD64L(x, y) \
- { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48) | \
- (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32) | \
- (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16) | \
- (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); }
-
-#ifdef ENDIAN_32BITWORD
-
-#define STORE32H(x, y) \
- { unsigned long __t = (x); memcpy(y, &__t, 4); }
-
-#define LOAD32H(x, y) \
- memcpy(&(x), y, 4);
-
-#define STORE64H(x, y) \
- { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
- (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
- (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
- (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
-
-#define LOAD64H(x, y) \
- { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48)| \
- (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32)| \
- (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16)| \
- (((ulong64)((y)[6] & 255))<<8)| (((ulong64)((y)[7] & 255))); }
-
-#else /* 64-bit words then */
-
-#define STORE32H(x, y) \
- { unsigned long __t = (x); memcpy(y, &__t, 4); }
-
-#define LOAD32H(x, y) \
- { memcpy(&(x), y, 4); x &= 0xFFFFFFFF; }
-
-#define STORE64H(x, y) \
- { ulong64 __t = (x); memcpy(y, &__t, 8); }
-
-#define LOAD64H(x, y) \
- { memcpy(&(x), y, 8); }
-
-#endif /* ENDIAN_64BITWORD */
-#endif /* ENDIAN_BIG */
-
-/*
- packet code */
-#if defined(USE_RSA) || defined(MDH) || defined(MECC)
- #define PACKET
-
-/*
- size of a packet header in bytes */
- #define PACKET_SIZE 4
-
-/*
- Section tags
- */
- #define PACKET_SECT_RSA 0
- #define PACKET_SECT_DH 1
- #define PACKET_SECT_ECC 2
- #define PACKET_SECT_DSA 3
-
-/*
- Subsection Tags for the first three sections
- */
- #define PACKET_SUB_KEY 0
- #define PACKET_SUB_ENCRYPTED 1
- #define PACKET_SUB_SIGNED 2
- #define PACKET_SUB_ENC_KEY 3
-#endif
-
-/*
- fix for MSVC ...evil!
- */
-#ifdef WIN32
-#ifdef _MSC_VER
- #define CONST64(n) n ## ui64
- typedef unsigned __int64 ulong64;
-#else
- #define CONST64(n) n ## ULL
- typedef unsigned long long ulong64;
-#endif
-#endif /* WIN32 */
-
-
-#define BSWAP(x) ( ((x>>24)&0x000000FFUL) | ((x<<24)&0xFF000000UL) | \
- ((x>>8)&0x0000FF00UL) | ((x<<8)&0x00FF0000UL) )
-
-#ifdef _MSC_VER
-
-/*
- instrinsic rotate
- */
-#include <stdlib.h>
-#pragma intrinsic(_lrotr,_lrotl)
-#define ROR(x,n) _lrotr(x,n)
-#define ROL(x,n) _lrotl(x,n)
-#define RORc(x,n) _lrotr(x,n)
-#define ROLc(x,n) _lrotl(x,n)
-
-/*
-#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) && !defined(INTEL_CC) && !defined(PS_NO_ASM)
-
-static inline unsigned ROL(unsigned word, int32 i)
-{
- asm ("roll %%cl,%0"
- :"0" (word),"c" (i));
- return word;
-}
-
-static inline unsigned ROR(unsigned word, int32 i)
-{
- asm ("rorl %%cl,%0"
- :"=r" (word)
- :"0" (word),"c" (i));
- return word;
-}
-*/
-/*
-#ifndef PS_NO_ROLC
-
-static inline unsigned ROLc(unsigned word, const int32 i)
-{
- asm ("roll %2,%0"
- :"=r" (word)
- :"0" (word),"I" (i));
- return word;
-}
-
-static inline unsigned RORc(unsigned word, const int32 i)
-{
- asm ("rorl %2,%0"
- :"=r" (word)
- :"0" (word),"I" (i));
- return word;
-}
-
-#else
-
-#define ROLc ROL
-#define RORc ROR
-
-#endif
-*/
-
-#else /* _MSC_VER */
-
-/*
- rotates the hard way
- */
-#define ROL(x, y) ( (((unsigned long)(x)<<(unsigned long)((y)&31)) | (((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
-#define ROR(x, y) ( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)((y)&31)) | ((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
-#define ROLc(x, y) ( (((unsigned long)(x)<<(unsigned long)((y)&31)) | (((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
-#define RORc(x, y) ( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)((y)&31)) | ((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
-
-#endif /* _MSC_VER */
-
-/* 64-bit Rotates */
-#if 0
-
-#if defined(__GNUC__) && defined(__x86_64__) && !defined(PS_NO_ASM)
-
-static inline unsigned long ROL64(unsigned long word, int32 i)
-{
- asm("rolq %%cl,%0"
- :"=r" (word)
- :"0" (word),"c" (i));
- return word;
-}
-
-static inline unsigned long ROR64(unsigned long word, int32 i)
-{
- asm("rorq %%cl,%0"
- :"=r" (word)
- :"0" (word),"c" (i));
- return word;
-}
-
-#ifndef PS_NO_ROLC
-
-static inline unsigned long ROL64c(unsigned long word, const int32 i)
-{
- asm("rolq %2,%0"
- :"=r" (word)
- :"0" (word),"J" (i));
- return word;
-}
-
-static inline unsigned long ROR64c(unsigned long word, const int32 i)
-{
- asm("rorq %2,%0"
- :"=r" (word)
- :"0" (word),"J" (i));
- return word;
-}
-
-#else /* PS_NO_ROLC */
-
-#define ROL64c ROL
-#define ROR64c ROR
-
-#endif /* PS_NO_ROLC */
-#endif
-#endif /* commented out */
-
-#define ROL64(x, y) \
- ( (((x)<<((ulong64)(y)&63)) | \
- (((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)64-((y)&63)))) & CONST64(0xFFFFFFFFFFFFFFFF))
-
-#define ROR64(x, y) \
- ( ((((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)(y)&CONST64(63))) | \
- ((x)<<((ulong64)(64-((y)&CONST64(63)))))) & CONST64(0xFFFFFFFFFFFFFFFF))
-
-#define ROL64c(x, y) \
- ( (((x)<<((ulong64)(y)&63)) | \
- (((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)64-((y)&63)))) & CONST64(0xFFFFFFFFFFFFFFFF))
-
-#define ROR64c(x, y) \
- ( ((((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)(y)&CONST64(63))) | \
- ((x)<<((ulong64)(64-((y)&CONST64(63)))))) & CONST64(0xFFFFFFFFFFFFFFFF))
-
-#undef MAX
-#undef MIN
-#define MAX(x, y) ( ((x)>(y))?(x):(y) )
-#define MIN(x, y) ( ((x)<(y))?(x):(y) )
-
-/*
- extract a byte portably This MSC code causes runtime errors in VS.NET,
- always use the other
- */
-/*
-#ifdef _MSC_VER
- #define byte(x, n) ((unsigned char)((x) >> (8 * (n))))
-#else
-*/
- #define byte(x, n) (((x) >> (8 * (n))) & 255)
-/*
-#endif
-*/
-#ifdef __cplusplus
- }
-#endif /* __cplusplus */
-
-#endif /* _h_PSCRYPTO */
-
-/******************************************************************************/
-
diff --git a/gpxe/src/crypto/ssl.c b/gpxe/src/crypto/ssl.c
deleted file mode 100644
index 8abd7af8..00000000
--- a/gpxe/src/crypto/ssl.c
+++ /dev/null
@@ -1,136 +0,0 @@
-#if 0
-
-#include "ssl.h"
-#include "ssl_constructs.h"
-#include <string.h> // for bcopy()
-#include <time.h> // for time()
-#include <stdlib.h> // for rand(), htons?, htonl?
-// note net byte order is big-endian
-// Need to set error codes
-
-int CreateSSLHello(SSL_t *ssl)
-{
- printf("In CreateSSLHello()\n",ssl);
-
- // Initalize the structure
- bzero(ssl,sizeof(SSL_t));
- //ssl->max_size = sizeof(ssl->buffer);
- ssl->max_size = 18456;
-
- // Declare variables
- int i; void *ptr;
-
- // Set pointers into buffer
- SSLPlaintext *record = (SSLPlaintext *)ssl->buffer;
- Handshake *handshake = (Handshake *)record->fragment;
- // the body starts right after the handshake
- printf("sizeof(Handshake) = %d\n",sizeof(Handshake));
- ClientHello *hello = (ClientHello *)(handshake + 1);
-
- printf("record->%#x, handshake->%#x, hello->%#x\n",record,handshake,hello);
-
- // Construct ClientHello Message
- hello->client_version = version;
- i = htonl(time(NULL));
- bcopy(&i,hello->random.gmt_unix_time,4);
- for(i=0;i<28;i++){ hello->random.random_bytes[i] = (uint8)rand(); }
- hello->session_id_length = 0;
- hello->session_id = &hello->session_id_length;
- hello->session_id_end = hello->session_id;
- hello->cipher_suites_length = (CipherSuiteLength *)(hello->session_id_end + 1);
- hello->cipher_suites = (hello->cipher_suites_length + 1);
- hello->cipher_suites_end = hello->cipher_suites;
- i = htons(2*5); // 2 bytes per Suite * 5 Suites
- bcopy(&i,hello->cipher_suites_length,2);
- bcopy(SSL_NULL_WITH_NULL_NULL,hello->cipher_suites_end,sizeof(CipherSuite));
- *hello->cipher_suites_end++;
- bcopy(SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA,hello->cipher_suites_end,sizeof(CipherSuite));
- *hello->cipher_suites_end++;
- bcopy(SSL_DH_DSS_WITH_DES_CBC_SHA,hello->cipher_suites_end,sizeof(CipherSuite));
- *hello->cipher_suites_end++;
- bcopy(SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA,hello->cipher_suites_end,sizeof(CipherSuite));
- *hello->cipher_suites_end++;
- bcopy(SSL_DH_anon_WITH_RC4_128_MD5,hello->cipher_suites_end,sizeof(CipherSuite));
- hello->compression_methods_length = (CompressionMethodLength *)(hello->cipher_suites_end + 1);
- hello->compression_methods = (hello->compression_methods_length + 1);
- hello->compression_methods_end = hello->compression_methods;
- *hello->compression_methods_length = 1;
- *hello->compression_methods_end = compression_method_null;
-
- // Construct Handshake Message
- handshake->msg_type = handshake_type_client_hello;
- i = (void *)(hello->compression_methods_end + 1) - (void *)hello;
- printf("Handshake.length = %d\n", i);
- handshake->length[0] = (char)*(&i+8);
- handshake->length[1] = (char)*(&i+8);
- handshake->length[2] = (char)i;
- //bcopy((&i+1),handshake->length,3); // +1 so we copy 3 bytes
-
- // Construct SSL Record
- printf("sizeof(ContentType)=%d\n",sizeof(ContentType));
- printf("sizeof(uint8)=%d\n",sizeof(uint8));
- record->type = content_type_handshake;
- record->version = version;
- i += sizeof(Handshake);
- printf("SSLPlaintext.length = %d\n",i);
- record->length[0] = (char)*(&i+8);
- record->length[1] = (char)i;
- //bcopy(&i,record->length,4); // length of handshake
-
- // Set total size of message
- i += sizeof(ContentType) + sizeof(ProtocolVersion) + sizeof(uint16);
- ssl->length = i;
- printf("End of CreateSSLHello\n");
- return 0;
-}
-
-void PrintSSLPacket(SSL_t *ssl)
-{
- printf("Printing packet with length:%d\n", ssl->length);
- char *ptr = ssl->buffer;
- char *begin = ptr;
- char *tmp;
- char *end = ssl->buffer + ssl->length;
- printf("Record Layer:\n");
- printf("\tContentType: %2hhX\n",(char)*ptr++);
- printf("\tVersion: %2hhX %2hhX\n", (char)*ptr++, (char)*ptr++);
- printf("\tLength: %2hhX %2hhX\n", (char)*ptr++, (char)*ptr++);
-
- printf("Handshake:\n");
- printf("\tType: %2hhX\n", (char)*ptr++);
- printf("\tLength: %2hhX %2hhX %2hhX\n", (char)*ptr++, (char)*ptr++, (char)*ptr++);
- printf("\tVersion: %2hhX %2hhX\n", (char)*ptr++, (char)*ptr++);
- printf("\tgmt_unix_time: %2hhX %2hhX %2hhX %2hhX\n", (char)*ptr++, (char)*ptr++, (char)*ptr++, (char)*ptr++);
- printf("\trandom: ");
- tmp = ptr + 28;
- for(;ptr<tmp;ptr++){printf("%2hhX ", (char)*ptr);}
-
- printf("\n\nHexDump:\n");
-
- int ctr = 0;
- for(;begin<end;begin++){printf("%2hhX ",(char)*begin);if(++ctr%10==0){printf("\n");}}
- printf("\n\n");
-}
-
-int ReadSSLHello(SSL_t *ssl)
-{
- SSLCiphertext *ct = (SSLCiphertext *)ssl->buffer;
-
- if(ct->type == content_type_alert){
- // assuming text is still plaintext
- Alert *a = (Alert *)&ct->fragment;
- if(a->level == alert_level_fatal){
- printf("Fatal Alert %d, connection terminated\n",a->description);
- return (1);
- }else if(a->level == alert_level_warning){
- printf("Warning Alert %d\n", a->description);
- }else{
- printf("Unknown alert level %d\n", a->level);
- }
- }else{
- printf("SSL type %d\n",ct->type);
- }
- return (0);
-}
-
-#endif
diff --git a/gpxe/src/crypto/ssl.h b/gpxe/src/crypto/ssl.h
deleted file mode 100644
index 06d43008..00000000
--- a/gpxe/src/crypto/ssl.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// At the moment I have hard coded one buffer. The size
-// is the max size of SSLCiphertext.length (so, actually it should
-// be increased to include the other information in the struct)
-// I might need to make a new, or split the current, buffer because
-// I have to have space to read in and write out, as well as keep
-// any data that has not been translated.
-// It works for now.
-typedef struct _ssl_t{
- char buffer[18456];
- int length;
- int max_size; // can't define const here
- // Current CipherSuite
- // Client random / Server random ???
- // pointers to different crypto functions
-} SSL_t;
-
-int CreateSSLHello(SSL_t *ssl);
-int ReadSSLHello(SSL_t *ssl);
-void PrintSSLPacket(SSL_t *ssl);
diff --git a/gpxe/src/crypto/ssl_constructs.h b/gpxe/src/crypto/ssl_constructs.h
deleted file mode 100644
index ab3aa703..00000000
--- a/gpxe/src/crypto/ssl_constructs.h
+++ /dev/null
@@ -1,342 +0,0 @@
-// Note: This file still needs some work.
-// Note: I had to redefine the enums to a set of const values,
-// so that the size of the variable would be correct.
-
-// Typedefs
-// (As defined by the SSL v3.0 RFC Draft)
-// URL: http://wp.netscape.com/eng/ssl3/draft302.txt
-typedef unsigned char uint8;
-typedef uint8 uint16[2];
-typedef uint8 uint24[3];
-typedef uint8 uint32[4];
-typedef uint8 uint64[8];
-
-// Record layers
-typedef struct _ProtocolVersion{
- uint8 major, minor;
-} ProtocolVersion;
-
-const ProtocolVersion version = { 3, 0 };
-
-typedef uint8 ContentType;
-const ContentType content_type_change_cipher_spec_type = 20;
-const ContentType content_type_alert = 21;
-const ContentType content_type_handshake = 22;
-const ContentType content_type_application_data = 23;
-
-typedef struct _SSLPlaintext{
- ContentType type;
- ProtocolVersion version;
- uint16 length; // can not exceed 2^14 bytes
- uint8 fragment[16384]; // 2^14 = 16,384 bytes
-} SSLPlaintext;
-
-typedef struct _SSLCompressed{
- ContentType type;
- ProtocolVersion version;
- uint16 length; // can not exceed 2^14 + 1024
- uint8 fragment[17408]; // SSLCompressed.length
-} SSLCompressed;
-
-typedef struct _SSLCiphertext{
- ContentType type;
- ProtocolVersion version;
- uint16 length;
- uint8 fragment; // so we have a pointer to the data, and don't have to do math
- // fragment; type GenericStreamCipher or GenericBlockCipher
-} SSLCiphertext; // recast to get fragment
-
-typedef struct _GenericStreamCipher{
- uint8 content[17408]; // SSLCompressed.length
- uint8 MAC[]; // CipherSpec.hash_size
-} GenericStreamCipher;
-
-typedef struct _SSLStreamCiphertext{
- ContentType type;
- ProtocolVersion version;
- uint16 length; // can not exceed 2^14 + 2048 = 18,456
- GenericStreamCipher fragment;
-} SSLStreamCiphertext;
-
-typedef struct _GenericBlockCipher{
- uint8 content[17408]; // SSLConpressed.length
- uint8 MAC[0]; // CipherSpec.hash_size
- // padding is used to bring the plaintext to
- // a multiple of the block cipher's block length.
- uint8 padding[0]; // GenericBlockCipher.padding_length
- uint8 padding_length;
-} GenericBlockCipher;
-
-typedef struct _SSLBlockCiphertext{
- ContentType type;
- ProtocolVersion version;
- uint16 length; // can not exceed 2^14 + 2048 = 18,456
- GenericBlockCipher fragment;
-} SSLBlockCiphertext;
-
-// Change cipher specs message
-typedef struct _ChangeCipherSpec{
- enum { type_change_cipher_spec=1, type_size=255 } type;
-} ChangeCipherSpec;
-
-// Alert messages
-typedef uint8 AlertLevel;
-const AlertLevel alert_level_warning = 1;
-const AlertLevel alert_level_fatal=2;
-
-typedef uint8 AlertDescription;
-const AlertDescription alert_description_close_notify = 0;
-const AlertDescription alert_description_unexpected_message = 10;
-const AlertDescription alert_description_bad_record_mac = 20;
-const AlertDescription alert_description_decompression_failure = 30;
-const AlertDescription alert_description_handshake_failure = 40;
-const AlertDescription alert_description_no_certificate = 41;
-const AlertDescription alert_description_bad_certificate = 42;
-const AlertDescription alert_description_unsupported_certificate = 43;
-const AlertDescription alert_description_certificate_revoked = 44;
-const AlertDescription alert_description_certificate_expired = 45;
-const AlertDescription alert_description_certificate_unknown = 46;
-const AlertDescription alert_description_illegal_parameter = 47;
-
-typedef struct _Alert{
- AlertLevel level;
- AlertDescription description;
-} Alert;
-
-// Handshake protocol
-// What is the best way to have a generic pointer to the body struct??
-typedef uint8 HandshakeType;
-const HandshakeType handshake_type_hello_request = 0;
-const HandshakeType handshake_type_client_hello = 1;
-const HandshakeType handshake_type_server_hello = 2;
-const HandshakeType handshake_type_certificate = 11;
-const HandshakeType handshake_type_server_key_exchange = 12;
-const HandshakeType handshake_type_certificate_request = 13;
-const HandshakeType handshake_type_server_done = 14;
-const HandshakeType handshake_type_certificate_verify = 15;
-const HandshakeType handshake_type_client_key_exchange = 16;
-const HandshakeType handshake_type_finished = 20;
-
-typedef struct _Handshake{
- HandshakeType msg_type;
- uint24 length;
- // body; // one of HandshakeType structs
-} Handshake; // generic Handshake, need to recast to get body
-
-// Hello messages
-typedef struct _HelloRequest{} HelloRequest;
-
-typedef struct _HelloRequestHandshake{
- HandshakeType msg_type;
- uint24 length;
- HelloRequest body;
-} HelloRequestHandshake;
-
-typedef struct _Random{
- uint32 gmt_unix_time;
- uint8 random_bytes[28];
-} Random;
-
-//typedef uint8 SessionID[32]; // <0..32>
-typedef uint8 SessionIDLength;
-typedef uint8 SessionID;
-
-typedef uint16 CipherSuiteLength;
-typedef uint8 CipherSuite[2];
-
-typedef uint8 CompressionMethodLength;
-typedef uint8 CompressionMethod;
-const CompressionMethod compression_method_null = 0;
-
-
-typedef struct _ClientHello{
- ProtocolVersion client_version;
- Random random;
- SessionIDLength session_id_length;
- SessionID *session_id;
- SessionID *session_id_end;
- CipherSuiteLength *cipher_suites_length;
- CipherSuite *cipher_suites; // min size is one entry
- CipherSuite *cipher_suites_end;
- //CipherSuite cipher_suites[32768]; // <2..2^16-1> = 65,536 bytes and CipherSuite is 2 bytes
- CompressionMethodLength *compression_methods_length;
- CompressionMethod *compression_methods;
- CompressionMethod *compression_methods_end;
- //CompressionMethod *compression_methods; // min size is zero
- //CompressionMethod compression_methods[256]; // <0..2^8-1> = 256 bytes and CompressionMethod is 1 byte
-} ClientHello;
-
-typedef struct _ClientHelloHandshake{
- //HandshakeType msg_type;
- uint8 msg_type;
- uint24 length;
- ClientHello body;
-} ClientHelloHandshake;
-
-typedef struct _ServerHello{
- ProtocolVersion server_version;
- Random random;
- SessionID session_id;
- CipherSuite cipher_suite;
- CompressionMethod compression_method;
-} ServerHello;
-
-typedef struct _ServerHelloHandshake{
- HandshakeType msg_type;
- uint24 length;
- ServerHello body;
-} ServerHelloHandshake;
-
-// Server authentication and key exchange messages
-typedef uint8 ASN1Cert[16777216]; // <1..2^24-1> = 16,777,216 bytes
-
-typedef struct _Certificate{
- ASN1Cert certificate_list[1]; // <1..2^24-1> / ANS1Cert = 1
- // for some reason the size of certificate_list and ASN1Cert is the same, so only one certificate in the list
-} Certificate;
-
-typedef uint8 KeyExchangeAlgorithm;
-const KeyExchangeAlgorithm key_exchange_algorithm_rsa = 0;
-const KeyExchangeAlgorithm key_exchange_algorithm_diffie_hellman = 1;
-const KeyExchangeAlgorithm key_exchange_algorithm_fortezza_kea = 2;
-
-typedef struct _AnonSignature{
- struct {};
-} AnonSignature;
-
-typedef struct _RSASignature{
- uint8 md5_hash[16];
- uint8 sha_hash[20];
-} RSASignature;
-
-typedef struct _DSASignature{
- uint8 sha_hash[20];
-} DSASignature;
-
-// use union??, make a mess to reference, but easy to make Signature type.
-typedef union _Signature{ AnonSignature anon; RSASignature rsa; DSASignature dsa; } Signature;
-
-typedef struct _ServerRSAParams{
- uint8 RSA_modulus[65536]; // <1..2^16-1> = 65,536
- uint8 RSA_exponent[65536]; // <1..2^16-1> = 65,536
-} ServerRSAParams;
-
-typedef struct _ServerDHParams{
- uint8 DH_p[65536]; // <1..2^16-1>
- uint8 DH_g[65536]; // <1..2^16-1>
- uint8 DH_Ys[65536]; // <1..2^16-1>
-} ServerDHParams;
-
-typedef struct _ServerDHKeyExchange{
- ServerDHParams params;
- Signature signed_params;
-} ServerDHKeyExchange;
-
-typedef struct _ServerRSAKeyExchange{
- ServerRSAParams params;
- Signature signed_params;
-} ServerRSAKeyExchange;
-
-typedef uint8 SignatureAlgorithm;
-const SignatureAlgorithm signature_algorithm_anonymous = 0;
-const SignatureAlgorithm signature_algorithm_rsa = 1;
-const SignatureAlgorithm signature_algorithm_dsa = 2;
-
-typedef uint8 CertificateType;
-const CertificateType certificate_type_RSA_sign = 1;
-const CertificateType certificate_type_DSS_sign = 2;
-const CertificateType certificate_type_RSA_fixed_DH = 3;
-const CertificateType certificate_type_DSS_fixed_DH = 4;
-const CertificateType certificate_type_RSA_ephemeral_DH = 5;
-const CertificateType certificate_type_DSS_ephemeral_DH = 6;
-const CertificateType certificate_type_FORTEZZA_MISSI = 20;
-
-typedef uint8 DistinguishedName[65536]; // <1..2^16-1> = 65,536
-
-typedef struct _CertificateRequest{
- CertificateType certificate_types[256]; // <1..2^8-1>
- DistinguishedName certificate_authorities[1]; // <3...2^16-1> / DistinguishedName
- // this is another one that is odd with a list size of 1
-} CertificateRequest;
-
-typedef struct _ServerHelloDone{} ServerHelloDone;
-
-// Client authentication and key exchange messages
-typedef struct _PreMasterSecret{
- ProtocolVersion client_version;
- uint8 random[46];
-} PreMasterSecret;
-
-typedef struct _EncryptedPreMasterSecret{
- PreMasterSecret pre_master_secret;
-} EncryptedPreMasterSecret;
-
-typedef struct _RSAClientKeyExchange{
- EncryptedPreMasterSecret exchange_keys;
-} RSAClientKeyExchange;
-
-typedef uint8 PublicValueEncoding;
-const PublicValueEncoding public_value_encoding_implicit = 0;
-const PublicValueEncoding public_value_encoding_explicit = 1;
-
-typedef struct _ClientDiffieHellmanPublic{
- // This is a select on PublicValueEncoding, and I chose the larger size
- uint8 dh_public[65536]; // DH_Yc<1..2^16-1>, the dh public value
-} ClientDiffieHellmanPublic;
-
-typedef struct _DHClientKeyExhange{
- ClientDiffieHellmanPublic exchange_keys;
-} DHClientKeyExchange;
-
-typedef struct _CertificateVerify{
- Signature signature;
-} CertificateVerify;
-
-// Handshake finalization message
-typedef struct _Finished{
- uint8 md5_hash[16];
- uint8 sha_hash[20];
-} Finished;
-
-// The CipherSuite
-CipherSuite SSL_NULL_WITH_NULL_NULL = { 0x00, 0x13 };
-CipherSuite SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = { 0x00, 0x0B };
-CipherSuite SSL_DH_DSS_WITH_DES_CBC_SHA = { 0x00, 0x0C };
-CipherSuite SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = { 0x00, 0x11 };
-CipherSuite SSL_DH_anon_EXPORT_WITH_RC4_40_MD5 = { 0x00, 0x17 };
-CipherSuite SSL_DH_anon_WITH_RC4_128_MD5 = { 0x00, 0x18 };
-
-// The CipherSpec
-typedef uint8 CipherType;
-const CipherType cipher_type_stream = 0;
-const CipherType cipher_type_block = 1;
-
-typedef uint8 IsExportable;
-const IsExportable is_exportable_true = 0;
-const IsExportable is_exportable_false = 1;
-
-typedef uint8 BulkCipherAlgorithm;
-const BulkCipherAlgorithm bulk_cipher_algorithm_null = 0;
-const BulkCipherAlgorithm bulk_cipher_algorithm_rc4 = 1;
-const BulkCipherAlgorithm bulk_cipher_algorithm_rc2 = 2;
-const BulkCipherAlgorithm bulk_cipher_algorithm_des = 3;
-const BulkCipherAlgorithm bulk_cipher_algorithm_3des = 4;
-const BulkCipherAlgorithm bulk_cipher_algorithm_des40 = 5;
-const BulkCipherAlgorithm bulk_cipher_algorithm_fortezza = 6;
-
-typedef uint8 MACAlgorithm;
-const MACAlgorithm mac_algorithm_null = 0;
-const MACAlgorithm mac_algorithm_md5 = 1;
-const MACAlgorithm mac_algorithm_sha = 2;
-
-typedef struct _CipherSpec{
- BulkCipherAlgorithm bulk_cipher_algorithm;
- MACAlgorithm mac_algorithm;
- CipherType cipher_type;
- IsExportable is_exportable;
- uint8 hash_size;
- uint8 key_material;
- uint8 IV_size;
-} CipherSpec;
-
-
diff --git a/gpxe/src/crypto/x509.c b/gpxe/src/crypto/x509.c
new file mode 100644
index 00000000..35adfa38
--- /dev/null
+++ b/gpxe/src/crypto/x509.c
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <gpxe/asn1.h>
+#include <gpxe/x509.h>
+
+/** @file
+ *
+ * X.509 certificates
+ *
+ * The structure of X.509v3 certificates is concisely documented in
+ * RFC5280 section 4.1. The structure of RSA public keys is
+ * documented in RFC2313.
+ */
+
+/** Object Identifier for "rsaEncryption" (1.2.840.113549.1.1.1) */
+static const uint8_t oid_rsa_encryption[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x01 };
+
+/**
+ * Identify X.509 certificate public key
+ *
+ * @v certificate Certificate
+ * @v algorithm Public key algorithm to fill in
+ * @v pubkey Public key value to fill in
+ * @ret rc Return status code
+ */
+static int x509_public_key ( const struct asn1_cursor *certificate,
+ struct asn1_cursor *algorithm,
+ struct asn1_cursor *pubkey ) {
+ struct asn1_cursor cursor;
+ int rc;
+
+ /* Locate subjectPublicKeyInfo */
+ memcpy ( &cursor, certificate, sizeof ( cursor ) );
+ rc = ( asn1_enter ( &cursor, ASN1_SEQUENCE ), /* Certificate */
+ asn1_enter ( &cursor, ASN1_SEQUENCE ), /* tbsCertificate */
+ asn1_skip ( &cursor, ASN1_EXPLICIT_TAG ), /* version */
+ asn1_skip ( &cursor, ASN1_INTEGER ), /* serialNumber */
+ asn1_skip ( &cursor, ASN1_SEQUENCE ), /* signature */
+ asn1_skip ( &cursor, ASN1_SEQUENCE ), /* issuer */
+ asn1_skip ( &cursor, ASN1_SEQUENCE ), /* validity */
+ asn1_skip ( &cursor, ASN1_SEQUENCE ), /* name */
+ asn1_enter ( &cursor, ASN1_SEQUENCE )/* subjectPublicKeyInfo*/);
+ if ( rc != 0 ) {
+ DBG ( "Cannot locate subjectPublicKeyInfo in:\n" );
+ DBG_HDA ( 0, certificate->data, certificate->len );
+ return rc;
+ }
+
+ /* Locate algorithm */
+ memcpy ( algorithm, &cursor, sizeof ( *algorithm ) );
+ rc = ( asn1_enter ( algorithm, ASN1_SEQUENCE ) /* algorithm */ );
+ if ( rc != 0 ) {
+ DBG ( "Cannot locate algorithm in:\n" );
+ DBG_HDA ( 0, certificate->data, certificate->len );
+ return rc;
+ }
+
+ /* Locate subjectPublicKey */
+ memcpy ( pubkey, &cursor, sizeof ( *pubkey ) );
+ rc = ( asn1_skip ( pubkey, ASN1_SEQUENCE ), /* algorithm */
+ asn1_enter ( pubkey, ASN1_BIT_STRING ) /* subjectPublicKey*/ );
+ if ( rc != 0 ) {
+ DBG ( "Cannot locate subjectPublicKey in:\n" );
+ DBG_HDA ( 0, certificate->data, certificate->len );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Identify X.509 certificate RSA modulus and public exponent
+ *
+ * @v certificate Certificate
+ * @v rsa RSA public key to fill in
+ * @ret rc Return status code
+ *
+ * The caller is responsible for eventually calling
+ * x509_free_rsa_public_key() to free the storage allocated to hold
+ * the RSA modulus and exponent.
+ */
+int x509_rsa_public_key ( const struct asn1_cursor *certificate,
+ struct x509_rsa_public_key *rsa_pubkey ) {
+ struct asn1_cursor algorithm;
+ struct asn1_cursor pubkey;
+ struct asn1_cursor modulus;
+ struct asn1_cursor exponent;
+ int rc;
+
+ /* First, extract the public key algorithm and key data */
+ if ( ( rc = x509_public_key ( certificate, &algorithm,
+ &pubkey ) ) != 0 )
+ return rc;
+
+ /* Check that algorithm is RSA */
+ rc = ( asn1_enter ( &algorithm, ASN1_OID ) /* algorithm */ );
+ if ( rc != 0 ) {
+ DBG ( "Cannot locate algorithm:\n" );
+ DBG_HDA ( 0, certificate->data, certificate->len );
+ return rc;
+ }
+ if ( ( algorithm.len != sizeof ( oid_rsa_encryption ) ) ||
+ ( memcmp ( algorithm.data, &oid_rsa_encryption,
+ sizeof ( oid_rsa_encryption ) ) != 0 ) ) {
+ DBG ( "algorithm is not rsaEncryption in:\n" );
+ DBG_HDA ( 0, certificate->data, certificate->len );
+ return -ENOTSUP;
+ }
+
+ /* Check that public key is a byte string, i.e. that the
+ * "unused bits" byte contains zero.
+ */
+ if ( ( pubkey.len < 1 ) ||
+ ( ( *( uint8_t * ) pubkey.data ) != 0 ) ) {
+ DBG ( "subjectPublicKey is not a byte string in:\n" );
+ DBG_HDA ( 0, certificate->data, certificate->len );
+ return -ENOTSUP;
+ }
+ pubkey.data++;
+ pubkey.len--;
+
+ /* Pick out the modulus and exponent */
+ rc = ( asn1_enter ( &pubkey, ASN1_SEQUENCE ) /* RSAPublicKey */ );
+ if ( rc != 0 ) {
+ DBG ( "Cannot locate RSAPublicKey in:\n" );
+ DBG_HDA ( 0, certificate->data, certificate->len );
+ return -ENOTSUP;
+ }
+ memcpy ( &modulus, &pubkey, sizeof ( modulus ) );
+ rc = ( asn1_enter ( &modulus, ASN1_INTEGER ) /* modulus */ );
+ if ( rc != 0 ) {
+ DBG ( "Cannot locate modulus in:\n" );
+ DBG_HDA ( 0, certificate->data, certificate->len );
+ return -ENOTSUP;
+ }
+ memcpy ( &exponent, &pubkey, sizeof ( exponent ) );
+ rc = ( asn1_skip ( &exponent, ASN1_INTEGER ), /* modulus */
+ asn1_enter ( &exponent, ASN1_INTEGER ) /* publicExponent */ );
+ if ( rc != 0 ) {
+ DBG ( "Cannot locate publicExponent in:\n" );
+ DBG_HDA ( 0, certificate->data, certificate->len );
+ return -ENOTSUP;
+ }
+
+ /* Allocate space and copy out modulus and exponent */
+ rsa_pubkey->modulus = malloc ( modulus.len + exponent.len );
+ if ( ! rsa_pubkey->modulus )
+ return -ENOMEM;
+ rsa_pubkey->exponent = ( rsa_pubkey->modulus + modulus.len );
+ memcpy ( rsa_pubkey->modulus, modulus.data, modulus.len );
+ rsa_pubkey->modulus_len = modulus.len;
+ memcpy ( rsa_pubkey->exponent, exponent.data, exponent.len );
+ rsa_pubkey->exponent_len = exponent.len;
+
+ DBG2 ( "RSA modulus:\n" );
+ DBG2_HDA ( 0, rsa_pubkey->modulus, rsa_pubkey->modulus_len );
+ DBG2 ( "RSA exponent:\n" );
+ DBG2_HDA ( 0, rsa_pubkey->exponent, rsa_pubkey->exponent_len );
+
+ return 0;
+}
diff --git a/gpxe/src/dl360.gpxe b/gpxe/src/dl360.gpxe
new file mode 100644
index 00000000..237555b7
--- /dev/null
+++ b/gpxe/src/dl360.gpxe
@@ -0,0 +1,4 @@
+#!gpxe
+kernel http://www.zytor.com/dl360/pxelinux.0
+set filename http://www.zytor.com/dl360/pxelinux.0
+boot
diff --git a/gpxe/src/drivers/bitbash/i2c_bit.c b/gpxe/src/drivers/bitbash/i2c_bit.c
index a3af610b..b85057af 100644
--- a/gpxe/src/drivers/bitbash/i2c_bit.c
+++ b/gpxe/src/drivers/bitbash/i2c_bit.c
@@ -19,6 +19,7 @@
#include <stddef.h>
#include <stdint.h>
#include <errno.h>
+#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <gpxe/bitbash.h>
@@ -49,6 +50,7 @@ static void i2c_delay ( void ) {
* @v state New state of SCL
*/
static void setscl ( struct bit_basher *basher, int state ) {
+ DBG2 ( "%c", ( state ? '/' : '\\' ) );
write_bit ( basher, I2C_BIT_SCL, state );
i2c_delay();
}
@@ -60,6 +62,7 @@ static void setscl ( struct bit_basher *basher, int state ) {
* @v state New state of SDA
*/
static void setsda ( struct bit_basher *basher, int state ) {
+ DBG2 ( "%c", ( state ? '1' : '0' ) );
write_bit ( basher, I2C_BIT_SDA, state );
i2c_delay();
}
@@ -71,7 +74,10 @@ static void setsda ( struct bit_basher *basher, int state ) {
* @ret state State of SDA
*/
static int getsda ( struct bit_basher *basher ) {
- return read_bit ( basher, I2C_BIT_SDA );
+ int state;
+ state = read_bit ( basher, I2C_BIT_SDA );
+ DBG2 ( "%c", ( state ? '+' : '-' ) );
+ return state;
}
/**
@@ -137,15 +143,20 @@ static void i2c_stop ( struct bit_basher *basher ) {
*/
static int i2c_send_byte ( struct bit_basher *basher, uint8_t byte ) {
int i;
-
+ int ack;
+
/* Send byte */
+ DBG2 ( "[send %02x]", byte );
for ( i = 8 ; i ; i-- ) {
i2c_send_bit ( basher, byte & 0x80 );
byte <<= 1;
}
/* Check for acknowledgement from slave */
- return ( i2c_recv_bit ( basher ) == 0 ? 0 : -EIO );
+ ack = ( i2c_recv_bit ( basher ) == 0 );
+ DBG2 ( "%s", ( ack ? "[acked]" : "[not acked]" ) );
+
+ return ( ack ? 0 : -EIO );
}
/**
@@ -157,19 +168,20 @@ static int i2c_send_byte ( struct bit_basher *basher, uint8_t byte ) {
* Receives a byte via the I2C bus and sends NACK to the slave device.
*/
static uint8_t i2c_recv_byte ( struct bit_basher *basher ) {
- uint8_t value = 0;
+ uint8_t byte = 0;
int i;
/* Receive byte */
for ( i = 8 ; i ; i-- ) {
- value <<= 1;
- value |= ( i2c_recv_bit ( basher ) & 0x1 );
+ byte <<= 1;
+ byte |= ( i2c_recv_bit ( basher ) & 0x1 );
}
/* Send NACK */
i2c_send_bit ( basher, 1 );
- return value;
+ DBG2 ( "[rcvd %02x]", byte );
+ return byte;
}
/**
@@ -177,30 +189,29 @@ static uint8_t i2c_recv_byte ( struct bit_basher *basher ) {
*
* @v basher Bit-bashing interface
* @v i2cdev I2C device
+ * @v offset Starting offset within the device
* @v direction I2C_READ or I2C_WRITE
* @ret rc Return status code
*/
static int i2c_select ( struct bit_basher *basher, struct i2c_device *i2cdev,
- unsigned int direction ) {
+ unsigned int offset, unsigned int direction ) {
unsigned int address;
+ int shift;
+ unsigned int byte;
int rc;
i2c_start ( basher );
- /* First byte of the address */
- address = i2cdev->address;
- if ( i2cdev->tenbit ) {
- address |= I2C_TENBIT_ADDRESS;
- address >>= 8;
- }
- if ( ( rc = i2c_send_byte ( basher,
- ( ( address << 1 ) | direction ) ) ) != 0 )
- return rc;
+ /* Calculate address to appear on bus */
+ address = ( ( ( i2cdev->dev_addr |
+ ( offset >> ( 8 * i2cdev->word_addr_len ) ) ) << 1 )
+ | direction );
- /* Second byte of the address (10-bit addresses only) */
- if ( i2cdev->tenbit ) {
- if ( ( rc = i2c_send_byte ( basher,
- ( i2cdev->address & 0xff ) ) ) !=0)
+ /* Send address a byte at a time */
+ for ( shift = ( 8 * ( i2cdev->dev_addr_len - 1 ) ) ;
+ shift >= 0 ; shift -= 8 ) {
+ byte = ( ( address >> shift ) & 0xff );
+ if ( ( rc = i2c_send_byte ( basher, byte ) ) != 0 )
return rc;
}
@@ -208,6 +219,46 @@ static int i2c_select ( struct bit_basher *basher, struct i2c_device *i2cdev,
}
/**
+ * Reset I2C bus
+ *
+ * @v basher Bit-bashing interface
+ * @ret rc Return status code
+ *
+ * i2c devices often don't have a reset line, so even a reboot or
+ * system power cycle is sometimes not enough to bring them back to a
+ * known state.
+ */
+static int i2c_reset ( struct bit_basher *basher ) {
+ unsigned int i;
+ int sda;
+
+ /* Clock through several cycles, waiting for an opportunity to
+ * pull SDA low while SCL is high (which creates a start
+ * condition).
+ */
+ setscl ( basher, 0 );
+ setsda ( basher, 1 );
+ for ( i = 0 ; i < I2C_RESET_MAX_CYCLES ; i++ ) {
+ setscl ( basher, 1 );
+ sda = getsda ( basher );
+ if ( sda ) {
+ /* Now that the device will see a start, issue it */
+ i2c_start ( basher );
+ /* Stop the bus to leave it in a known good state */
+ i2c_stop ( basher );
+ DBGC ( basher, "I2CBIT %p reset after %d attempts\n",
+ basher, ( i + 1 ) );
+ return 0;
+ }
+ setscl ( basher, 0 );
+ }
+
+ DBGC ( basher, "I2CBIT %p could not reset after %d attempts\n",
+ basher, i );
+ return -ETIMEDOUT;
+}
+
+/**
* Read data from I2C device via bit-bashing interface
*
* @v i2c I2C interface
@@ -228,12 +279,14 @@ static int i2c_bit_read ( struct i2c_interface *i2c,
struct bit_basher *basher = &i2cbit->basher;
int rc = 0;
- DBG ( "Reading from I2C device %x: ", i2cdev->address );
+ DBGC ( basher, "I2CBIT %p reading from device %x: ",
+ basher, i2cdev->dev_addr );
- while ( 1 ) {
+ for ( ; ; data++, offset++ ) {
/* Select device for writing */
- if ( ( rc = i2c_select ( basher, i2cdev, I2C_WRITE ) ) != 0 )
+ if ( ( rc = i2c_select ( basher, i2cdev, offset,
+ I2C_WRITE ) ) != 0 )
break;
/* Abort at end of data */
@@ -241,19 +294,20 @@ static int i2c_bit_read ( struct i2c_interface *i2c,
break;
/* Select offset */
- if ( ( rc = i2c_send_byte ( basher, offset++ ) ) != 0 )
+ if ( ( rc = i2c_send_byte ( basher, offset ) ) != 0 )
break;
/* Select device for reading */
- if ( ( rc = i2c_select ( basher, i2cdev, I2C_READ ) ) != 0 )
+ if ( ( rc = i2c_select ( basher, i2cdev, offset,
+ I2C_READ ) ) != 0 )
break;
/* Read byte */
- *data++ = i2c_recv_byte ( basher );
- DBG ( "%02x ", *(data - 1) );
+ *data = i2c_recv_byte ( basher );
+ DBGC ( basher, "%02x ", *data );
}
- DBG ( "%s\n", ( rc ? "failed" : "" ) );
+ DBGC ( basher, "%s\n", ( rc ? "failed" : "" ) );
i2c_stop ( basher );
return rc;
}
@@ -279,12 +333,14 @@ static int i2c_bit_write ( struct i2c_interface *i2c,
struct bit_basher *basher = &i2cbit->basher;
int rc = 0;
- DBG ( "Writing to I2C device %x: ", i2cdev->address );
+ DBGC ( basher, "I2CBIT %p writing to device %x: ",
+ basher, i2cdev->dev_addr );
- while ( 1 ) {
+ for ( ; ; data++, offset++ ) {
/* Select device for writing */
- if ( ( rc = i2c_select ( basher, i2cdev, I2C_WRITE ) ) != 0 )
+ if ( ( rc = i2c_select ( basher, i2cdev, offset,
+ I2C_WRITE ) ) != 0 )
break;
/* Abort at end of data */
@@ -292,16 +348,16 @@ static int i2c_bit_write ( struct i2c_interface *i2c,
break;
/* Select offset */
- if ( ( rc = i2c_send_byte ( basher, offset++ ) ) != 0 )
+ if ( ( rc = i2c_send_byte ( basher, offset ) ) != 0 )
break;
/* Write data to device */
- DBG ( "%02x ", *data );
- if ( ( rc = i2c_send_byte ( basher, *data++ ) ) != 0 )
+ DBGC ( basher, "%02x ", *data );
+ if ( ( rc = i2c_send_byte ( basher, *data ) ) != 0 )
break;
}
- DBG ( "%s\n", ( rc ? "failed" : "" ) );
+ DBGC ( basher, "%s\n", ( rc ? "failed" : "" ) );
i2c_stop ( basher );
return rc;
}
@@ -310,13 +366,26 @@ static int i2c_bit_write ( struct i2c_interface *i2c,
* Initialise I2C bit-bashing interface
*
* @v i2cbit I2C bit-bashing interface
+ * @v bash_op Bit-basher operations
*/
-void init_i2c_bit_basher ( struct i2c_bit_basher *i2cbit ) {
+int init_i2c_bit_basher ( struct i2c_bit_basher *i2cbit,
+ struct bit_basher_operations *bash_op ) {
struct bit_basher *basher = &i2cbit->basher;
-
+ int rc;
+
+ /* Initialise data structures */
+ basher->op = bash_op;
assert ( basher->op->read != NULL );
assert ( basher->op->write != NULL );
i2cbit->i2c.read = i2c_bit_read;
i2cbit->i2c.write = i2c_bit_write;
- i2c_stop ( basher );
+
+ /* Reset I2C bus */
+ if ( ( rc = i2c_reset ( basher ) ) != 0 ) {
+ DBGC ( basher, "I2CBIT %p could not reset I2C bus: %s\n",
+ basher, strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
}
diff --git a/gpxe/src/drivers/block/ata.c b/gpxe/src/drivers/block/ata.c
index 555a5f6e..c21d2f65 100644
--- a/gpxe/src/drivers/block/ata.c
+++ b/gpxe/src/drivers/block/ata.c
@@ -139,6 +139,11 @@ static int ata_identify ( struct block_device *blockdev ) {
return 0;
}
+static struct block_device_operations ata_operations = {
+ .read = ata_read,
+ .write = ata_write
+};
+
/**
* Initialise ATA device
*
@@ -153,7 +158,6 @@ static int ata_identify ( struct block_device *blockdev ) {
*/
int init_atadev ( struct ata_device *ata ) {
/** Fill in read and write methods, and get device capacity */
- ata->blockdev.read = ata_read;
- ata->blockdev.write = ata_write;
+ ata->blockdev.op = &ata_operations;
return ata_identify ( &ata->blockdev );
}
diff --git a/gpxe/src/drivers/block/ramdisk.c b/gpxe/src/drivers/block/ramdisk.c
index b5324bf1..50911994 100644
--- a/gpxe/src/drivers/block/ramdisk.c
+++ b/gpxe/src/drivers/block/ramdisk.c
@@ -75,6 +75,11 @@ static int ramdisk_write ( struct block_device *blockdev, uint64_t block,
return 0;
}
+static struct block_device_operations ramdisk_operations = {
+ .read = ramdisk_read,
+ .write = ramdisk_write
+};
+
int init_ramdisk ( struct ramdisk *ramdisk, userptr_t data, size_t len,
unsigned int blksize ) {
@@ -82,8 +87,7 @@ int init_ramdisk ( struct ramdisk *ramdisk, userptr_t data, size_t len,
blksize = 512;
ramdisk->data = data;
- ramdisk->blockdev.read = ramdisk_read;
- ramdisk->blockdev.write = ramdisk_write;
+ ramdisk->blockdev.op = &ramdisk_operations;
ramdisk->blockdev.blksize = blksize;
ramdisk->blockdev.blocks = ( len / blksize );
diff --git a/gpxe/src/drivers/block/scsi.c b/gpxe/src/drivers/block/scsi.c
index 9651583a..71d22040 100644
--- a/gpxe/src/drivers/block/scsi.c
+++ b/gpxe/src/drivers/block/scsi.c
@@ -29,6 +29,13 @@
*
*/
+/** Maximum number of dummy "read capacity (10)" operations
+ *
+ * These are issued at connection setup to draw out various useless
+ * power-on messages.
+ */
+#define SCSI_MAX_DUMMY_READ_CAP 10
+
static inline __attribute__ (( always_inline )) struct scsi_device *
block_to_scsi ( struct block_device *blockdev ) {
return container_of ( blockdev, struct scsi_device, blockdev );
@@ -228,6 +235,16 @@ static int scsi_read_capacity_16 ( struct block_device *blockdev ) {
return 0;
}
+static struct block_device_operations scsi_operations_16 = {
+ .read = scsi_read_16,
+ .write = scsi_write_16,
+};
+
+static struct block_device_operations scsi_operations_10 = {
+ .read = scsi_read_10,
+ .write = scsi_write_10,
+};
+
/**
* Initialise SCSI device
*
@@ -240,18 +257,24 @@ static int scsi_read_capacity_16 ( struct block_device *blockdev ) {
* CAPACITY call to determine the block size and total device size.
*/
int init_scsidev ( struct scsi_device *scsi ) {
+ unsigned int i;
int rc;
- /* Issue a theoretically extraneous READ CAPACITY (10)
- * command, solely in order to draw out the "CHECK CONDITION
- * (power-on occurred)" that some dumb targets insist on
- * sending as an error at start of day.
+ /* Issue some theoretically extraneous READ CAPACITY (10)
+ * commands, solely in order to draw out the "CHECK CONDITION
+ * (power-on occurred)", "CHECK CONDITION (reported LUNs data
+ * has changed)" etc. that some dumb targets insist on sending
+ * as an error at start of day. The precise command that we
+ * use is unimportant; we just need to provide the target with
+ * an opportunity to send its responses.
*/
- scsi_read_capacity_10 ( &scsi->blockdev );
+ for ( i = 0 ; i < SCSI_MAX_DUMMY_READ_CAP ; i++ ) {
+ if ( ( rc = scsi_read_capacity_10 ( &scsi->blockdev ) ) == 0 )
+ break;
+ }
/* Try READ CAPACITY (10), which is a mandatory command, first. */
- scsi->blockdev.read = scsi_read_10;
- scsi->blockdev.write = scsi_write_10;
+ scsi->blockdev.op = &scsi_operations_10;
if ( ( rc = scsi_read_capacity_10 ( &scsi->blockdev ) ) != 0 )
return rc;
@@ -261,8 +284,7 @@ int init_scsidev ( struct scsi_device *scsi ) {
* mandatory, so we can't just use it straight off.
*/
if ( scsi->blockdev.blocks == 0 ) {
- scsi->blockdev.read = scsi_read_16;
- scsi->blockdev.write = scsi_write_16;
+ scsi->blockdev.op = &scsi_operations_16;
if ( ( rc = scsi_read_capacity_16 ( &scsi->blockdev ) ) != 0 )
return rc;
}
diff --git a/gpxe/src/drivers/bus/eisa.c b/gpxe/src/drivers/bus/eisa.c
index ee03df3a..d9e42359 100644
--- a/gpxe/src/drivers/bus/eisa.c
+++ b/gpxe/src/drivers/bus/eisa.c
@@ -3,7 +3,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
-#include <io.h>
+#include <gpxe/io.h>
#include <unistd.h>
#include <gpxe/eisa.h>
diff --git a/gpxe/src/drivers/bus/isa.c b/gpxe/src/drivers/bus/isa.c
index a4105fd0..fa5def54 100644
--- a/gpxe/src/drivers/bus/isa.c
+++ b/gpxe/src/drivers/bus/isa.c
@@ -3,7 +3,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
-#include <io.h>
+#include <gpxe/io.h>
#include <gpxe/isa.h>
/*
@@ -49,9 +49,9 @@ static isa_probe_addr_t isa_extra_probe_addrs[] = {
(driver)->probe_addrs[(ioidx)] )
static struct isa_driver isa_drivers[0]
- __table_start ( struct isa_driver, isa_driver );
+ __table_start ( struct isa_driver, isa_drivers );
static struct isa_driver isa_drivers_end[0]
- __table_end ( struct isa_driver, isa_driver );
+ __table_end ( struct isa_driver, isa_drivers );
static void isabus_remove ( struct root_device *rootdev );
diff --git a/gpxe/src/drivers/bus/isapnp.c b/gpxe/src/drivers/bus/isapnp.c
index f4968eb1..8f812df8 100644
--- a/gpxe/src/drivers/bus/isapnp.c
+++ b/gpxe/src/drivers/bus/isapnp.c
@@ -60,7 +60,7 @@
#include <string.h>
#include <stdio.h>
#include <errno.h>
-#include <io.h>
+#include <gpxe/io.h>
#include <unistd.h>
#include <gpxe/isapnp.h>
@@ -84,7 +84,7 @@ static void isapnpbus_remove ( struct root_device *rootdev );
*
*/
-#define ISAPNP_CARD_ID_FMT "ID %04x:%04x (\"%s\") serial %lx"
+#define ISAPNP_CARD_ID_FMT "ID %04x:%04x (\"%s\") serial %x"
#define ISAPNP_CARD_ID_DATA(identifier) \
(identifier)->vendor_id, (identifier)->prod_id, \
isa_id_string ( (identifier)->vendor_id, (identifier)->prod_id ), \
diff --git a/gpxe/src/drivers/bus/mca.c b/gpxe/src/drivers/bus/mca.c
index eb7b7e39..e9233813 100644
--- a/gpxe/src/drivers/bus/mca.c
+++ b/gpxe/src/drivers/bus/mca.c
@@ -10,7 +10,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
-#include <io.h>
+#include <gpxe/io.h>
#include <gpxe/mca.h>
static struct mca_driver mca_drivers[0]
diff --git a/gpxe/src/drivers/bus/pci.c b/gpxe/src/drivers/bus/pci.c
index 967441ac..2dc9d43a 100644
--- a/gpxe/src/drivers/bus/pci.c
+++ b/gpxe/src/drivers/bus/pci.c
@@ -67,7 +67,7 @@ static unsigned long pci_bar ( struct pci_device *pci, unsigned int reg ) {
if ( sizeof ( unsigned long ) > sizeof ( uint32_t ) ) {
return ( ( ( uint64_t ) high << 32 ) | low );
} else {
- DBG ( "Unhandled 64-bit BAR %08lx%08lx\n",
+ DBG ( "Unhandled 64-bit BAR %08x%08x\n",
high, low );
return PCI_BASE_ADDRESS_MEM_TYPE_64;
}
@@ -148,7 +148,8 @@ void adjust_pci_device ( struct pci_device *pci ) {
unsigned char pci_latency;
pci_read_config_word ( pci, PCI_COMMAND, &pci_command );
- new_command = pci_command | PCI_COMMAND_MASTER | PCI_COMMAND_IO;
+ new_command = ( pci_command | PCI_COMMAND_MASTER |
+ PCI_COMMAND_MEM | PCI_COMMAND_IO );
if ( pci_command != new_command ) {
DBG ( "PCI BIOS has not enabled device %02x:%02x.%x! "
"Updating PCI command %04x->%04x\n", pci->bus,
diff --git a/gpxe/src/drivers/bus/virtio-pci.c b/gpxe/src/drivers/bus/virtio-pci.c
new file mode 100644
index 00000000..34acce2d
--- /dev/null
+++ b/gpxe/src/drivers/bus/virtio-pci.c
@@ -0,0 +1,64 @@
+/* virtio-pci.c - pci interface for virtio interface
+ *
+ * (c) Copyright 2008 Bull S.A.S.
+ *
+ * Author: Laurent Vivier <Laurent.Vivier@bull.net>
+ *
+ * some parts from Linux Virtio PCI driver
+ *
+ * Copyright IBM Corp. 2007
+ * Authors: Anthony Liguori <aliguori@us.ibm.com>
+ *
+ */
+
+#include "etherboot.h"
+#include "gpxe/io.h"
+#include "gpxe/virtio-ring.h"
+#include "gpxe/virtio-pci.h"
+
+int vp_find_vq(unsigned int ioaddr, int queue_index,
+ struct vring_virtqueue *vq)
+{
+ struct vring * vr = &vq->vring;
+ u16 num;
+
+ /* select the queue */
+
+ outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_SEL);
+
+ /* check if the queue is available */
+
+ num = inw(ioaddr + VIRTIO_PCI_QUEUE_NUM);
+ if (!num) {
+ printf("ERROR: queue size is 0\n");
+ return -1;
+ }
+
+ if (num > MAX_QUEUE_NUM) {
+ printf("ERROR: queue size %d > %d\n", num, MAX_QUEUE_NUM);
+ return -1;
+ }
+
+ /* check if the queue is already active */
+
+ if (inl(ioaddr + VIRTIO_PCI_QUEUE_PFN)) {
+ printf("ERROR: queue already active\n");
+ return -1;
+ }
+
+ vq->queue_index = queue_index;
+
+ /* initialize the queue */
+
+ vring_init(vr, num, (unsigned char*)&vq->queue);
+
+ /* activate the queue
+ *
+ * NOTE: vr->desc is initialized by vring_init()
+ */
+
+ outl((unsigned long)virt_to_phys(vr->desc) >> PAGE_SHIFT,
+ ioaddr + VIRTIO_PCI_QUEUE_PFN);
+
+ return num;
+}
diff --git a/gpxe/src/drivers/bus/virtio-ring.c b/gpxe/src/drivers/bus/virtio-ring.c
new file mode 100644
index 00000000..6415f626
--- /dev/null
+++ b/gpxe/src/drivers/bus/virtio-ring.c
@@ -0,0 +1,134 @@
+/* virtio-pci.c - virtio ring management
+ *
+ * (c) Copyright 2008 Bull S.A.S.
+ *
+ * Author: Laurent Vivier <Laurent.Vivier@bull.net>
+ *
+ * some parts from Linux Virtio Ring
+ *
+ * Copyright Rusty Russell IBM Corporation 2007
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ *
+ */
+
+#include "etherboot.h"
+#include "gpxe/io.h"
+#include "gpxe/virtio-ring.h"
+#include "gpxe/virtio-pci.h"
+
+#define BUG() do { \
+ printf("BUG: failure at %s:%d/%s()!\n", \
+ __FILE__, __LINE__, __FUNCTION__); \
+ while(1); \
+} while (0)
+#define BUG_ON(condition) do { if (condition) BUG(); } while (0)
+
+/*
+ * vring_free
+ *
+ * put at the begin of the free list the current desc[head]
+ */
+
+void vring_detach(struct vring_virtqueue *vq, unsigned int head)
+{
+ struct vring *vr = &vq->vring;
+ unsigned int i;
+
+ /* find end of given descriptor */
+
+ i = head;
+ while (vr->desc[i].flags & VRING_DESC_F_NEXT)
+ i = vr->desc[i].next;
+
+ /* link it with free list and point to it */
+
+ vr->desc[i].next = vq->free_head;
+ wmb();
+ vq->free_head = head;
+}
+
+/*
+ * vring_get_buf
+ *
+ * get a buffer from the used list
+ *
+ */
+
+int vring_get_buf(struct vring_virtqueue *vq, unsigned int *len)
+{
+ struct vring *vr = &vq->vring;
+ struct vring_used_elem *elem;
+ u32 id;
+ int ret;
+
+ BUG_ON(!vring_more_used(vq));
+
+ elem = &vr->used->ring[vq->last_used_idx % vr->num];
+ wmb();
+ id = elem->id;
+ if (len != NULL)
+ *len = elem->len;
+
+ ret = vq->vdata[id];
+
+ vring_detach(vq, id);
+
+ vq->last_used_idx++;
+
+ return ret;
+}
+
+void vring_add_buf(struct vring_virtqueue *vq,
+ struct vring_list list[],
+ unsigned int out, unsigned int in,
+ int index, int num_added)
+{
+ struct vring *vr = &vq->vring;
+ int i, avail, head, prev;
+
+ BUG_ON(out + in == 0);
+
+ prev = 0;
+ head = vq->free_head;
+ for (i = head; out; i = vr->desc[i].next, out--) {
+
+ vr->desc[i].flags = VRING_DESC_F_NEXT;
+ vr->desc[i].addr = (u64)virt_to_phys(list->addr);
+ vr->desc[i].len = list->length;
+ prev = i;
+ list++;
+ }
+ for ( ; in; i = vr->desc[i].next, in--) {
+
+ vr->desc[i].flags = VRING_DESC_F_NEXT|VRING_DESC_F_WRITE;
+ vr->desc[i].addr = (u64)virt_to_phys(list->addr);
+ vr->desc[i].len = list->length;
+ prev = i;
+ list++;
+ }
+ vr->desc[prev].flags &= ~VRING_DESC_F_NEXT;
+
+ vq->free_head = i;
+
+ vq->vdata[head] = index;
+
+ avail = (vr->avail->idx + num_added) % vr->num;
+ vr->avail->ring[avail] = head;
+ wmb();
+}
+
+void vring_kick(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added)
+{
+ struct vring *vr = &vq->vring;
+
+ wmb();
+ vr->avail->idx += num_added;
+
+ mb();
+ if (!(vr->used->flags & VRING_USED_F_NO_NOTIFY))
+ vp_notify(ioaddr, vq->queue_index);
+}
+
diff --git a/gpxe/src/drivers/infiniband/arbel.c b/gpxe/src/drivers/infiniband/arbel.c
index 1b55131b..1756a6e2 100644
--- a/gpxe/src/drivers/infiniband/arbel.c
+++ b/gpxe/src/drivers/infiniband/arbel.c
@@ -27,12 +27,14 @@
#include <unistd.h>
#include <errno.h>
#include <byteswap.h>
+#include <gpxe/io.h>
#include <gpxe/pci.h>
#include <gpxe/malloc.h>
#include <gpxe/umalloc.h>
#include <gpxe/iobuf.h>
#include <gpxe/netdevice.h>
#include <gpxe/infiniband.h>
+#include <gpxe/ib_smc.h>
#include "arbel.h"
/**
@@ -484,6 +486,50 @@ arbel_cmd_map_fa ( struct arbel *arbel,
/***************************************************************************
*
+ * MAD operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Issue management datagram
+ *
+ * @v ibdev Infiniband device
+ * @v mad Management datagram
+ * @ret rc Return status code
+ */
+static int arbel_mad ( struct ib_device *ibdev, union ib_mad *mad ) {
+ struct arbel *arbel = ib_get_drvdata ( ibdev );
+ union arbelprm_mad mad_ifc;
+ int rc;
+
+ linker_assert ( sizeof ( *mad ) == sizeof ( mad_ifc.mad ),
+ mad_size_mismatch );
+
+ /* Copy in request packet */
+ memcpy ( &mad_ifc.mad, mad, sizeof ( mad_ifc.mad ) );
+
+ /* Issue MAD */
+ if ( ( rc = arbel_cmd_mad_ifc ( arbel, ibdev->port,
+ &mad_ifc ) ) != 0 ) {
+ DBGC ( arbel, "Arbel %p could not issue MAD IFC: %s\n",
+ arbel, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Copy out reply packet */
+ memcpy ( mad, &mad_ifc.mad, sizeof ( *mad ) );
+
+ if ( mad->hdr.status != 0 ) {
+ DBGC ( arbel, "Arbel %p MAD IFC status %04x\n",
+ arbel, ntohs ( mad->hdr.status ) );
+ return -EIO;
+ }
+ return 0;
+}
+
+/***************************************************************************
+ *
* Completion queue operations
*
***************************************************************************
@@ -947,7 +993,7 @@ static void arbel_ring_doorbell ( struct arbel *arbel,
union arbelprm_doorbell_register *db_reg,
unsigned int offset ) {
- DBGC2 ( arbel, "Arbel %p ringing doorbell %08lx:%08lx at %lx\n",
+ DBGC2 ( arbel, "Arbel %p ringing doorbell %08x:%08x at %lx\n",
arbel, db_reg->dword[0], db_reg->dword[1],
virt_to_phys ( arbel->uar + offset ) );
@@ -1006,7 +1052,7 @@ static int arbel_post_send ( struct ib_device *ibdev,
ud_address_vector.pd, ARBEL_GLOBAL_PD,
ud_address_vector.port_number, ibdev->port );
MLX_FILL_2 ( &wqe->ud, 1,
- ud_address_vector.rlid, av->dlid,
+ ud_address_vector.rlid, av->lid,
ud_address_vector.g, av->gid_present );
MLX_FILL_2 ( &wqe->ud, 2,
ud_address_vector.max_stat_rate,
@@ -1015,7 +1061,7 @@ static int arbel_post_send ( struct ib_device *ibdev,
MLX_FILL_1 ( &wqe->ud, 3, ud_address_vector.sl, av->sl );
gid = ( av->gid_present ? &av->gid : &arbel_no_gid );
memcpy ( &wqe->ud.u.dwords[4], gid, sizeof ( *gid ) );
- MLX_FILL_1 ( &wqe->ud, 8, destination_qp, av->dest_qp );
+ MLX_FILL_1 ( &wqe->ud, 8, destination_qp, av->qpn );
MLX_FILL_1 ( &wqe->ud, 9, q_key, av->qkey );
MLX_FILL_1 ( &wqe->data[0], 0, byte_count, iob_len ( iobuf ) );
MLX_FILL_1 ( &wqe->data[0], 1, l_key, arbel->reserved_lkey );
@@ -1106,17 +1152,12 @@ static int arbel_post_recv ( struct ib_device *ibdev,
* @v ibdev Infiniband device
* @v cq Completion queue
* @v cqe Hardware completion queue entry
- * @v complete_send Send completion handler
- * @v complete_recv Receive completion handler
* @ret rc Return status code
*/
static int arbel_complete ( struct ib_device *ibdev,
struct ib_completion_queue *cq,
- union arbelprm_completion_entry *cqe,
- ib_completer_t complete_send,
- ib_completer_t complete_recv ) {
+ union arbelprm_completion_entry *cqe ) {
struct arbel *arbel = ib_get_drvdata ( ibdev );
- struct ib_completion completion;
struct ib_work_queue *wq;
struct ib_queue_pair *qp;
struct arbel_queue_pair *arbel_qp;
@@ -1124,16 +1165,17 @@ static int arbel_complete ( struct ib_device *ibdev,
struct arbel_recv_work_queue *arbel_recv_wq;
struct arbelprm_recv_wqe *recv_wqe;
struct io_buffer *iobuf;
- ib_completer_t complete;
+ struct ib_address_vector av;
+ struct ib_global_route_header *grh;
unsigned int opcode;
unsigned long qpn;
int is_send;
unsigned long wqe_adr;
unsigned int wqe_idx;
+ size_t len;
int rc = 0;
/* Parse completion */
- memset ( &completion, 0, sizeof ( completion ) );
qpn = MLX_GET ( &cqe->normal, my_qpn );
is_send = MLX_GET ( &cqe->normal, s );
wqe_adr = ( MLX_GET ( &cqe->normal, wqe_adr ) << 6 );
@@ -1141,9 +1183,8 @@ static int arbel_complete ( struct ib_device *ibdev,
if ( opcode >= ARBEL_OPCODE_RECV_ERROR ) {
/* "s" field is not valid for error opcodes */
is_send = ( opcode == ARBEL_OPCODE_SEND_ERROR );
- completion.syndrome = MLX_GET ( &cqe->error, syndrome );
- DBGC ( arbel, "Arbel %p CPN %lx syndrome %x vendor %lx\n",
- arbel, cq->cqn, completion.syndrome,
+ DBGC ( arbel, "Arbel %p CPN %lx syndrome %x vendor %x\n",
+ arbel, cq->cqn, MLX_GET ( &cqe->error, syndrome ),
MLX_GET ( &cqe->error, vendor_code ) );
rc = -EIO;
/* Don't return immediately; propagate error to completer */
@@ -1181,9 +1222,12 @@ static int arbel_complete ( struct ib_device *ibdev,
}
wq->iobufs[wqe_idx] = NULL;
- /* Fill in length for received packets */
- if ( ! is_send ) {
- completion.len = MLX_GET ( &cqe->normal, byte_cnt );
+ if ( is_send ) {
+ /* Hand off to completion handler */
+ ib_complete_send ( ibdev, qp, iobuf, rc );
+ } else {
+ /* Set received length */
+ len = MLX_GET ( &cqe->normal, byte_cnt );
recv_wqe = &arbel_recv_wq->wqe[wqe_idx].recv;
assert ( MLX_GET ( &recv_wqe->data[0], local_address_l ) ==
virt_to_bus ( iobuf->data ) );
@@ -1192,18 +1236,22 @@ static int arbel_complete ( struct ib_device *ibdev,
MLX_FILL_1 ( &recv_wqe->data[0], 0, byte_count, 0 );
MLX_FILL_1 ( &recv_wqe->data[0], 1,
l_key, ARBEL_INVALID_LKEY );
- if ( completion.len > iob_tailroom ( iobuf ) ) {
- DBGC ( arbel, "Arbel %p CQN %lx QPN %lx IDX %x "
- "overlength received packet length %zd\n",
- arbel, cq->cqn, qpn, wqe_idx, completion.len );
- return -EIO;
- }
+ assert ( len <= iob_tailroom ( iobuf ) );
+ iob_put ( iobuf, len );
+ assert ( iob_len ( iobuf ) >= sizeof ( *grh ) );
+ grh = iobuf->data;
+ iob_pull ( iobuf, sizeof ( *grh ) );
+ /* Construct address vector */
+ memset ( &av, 0, sizeof ( av ) );
+ av.qpn = MLX_GET ( &cqe->normal, rqpn );
+ av.lid = MLX_GET ( &cqe->normal, rlid );
+ av.sl = MLX_GET ( &cqe->normal, sl );
+ av.gid_present = MLX_GET ( &cqe->normal, g );
+ memcpy ( &av.gid, &grh->sgid, sizeof ( av.gid ) );
+ /* Hand off to completion handler */
+ ib_complete_recv ( ibdev, qp, &av, iobuf, rc );
}
- /* Pass off to caller's completion handler */
- complete = ( is_send ? complete_send : complete_recv );
- complete ( ibdev, qp, &completion, iobuf );
-
return rc;
}
@@ -1212,13 +1260,9 @@ static int arbel_complete ( struct ib_device *ibdev,
*
* @v ibdev Infiniband device
* @v cq Completion queue
- * @v complete_send Send completion handler
- * @v complete_recv Receive completion handler
*/
static void arbel_poll_cq ( struct ib_device *ibdev,
- struct ib_completion_queue *cq,
- ib_completer_t complete_send,
- ib_completer_t complete_recv ) {
+ struct ib_completion_queue *cq ) {
struct arbel *arbel = ib_get_drvdata ( ibdev );
struct arbel_completion_queue *arbel_cq = ib_cq_get_drvdata ( cq );
struct arbelprm_cq_ci_db_record *ci_db_rec;
@@ -1236,8 +1280,7 @@ static void arbel_poll_cq ( struct ib_device *ibdev,
}
/* Handle completion */
- if ( ( rc = arbel_complete ( ibdev, cq, cqe, complete_send,
- complete_recv ) ) != 0 ) {
+ if ( ( rc = arbel_complete ( ibdev, cq, cqe ) ) != 0 ) {
DBGC ( arbel, "Arbel %p failed to complete: %s\n",
arbel, strerror ( rc ) );
DBGC_HD ( arbel, cqe, sizeof ( *cqe ) );
@@ -1397,6 +1440,9 @@ static void arbel_event_port_state_change ( struct arbel *arbel,
return;
}
+ /* Update MAD parameters */
+ ib_smc_update ( arbel->ibdev[port], arbel_mad );
+
/* Notify Infiniband core of link state change */
ib_link_state_changed ( arbel->ibdev[port] );
}
@@ -1447,7 +1493,7 @@ static void arbel_poll_eq ( struct ib_device *ibdev ) {
/* Ring doorbell */
MLX_FILL_1 ( &db_reg.ci, 0, ci, arbel_eq->next_idx );
- DBGCP ( arbel, "Ringing doorbell %08lx with %08lx\n",
+ DBGCP ( arbel, "Ringing doorbell %08lx with %08x\n",
virt_to_phys ( arbel_eq->doorbell ),
db_reg.dword[0] );
writel ( db_reg.dword[0], arbel_eq->doorbell );
@@ -1486,6 +1532,9 @@ static int arbel_open ( struct ib_device *ibdev ) {
return rc;
}
+ /* Update MAD parameters */
+ ib_smc_update ( ibdev, arbel_mad );
+
return 0;
}
@@ -1601,51 +1650,6 @@ static void arbel_mcast_detach ( struct ib_device *ibdev,
}
}
-/***************************************************************************
- *
- * MAD operations
- *
- ***************************************************************************
- */
-
-/**
- * Issue management datagram
- *
- * @v ibdev Infiniband device
- * @v mad Management datagram
- * @v len Length of management datagram
- * @ret rc Return status code
- */
-static int arbel_mad ( struct ib_device *ibdev, struct ib_mad_hdr *mad,
- size_t len ) {
- struct arbel *arbel = ib_get_drvdata ( ibdev );
- union arbelprm_mad mad_ifc;
- int rc;
-
- /* Copy in request packet */
- memset ( &mad_ifc, 0, sizeof ( mad_ifc ) );
- assert ( len <= sizeof ( mad_ifc.mad ) );
- memcpy ( &mad_ifc.mad, mad, len );
-
- /* Issue MAD */
- if ( ( rc = arbel_cmd_mad_ifc ( arbel, ibdev->port,
- &mad_ifc ) ) != 0 ) {
- DBGC ( arbel, "Arbel %p could not issue MAD IFC: %s\n",
- arbel, strerror ( rc ) );
- return rc;
- }
-
- /* Copy out reply packet */
- memcpy ( mad, &mad_ifc.mad, len );
-
- if ( mad->status != 0 ) {
- DBGC ( arbel, "Arbel %p MAD IFC status %04x\n",
- arbel, ntohs ( mad->status ) );
- return -EIO;
- }
- return 0;
-}
-
/** Arbel Infiniband operations */
static struct ib_device_operations arbel_ib_operations = {
.create_cq = arbel_create_cq,
@@ -1661,7 +1665,6 @@ static struct ib_device_operations arbel_ib_operations = {
.close = arbel_close,
.mcast_attach = arbel_mcast_attach,
.mcast_detach = arbel_mcast_detach,
- .mad = arbel_mad,
};
/***************************************************************************
@@ -1694,7 +1697,7 @@ static int arbel_start_firmware ( struct arbel *arbel ) {
arbel, strerror ( rc ) );
goto err_query_fw;
}
- DBGC ( arbel, "Arbel %p firmware version %ld.%ld.%ld\n", arbel,
+ DBGC ( arbel, "Arbel %p firmware version %d.%d.%d\n", arbel,
MLX_GET ( &fw, fw_rev_major ), MLX_GET ( &fw, fw_rev_minor ),
MLX_GET ( &fw, fw_rev_subminor ) );
fw_pages = MLX_GET ( &fw, fw_pages );
@@ -2172,6 +2175,10 @@ static int arbel_probe ( struct pci_device *pci,
if ( ( rc = arbel_create_eq ( arbel ) ) != 0 )
goto err_create_eq;
+ /* Update MAD parameters */
+ for ( i = 0 ; i < ARBEL_NUM_PORTS ; i++ )
+ ib_smc_update ( arbel->ibdev[i], arbel_mad );
+
/* Register Infiniband devices */
for ( i = 0 ; i < ARBEL_NUM_PORTS ; i++ ) {
if ( ( rc = register_ibdev ( arbel->ibdev[i] ) ) != 0 ) {
diff --git a/gpxe/src/drivers/infiniband/hermon.c b/gpxe/src/drivers/infiniband/hermon.c
index 3ca60033..40add28a 100644
--- a/gpxe/src/drivers/infiniband/hermon.c
+++ b/gpxe/src/drivers/infiniband/hermon.c
@@ -25,12 +25,14 @@
#include <unistd.h>
#include <errno.h>
#include <byteswap.h>
+#include <gpxe/io.h>
#include <gpxe/pci.h>
#include <gpxe/malloc.h>
#include <gpxe/umalloc.h>
#include <gpxe/iobuf.h>
#include <gpxe/netdevice.h>
#include <gpxe/infiniband.h>
+#include <gpxe/ib_smc.h>
#include "hermon.h"
/**
@@ -610,6 +612,50 @@ static void hermon_free_mtt ( struct hermon *hermon,
/***************************************************************************
*
+ * MAD operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Issue management datagram
+ *
+ * @v ibdev Infiniband device
+ * @v mad Management datagram
+ * @ret rc Return status code
+ */
+static int hermon_mad ( struct ib_device *ibdev, union ib_mad *mad ) {
+ struct hermon *hermon = ib_get_drvdata ( ibdev );
+ union hermonprm_mad mad_ifc;
+ int rc;
+
+ linker_assert ( sizeof ( *mad ) == sizeof ( mad_ifc.mad ),
+ mad_size_mismatch );
+
+ /* Copy in request packet */
+ memcpy ( &mad_ifc.mad, mad, sizeof ( mad_ifc.mad ) );
+
+ /* Issue MAD */
+ if ( ( rc = hermon_cmd_mad_ifc ( hermon, ibdev->port,
+ &mad_ifc ) ) != 0 ) {
+ DBGC ( hermon, "Hermon %p could not issue MAD IFC: %s\n",
+ hermon, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Copy out reply packet */
+ memcpy ( mad, &mad_ifc.mad, sizeof ( *mad ) );
+
+ if ( mad->hdr.status != 0 ) {
+ DBGC ( hermon, "Hermon %p MAD IFC status %04x\n",
+ hermon, ntohs ( mad->hdr.status ) );
+ return -EIO;
+ }
+ return 0;
+}
+
+/***************************************************************************
+ *
* Completion queue operations
*
***************************************************************************
@@ -1015,7 +1061,7 @@ static int hermon_post_send ( struct ib_device *ibdev,
ud_address_vector.pd, HERMON_GLOBAL_PD,
ud_address_vector.port_number, ibdev->port );
MLX_FILL_2 ( &wqe->ud, 1,
- ud_address_vector.rlid, av->dlid,
+ ud_address_vector.rlid, av->lid,
ud_address_vector.g, av->gid_present );
MLX_FILL_1 ( &wqe->ud, 2,
ud_address_vector.max_stat_rate,
@@ -1024,7 +1070,7 @@ static int hermon_post_send ( struct ib_device *ibdev,
MLX_FILL_1 ( &wqe->ud, 3, ud_address_vector.sl, av->sl );
gid = ( av->gid_present ? &av->gid : &hermon_no_gid );
memcpy ( &wqe->ud.u.dwords[4], gid, sizeof ( *gid ) );
- MLX_FILL_1 ( &wqe->ud, 8, destination_qp, av->dest_qp );
+ MLX_FILL_1 ( &wqe->ud, 8, destination_qp, av->qpn );
MLX_FILL_1 ( &wqe->ud, 9, q_key, av->qkey );
MLX_FILL_1 ( &wqe->data[0], 0, byte_count, iob_len ( iobuf ) );
MLX_FILL_1 ( &wqe->data[0], 1, l_key, hermon->reserved_lkey );
@@ -1041,7 +1087,7 @@ static int hermon_post_send ( struct ib_device *ibdev,
/* Ring doorbell register */
MLX_FILL_1 ( &db_reg.send, 0, qn, qp->qpn );
- DBGCP ( hermon, "Ringing doorbell %08lx with %08lx\n",
+ DBGCP ( hermon, "Ringing doorbell %08lx with %08x\n",
virt_to_phys ( hermon_send_wq->doorbell ), db_reg.dword[0] );
writel ( db_reg.dword[0], ( hermon_send_wq->doorbell ) );
@@ -1101,39 +1147,34 @@ static int hermon_post_recv ( struct ib_device *ibdev,
* @v ibdev Infiniband device
* @v cq Completion queue
* @v cqe Hardware completion queue entry
- * @v complete_send Send completion handler
- * @v complete_recv Receive completion handler
* @ret rc Return status code
*/
static int hermon_complete ( struct ib_device *ibdev,
struct ib_completion_queue *cq,
- union hermonprm_completion_entry *cqe,
- ib_completer_t complete_send,
- ib_completer_t complete_recv ) {
+ union hermonprm_completion_entry *cqe ) {
struct hermon *hermon = ib_get_drvdata ( ibdev );
- struct ib_completion completion;
struct ib_work_queue *wq;
struct ib_queue_pair *qp;
struct hermon_queue_pair *hermon_qp;
struct io_buffer *iobuf;
- ib_completer_t complete;
+ struct ib_address_vector av;
+ struct ib_global_route_header *grh;
unsigned int opcode;
unsigned long qpn;
int is_send;
unsigned int wqe_idx;
+ size_t len;
int rc = 0;
/* Parse completion */
- memset ( &completion, 0, sizeof ( completion ) );
qpn = MLX_GET ( &cqe->normal, qpn );
is_send = MLX_GET ( &cqe->normal, s_r );
opcode = MLX_GET ( &cqe->normal, opcode );
if ( opcode >= HERMON_OPCODE_RECV_ERROR ) {
/* "s" field is not valid for error opcodes */
is_send = ( opcode == HERMON_OPCODE_SEND_ERROR );
- completion.syndrome = MLX_GET ( &cqe->error, syndrome );
- DBGC ( hermon, "Hermon %p CQN %lx syndrome %x vendor %lx\n",
- hermon, cq->cqn, completion.syndrome,
+ DBGC ( hermon, "Hermon %p CQN %lx syndrome %x vendor %x\n",
+ hermon, cq->cqn, MLX_GET ( &cqe->error, syndrome ),
MLX_GET ( &cqe->error, vendor_error_syndrome ) );
rc = -EIO;
/* Don't return immediately; propagate error to completer */
@@ -1160,21 +1201,28 @@ static int hermon_complete ( struct ib_device *ibdev,
}
wq->iobufs[wqe_idx] = NULL;
- /* Fill in length for received packets */
- if ( ! is_send ) {
- completion.len = MLX_GET ( &cqe->normal, byte_cnt );
- if ( completion.len > iob_tailroom ( iobuf ) ) {
- DBGC ( hermon, "Hermon %p CQN %lx QPN %lx IDX %x "
- "overlength received packet length %zd\n",
- hermon, cq->cqn, qpn, wqe_idx, completion.len );
- return -EIO;
- }
+ if ( is_send ) {
+ /* Hand off to completion handler */
+ ib_complete_send ( ibdev, qp, iobuf, rc );
+ } else {
+ /* Set received length */
+ len = MLX_GET ( &cqe->normal, byte_cnt );
+ assert ( len <= iob_tailroom ( iobuf ) );
+ iob_put ( iobuf, len );
+ assert ( iob_len ( iobuf ) >= sizeof ( *grh ) );
+ grh = iobuf->data;
+ iob_pull ( iobuf, sizeof ( *grh ) );
+ /* Construct address vector */
+ memset ( &av, 0, sizeof ( av ) );
+ av.qpn = MLX_GET ( &cqe->normal, srq_rqpn );
+ av.lid = MLX_GET ( &cqe->normal, slid_smac47_32 );
+ av.sl = MLX_GET ( &cqe->normal, sl );
+ av.gid_present = MLX_GET ( &cqe->normal, g );
+ memcpy ( &av.gid, &grh->sgid, sizeof ( av.gid ) );
+ /* Hand off to completion handler */
+ ib_complete_recv ( ibdev, qp, &av, iobuf, rc );
}
- /* Pass off to caller's completion handler */
- complete = ( is_send ? complete_send : complete_recv );
- complete ( ibdev, qp, &completion, iobuf );
-
return rc;
}
@@ -1183,13 +1231,9 @@ static int hermon_complete ( struct ib_device *ibdev,
*
* @v ibdev Infiniband device
* @v cq Completion queue
- * @v complete_send Send completion handler
- * @v complete_recv Receive completion handler
*/
static void hermon_poll_cq ( struct ib_device *ibdev,
- struct ib_completion_queue *cq,
- ib_completer_t complete_send,
- ib_completer_t complete_recv ) {
+ struct ib_completion_queue *cq ) {
struct hermon *hermon = ib_get_drvdata ( ibdev );
struct hermon_completion_queue *hermon_cq = ib_cq_get_drvdata ( cq );
union hermonprm_completion_entry *cqe;
@@ -1209,8 +1253,7 @@ static void hermon_poll_cq ( struct ib_device *ibdev,
DBGCP_HD ( hermon, cqe, sizeof ( *cqe ) );
/* Handle completion */
- if ( ( rc = hermon_complete ( ibdev, cq, cqe, complete_send,
- complete_recv ) ) != 0 ) {
+ if ( ( rc = hermon_complete ( ibdev, cq, cqe ) ) != 0 ) {
DBGC ( hermon, "Hermon %p failed to complete: %s\n",
hermon, strerror ( rc ) );
DBGC_HD ( hermon, cqe, sizeof ( *cqe ) );
@@ -1380,6 +1423,9 @@ static void hermon_event_port_state_change ( struct hermon *hermon,
return;
}
+ /* Update MAD parameters */
+ ib_smc_update ( hermon->ibdev[port], hermon_mad );
+
/* Notify Infiniband core of link state change */
ib_link_state_changed ( hermon->ibdev[port] );
}
@@ -1428,7 +1474,7 @@ static void hermon_poll_eq ( struct ib_device *ibdev ) {
/* Ring doorbell */
MLX_FILL_1 ( &db_reg.event, 0,
ci, ( hermon_eq->next_idx & 0x00ffffffUL ) );
- DBGCP ( hermon, "Ringing doorbell %08lx with %08lx\n",
+ DBGCP ( hermon, "Ringing doorbell %08lx with %08x\n",
virt_to_phys ( hermon_eq->doorbell ),
db_reg.dword[0] );
writel ( db_reg.dword[0], hermon_eq->doorbell );
@@ -1468,6 +1514,9 @@ static int hermon_open ( struct ib_device *ibdev ) {
return rc;
}
+ /* Update MAD parameters */
+ ib_smc_update ( ibdev, hermon_mad );
+
return 0;
}
@@ -1582,51 +1631,6 @@ static void hermon_mcast_detach ( struct ib_device *ibdev,
}
}
-/***************************************************************************
- *
- * MAD operations
- *
- ***************************************************************************
- */
-
-/**
- * Issue management datagram
- *
- * @v ibdev Infiniband device
- * @v mad Management datagram
- * @v len Length of management datagram
- * @ret rc Return status code
- */
-static int hermon_mad ( struct ib_device *ibdev, struct ib_mad_hdr *mad,
- size_t len ) {
- struct hermon *hermon = ib_get_drvdata ( ibdev );
- union hermonprm_mad mad_ifc;
- int rc;
-
- /* Copy in request packet */
- memset ( &mad_ifc, 0, sizeof ( mad_ifc ) );
- assert ( len <= sizeof ( mad_ifc.mad ) );
- memcpy ( &mad_ifc.mad, mad, len );
-
- /* Issue MAD */
- if ( ( rc = hermon_cmd_mad_ifc ( hermon, ibdev->port,
- &mad_ifc ) ) != 0 ) {
- DBGC ( hermon, "Hermon %p could not issue MAD IFC: %s\n",
- hermon, strerror ( rc ) );
- return rc;
- }
-
- /* Copy out reply packet */
- memcpy ( mad, &mad_ifc.mad, len );
-
- if ( mad->status != 0 ) {
- DBGC ( hermon, "Hermon %p MAD IFC status %04x\n",
- hermon, ntohs ( mad->status ) );
- return -EIO;
- }
- return 0;
-}
-
/** Hermon Infiniband operations */
static struct ib_device_operations hermon_ib_operations = {
.create_cq = hermon_create_cq,
@@ -1642,7 +1646,6 @@ static struct ib_device_operations hermon_ib_operations = {
.close = hermon_close,
.mcast_attach = hermon_mcast_attach,
.mcast_detach = hermon_mcast_detach,
- .mad = hermon_mad,
};
/***************************************************************************
@@ -1712,7 +1715,7 @@ static int hermon_start_firmware ( struct hermon *hermon ) {
hermon, strerror ( rc ) );
goto err_query_fw;
}
- DBGC ( hermon, "Hermon %p firmware version %ld.%ld.%ld\n", hermon,
+ DBGC ( hermon, "Hermon %p firmware version %d.%d.%d\n", hermon,
MLX_GET ( &fw, fw_rev_major ), MLX_GET ( &fw, fw_rev_minor ),
MLX_GET ( &fw, fw_rev_subminor ) );
fw_pages = MLX_GET ( &fw, fw_pages );
@@ -2241,6 +2244,10 @@ static int hermon_probe ( struct pci_device *pci,
if ( ( rc = hermon_create_eq ( hermon ) ) != 0 )
goto err_create_eq;
+ /* Update MAD parameters */
+ for ( i = 0 ; i < HERMON_NUM_PORTS ; i++ )
+ ib_smc_update ( hermon->ibdev[i], hermon_mad );
+
/* Register Infiniband devices */
for ( i = 0 ; i < HERMON_NUM_PORTS ; i++ ) {
if ( ( rc = register_ibdev ( hermon->ibdev[i] ) ) != 0 ) {
@@ -2306,6 +2313,7 @@ static struct pci_device_id hermon_nics[] = {
PCI_ROM ( 0x15b3, 0x6340, "mt25408", "MT25408 HCA driver" ),
PCI_ROM ( 0x15b3, 0x634a, "mt25418", "MT25418 HCA driver" ),
PCI_ROM ( 0x15b3, 0x6732, "mt26418", "MT26418 HCA driver" ),
+ PCI_ROM ( 0x15b3, 0x673c, "mt26428", "MT26428 HCA driver" ),
};
struct pci_driver hermon_driver __pci_driver = {
diff --git a/gpxe/src/drivers/infiniband/ib_packet.c b/gpxe/src/drivers/infiniband/ib_packet.c
new file mode 100644
index 00000000..0f21617f
--- /dev/null
+++ b/gpxe/src/drivers/infiniband/ib_packet.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <gpxe/iobuf.h>
+#include <gpxe/infiniband.h>
+#include <gpxe/ib_packet.h>
+
+/**
+ * @file
+ *
+ * Infiniband Packet Formats
+ *
+ */
+
+/**
+ * Add IB headers
+ *
+ * @v ibdev Infiniband device
+ * @v iobuf I/O buffer to contain headers
+ * @v qp Queue pair
+ * @v payload_len Payload length
+ * @v av Address vector
+ */
+int ib_push ( struct ib_device *ibdev, struct io_buffer *iobuf,
+ struct ib_queue_pair *qp, size_t payload_len,
+ const struct ib_address_vector *av ) {
+ struct ib_local_route_header *lrh;
+ struct ib_global_route_header *grh;
+ struct ib_base_transport_header *bth;
+ struct ib_datagram_extended_transport_header *deth;
+ size_t orig_iob_len = iob_len ( iobuf );
+ size_t pad_len;
+ size_t lrh_len;
+ size_t grh_len;
+ unsigned int vl;
+ unsigned int lnh;
+
+ DBGC2 ( ibdev, "IBDEV %p TX %04x:%08lx => %04x:%08lx (key %08lx)\n",
+ ibdev, ibdev->lid, qp->qpn, av->lid, av->qpn, av->qkey );
+
+ /* Calculate packet length */
+ pad_len = ( (-payload_len) & 0x3 );
+ payload_len += pad_len;
+ payload_len += 4; /* ICRC */
+
+ /* Reserve space for headers */
+ orig_iob_len = iob_len ( iobuf );
+ deth = iob_push ( iobuf, sizeof ( *deth ) );
+ bth = iob_push ( iobuf, sizeof ( *bth ) );
+ grh_len = ( payload_len + iob_len ( iobuf ) - orig_iob_len );
+ grh = ( av->gid_present ?
+ iob_push ( iobuf, sizeof ( *grh ) ) : NULL );
+ lrh = iob_push ( iobuf, sizeof ( *lrh ) );
+ lrh_len = ( payload_len + iob_len ( iobuf ) - orig_iob_len );
+
+ /* Construct LRH */
+ vl = ( ( av->qpn == IB_QPN_SMP ) ? IB_VL_SMP : IB_VL_DEFAULT );
+ lrh->vl__lver = ( vl << 4 );
+ lnh = ( grh ? IB_LNH_GRH : IB_LNH_BTH );
+ lrh->sl__lnh = ( ( av->sl << 4 ) | lnh );
+ lrh->dlid = htons ( av->lid );
+ lrh->length = htons ( lrh_len >> 2 );
+ lrh->slid = htons ( ibdev->lid );
+
+ /* Construct GRH, if required */
+ if ( grh ) {
+ grh->ipver__tclass__flowlabel =
+ htonl ( IB_GRH_IPVER_IPv6 << 28 );
+ grh->paylen = htons ( grh_len );
+ grh->nxthdr = IB_GRH_NXTHDR_IBA;
+ grh->hoplmt = 0;
+ memcpy ( &grh->sgid, &ibdev->gid, sizeof ( grh->sgid ) );
+ memcpy ( &grh->dgid, &av->gid, sizeof ( grh->dgid ) );
+ }
+
+ /* Construct BTH */
+ bth->opcode = BTH_OPCODE_UD_SEND;
+ bth->se__m__padcnt__tver = ( pad_len << 4 );
+ bth->pkey = htons ( ibdev->pkey );
+ bth->dest_qp = htonl ( av->qpn );
+ bth->ack__psn = htonl ( ( ibdev->psn++ ) & 0xffffffUL );
+
+ /* Construct DETH */
+ deth->qkey = htonl ( av->qkey );
+ deth->src_qp = htonl ( qp->qpn );
+
+ DBGCP_HDA ( ibdev, 0, iobuf->data,
+ ( iob_len ( iobuf ) - orig_iob_len ) );
+
+ return 0;
+}
+
+/**
+ * Remove IB headers
+ *
+ * @v ibdev Infiniband device
+ * @v iobuf I/O buffer containing headers
+ * @v qp Queue pair to fill in, or NULL
+ * @v payload_len Payload length to fill in, or NULL
+ * @v av Address vector to fill in
+ */
+int ib_pull ( struct ib_device *ibdev, struct io_buffer *iobuf,
+ struct ib_queue_pair **qp, size_t *payload_len,
+ struct ib_address_vector *av ) {
+ struct ib_local_route_header *lrh;
+ struct ib_global_route_header *grh;
+ struct ib_base_transport_header *bth;
+ struct ib_datagram_extended_transport_header *deth;
+ size_t orig_iob_len = iob_len ( iobuf );
+ unsigned int lnh;
+ size_t pad_len;
+ unsigned long qpn;
+ unsigned int lid;
+
+ /* Clear return values */
+ if ( qp )
+ *qp = NULL;
+ if ( payload_len )
+ *payload_len = 0;
+ memset ( av, 0, sizeof ( *av ) );
+
+ /* Extract LRH */
+ if ( iob_len ( iobuf ) < sizeof ( *lrh ) ) {
+ DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) for LRH\n",
+ ibdev, iob_len ( iobuf ) );
+ return -EINVAL;
+ }
+ lrh = iobuf->data;
+ iob_pull ( iobuf, sizeof ( *lrh ) );
+ av->lid = ntohs ( lrh->slid );
+ av->sl = ( lrh->sl__lnh >> 4 );
+ lnh = ( lrh->sl__lnh & 0x3 );
+ lid = ntohs ( lrh->dlid );
+
+ /* Reject unsupported packets */
+ if ( ! ( ( lnh == IB_LNH_BTH ) || ( lnh == IB_LNH_GRH ) ) ) {
+ DBGC ( ibdev, "IBDEV %p RX unsupported LNH %x\n",
+ ibdev, lnh );
+ return -ENOTSUP;
+ }
+
+ /* Extract GRH, if present */
+ if ( lnh == IB_LNH_GRH ) {
+ if ( iob_len ( iobuf ) < sizeof ( *grh ) ) {
+ DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) "
+ "for GRH\n", ibdev, iob_len ( iobuf ) );
+ return -EINVAL;
+ }
+ grh = iobuf->data;
+ iob_pull ( iobuf, sizeof ( *grh ) );
+ av->gid_present = 1;
+ memcpy ( &av->gid, &grh->sgid, sizeof ( av->gid ) );
+ } else {
+ grh = NULL;
+ }
+
+ /* Extract BTH */
+ if ( iob_len ( iobuf ) < sizeof ( *bth ) ) {
+ DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) for BTH\n",
+ ibdev, iob_len ( iobuf ) );
+ return -EINVAL;
+ }
+ bth = iobuf->data;
+ iob_pull ( iobuf, sizeof ( *bth ) );
+ if ( bth->opcode != BTH_OPCODE_UD_SEND ) {
+ DBGC ( ibdev, "IBDEV %p unsupported BTH opcode %x\n",
+ ibdev, bth->opcode );
+ return -ENOTSUP;
+ }
+ qpn = ntohl ( bth->dest_qp );
+
+ /* Extract DETH */
+ if ( iob_len ( iobuf ) < sizeof ( *deth ) ) {
+ DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) for DETH\n",
+ ibdev, iob_len ( iobuf ) );
+ return -EINVAL;
+ }
+ deth = iobuf->data;
+ iob_pull ( iobuf, sizeof ( *deth ) );
+ av->qpn = ntohl ( deth->src_qp );
+ av->qkey = ntohl ( deth->qkey );
+
+ /* Calculate payload length, if applicable */
+ if ( payload_len ) {
+ pad_len = ( ( bth->se__m__padcnt__tver >> 4 ) & 0x3 );
+ *payload_len = ( ( ntohs ( lrh->length ) << 2 )
+ - ( orig_iob_len - iob_len ( iobuf ) )
+ - pad_len - 4 /* ICRC */ );
+ }
+
+ /* Determine destination QP, if applicable */
+ if ( qp ) {
+ if ( IB_LID_MULTICAST ( lid ) && grh ) {
+ *qp = ib_find_qp_mgid ( ibdev, &grh->dgid );
+ } else {
+ *qp = ib_find_qp_qpn ( ibdev, qpn );
+ }
+ if ( ! *qp ) {
+ DBGC ( ibdev, "IBDEV %p RX for nonexistent QP\n",
+ ibdev );
+ return -ENODEV;
+ }
+ }
+
+ DBGC2 ( ibdev, "IBDEV %p RX %04x:%08lx <= %04x:%08lx (key %08x)\n",
+ ibdev, lid,
+ ( IB_LID_MULTICAST( lid ) ? ( qp ? (*qp)->qpn : -1UL ) : qpn ),
+ av->lid, av->qpn, ntohl ( deth->qkey ) );
+ DBGCP_HDA ( ibdev, 0,
+ ( iobuf->data - ( orig_iob_len - iob_len ( iobuf ) ) ),
+ ( orig_iob_len - iob_len ( iobuf ) ) );
+
+ return 0;
+}
diff --git a/gpxe/src/drivers/infiniband/ib_sma.c b/gpxe/src/drivers/infiniband/ib_sma.c
new file mode 100644
index 00000000..2bd3a9e8
--- /dev/null
+++ b/gpxe/src/drivers/infiniband/ib_sma.c
@@ -0,0 +1,553 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <byteswap.h>
+#include <gpxe/infiniband.h>
+#include <gpxe/iobuf.h>
+#include <gpxe/process.h>
+#include <gpxe/ib_sma.h>
+
+/**
+ * @file
+ *
+ * Infiniband Subnet Management Agent
+ *
+ */
+
+/**
+ * Get node information
+ *
+ * @v sma Subnet management agent
+ * @v get Attribute to get
+ */
+static void ib_sma_get_node_info ( struct ib_sma *sma,
+ union ib_smp_data *get ) {
+ struct ib_device *ibdev = sma->ibdev;
+ struct ib_node_info *node_info = &get->node_info;
+ struct ib_device *tmp;
+
+ memset ( node_info, 0, sizeof ( *node_info ) );
+ node_info->base_version = IB_MGMT_BASE_VERSION;
+ node_info->class_version = IB_SMP_CLASS_VERSION;
+ node_info->node_type = IB_NODE_TYPE_HCA;
+ /* Search for IB devices with the same physical device to
+ * identify port count and a suitable Node GUID.
+ */
+ for_each_ibdev ( tmp ) {
+ if ( tmp->dev != ibdev->dev )
+ continue;
+ if ( node_info->num_ports == 0 ) {
+ memcpy ( node_info->sys_guid, &tmp->gid.u.half[1],
+ sizeof ( node_info->sys_guid ) );
+ memcpy ( node_info->node_guid, &tmp->gid.u.half[1],
+ sizeof ( node_info->node_guid ) );
+ }
+ node_info->num_ports++;
+ }
+ memcpy ( node_info->port_guid, &ibdev->gid.u.half[1],
+ sizeof ( node_info->port_guid ) );
+ node_info->partition_cap = htons ( 1 );
+ node_info->local_port_num = ibdev->port;
+}
+
+/**
+ * Get node description
+ *
+ * @v sma Subnet management agent
+ * @v get Attribute to get
+ */
+static void ib_sma_get_node_desc ( struct ib_sma *sma,
+ union ib_smp_data *get ) {
+ struct ib_device *ibdev = sma->ibdev;
+ struct ib_node_desc *node_desc = &get->node_desc;
+ struct ib_gid_half *guid = &ibdev->gid.u.half[1];
+
+ memset ( node_desc, 0, sizeof ( *node_desc ) );
+ snprintf ( node_desc->node_string, sizeof ( node_desc->node_string ),
+ "gPXE %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x (%s)",
+ guid->bytes[0], guid->bytes[1], guid->bytes[2],
+ guid->bytes[3], guid->bytes[4], guid->bytes[5],
+ guid->bytes[6], guid->bytes[7], ibdev->dev->name );
+}
+
+/**
+ * Get GUID information
+ *
+ * @v sma Subnet management agent
+ * @v get Attribute to get
+ */
+static void ib_sma_get_guid_info ( struct ib_sma *sma,
+ union ib_smp_data *get ) {
+ struct ib_device *ibdev = sma->ibdev;
+ struct ib_guid_info *guid_info = &get->guid_info;
+
+ memset ( guid_info, 0, sizeof ( *guid_info ) );
+ memcpy ( guid_info->guid[0], &ibdev->gid.u.half[1],
+ sizeof ( guid_info->guid[0] ) );
+}
+
+/**
+ * Get port information
+ *
+ * @v sma Subnet management agent
+ * @v get Attribute to get
+ */
+static void ib_sma_get_port_info ( struct ib_sma *sma,
+ union ib_smp_data *get ) {
+ struct ib_device *ibdev = sma->ibdev;
+ struct ib_port_info *port_info = &get->port_info;
+
+ memset ( port_info, 0, sizeof ( *port_info ) );
+ memcpy ( port_info->gid_prefix, &ibdev->gid.u.half[0],
+ sizeof ( port_info->gid_prefix ) );
+ port_info->lid = ntohs ( ibdev->lid );
+ port_info->mastersm_lid = ntohs ( ibdev->sm_lid );
+ port_info->local_port_num = ibdev->port;
+ port_info->link_width_enabled = ibdev->link_width;
+ port_info->link_width_supported = ibdev->link_width;
+ port_info->link_width_active = ibdev->link_width;
+ port_info->link_speed_supported__port_state =
+ ( ( ibdev->link_speed << 4 ) | ibdev->port_state );
+ port_info->port_phys_state__link_down_def_state =
+ ( ( IB_PORT_PHYS_STATE_POLLING << 4 ) |
+ IB_PORT_PHYS_STATE_POLLING );
+ port_info->link_speed_active__link_speed_enabled =
+ ( ( ibdev->link_speed << 4 ) | ibdev->link_speed );
+ port_info->neighbour_mtu__mastersm_sl =
+ ( ( IB_MTU_2048 << 4 ) | ibdev->sm_sl );
+ port_info->vl_cap__init_type = ( IB_VL_0 << 4 );
+ port_info->init_type_reply__mtu_cap = IB_MTU_2048;
+ port_info->operational_vls__enforcement = ( IB_VL_0 << 4 );
+ port_info->guid_cap = 1;
+}
+
+/**
+ * Set port information
+ *
+ * @v sma Subnet management agent
+ * @v set Attribute to set
+ * @ret rc Return status code
+ */
+static int ib_sma_set_port_info ( struct ib_sma *sma,
+ const union ib_smp_data *set ) {
+ struct ib_device *ibdev = sma->ibdev;
+ const struct ib_port_info *port_info = &set->port_info;
+
+ memcpy ( &ibdev->gid.u.half[0], port_info->gid_prefix,
+ sizeof ( ibdev->gid.u.half[0] ) );
+ ibdev->lid = ntohs ( port_info->lid );
+ ibdev->sm_lid = ntohs ( port_info->mastersm_lid );
+ ibdev->sm_sl = ( port_info->neighbour_mtu__mastersm_sl & 0xf );
+
+ if ( ! sma->op->set_port_info ) {
+ /* Not an error; we just ignore all other settings */
+ return 0;
+ }
+
+ return sma->op->set_port_info ( ibdev, port_info );
+}
+
+/**
+ * Get partition key table
+ *
+ * @v sma Subnet management agent
+ * @v get Attribute to get
+ */
+static void ib_sma_get_pkey_table ( struct ib_sma *sma,
+ union ib_smp_data *get ) {
+ struct ib_device *ibdev = sma->ibdev;
+ struct ib_pkey_table *pkey_table = &get->pkey_table;
+
+ memset ( pkey_table, 0, sizeof ( *pkey_table ) );
+ pkey_table->pkey[0] = htons ( ibdev->pkey );
+}
+
+/**
+ * Set partition key table
+ *
+ * @v sma Subnet management agent
+ * @v set Attribute to set
+ */
+static int ib_sma_set_pkey_table ( struct ib_sma *sma,
+ const union ib_smp_data *get ) {
+ struct ib_device *ibdev = sma->ibdev;
+ const struct ib_pkey_table *pkey_table = &get->pkey_table;
+
+ ibdev->pkey = ntohs ( pkey_table->pkey[0] );
+ return 0;
+}
+
+/** An attribute handler */
+struct ib_sma_handler {
+ /** Attribute (in network byte order) */
+ uint16_t attr_id;
+ /** Get attribute
+ *
+ * @v sma Subnet management agent
+ * @v get Attribute to get
+ * @ret rc Return status code
+ */
+ void ( * get ) ( struct ib_sma *sma, union ib_smp_data *get );
+ /** Set attribute
+ *
+ * @v sma Subnet management agent
+ * @v set Attribute to set
+ * @ret rc Return status code
+ */
+ int ( * set ) ( struct ib_sma *sma, const union ib_smp_data *set );
+};
+
+/** List of attribute handlers */
+static struct ib_sma_handler ib_sma_handlers[] = {
+ { htons ( IB_SMP_ATTR_NODE_DESC ),
+ ib_sma_get_node_desc, NULL },
+ { htons ( IB_SMP_ATTR_NODE_INFO ),
+ ib_sma_get_node_info, NULL },
+ { htons ( IB_SMP_ATTR_GUID_INFO ),
+ ib_sma_get_guid_info, NULL },
+ { htons ( IB_SMP_ATTR_PORT_INFO ),
+ ib_sma_get_port_info, ib_sma_set_port_info },
+ { htons ( IB_SMP_ATTR_PKEY_TABLE ),
+ ib_sma_get_pkey_table, ib_sma_set_pkey_table },
+};
+
+/**
+ * Identify attribute handler
+ *
+ * @v attr_id Attribute ID (in network byte order)
+ * @ret handler Attribute handler (or NULL)
+ */
+static struct ib_sma_handler * ib_sma_handler ( uint16_t attr_id ) {
+ struct ib_sma_handler *handler;
+ unsigned int i;
+
+ for ( i = 0 ; i < ( sizeof ( ib_sma_handlers ) /
+ sizeof ( ib_sma_handlers[0] ) ) ; i++ ) {
+ handler = &ib_sma_handlers[i];
+ if ( handler->attr_id == attr_id )
+ return handler;
+ }
+
+ return NULL;
+}
+
+/**
+ * Respond to management datagram
+ *
+ * @v sma Subnet management agent
+ * @v mad Management datagram
+ * @ret rc Return status code
+ */
+static int ib_sma_mad ( struct ib_sma *sma, union ib_mad *mad ) {
+ struct ib_device *ibdev = sma->ibdev;
+ struct ib_mad_hdr *hdr = &mad->hdr;
+ struct ib_mad_smp *smp = &mad->smp;
+ struct ib_sma_handler *handler = NULL;
+ unsigned int hop_pointer;
+ unsigned int hop_count;
+ int rc;
+
+ DBGC ( sma, "SMA %p received SMP with bv=%02x mc=%02x cv=%02x "
+ "meth=%02x attr=%04x mod=%08x\n", sma, hdr->base_version,
+ hdr->mgmt_class, hdr->class_version, hdr->method,
+ ntohs ( hdr->attr_id ), ntohl ( hdr->attr_mod ) );
+ DBGC2_HDA ( sma, 0, mad, sizeof ( *mad ) );
+
+ /* Sanity checks */
+ if ( hdr->base_version != IB_MGMT_BASE_VERSION ) {
+ DBGC ( sma, "SMA %p unsupported base version %x\n",
+ sma, hdr->base_version );
+ return -ENOTSUP;
+ }
+ if ( ( hdr->mgmt_class != IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE ) &&
+ ( hdr->mgmt_class != IB_MGMT_CLASS_SUBN_LID_ROUTED ) ) {
+ DBGC ( sma, "SMA %p unsupported management class %x\n",
+ sma, hdr->mgmt_class );
+ return -ENOTSUP;
+ }
+ if ( hdr->class_version != IB_SMP_CLASS_VERSION ) {
+ DBGC ( sma, "SMA %p unsupported class version %x\n",
+ sma, hdr->class_version );
+ return -ENOTSUP;
+ }
+ if ( ( hdr->method != IB_MGMT_METHOD_GET ) &&
+ ( hdr->method != IB_MGMT_METHOD_SET ) ) {
+ DBGC ( sma, "SMA %p unsupported method %x\n",
+ sma, hdr->method );
+ return -ENOTSUP;
+ }
+
+ /* Identify handler */
+ if ( ! ( handler = ib_sma_handler ( hdr->attr_id ) ) ) {
+ DBGC ( sma, "SMA %p unsupported attribute %x\n",
+ sma, ntohs ( hdr->attr_id ) );
+ hdr->status = htons ( IB_MGMT_STATUS_UNSUPPORTED_METHOD_ATTR );
+ goto respond_without_data;
+ }
+
+ /* Set attribute (if applicable) */
+ if ( hdr->method != IB_MGMT_METHOD_SET ) {
+ hdr->status = htons ( IB_MGMT_STATUS_OK );
+ goto respond;
+ }
+ if ( ! handler->set ) {
+ DBGC ( sma, "SMA %p attribute %x is unsettable\n",
+ sma, ntohs ( hdr->attr_id ) );
+ hdr->status = htons ( IB_MGMT_STATUS_UNSUPPORTED_METHOD_ATTR );
+ goto respond;
+ }
+ if ( ( rc = handler->set ( sma, &smp->smp_data ) ) != 0 ) {
+ DBGC ( sma, "SMA %p could not set attribute %x: %s\n",
+ sma, ntohs ( hdr->attr_id ), strerror ( rc ) );
+ hdr->status = htons ( IB_MGMT_STATUS_UNSUPPORTED_METHOD_ATTR );
+ goto respond;
+ }
+
+ hdr->status = htons ( IB_MGMT_STATUS_OK );
+
+ respond:
+ /* Get attribute */
+ handler->get ( sma, &smp->smp_data );
+
+ respond_without_data:
+
+ /* Set method to "Get Response" */
+ hdr->method = IB_MGMT_METHOD_GET_RESP;
+
+ /* Set response fields for directed route SMPs */
+ if ( hdr->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE ) {
+ hdr->status |= htons ( IB_SMP_STATUS_D_INBOUND );
+ hop_pointer = smp->mad_hdr.class_specific.smp.hop_pointer;
+ hop_count = smp->mad_hdr.class_specific.smp.hop_count;
+ assert ( hop_count == hop_pointer );
+ if ( hop_pointer < ( sizeof ( smp->return_path.hops ) /
+ sizeof ( smp->return_path.hops[0] ) ) ) {
+ smp->return_path.hops[hop_pointer] = ibdev->port;
+ } else {
+ DBGC ( sma, "SMA %p invalid hop pointer %d\n",
+ sma, hop_pointer );
+ return -EINVAL;
+ }
+ }
+
+ DBGC ( sma, "SMA %p responding with status=%04x\n",
+ sma, ntohs ( hdr->status ) );
+ DBGC2_HDA ( sma, 0, mad, sizeof ( *mad ) );
+
+ return 0;
+}
+
+/**
+ * Refill SMA receive ring
+ *
+ * @v sma Subnet management agent
+ */
+static void ib_sma_refill_recv ( struct ib_sma *sma ) {
+ struct ib_device *ibdev = sma->ibdev;
+ struct io_buffer *iobuf;
+ int rc;
+
+ while ( sma->qp->recv.fill < IB_SMA_NUM_RECV_WQES ) {
+
+ /* Allocate I/O buffer */
+ iobuf = alloc_iob ( IB_SMA_PAYLOAD_LEN );
+ if ( ! iobuf ) {
+ /* Non-fatal; we will refill on next attempt */
+ return;
+ }
+
+ /* Post I/O buffer */
+ if ( ( rc = ib_post_recv ( ibdev, sma->qp, iobuf ) ) != 0 ) {
+ DBGC ( sma, "SMA %p could not refill: %s\n",
+ sma, strerror ( rc ) );
+ free_iob ( iobuf );
+ /* Give up */
+ return;
+ }
+ }
+}
+
+/**
+ * Complete SMA send
+ *
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ * @v iobuf I/O buffer
+ * @v rc Completion status code
+ */
+static void ib_sma_complete_send ( struct ib_device *ibdev __unused,
+ struct ib_queue_pair *qp,
+ struct io_buffer *iobuf, int rc ) {
+ struct ib_sma *sma = ib_qp_get_ownerdata ( qp );
+
+ if ( rc != 0 ) {
+ DBGC ( sma, "SMA %p send completion error: %s\n",
+ sma, strerror ( rc ) );
+ }
+ free_iob ( iobuf );
+}
+
+/**
+ * Complete SMA receive
+ *
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ * @v av Address vector
+ * @v iobuf I/O buffer
+ * @v rc Completion status code
+ */
+static void ib_sma_complete_recv ( struct ib_device *ibdev,
+ struct ib_queue_pair *qp,
+ struct ib_address_vector *av,
+ struct io_buffer *iobuf, int rc ) {
+ struct ib_sma *sma = ib_qp_get_ownerdata ( qp );
+ union ib_mad *mad;
+
+ /* Ignore errors */
+ if ( rc != 0 ) {
+ DBGC ( sma, "SMA %p RX error: %s\n", sma, strerror ( rc ) );
+ goto err;
+ }
+
+ /* Sanity check */
+ if ( iob_len ( iobuf ) != sizeof ( *mad ) ) {
+ DBGC ( sma, "SMA %p RX bad size (%zd bytes)\n",
+ sma, iob_len ( iobuf ) );
+ goto err;
+ }
+ mad = iobuf->data;
+
+ /* Construct MAD response */
+ if ( ( rc = ib_sma_mad ( sma, mad ) ) != 0 ) {
+ DBGC ( sma, "SMA %p could not construct MAD response: %s\n",
+ sma, strerror ( rc ) );
+ goto err;
+ }
+
+ /* Send MAD response */
+ if ( ( rc = ib_post_send ( ibdev, qp, av, iobuf ) ) != 0 ) {
+ DBGC ( sma, "SMA %p could not send MAD response: %s\n",
+ sma, strerror ( rc ) );
+ goto err;
+ }
+
+ return;
+
+ err:
+ free_iob ( iobuf );
+}
+
+/** SMA completion operations */
+static struct ib_completion_queue_operations ib_sma_completion_ops = {
+ .complete_send = ib_sma_complete_send,
+ .complete_recv = ib_sma_complete_recv,
+};
+
+/**
+ * Poll SMA
+ *
+ * @v process Process
+ */
+static void ib_sma_step ( struct process *process ) {
+ struct ib_sma *sma =
+ container_of ( process, struct ib_sma, poll );
+ struct ib_device *ibdev = sma->ibdev;
+
+ /* Poll the kernel completion queue */
+ ib_poll_cq ( ibdev, sma->cq );
+
+ /* Refill the receive ring */
+ ib_sma_refill_recv ( sma );
+}
+
+/**
+ * Create SMA
+ *
+ * @v sma Subnet management agent
+ * @v ibdev Infiniband device
+ * @v op Subnet management operations
+ * @ret rc Return status code
+ */
+int ib_create_sma ( struct ib_sma *sma, struct ib_device *ibdev,
+ struct ib_sma_operations *op ) {
+ int rc;
+
+ /* Initialise fields */
+ memset ( sma, 0, sizeof ( *sma ) );
+ sma->ibdev = ibdev;
+ sma->op = op;
+ process_init ( &sma->poll, ib_sma_step, &ibdev->refcnt );
+
+ /* Create completion queue */
+ sma->cq = ib_create_cq ( ibdev, IB_SMA_NUM_CQES,
+ &ib_sma_completion_ops );
+ if ( ! sma->cq ) {
+ rc = -ENOMEM;
+ goto err_create_cq;
+ }
+
+ /* Create queue pair */
+ sma->qp = ib_create_qp ( ibdev, IB_SMA_NUM_SEND_WQES, sma->cq,
+ IB_SMA_NUM_RECV_WQES, sma->cq, 0 );
+ if ( ! sma->qp ) {
+ rc = -ENOMEM;
+ goto err_create_qp;
+ }
+ ib_qp_set_ownerdata ( sma->qp, sma );
+
+ /* If we don't get QP0, we can't function */
+ if ( sma->qp->qpn != IB_QPN_SMP ) {
+ DBGC ( sma, "SMA %p on QPN %lx, needs to be on QPN 0\n",
+ sma, sma->qp->qpn );
+ rc = -ENOTSUP;
+ goto err_not_qp0;
+ }
+
+ /* Fill receive ring */
+ ib_sma_refill_recv ( sma );
+ return 0;
+
+ err_not_qp0:
+ ib_destroy_qp ( ibdev, sma->qp );
+ err_create_qp:
+ ib_destroy_cq ( ibdev, sma->cq );
+ err_create_cq:
+ process_del ( &sma->poll );
+ return rc;
+}
+
+/**
+ * Destroy SMA
+ *
+ * @v sma Subnet management agent
+ */
+void ib_destroy_sma ( struct ib_sma *sma ) {
+ struct ib_device *ibdev = sma->ibdev;
+
+ ib_destroy_qp ( ibdev, sma->qp );
+ ib_destroy_cq ( ibdev, sma->cq );
+ process_del ( &sma->poll );
+}
diff --git a/gpxe/src/drivers/infiniband/ib_smc.c b/gpxe/src/drivers/infiniband/ib_smc.c
new file mode 100644
index 00000000..af0c4ab9
--- /dev/null
+++ b/gpxe/src/drivers/infiniband/ib_smc.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <byteswap.h>
+#include <gpxe/infiniband.h>
+#include <gpxe/ib_smc.h>
+
+/**
+ * @file
+ *
+ * Infiniband Subnet Management Client
+ *
+ */
+
+/**
+ * Get port information
+ *
+ * @v ibdev Infiniband device
+ * @v local_mad Method for issuing local MADs
+ * @v mad Management datagram to fill in
+ * @ret rc Return status code
+ */
+static int ib_smc_get_port_info ( struct ib_device *ibdev,
+ ib_local_mad_t local_mad,
+ union ib_mad *mad ) {
+ int rc;
+
+ /* Construct MAD */
+ memset ( mad, 0, sizeof ( *mad ) );
+ mad->hdr.base_version = IB_MGMT_BASE_VERSION;
+ mad->hdr.mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED;
+ mad->hdr.class_version = 1;
+ mad->hdr.method = IB_MGMT_METHOD_GET;
+ mad->hdr.attr_id = htons ( IB_SMP_ATTR_PORT_INFO );
+ mad->hdr.attr_mod = htonl ( ibdev->port );
+
+ if ( ( rc = local_mad ( ibdev, mad ) ) != 0 ) {
+ DBGC ( ibdev, "IBDEV %p could not get port info: %s\n",
+ ibdev, strerror ( rc ) );
+ return rc;
+ }
+ return 0;
+}
+
+/**
+ * Get GUID information
+ *
+ * @v ibdev Infiniband device
+ * @v local_mad Method for issuing local MADs
+ * @v mad Management datagram to fill in
+ * @ret rc Return status code
+ */
+static int ib_smc_get_guid_info ( struct ib_device *ibdev,
+ ib_local_mad_t local_mad,
+ union ib_mad *mad ) {
+ int rc;
+
+ /* Construct MAD */
+ memset ( mad, 0, sizeof ( *mad ) );
+ mad->hdr.base_version = IB_MGMT_BASE_VERSION;
+ mad->hdr.mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED;
+ mad->hdr.class_version = 1;
+ mad->hdr.method = IB_MGMT_METHOD_GET;
+ mad->hdr.attr_id = htons ( IB_SMP_ATTR_GUID_INFO );
+
+ if ( ( rc = local_mad ( ibdev, mad ) ) != 0 ) {
+ DBGC ( ibdev, "IBDEV %p could not get GUID info: %s\n",
+ ibdev, strerror ( rc ) );
+ return rc;
+ }
+ return 0;
+}
+
+/**
+ * Get partition key table
+ *
+ * @v ibdev Infiniband device
+ * @v local_mad Method for issuing local MADs
+ * @v mad Management datagram to fill in
+ * @ret rc Return status code
+ */
+static int ib_smc_get_pkey_table ( struct ib_device *ibdev,
+ ib_local_mad_t local_mad,
+ union ib_mad *mad ) {
+ int rc;
+
+ /* Construct MAD */
+ memset ( mad, 0, sizeof ( *mad ) );
+ mad->hdr.base_version = IB_MGMT_BASE_VERSION;
+ mad->hdr.mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED;
+ mad->hdr.class_version = 1;
+ mad->hdr.method = IB_MGMT_METHOD_GET;
+ mad->hdr.attr_id = htons ( IB_SMP_ATTR_PKEY_TABLE );
+
+ if ( ( rc = local_mad ( ibdev, mad ) ) != 0 ) {
+ DBGC ( ibdev, "IBDEV %p could not get pkey table: %s\n",
+ ibdev, strerror ( rc ) );
+ return rc;
+ }
+ return 0;
+}
+
+/**
+ * Get MAD parameters
+ *
+ * @v ibdev Infiniband device
+ * @v local_mad Method for issuing local MADs
+ * @ret rc Return status code
+ */
+int ib_smc_update ( struct ib_device *ibdev, ib_local_mad_t local_mad ) {
+ union ib_mad mad;
+ union ib_smp_data *smp = &mad.smp.smp_data;
+ int rc;
+
+ /* Port info gives us the link state, the first half of the
+ * port GID and the SM LID.
+ */
+ if ( ( rc = ib_smc_get_port_info ( ibdev, local_mad, &mad ) ) != 0 )
+ return rc;
+ ibdev->port_state =
+ ( smp->port_info.link_speed_supported__port_state & 0x0f );
+ memcpy ( &ibdev->gid.u.half[0], smp->port_info.gid_prefix,
+ sizeof ( ibdev->gid.u.half[0] ) );
+ ibdev->lid = ntohs ( smp->port_info.lid );
+ ibdev->sm_lid = ntohs ( smp->port_info.mastersm_lid );
+ ibdev->sm_sl = ( smp->port_info.neighbour_mtu__mastersm_sl & 0xf );
+
+ /* GUID info gives us the second half of the port GID */
+ if ( ( rc = ib_smc_get_guid_info ( ibdev, local_mad, &mad ) ) != 0 )
+ return rc;
+ memcpy ( &ibdev->gid.u.half[1], smp->guid_info.guid[0],
+ sizeof ( ibdev->gid.u.half[1] ) );
+
+ /* Get partition key */
+ if ( ( rc = ib_smc_get_pkey_table ( ibdev, local_mad, &mad ) ) != 0 )
+ return rc;
+ ibdev->pkey = ntohs ( smp->pkey_table.pkey[0] );
+
+ DBGC ( ibdev, "IBDEV %p port GID is %08x:%08x:%08x:%08x\n", ibdev,
+ htonl ( ibdev->gid.u.dwords[0] ),
+ htonl ( ibdev->gid.u.dwords[1] ),
+ htonl ( ibdev->gid.u.dwords[2] ),
+ htonl ( ibdev->gid.u.dwords[3] ) );
+
+ return 0;
+}
diff --git a/gpxe/src/drivers/infiniband/linda.c b/gpxe/src/drivers/infiniband/linda.c
new file mode 100644
index 00000000..c5d13177
--- /dev/null
+++ b/gpxe/src/drivers/infiniband/linda.c
@@ -0,0 +1,2397 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <assert.h>
+#include <gpxe/io.h>
+#include <gpxe/pci.h>
+#include <gpxe/infiniband.h>
+#include <gpxe/i2c.h>
+#include <gpxe/bitbash.h>
+#include <gpxe/malloc.h>
+#include <gpxe/iobuf.h>
+#include <gpxe/ib_sma.h>
+#include "linda.h"
+
+/**
+ * @file
+ *
+ * QLogic Linda Infiniband HCA
+ *
+ */
+
+/** A Linda send work queue */
+struct linda_send_work_queue {
+ /** Send buffer usage */
+ uint8_t *send_buf;
+ /** Producer index */
+ unsigned int prod;
+ /** Consumer index */
+ unsigned int cons;
+};
+
+/** A Linda receive work queue */
+struct linda_recv_work_queue {
+ /** Receive header ring */
+ void *header;
+ /** Receive header producer offset (written by hardware) */
+ struct QIB_7220_scalar header_prod;
+ /** Receive header consumer offset */
+ unsigned int header_cons;
+ /** Offset within register space of the eager array */
+ unsigned long eager_array;
+ /** Number of entries in eager array */
+ unsigned int eager_entries;
+ /** Eager array producer index */
+ unsigned int eager_prod;
+ /** Eager array consumer index */
+ unsigned int eager_cons;
+};
+
+/** A Linda HCA */
+struct linda {
+ /** Registers */
+ void *regs;
+
+ /** In-use contexts */
+ uint8_t used_ctx[LINDA_NUM_CONTEXTS];
+ /** Send work queues */
+ struct linda_send_work_queue send_wq[LINDA_NUM_CONTEXTS];
+ /** Receive work queues */
+ struct linda_recv_work_queue recv_wq[LINDA_NUM_CONTEXTS];
+
+ /** Offset within register space of the first send buffer */
+ unsigned long send_buffer_base;
+ /** Send buffer availability (reported by hardware) */
+ struct QIB_7220_SendBufAvail *sendbufavail;
+ /** Send buffer availability (maintained by software) */
+ uint8_t send_buf[LINDA_MAX_SEND_BUFS];
+ /** Send buffer availability producer counter */
+ unsigned int send_buf_prod;
+ /** Send buffer availability consumer counter */
+ unsigned int send_buf_cons;
+ /** Number of reserved send buffers (across all QPs) */
+ unsigned int reserved_send_bufs;
+
+ /** I2C bit-bashing interface */
+ struct i2c_bit_basher i2c;
+ /** I2C serial EEPROM */
+ struct i2c_device eeprom;
+
+ /** Subnet management agent */
+ struct ib_sma sma;
+};
+
+/***************************************************************************
+ *
+ * Linda register access
+ *
+ ***************************************************************************
+ *
+ * This card requires atomic 64-bit accesses. Strange things happen
+ * if you try to use 32-bit accesses; sometimes they work, sometimes
+ * they don't, sometimes you get random data.
+ *
+ * These accessors use the "movq" MMX instruction, and so won't work
+ * on really old Pentiums (which won't have PCIe anyway, so this is
+ * something of a moot point).
+ */
+
+/**
+ * Read Linda qword register
+ *
+ * @v linda Linda device
+ * @v dwords Register buffer to read into
+ * @v offset Register offset
+ */
+static void linda_readq ( struct linda *linda, uint32_t *dwords,
+ unsigned long offset ) {
+ void *addr = ( linda->regs + offset );
+
+ __asm__ __volatile__ ( "movq (%1), %%mm0\n\t"
+ "movq %%mm0, (%0)\n\t"
+ : : "r" ( dwords ), "r" ( addr ) : "memory" );
+
+ DBGIO ( "[%08lx] => %08x%08x\n",
+ virt_to_phys ( addr ), dwords[1], dwords[0] );
+}
+#define linda_readq( _linda, _ptr, _offset ) \
+ linda_readq ( (_linda), (_ptr)->u.dwords, (_offset) )
+#define linda_readq_array8b( _linda, _ptr, _offset, _idx ) \
+ linda_readq ( (_linda), (_ptr), ( (_offset) + ( (_idx) * 8 ) ) )
+#define linda_readq_array64k( _linda, _ptr, _offset, _idx ) \
+ linda_readq ( (_linda), (_ptr), ( (_offset) + ( (_idx) * 65536 ) ) )
+
+/**
+ * Write Linda qword register
+ *
+ * @v linda Linda device
+ * @v dwords Register buffer to write
+ * @v offset Register offset
+ */
+static void linda_writeq ( struct linda *linda, const uint32_t *dwords,
+ unsigned long offset ) {
+ void *addr = ( linda->regs + offset );
+
+ DBGIO ( "[%08lx] <= %08x%08x\n",
+ virt_to_phys ( addr ), dwords[1], dwords[0] );
+
+ __asm__ __volatile__ ( "movq (%0), %%mm0\n\t"
+ "movq %%mm0, (%1)\n\t"
+ : : "r" ( dwords ), "r" ( addr ) : "memory" );
+}
+#define linda_writeq( _linda, _ptr, _offset ) \
+ linda_writeq ( (_linda), (_ptr)->u.dwords, (_offset) )
+#define linda_writeq_array8b( _linda, _ptr, _offset, _idx ) \
+ linda_writeq ( (_linda), (_ptr), ( (_offset) + ( (_idx) * 8 ) ) )
+#define linda_writeq_array64k( _linda, _ptr, _offset, _idx ) \
+ linda_writeq ( (_linda), (_ptr), ( (_offset) + ( (_idx) * 65536 ) ) )
+
+/**
+ * Write Linda dword register
+ *
+ * @v linda Linda device
+ * @v dword Value to write
+ * @v offset Register offset
+ */
+static void linda_writel ( struct linda *linda, uint32_t dword,
+ unsigned long offset ) {
+ writel ( dword, ( linda->regs + offset ) );
+}
+
+/***************************************************************************
+ *
+ * Link state management
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Textual representation of link state
+ *
+ * @v link_state Link state
+ * @ret link_text Link state text
+ */
+static const char * linda_link_state_text ( unsigned int link_state ) {
+ switch ( link_state ) {
+ case LINDA_LINK_STATE_DOWN: return "DOWN";
+ case LINDA_LINK_STATE_INIT: return "INIT";
+ case LINDA_LINK_STATE_ARM: return "ARM";
+ case LINDA_LINK_STATE_ACTIVE: return "ACTIVE";
+ case LINDA_LINK_STATE_ACT_DEFER:return "ACT_DEFER";
+ default: return "UNKNOWN";
+ }
+}
+
+/**
+ * Handle link state change
+ *
+ * @v linda Linda device
+ */
+static void linda_link_state_changed ( struct ib_device *ibdev ) {
+ struct linda *linda = ib_get_drvdata ( ibdev );
+ struct QIB_7220_IBCStatus ibcstatus;
+ struct QIB_7220_EXTCtrl extctrl;
+ unsigned int link_state;
+ unsigned int link_width;
+ unsigned int link_speed;
+
+ /* Read link state */
+ linda_readq ( linda, &ibcstatus, QIB_7220_IBCStatus_offset );
+ link_state = BIT_GET ( &ibcstatus, LinkState );
+ link_width = BIT_GET ( &ibcstatus, LinkWidthActive );
+ link_speed = BIT_GET ( &ibcstatus, LinkSpeedActive );
+ DBGC ( linda, "Linda %p link state %s (%s %s)\n", linda,
+ linda_link_state_text ( link_state ),
+ ( link_speed ? "DDR" : "SDR" ), ( link_width ? "x4" : "x1" ) );
+
+ /* Set LEDs according to link state */
+ linda_readq ( linda, &extctrl, QIB_7220_EXTCtrl_offset );
+ BIT_SET ( &extctrl, LEDPriPortGreenOn,
+ ( ( link_state >= LINDA_LINK_STATE_INIT ) ? 1 : 0 ) );
+ BIT_SET ( &extctrl, LEDPriPortYellowOn,
+ ( ( link_state >= LINDA_LINK_STATE_ACTIVE ) ? 1 : 0 ) );
+ linda_writeq ( linda, &extctrl, QIB_7220_EXTCtrl_offset );
+
+ /* Notify Infiniband core of link state change */
+ ibdev->port_state = ( link_state + 1 );
+ ibdev->link_width =
+ ( link_width ? IB_LINK_WIDTH_4X : IB_LINK_WIDTH_1X );
+ ibdev->link_speed =
+ ( link_speed ? IB_LINK_SPEED_DDR : IB_LINK_SPEED_SDR );
+ ib_link_state_changed ( ibdev );
+}
+
+/**
+ * Set port information
+ *
+ * @v ibdev Infiniband device
+ * @v port_info New port information
+ */
+static int linda_set_port_info ( struct ib_device *ibdev,
+ const struct ib_port_info *port_info ) {
+ struct linda *linda = ib_get_drvdata ( ibdev );
+ struct QIB_7220_IBCCtrl ibcctrl;
+ unsigned int port_state;
+ unsigned int link_state;
+
+ /* Set new link state */
+ port_state = ( port_info->link_speed_supported__port_state & 0xf );
+ if ( port_state ) {
+ link_state = ( port_state - 1 );
+ DBGC ( linda, "Linda %p set link state to %s (%x)\n", linda,
+ linda_link_state_text ( link_state ), link_state );
+ linda_readq ( linda, &ibcctrl, QIB_7220_IBCCtrl_offset );
+ BIT_SET ( &ibcctrl, LinkCmd, link_state );
+ linda_writeq ( linda, &ibcctrl, QIB_7220_IBCCtrl_offset );
+ }
+
+ /* Detect and report link state change */
+ linda_link_state_changed ( ibdev );
+
+ return 0;
+}
+
+/** Linda subnet management operations */
+static struct ib_sma_operations linda_sma_operations = {
+ .set_port_info = linda_set_port_info,
+};
+
+/***************************************************************************
+ *
+ * Context allocation
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Map context number to QPN
+ *
+ * @v ctx Context index
+ * @ret qpn Queue pair number
+ */
+static int linda_ctx_to_qpn ( unsigned int ctx ) {
+ /* This mapping is fixed by hardware */
+ return ( ctx * 2 );
+}
+
+/**
+ * Map QPN to context number
+ *
+ * @v qpn Queue pair number
+ * @ret ctx Context index
+ */
+static int linda_qpn_to_ctx ( unsigned int qpn ) {
+ /* This mapping is fixed by hardware */
+ return ( qpn / 2 );
+}
+
+/**
+ * Allocate a context
+ *
+ * @v linda Linda device
+ * @ret ctx Context index, or negative error
+ */
+static int linda_alloc_ctx ( struct linda *linda ) {
+ unsigned int ctx;
+
+ for ( ctx = 0 ; ctx < LINDA_NUM_CONTEXTS ; ctx++ ) {
+
+ if ( ! linda->used_ctx[ctx] ) {
+ linda->used_ctx[ctx ] = 1;
+ DBGC2 ( linda, "Linda %p CTX %d allocated\n",
+ linda, ctx );
+ return ctx;
+ }
+ }
+
+ DBGC ( linda, "Linda %p out of available contexts\n", linda );
+ return -ENOENT;
+}
+
+/**
+ * Free a context
+ *
+ * @v linda Linda device
+ * @v ctx Context index
+ */
+static void linda_free_ctx ( struct linda *linda, unsigned int ctx ) {
+
+ linda->used_ctx[ctx] = 0;
+ DBGC2 ( linda, "Linda %p CTX %d freed\n", linda, ctx );
+}
+
+/***************************************************************************
+ *
+ * Send datapath
+ *
+ ***************************************************************************
+ */
+
+/** Send buffer toggle bit
+ *
+ * We encode send buffers as 7 bits of send buffer index plus a single
+ * bit which should match the "check" bit in the SendBufAvail array.
+ */
+#define LINDA_SEND_BUF_TOGGLE 0x80
+
+/**
+ * Allocate a send buffer
+ *
+ * @v linda Linda device
+ * @ret send_buf Send buffer
+ *
+ * You must guarantee that a send buffer is available. This is done
+ * by refusing to allocate more TX WQEs in total than the number of
+ * available send buffers.
+ */
+static unsigned int linda_alloc_send_buf ( struct linda *linda ) {
+ unsigned int send_buf;
+
+ send_buf = linda->send_buf[linda->send_buf_cons];
+ send_buf ^= LINDA_SEND_BUF_TOGGLE;
+ linda->send_buf_cons = ( ( linda->send_buf_cons + 1 ) %
+ LINDA_MAX_SEND_BUFS );
+ return send_buf;
+}
+
+/**
+ * Free a send buffer
+ *
+ * @v linda Linda device
+ * @v send_buf Send buffer
+ */
+static void linda_free_send_buf ( struct linda *linda,
+ unsigned int send_buf ) {
+ linda->send_buf[linda->send_buf_prod] = send_buf;
+ linda->send_buf_prod = ( ( linda->send_buf_prod + 1 ) %
+ LINDA_MAX_SEND_BUFS );
+}
+
+/**
+ * Check to see if send buffer is in use
+ *
+ * @v linda Linda device
+ * @v send_buf Send buffer
+ * @ret in_use Send buffer is in use
+ */
+static int linda_send_buf_in_use ( struct linda *linda,
+ unsigned int send_buf ) {
+ unsigned int send_idx;
+ unsigned int send_check;
+ unsigned int inusecheck;
+ unsigned int inuse;
+ unsigned int check;
+
+ send_idx = ( send_buf & ~LINDA_SEND_BUF_TOGGLE );
+ send_check = ( !! ( send_buf & LINDA_SEND_BUF_TOGGLE ) );
+ inusecheck = BIT_GET ( linda->sendbufavail, InUseCheck[send_idx] );
+ inuse = ( !! ( inusecheck & 0x02 ) );
+ check = ( !! ( inusecheck & 0x01 ) );
+ return ( inuse || ( check != send_check ) );
+}
+
+/**
+ * Calculate starting offset for send buffer
+ *
+ * @v linda Linda device
+ * @v send_buf Send buffer
+ * @ret offset Starting offset
+ */
+static unsigned long linda_send_buffer_offset ( struct linda *linda,
+ unsigned int send_buf ) {
+ return ( linda->send_buffer_base +
+ ( ( send_buf & ~LINDA_SEND_BUF_TOGGLE ) *
+ LINDA_SEND_BUF_SIZE ) );
+}
+
+/**
+ * Create send work queue
+ *
+ * @v linda Linda device
+ * @v qp Queue pair
+ */
+static int linda_create_send_wq ( struct linda *linda,
+ struct ib_queue_pair *qp ) {
+ struct ib_work_queue *wq = &qp->send;
+ struct linda_send_work_queue *linda_wq = ib_wq_get_drvdata ( wq );
+ int rc;
+
+ /* Reserve send buffers */
+ if ( ( linda->reserved_send_bufs + qp->send.num_wqes ) >
+ LINDA_MAX_SEND_BUFS ) {
+ DBGC ( linda, "Linda %p out of send buffers (have %d, used "
+ "%d, need %d)\n", linda, LINDA_MAX_SEND_BUFS,
+ linda->reserved_send_bufs, qp->send.num_wqes );
+ rc = -ENOBUFS;
+ goto err_reserve_bufs;
+ }
+ linda->reserved_send_bufs += qp->send.num_wqes;
+
+ /* Reset work queue */
+ linda_wq->prod = 0;
+ linda_wq->cons = 0;
+
+ /* Allocate space for send buffer uasge list */
+ linda_wq->send_buf = zalloc ( qp->send.num_wqes *
+ sizeof ( linda_wq->send_buf[0] ) );
+ if ( ! linda_wq->send_buf ) {
+ rc = -ENOBUFS;
+ goto err_alloc_send_buf;
+ }
+
+ return 0;
+
+ free ( linda_wq->send_buf );
+ err_alloc_send_buf:
+ linda->reserved_send_bufs -= qp->send.num_wqes;
+ err_reserve_bufs:
+ return rc;
+}
+
+/**
+ * Destroy send work queue
+ *
+ * @v linda Linda device
+ * @v qp Queue pair
+ */
+static void linda_destroy_send_wq ( struct linda *linda,
+ struct ib_queue_pair *qp ) {
+ struct ib_work_queue *wq = &qp->send;
+ struct linda_send_work_queue *linda_wq = ib_wq_get_drvdata ( wq );
+
+ free ( linda_wq->send_buf );
+ linda->reserved_send_bufs -= qp->send.num_wqes;
+}
+
+/**
+ * Initialise send datapath
+ *
+ * @v linda Linda device
+ * @ret rc Return status code
+ */
+static int linda_init_send ( struct linda *linda ) {
+ struct QIB_7220_SendBufBase sendbufbase;
+ struct QIB_7220_SendBufAvailAddr sendbufavailaddr;
+ struct QIB_7220_SendCtrl sendctrl;
+ unsigned int i;
+ int rc;
+
+ /* Retrieve SendBufBase */
+ linda_readq ( linda, &sendbufbase, QIB_7220_SendBufBase_offset );
+ linda->send_buffer_base = BIT_GET ( &sendbufbase,
+ BaseAddr_SmallPIO );
+ DBGC ( linda, "Linda %p send buffers at %lx\n",
+ linda, linda->send_buffer_base );
+
+ /* Initialise the send_buf[] array */
+ for ( i = 0 ; i < LINDA_MAX_SEND_BUFS ; i++ )
+ linda->send_buf[i] = i;
+
+ /* Allocate space for the SendBufAvail array */
+ linda->sendbufavail = malloc_dma ( sizeof ( *linda->sendbufavail ),
+ LINDA_SENDBUFAVAIL_ALIGN );
+ if ( ! linda->sendbufavail ) {
+ rc = -ENOMEM;
+ goto err_alloc_sendbufavail;
+ }
+ memset ( linda->sendbufavail, 0, sizeof ( linda->sendbufavail ) );
+
+ /* Program SendBufAvailAddr into the hardware */
+ memset ( &sendbufavailaddr, 0, sizeof ( sendbufavailaddr ) );
+ BIT_FILL_1 ( &sendbufavailaddr, SendBufAvailAddr,
+ ( virt_to_bus ( linda->sendbufavail ) >> 6 ) );
+ linda_writeq ( linda, &sendbufavailaddr,
+ QIB_7220_SendBufAvailAddr_offset );
+
+ /* Enable sending and DMA of SendBufAvail */
+ memset ( &sendctrl, 0, sizeof ( sendctrl ) );
+ BIT_FILL_2 ( &sendctrl,
+ SendBufAvailUpd, 1,
+ SPioEnable, 1 );
+ linda_writeq ( linda, &sendctrl, QIB_7220_SendCtrl_offset );
+
+ return 0;
+
+ free_dma ( linda->sendbufavail, sizeof ( *linda->sendbufavail ) );
+ err_alloc_sendbufavail:
+ return rc;
+}
+
+/**
+ * Shut down send datapath
+ *
+ * @v linda Linda device
+ */
+static void linda_fini_send ( struct linda *linda ) {
+ struct QIB_7220_SendCtrl sendctrl;
+
+ /* Disable sending and DMA of SendBufAvail */
+ memset ( &sendctrl, 0, sizeof ( sendctrl ) );
+ linda_writeq ( linda, &sendctrl, QIB_7220_SendCtrl_offset );
+ mb();
+
+ /* Ensure hardware has seen this disable */
+ linda_readq ( linda, &sendctrl, QIB_7220_SendCtrl_offset );
+
+ free_dma ( linda->sendbufavail, sizeof ( *linda->sendbufavail ) );
+}
+
+/***************************************************************************
+ *
+ * Receive datapath
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Create receive work queue
+ *
+ * @v linda Linda device
+ * @v qp Queue pair
+ * @ret rc Return status code
+ */
+static int linda_create_recv_wq ( struct linda *linda,
+ struct ib_queue_pair *qp ) {
+ struct ib_work_queue *wq = &qp->recv;
+ struct linda_recv_work_queue *linda_wq = ib_wq_get_drvdata ( wq );
+ struct QIB_7220_RcvHdrAddr0 rcvhdraddr;
+ struct QIB_7220_RcvHdrTailAddr0 rcvhdrtailaddr;
+ struct QIB_7220_RcvHdrHead0 rcvhdrhead;
+ struct QIB_7220_scalar rcvegrindexhead;
+ struct QIB_7220_RcvCtrl rcvctrl;
+ unsigned int ctx = linda_qpn_to_ctx ( qp->qpn );
+ int rc;
+
+ /* Reset context information */
+ memset ( &linda_wq->header_prod, 0,
+ sizeof ( linda_wq->header_prod ) );
+ linda_wq->header_cons = 0;
+ linda_wq->eager_prod = 0;
+ linda_wq->eager_cons = 0;
+
+ /* Allocate receive header buffer */
+ linda_wq->header = malloc_dma ( LINDA_RECV_HEADERS_SIZE,
+ LINDA_RECV_HEADERS_ALIGN );
+ if ( ! linda_wq->header ) {
+ rc = -ENOMEM;
+ goto err_alloc_header;
+ }
+
+ /* Enable context in hardware */
+ memset ( &rcvhdraddr, 0, sizeof ( rcvhdraddr ) );
+ BIT_FILL_1 ( &rcvhdraddr, RcvHdrAddr0,
+ ( virt_to_bus ( linda_wq->header ) >> 2 ) );
+ linda_writeq_array8b ( linda, &rcvhdraddr,
+ QIB_7220_RcvHdrAddr0_offset, ctx );
+ memset ( &rcvhdrtailaddr, 0, sizeof ( rcvhdrtailaddr ) );
+ BIT_FILL_1 ( &rcvhdrtailaddr, RcvHdrTailAddr0,
+ ( virt_to_bus ( &linda_wq->header_prod ) >> 2 ) );
+ linda_writeq_array8b ( linda, &rcvhdrtailaddr,
+ QIB_7220_RcvHdrTailAddr0_offset, ctx );
+ memset ( &rcvhdrhead, 0, sizeof ( rcvhdrhead ) );
+ BIT_FILL_1 ( &rcvhdrhead, counter, 1 );
+ linda_writeq_array64k ( linda, &rcvhdrhead,
+ QIB_7220_RcvHdrHead0_offset, ctx );
+ memset ( &rcvegrindexhead, 0, sizeof ( rcvegrindexhead ) );
+ BIT_FILL_1 ( &rcvegrindexhead, Value, 1 );
+ linda_writeq_array64k ( linda, &rcvegrindexhead,
+ QIB_7220_RcvEgrIndexHead0_offset, ctx );
+ linda_readq ( linda, &rcvctrl, QIB_7220_RcvCtrl_offset );
+ BIT_SET ( &rcvctrl, PortEnable[ctx], 1 );
+ BIT_SET ( &rcvctrl, IntrAvail[ctx], 1 );
+ linda_writeq ( linda, &rcvctrl, QIB_7220_RcvCtrl_offset );
+
+ DBGC ( linda, "Linda %p QPN %ld CTX %d hdrs [%lx,%lx) prod %lx\n",
+ linda, qp->qpn, ctx, virt_to_bus ( linda_wq->header ),
+ ( virt_to_bus ( linda_wq->header ) + LINDA_RECV_HEADERS_SIZE ),
+ virt_to_bus ( &linda_wq->header_prod ) );
+ return 0;
+
+ free_dma ( linda_wq->header, LINDA_RECV_HEADERS_SIZE );
+ err_alloc_header:
+ return rc;
+}
+
+/**
+ * Destroy receive work queue
+ *
+ * @v linda Linda device
+ * @v qp Queue pair
+ */
+static void linda_destroy_recv_wq ( struct linda *linda,
+ struct ib_queue_pair *qp ) {
+ struct ib_work_queue *wq = &qp->recv;
+ struct linda_recv_work_queue *linda_wq = ib_wq_get_drvdata ( wq );
+ struct QIB_7220_RcvCtrl rcvctrl;
+ unsigned int ctx = linda_qpn_to_ctx ( qp->qpn );
+
+ /* Disable context in hardware */
+ linda_readq ( linda, &rcvctrl, QIB_7220_RcvCtrl_offset );
+ BIT_SET ( &rcvctrl, PortEnable[ctx], 0 );
+ BIT_SET ( &rcvctrl, IntrAvail[ctx], 0 );
+ linda_writeq ( linda, &rcvctrl, QIB_7220_RcvCtrl_offset );
+
+ /* Make sure the hardware has seen that the context is disabled */
+ linda_readq ( linda, &rcvctrl, QIB_7220_RcvCtrl_offset );
+ mb();
+
+ /* Free headers ring */
+ free_dma ( linda_wq->header, LINDA_RECV_HEADERS_SIZE );
+
+ /* Free context */
+ linda_free_ctx ( linda, ctx );
+}
+
+/**
+ * Initialise receive datapath
+ *
+ * @v linda Linda device
+ * @ret rc Return status code
+ */
+static int linda_init_recv ( struct linda *linda ) {
+ struct QIB_7220_RcvCtrl rcvctrl;
+ struct QIB_7220_scalar rcvegrbase;
+ struct QIB_7220_scalar rcvhdrentsize;
+ struct QIB_7220_scalar rcvhdrcnt;
+ struct QIB_7220_RcvBTHQP rcvbthqp;
+ unsigned int portcfg;
+ unsigned long egrbase;
+ unsigned int eager_array_size_0;
+ unsigned int eager_array_size_other;
+ unsigned int ctx;
+
+ /* Select configuration based on number of contexts */
+ switch ( LINDA_NUM_CONTEXTS ) {
+ case 5:
+ portcfg = LINDA_PORTCFG_5CTX;
+ eager_array_size_0 = LINDA_EAGER_ARRAY_SIZE_5CTX_0;
+ eager_array_size_other = LINDA_EAGER_ARRAY_SIZE_5CTX_OTHER;
+ break;
+ case 9:
+ portcfg = LINDA_PORTCFG_9CTX;
+ eager_array_size_0 = LINDA_EAGER_ARRAY_SIZE_9CTX_0;
+ eager_array_size_other = LINDA_EAGER_ARRAY_SIZE_9CTX_OTHER;
+ break;
+ case 17:
+ portcfg = LINDA_PORTCFG_17CTX;
+ eager_array_size_0 = LINDA_EAGER_ARRAY_SIZE_17CTX_0;
+ eager_array_size_other = LINDA_EAGER_ARRAY_SIZE_17CTX_OTHER;
+ break;
+ default:
+ linker_assert ( 0, invalid_LINDA_NUM_CONTEXTS );
+ return -EINVAL;
+ }
+
+ /* Configure number of contexts */
+ memset ( &rcvctrl, 0, sizeof ( rcvctrl ) );
+ BIT_FILL_3 ( &rcvctrl,
+ TailUpd, 1,
+ PortCfg, portcfg,
+ RcvQPMapEnable, 1 );
+ linda_writeq ( linda, &rcvctrl, QIB_7220_RcvCtrl_offset );
+
+ /* Configure receive header buffer sizes */
+ memset ( &rcvhdrcnt, 0, sizeof ( rcvhdrcnt ) );
+ BIT_FILL_1 ( &rcvhdrcnt, Value, LINDA_RECV_HEADER_COUNT );
+ linda_writeq ( linda, &rcvhdrcnt, QIB_7220_RcvHdrCnt_offset );
+ memset ( &rcvhdrentsize, 0, sizeof ( rcvhdrentsize ) );
+ BIT_FILL_1 ( &rcvhdrentsize, Value, ( LINDA_RECV_HEADER_SIZE >> 2 ) );
+ linda_writeq ( linda, &rcvhdrentsize, QIB_7220_RcvHdrEntSize_offset );
+
+ /* Calculate eager array start addresses for each context */
+ linda_readq ( linda, &rcvegrbase, QIB_7220_RcvEgrBase_offset );
+ egrbase = BIT_GET ( &rcvegrbase, Value );
+ linda->recv_wq[0].eager_array = egrbase;
+ linda->recv_wq[0].eager_entries = eager_array_size_0;
+ egrbase += ( eager_array_size_0 * sizeof ( struct QIB_7220_RcvEgr ) );
+ for ( ctx = 1 ; ctx < LINDA_NUM_CONTEXTS ; ctx++ ) {
+ linda->recv_wq[ctx].eager_array = egrbase;
+ linda->recv_wq[ctx].eager_entries = eager_array_size_other;
+ egrbase += ( eager_array_size_other *
+ sizeof ( struct QIB_7220_RcvEgr ) );
+ }
+ for ( ctx = 0 ; ctx < LINDA_NUM_CONTEXTS ; ctx++ ) {
+ DBGC ( linda, "Linda %p CTX %d eager array at %lx (%d "
+ "entries)\n", linda, ctx,
+ linda->recv_wq[ctx].eager_array,
+ linda->recv_wq[ctx].eager_entries );
+ }
+
+ /* Set the BTH QP for Infinipath packets to an unused value */
+ memset ( &rcvbthqp, 0, sizeof ( rcvbthqp ) );
+ BIT_FILL_1 ( &rcvbthqp, RcvBTHQP, LINDA_QP_IDETH );
+ linda_writeq ( linda, &rcvbthqp, QIB_7220_RcvBTHQP_offset );
+
+ return 0;
+}
+
+/**
+ * Shut down receive datapath
+ *
+ * @v linda Linda device
+ */
+static void linda_fini_recv ( struct linda *linda __unused ) {
+ /* Nothing to do; all contexts were already disabled when the
+ * queue pairs were destroyed
+ */
+}
+
+/***************************************************************************
+ *
+ * Completion queue operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Create completion queue
+ *
+ * @v ibdev Infiniband device
+ * @v cq Completion queue
+ * @ret rc Return status code
+ */
+static int linda_create_cq ( struct ib_device *ibdev,
+ struct ib_completion_queue *cq ) {
+ struct linda *linda = ib_get_drvdata ( ibdev );
+ static int cqn;
+
+ /* The hardware has no concept of completion queues. We
+ * simply use the association between CQs and WQs (already
+ * handled by the IB core) to decide which WQs to poll.
+ *
+ * We do set a CQN, just to avoid confusing debug messages
+ * from the IB core.
+ */
+ cq->cqn = ++cqn;
+ DBGC ( linda, "Linda %p CQN %ld created\n", linda, cq->cqn );
+
+ return 0;
+}
+
+/**
+ * Destroy completion queue
+ *
+ * @v ibdev Infiniband device
+ * @v cq Completion queue
+ */
+static void linda_destroy_cq ( struct ib_device *ibdev,
+ struct ib_completion_queue *cq ) {
+ struct linda *linda = ib_get_drvdata ( ibdev );
+
+ /* Nothing to do */
+ DBGC ( linda, "Linda %p CQN %ld destroyed\n", linda, cq->cqn );
+}
+
+/***************************************************************************
+ *
+ * Queue pair operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Create queue pair
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ * @ret rc Return status code
+ */
+static int linda_create_qp ( struct ib_device *ibdev,
+ struct ib_queue_pair *qp ) {
+ struct linda *linda = ib_get_drvdata ( ibdev );
+ int ctx;
+ int rc;
+
+ /* Locate an available context */
+ ctx = linda_alloc_ctx ( linda );
+ if ( ctx < 0 ) {
+ rc = ctx;
+ goto err_alloc_ctx;
+ }
+
+ /* Set queue pair number based on context index */
+ qp->qpn = linda_ctx_to_qpn ( ctx );
+
+ /* Set work-queue private data pointers */
+ ib_wq_set_drvdata ( &qp->send, &linda->send_wq[ctx] );
+ ib_wq_set_drvdata ( &qp->recv, &linda->recv_wq[ctx] );
+
+ /* Create receive work queue */
+ if ( ( rc = linda_create_recv_wq ( linda, qp ) ) != 0 )
+ goto err_create_recv_wq;
+
+ /* Create send work queue */
+ if ( ( rc = linda_create_send_wq ( linda, qp ) ) != 0 )
+ goto err_create_send_wq;
+
+ return 0;
+
+ linda_destroy_send_wq ( linda, qp );
+ err_create_send_wq:
+ linda_destroy_recv_wq ( linda, qp );
+ err_create_recv_wq:
+ linda_free_ctx ( linda, ctx );
+ err_alloc_ctx:
+ return rc;
+}
+
+/**
+ * Modify queue pair
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ * @v mod_list Modification list
+ * @ret rc Return status code
+ */
+static int linda_modify_qp ( struct ib_device *ibdev,
+ struct ib_queue_pair *qp,
+ unsigned long mod_list __unused ) {
+ struct linda *linda = ib_get_drvdata ( ibdev );
+
+ /* Nothing to do; the hardware doesn't have a notion of queue
+ * keys
+ */
+ DBGC ( linda, "Linda %p QPN %ld modified\n", linda, qp->qpn );
+ return 0;
+}
+
+/**
+ * Destroy queue pair
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ */
+static void linda_destroy_qp ( struct ib_device *ibdev,
+ struct ib_queue_pair *qp ) {
+ struct linda *linda = ib_get_drvdata ( ibdev );
+
+ linda_destroy_send_wq ( linda, qp );
+ linda_destroy_recv_wq ( linda, qp );
+}
+
+/***************************************************************************
+ *
+ * Work request operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Post send work queue entry
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ * @v av Address vector
+ * @v iobuf I/O buffer
+ * @ret rc Return status code
+ */
+static int linda_post_send ( struct ib_device *ibdev,
+ struct ib_queue_pair *qp,
+ struct ib_address_vector *av,
+ struct io_buffer *iobuf ) {
+ struct linda *linda = ib_get_drvdata ( ibdev );
+ struct ib_work_queue *wq = &qp->send;
+ struct linda_send_work_queue *linda_wq = ib_wq_get_drvdata ( wq );
+ struct QIB_7220_SendPbc sendpbc;
+ uint8_t header_buf[IB_MAX_HEADER_SIZE];
+ struct io_buffer headers;
+ unsigned int send_buf;
+ unsigned long start_offset;
+ unsigned long offset;
+ size_t len;
+ ssize_t frag_len;
+ uint32_t *data;
+
+ /* Allocate send buffer and calculate offset */
+ send_buf = linda_alloc_send_buf ( linda );
+ start_offset = offset = linda_send_buffer_offset ( linda, send_buf );
+
+ /* Store I/O buffer and send buffer index */
+ assert ( wq->iobufs[linda_wq->prod] == NULL );
+ wq->iobufs[linda_wq->prod] = iobuf;
+ linda_wq->send_buf[linda_wq->prod] = send_buf;
+
+ /* Construct headers */
+ iob_populate ( &headers, header_buf, 0, sizeof ( header_buf ) );
+ iob_reserve ( &headers, sizeof ( header_buf ) );
+ ib_push ( ibdev, &headers, qp, iob_len ( iobuf ), av );
+
+ /* Calculate packet length */
+ len = ( ( sizeof ( sendpbc ) + iob_len ( &headers ) +
+ iob_len ( iobuf ) + 3 ) & ~3 );
+
+ /* Construct send per-buffer control word */
+ memset ( &sendpbc, 0, sizeof ( sendpbc ) );
+ BIT_FILL_2 ( &sendpbc,
+ LengthP1_toibc, ( ( len >> 2 ) - 1 ),
+ VL15, 1 );
+
+ /* Write SendPbc */
+ DBG_DISABLE ( DBGLVL_IO );
+ linda_writeq ( linda, &sendpbc, offset );
+ offset += sizeof ( sendpbc );
+
+ /* Write headers */
+ for ( data = headers.data, frag_len = iob_len ( &headers ) ;
+ frag_len > 0 ; data++, offset += 4, frag_len -= 4 ) {
+ linda_writel ( linda, *data, offset );
+ }
+
+ /* Write data */
+ for ( data = iobuf->data, frag_len = iob_len ( iobuf ) ;
+ frag_len > 0 ; data++, offset += 4, frag_len -= 4 ) {
+ linda_writel ( linda, *data, offset );
+ }
+ DBG_ENABLE ( DBGLVL_IO );
+
+ assert ( ( start_offset + len ) == offset );
+ DBGC2 ( linda, "Linda %p QPN %ld TX %d(%d) posted [%lx,%lx)\n",
+ linda, qp->qpn, send_buf, linda_wq->prod,
+ start_offset, offset );
+
+ /* Increment producer counter */
+ linda_wq->prod = ( ( linda_wq->prod + 1 ) & ( wq->num_wqes - 1 ) );
+
+ return 0;
+}
+
+/**
+ * Complete send work queue entry
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ * @v wqe_idx Work queue entry index
+ */
+static void linda_complete_send ( struct ib_device *ibdev,
+ struct ib_queue_pair *qp,
+ unsigned int wqe_idx ) {
+ struct linda *linda = ib_get_drvdata ( ibdev );
+ struct ib_work_queue *wq = &qp->send;
+ struct linda_send_work_queue *linda_wq = ib_wq_get_drvdata ( wq );
+ struct io_buffer *iobuf;
+ unsigned int send_buf;
+
+ /* Parse completion */
+ send_buf = linda_wq->send_buf[wqe_idx];
+ DBGC2 ( linda, "Linda %p QPN %ld TX %d(%d) complete\n",
+ linda, qp->qpn, send_buf, wqe_idx );
+
+ /* Complete work queue entry */
+ iobuf = wq->iobufs[wqe_idx];
+ assert ( iobuf != NULL );
+ ib_complete_send ( ibdev, qp, iobuf, 0 );
+ wq->iobufs[wqe_idx] = NULL;
+
+ /* Free send buffer */
+ linda_free_send_buf ( linda, send_buf );
+}
+
+/**
+ * Poll send work queue
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ */
+static void linda_poll_send_wq ( struct ib_device *ibdev,
+ struct ib_queue_pair *qp ) {
+ struct linda *linda = ib_get_drvdata ( ibdev );
+ struct ib_work_queue *wq = &qp->send;
+ struct linda_send_work_queue *linda_wq = ib_wq_get_drvdata ( wq );
+ unsigned int send_buf;
+
+ /* Look for completions */
+ while ( wq->fill ) {
+
+ /* Check to see if send buffer has completed */
+ send_buf = linda_wq->send_buf[linda_wq->cons];
+ if ( linda_send_buf_in_use ( linda, send_buf ) )
+ break;
+
+ /* Complete this buffer */
+ linda_complete_send ( ibdev, qp, linda_wq->cons );
+
+ /* Increment consumer counter */
+ linda_wq->cons = ( ( linda_wq->cons + 1 ) &
+ ( wq->num_wqes - 1 ) );
+ }
+}
+
+/**
+ * Post receive work queue entry
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ * @v iobuf I/O buffer
+ * @ret rc Return status code
+ */
+static int linda_post_recv ( struct ib_device *ibdev,
+ struct ib_queue_pair *qp,
+ struct io_buffer *iobuf ) {
+ struct linda *linda = ib_get_drvdata ( ibdev );
+ struct ib_work_queue *wq = &qp->recv;
+ struct linda_recv_work_queue *linda_wq = ib_wq_get_drvdata ( wq );
+ struct QIB_7220_RcvEgr rcvegr;
+ struct QIB_7220_scalar rcvegrindexhead;
+ unsigned int ctx = linda_qpn_to_ctx ( qp->qpn );
+ physaddr_t addr;
+ size_t len;
+ unsigned int wqe_idx;
+ unsigned int bufsize;
+
+ /* Sanity checks */
+ addr = virt_to_bus ( iobuf->data );
+ len = iob_tailroom ( iobuf );
+ if ( addr & ( LINDA_EAGER_BUFFER_ALIGN - 1 ) ) {
+ DBGC ( linda, "Linda %p QPN %ld misaligned RX buffer "
+ "(%08lx)\n", linda, qp->qpn, addr );
+ return -EINVAL;
+ }
+ if ( len != LINDA_RECV_PAYLOAD_SIZE ) {
+ DBGC ( linda, "Linda %p QPN %ld wrong RX buffer size (%zd)\n",
+ linda, qp->qpn, len );
+ return -EINVAL;
+ }
+
+ /* Calculate eager producer index and WQE index */
+ wqe_idx = ( linda_wq->eager_prod & ( wq->num_wqes - 1 ) );
+ assert ( wq->iobufs[wqe_idx] == NULL );
+
+ /* Store I/O buffer */
+ wq->iobufs[wqe_idx] = iobuf;
+
+ /* Calculate buffer size */
+ switch ( LINDA_RECV_PAYLOAD_SIZE ) {
+ case 2048: bufsize = LINDA_EAGER_BUFFER_2K; break;
+ case 4096: bufsize = LINDA_EAGER_BUFFER_4K; break;
+ case 8192: bufsize = LINDA_EAGER_BUFFER_8K; break;
+ case 16384: bufsize = LINDA_EAGER_BUFFER_16K; break;
+ case 32768: bufsize = LINDA_EAGER_BUFFER_32K; break;
+ case 65536: bufsize = LINDA_EAGER_BUFFER_64K; break;
+ default: linker_assert ( 0, invalid_rx_payload_size );
+ bufsize = LINDA_EAGER_BUFFER_NONE;
+ }
+
+ /* Post eager buffer */
+ memset ( &rcvegr, 0, sizeof ( rcvegr ) );
+ BIT_FILL_2 ( &rcvegr,
+ Addr, ( addr >> 11 ),
+ BufSize, bufsize );
+ linda_writeq_array8b ( linda, &rcvegr,
+ linda_wq->eager_array, linda_wq->eager_prod );
+ DBGC2 ( linda, "Linda %p QPN %ld RX egr %d(%d) posted [%lx,%lx)\n",
+ linda, qp->qpn, linda_wq->eager_prod, wqe_idx,
+ addr, ( addr + len ) );
+
+ /* Increment producer index */
+ linda_wq->eager_prod = ( ( linda_wq->eager_prod + 1 ) &
+ ( linda_wq->eager_entries - 1 ) );
+
+ /* Update head index */
+ memset ( &rcvegrindexhead, 0, sizeof ( rcvegrindexhead ) );
+ BIT_FILL_1 ( &rcvegrindexhead,
+ Value, ( ( linda_wq->eager_prod + 1 ) &
+ ( linda_wq->eager_entries - 1 ) ) );
+ linda_writeq_array64k ( linda, &rcvegrindexhead,
+ QIB_7220_RcvEgrIndexHead0_offset, ctx );
+
+ return 0;
+}
+
+/**
+ * Complete receive work queue entry
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ * @v header_offs Header offset
+ */
+static void linda_complete_recv ( struct ib_device *ibdev,
+ struct ib_queue_pair *qp,
+ unsigned int header_offs ) {
+ struct linda *linda = ib_get_drvdata ( ibdev );
+ struct ib_work_queue *wq = &qp->recv;
+ struct linda_recv_work_queue *linda_wq = ib_wq_get_drvdata ( wq );
+ struct QIB_7220_RcvHdrFlags *rcvhdrflags;
+ struct QIB_7220_RcvEgr rcvegr;
+ struct io_buffer headers;
+ struct io_buffer *iobuf;
+ struct ib_queue_pair *intended_qp;
+ struct ib_address_vector av;
+ unsigned int rcvtype;
+ unsigned int pktlen;
+ unsigned int egrindex;
+ unsigned int useegrbfr;
+ unsigned int iberr, mkerr, tiderr, khdrerr, mtuerr;
+ unsigned int lenerr, parityerr, vcrcerr, icrcerr;
+ unsigned int err;
+ unsigned int hdrqoffset;
+ unsigned int header_len;
+ unsigned int padded_payload_len;
+ unsigned int wqe_idx;
+ size_t payload_len;
+ int qp0;
+ int rc;
+
+ /* RcvHdrFlags are at the end of the header entry */
+ rcvhdrflags = ( linda_wq->header + header_offs +
+ LINDA_RECV_HEADER_SIZE - sizeof ( *rcvhdrflags ) );
+ rcvtype = BIT_GET ( rcvhdrflags, RcvType );
+ pktlen = ( BIT_GET ( rcvhdrflags, PktLen ) << 2 );
+ egrindex = BIT_GET ( rcvhdrflags, EgrIndex );
+ useegrbfr = BIT_GET ( rcvhdrflags, UseEgrBfr );
+ hdrqoffset = ( BIT_GET ( rcvhdrflags, HdrqOffset ) << 2 );
+ iberr = BIT_GET ( rcvhdrflags, IBErr );
+ mkerr = BIT_GET ( rcvhdrflags, MKErr );
+ tiderr = BIT_GET ( rcvhdrflags, TIDErr );
+ khdrerr = BIT_GET ( rcvhdrflags, KHdrErr );
+ mtuerr = BIT_GET ( rcvhdrflags, MTUErr );
+ lenerr = BIT_GET ( rcvhdrflags, LenErr );
+ parityerr = BIT_GET ( rcvhdrflags, ParityErr );
+ vcrcerr = BIT_GET ( rcvhdrflags, VCRCErr );
+ icrcerr = BIT_GET ( rcvhdrflags, ICRCErr );
+ header_len = ( LINDA_RECV_HEADER_SIZE - hdrqoffset -
+ sizeof ( *rcvhdrflags ) );
+ padded_payload_len = ( pktlen - header_len - 4 /* ICRC */ );
+ err = ( iberr | mkerr | tiderr | khdrerr | mtuerr |
+ lenerr | parityerr | vcrcerr | icrcerr );
+ /* IB header is placed immediately before RcvHdrFlags */
+ iob_populate ( &headers, ( ( ( void * ) rcvhdrflags ) - header_len ),
+ header_len, header_len );
+
+ /* Dump diagnostic information */
+ if ( err || ( ! useegrbfr ) ) {
+ DBGC ( linda, "Linda %p QPN %ld RX egr %d%s hdr %d type %d "
+ "len %d(%d+%d+4)%s%s%s%s%s%s%s%s%s%s%s\n", linda,
+ qp->qpn, egrindex, ( useegrbfr ? "" : "(unused)" ),
+ ( header_offs / LINDA_RECV_HEADER_SIZE ), rcvtype,
+ pktlen, header_len, padded_payload_len,
+ ( err ? " [Err" : "" ), ( iberr ? " IB" : "" ),
+ ( mkerr ? " MK" : "" ), ( tiderr ? " TID" : "" ),
+ ( khdrerr ? " KHdr" : "" ), ( mtuerr ? " MTU" : "" ),
+ ( lenerr ? " Len" : "" ), ( parityerr ? " Parity" : ""),
+ ( vcrcerr ? " VCRC" : "" ), ( icrcerr ? " ICRC" : "" ),
+ ( err ? "]" : "" ) );
+ } else {
+ DBGC2 ( linda, "Linda %p QPN %ld RX egr %d hdr %d type %d "
+ "len %d(%d+%d+4)\n", linda, qp->qpn, egrindex,
+ ( header_offs / LINDA_RECV_HEADER_SIZE ), rcvtype,
+ pktlen, header_len, padded_payload_len );
+ }
+ DBGCP_HDA ( linda, hdrqoffset, headers.data,
+ ( header_len + sizeof ( *rcvhdrflags ) ) );
+
+ /* Parse header to generate address vector */
+ qp0 = ( qp->qpn == 0 );
+ intended_qp = NULL;
+ if ( ( rc = ib_pull ( ibdev, &headers, ( qp0 ? &intended_qp : NULL ),
+ &payload_len, &av ) ) != 0 ) {
+ DBGC ( linda, "Linda %p could not parse headers: %s\n",
+ linda, strerror ( rc ) );
+ err = 1;
+ }
+ if ( ! intended_qp )
+ intended_qp = qp;
+
+ /* Complete this buffer and any skipped buffers. Note that
+ * when the hardware runs out of buffers, it will repeatedly
+ * report the same buffer (the tail) as a TID error, and that
+ * it also has a habit of sometimes skipping over several
+ * buffers at once.
+ */
+ while ( 1 ) {
+
+ /* If we have caught up to the producer counter, stop.
+ * This will happen when the hardware first runs out
+ * of buffers and starts reporting TID errors against
+ * the eager buffer it wants to use next.
+ */
+ if ( linda_wq->eager_cons == linda_wq->eager_prod )
+ break;
+
+ /* If we have caught up to where we should be after
+ * completing this egrindex, stop. We phrase the test
+ * this way to avoid completing the entire ring when
+ * we receive the same egrindex twice in a row.
+ */
+ if ( ( linda_wq->eager_cons ==
+ ( ( egrindex + 1 ) & ( linda_wq->eager_entries - 1 ) )))
+ break;
+
+ /* Identify work queue entry and corresponding I/O
+ * buffer.
+ */
+ wqe_idx = ( linda_wq->eager_cons & ( wq->num_wqes - 1 ) );
+ iobuf = wq->iobufs[wqe_idx];
+ assert ( iobuf != NULL );
+ wq->iobufs[wqe_idx] = NULL;
+
+ /* Complete the eager buffer */
+ if ( linda_wq->eager_cons == egrindex ) {
+ /* Completing the eager buffer described in
+ * this header entry.
+ */
+ iob_put ( iobuf, payload_len );
+ rc = ( err ? -EIO : ( useegrbfr ? 0 : -ECANCELED ) );
+ /* Redirect to target QP if necessary */
+ if ( qp != intended_qp ) {
+ DBGC ( linda, "Linda %p redirecting QPN %ld "
+ "=> %ld\n",
+ linda, qp->qpn, intended_qp->qpn );
+ /* Compensate for incorrect fill levels */
+ qp->recv.fill--;
+ intended_qp->recv.fill++;
+ }
+ ib_complete_recv ( ibdev, intended_qp, &av, iobuf, rc);
+ } else {
+ /* Completing on a skipped-over eager buffer */
+ ib_complete_recv ( ibdev, qp, &av, iobuf, -ECANCELED );
+ }
+
+ /* Clear eager buffer */
+ memset ( &rcvegr, 0, sizeof ( rcvegr ) );
+ linda_writeq_array8b ( linda, &rcvegr, linda_wq->eager_array,
+ linda_wq->eager_cons );
+
+ /* Increment consumer index */
+ linda_wq->eager_cons = ( ( linda_wq->eager_cons + 1 ) &
+ ( linda_wq->eager_entries - 1 ) );
+ }
+}
+
+/**
+ * Poll receive work queue
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ */
+static void linda_poll_recv_wq ( struct ib_device *ibdev,
+ struct ib_queue_pair *qp ) {
+ struct linda *linda = ib_get_drvdata ( ibdev );
+ struct ib_work_queue *wq = &qp->recv;
+ struct linda_recv_work_queue *linda_wq = ib_wq_get_drvdata ( wq );
+ struct QIB_7220_RcvHdrHead0 rcvhdrhead;
+ unsigned int ctx = linda_qpn_to_ctx ( qp->qpn );
+ unsigned int header_prod;
+
+ /* Check for received packets */
+ header_prod = ( BIT_GET ( &linda_wq->header_prod, Value ) << 2 );
+ if ( header_prod == linda_wq->header_cons )
+ return;
+
+ /* Process all received packets */
+ while ( linda_wq->header_cons != header_prod ) {
+
+ /* Complete the receive */
+ linda_complete_recv ( ibdev, qp, linda_wq->header_cons );
+
+ /* Increment the consumer offset */
+ linda_wq->header_cons += LINDA_RECV_HEADER_SIZE;
+ linda_wq->header_cons %= LINDA_RECV_HEADERS_SIZE;
+ }
+
+ /* Update consumer offset */
+ memset ( &rcvhdrhead, 0, sizeof ( rcvhdrhead ) );
+ BIT_FILL_2 ( &rcvhdrhead,
+ RcvHeadPointer, ( linda_wq->header_cons >> 2 ),
+ counter, 1 );
+ linda_writeq_array64k ( linda, &rcvhdrhead,
+ QIB_7220_RcvHdrHead0_offset, ctx );
+}
+
+/**
+ * Poll completion queue
+ *
+ * @v ibdev Infiniband device
+ * @v cq Completion queue
+ */
+static void linda_poll_cq ( struct ib_device *ibdev,
+ struct ib_completion_queue *cq ) {
+ struct ib_work_queue *wq;
+
+ /* Poll associated send and receive queues */
+ list_for_each_entry ( wq, &cq->work_queues, list ) {
+ if ( wq->is_send ) {
+ linda_poll_send_wq ( ibdev, wq->qp );
+ } else {
+ linda_poll_recv_wq ( ibdev, wq->qp );
+ }
+ }
+}
+
+/***************************************************************************
+ *
+ * Event queues
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Poll event queue
+ *
+ * @v ibdev Infiniband device
+ */
+static void linda_poll_eq ( struct ib_device *ibdev ) {
+ struct linda *linda = ib_get_drvdata ( ibdev );
+ struct QIB_7220_ErrStatus errstatus;
+ struct QIB_7220_ErrClear errclear;
+
+ /* Check for link status changes */
+ DBG_DISABLE ( DBGLVL_IO );
+ linda_readq ( linda, &errstatus, QIB_7220_ErrStatus_offset );
+ DBG_ENABLE ( DBGLVL_IO );
+ if ( BIT_GET ( &errstatus, IBStatusChanged ) ) {
+ linda_link_state_changed ( ibdev );
+ memset ( &errclear, 0, sizeof ( errclear ) );
+ BIT_FILL_1 ( &errclear, IBStatusChangedClear, 1 );
+ linda_writeq ( linda, &errclear, QIB_7220_ErrClear_offset );
+ }
+}
+
+/***************************************************************************
+ *
+ * Infiniband link-layer operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Initialise Infiniband link
+ *
+ * @v ibdev Infiniband device
+ * @ret rc Return status code
+ */
+static int linda_open ( struct ib_device *ibdev ) {
+ struct linda *linda = ib_get_drvdata ( ibdev );
+ struct QIB_7220_Control control;
+
+ /* Disable link */
+ linda_readq ( linda, &control, QIB_7220_Control_offset );
+ BIT_SET ( &control, LinkEn, 1 );
+ linda_writeq ( linda, &control, QIB_7220_Control_offset );
+ return 0;
+}
+
+/**
+ * Close Infiniband link
+ *
+ * @v ibdev Infiniband device
+ */
+static void linda_close ( struct ib_device *ibdev ) {
+ struct linda *linda = ib_get_drvdata ( ibdev );
+ struct QIB_7220_Control control;
+
+ /* Disable link */
+ linda_readq ( linda, &control, QIB_7220_Control_offset );
+ BIT_SET ( &control, LinkEn, 0 );
+ linda_writeq ( linda, &control, QIB_7220_Control_offset );
+}
+
+/***************************************************************************
+ *
+ * Multicast group operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Attach to multicast group
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ * @v gid Multicast GID
+ * @ret rc Return status code
+ */
+static int linda_mcast_attach ( struct ib_device *ibdev,
+ struct ib_queue_pair *qp,
+ struct ib_gid *gid ) {
+ struct linda *linda = ib_get_drvdata ( ibdev );
+
+ ( void ) linda;
+ ( void ) qp;
+ ( void ) gid;
+ return 0;
+}
+
+/**
+ * Detach from multicast group
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ * @v gid Multicast GID
+ */
+static void linda_mcast_detach ( struct ib_device *ibdev,
+ struct ib_queue_pair *qp,
+ struct ib_gid *gid ) {
+ struct linda *linda = ib_get_drvdata ( ibdev );
+
+ ( void ) linda;
+ ( void ) qp;
+ ( void ) gid;
+}
+
+/** Linda Infiniband operations */
+static struct ib_device_operations linda_ib_operations = {
+ .create_cq = linda_create_cq,
+ .destroy_cq = linda_destroy_cq,
+ .create_qp = linda_create_qp,
+ .modify_qp = linda_modify_qp,
+ .destroy_qp = linda_destroy_qp,
+ .post_send = linda_post_send,
+ .post_recv = linda_post_recv,
+ .poll_cq = linda_poll_cq,
+ .poll_eq = linda_poll_eq,
+ .open = linda_open,
+ .close = linda_close,
+ .mcast_attach = linda_mcast_attach,
+ .mcast_detach = linda_mcast_detach,
+};
+
+/***************************************************************************
+ *
+ * I2C bus operations
+ *
+ ***************************************************************************
+ */
+
+/** Linda I2C bit to GPIO mappings */
+static unsigned int linda_i2c_bits[] = {
+ [I2C_BIT_SCL] = ( 1 << LINDA_GPIO_SCL ),
+ [I2C_BIT_SDA] = ( 1 << LINDA_GPIO_SDA ),
+};
+
+/**
+ * Read Linda I2C line status
+ *
+ * @v basher Bit-bashing interface
+ * @v bit_id Bit number
+ * @ret zero Input is a logic 0
+ * @ret non-zero Input is a logic 1
+ */
+static int linda_i2c_read_bit ( struct bit_basher *basher,
+ unsigned int bit_id ) {
+ struct linda *linda =
+ container_of ( basher, struct linda, i2c.basher );
+ struct QIB_7220_EXTStatus extstatus;
+ unsigned int status;
+
+ DBG_DISABLE ( DBGLVL_IO );
+
+ linda_readq ( linda, &extstatus, QIB_7220_EXTStatus_offset );
+ status = ( BIT_GET ( &extstatus, GPIOIn ) & linda_i2c_bits[bit_id] );
+
+ DBG_ENABLE ( DBGLVL_IO );
+
+ return status;
+}
+
+/**
+ * Write Linda I2C line status
+ *
+ * @v basher Bit-bashing interface
+ * @v bit_id Bit number
+ * @v data Value to write
+ */
+static void linda_i2c_write_bit ( struct bit_basher *basher,
+ unsigned int bit_id, unsigned long data ) {
+ struct linda *linda =
+ container_of ( basher, struct linda, i2c.basher );
+ struct QIB_7220_EXTCtrl extctrl;
+ struct QIB_7220_GPIO gpioout;
+ unsigned int bit = linda_i2c_bits[bit_id];
+ unsigned int outputs = 0;
+ unsigned int output_enables = 0;
+
+ DBG_DISABLE ( DBGLVL_IO );
+
+ /* Read current GPIO mask and outputs */
+ linda_readq ( linda, &extctrl, QIB_7220_EXTCtrl_offset );
+ linda_readq ( linda, &gpioout, QIB_7220_GPIOOut_offset );
+
+ /* Update outputs and output enables. I2C lines are tied
+ * high, so we always set the output to 0 and use the output
+ * enable to control the line.
+ */
+ output_enables = BIT_GET ( &extctrl, GPIOOe );
+ output_enables = ( ( output_enables & ~bit ) | ( ~data & bit ) );
+ outputs = BIT_GET ( &gpioout, GPIO );
+ outputs = ( outputs & ~bit );
+ BIT_SET ( &extctrl, GPIOOe, output_enables );
+ BIT_SET ( &gpioout, GPIO, outputs );
+
+ /* Write the output enable first; that way we avoid logic
+ * hazards.
+ */
+ linda_writeq ( linda, &extctrl, QIB_7220_EXTCtrl_offset );
+ linda_writeq ( linda, &gpioout, QIB_7220_GPIOOut_offset );
+ mb();
+
+ DBG_ENABLE ( DBGLVL_IO );
+}
+
+/** Linda I2C bit-bashing interface operations */
+static struct bit_basher_operations linda_i2c_basher_ops = {
+ .read = linda_i2c_read_bit,
+ .write = linda_i2c_write_bit,
+};
+
+/**
+ * Initialise Linda I2C subsystem
+ *
+ * @v linda Linda device
+ * @ret rc Return status code
+ */
+static int linda_init_i2c ( struct linda *linda ) {
+ static int try_eeprom_address[] = { 0x51, 0x50 };
+ unsigned int i;
+ int rc;
+
+ /* Initialise bus */
+ if ( ( rc = init_i2c_bit_basher ( &linda->i2c,
+ &linda_i2c_basher_ops ) ) != 0 ) {
+ DBGC ( linda, "Linda %p could not initialise I2C bus: %s\n",
+ linda, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Probe for devices */
+ for ( i = 0 ; i < ( sizeof ( try_eeprom_address ) /
+ sizeof ( try_eeprom_address[0] ) ) ; i++ ) {
+ init_i2c_eeprom ( &linda->eeprom, try_eeprom_address[i] );
+ if ( ( rc = i2c_check_presence ( &linda->i2c.i2c,
+ &linda->eeprom ) ) == 0 ) {
+ DBGC2 ( linda, "Linda %p found EEPROM at %02x\n",
+ linda, try_eeprom_address[i] );
+ return 0;
+ }
+ }
+
+ DBGC ( linda, "Linda %p could not find EEPROM\n", linda );
+ return -ENODEV;
+}
+
+/**
+ * Read EEPROM parameters
+ *
+ * @v linda Linda device
+ * @v guid GUID to fill in
+ * @ret rc Return status code
+ */
+static int linda_read_eeprom ( struct linda *linda,
+ struct ib_gid_half *guid ) {
+ struct i2c_interface *i2c = &linda->i2c.i2c;
+ int rc;
+
+ /* Read GUID */
+ if ( ( rc = i2c->read ( i2c, &linda->eeprom, LINDA_EEPROM_GUID_OFFSET,
+ guid->bytes, sizeof ( *guid ) ) ) != 0 ) {
+ DBGC ( linda, "Linda %p could not read GUID: %s\n",
+ linda, strerror ( rc ) );
+ return rc;
+ }
+ DBGC2 ( linda, "Linda %p has GUID %02x:%02x:%02x:%02x:%02x:%02x:"
+ "%02x:%02x\n", linda, guid->bytes[0], guid->bytes[1],
+ guid->bytes[2], guid->bytes[3], guid->bytes[4],
+ guid->bytes[5], guid->bytes[6], guid->bytes[7] );
+
+ /* Read serial number (debug only) */
+ if ( DBG_LOG ) {
+ uint8_t serial[LINDA_EEPROM_SERIAL_SIZE + 1];
+
+ serial[ sizeof ( serial ) - 1 ] = '\0';
+ if ( ( rc = i2c->read ( i2c, &linda->eeprom,
+ LINDA_EEPROM_SERIAL_OFFSET, serial,
+ ( sizeof ( serial ) - 1 ) ) ) != 0 ) {
+ DBGC ( linda, "Linda %p could not read serial: %s\n",
+ linda, strerror ( rc ) );
+ return rc;
+ }
+ DBGC2 ( linda, "Linda %p has serial number \"%s\"\n",
+ linda, serial );
+ }
+
+ return 0;
+}
+
+/***************************************************************************
+ *
+ * External parallel bus access
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Request ownership of the IB external parallel bus
+ *
+ * @v linda Linda device
+ * @ret rc Return status code
+ */
+static int linda_ib_epb_request ( struct linda *linda ) {
+ struct QIB_7220_ibsd_epb_access_ctrl access;
+ unsigned int i;
+
+ /* Request ownership */
+ memset ( &access, 0, sizeof ( access ) );
+ BIT_FILL_1 ( &access, sw_ib_epb_req, 1 );
+ linda_writeq ( linda, &access, QIB_7220_ibsd_epb_access_ctrl_offset );
+
+ /* Wait for ownership to be granted */
+ for ( i = 0 ; i < LINDA_EPB_REQUEST_MAX_WAIT_US ; i++ ) {
+ linda_readq ( linda, &access,
+ QIB_7220_ibsd_epb_access_ctrl_offset );
+ if ( BIT_GET ( &access, sw_ib_epb_req_granted ) )
+ return 0;
+ udelay ( 1 );
+ }
+
+ DBGC ( linda, "Linda %p timed out waiting for IB EPB request\n",
+ linda );
+ return -ETIMEDOUT;
+}
+
+/**
+ * Wait for IB external parallel bus transaction to complete
+ *
+ * @v linda Linda device
+ * @v xact Buffer to hold transaction result
+ * @ret rc Return status code
+ */
+static int linda_ib_epb_wait ( struct linda *linda,
+ struct QIB_7220_ibsd_epb_transaction_reg *xact ) {
+ unsigned int i;
+
+ /* Discard first read to allow for signals crossing clock domains */
+ linda_readq ( linda, xact, QIB_7220_ibsd_epb_transaction_reg_offset );
+
+ for ( i = 0 ; i < LINDA_EPB_XACT_MAX_WAIT_US ; i++ ) {
+ linda_readq ( linda, xact,
+ QIB_7220_ibsd_epb_transaction_reg_offset );
+ if ( BIT_GET ( xact, ib_epb_rdy ) ) {
+ if ( BIT_GET ( xact, ib_epb_req_error ) ) {
+ DBGC ( linda, "Linda %p EPB transaction "
+ "failed\n", linda );
+ return -EIO;
+ } else {
+ return 0;
+ }
+ }
+ udelay ( 1 );
+ }
+
+ DBGC ( linda, "Linda %p timed out waiting for IB EPB transaction\n",
+ linda );
+ return -ETIMEDOUT;
+}
+
+/**
+ * Release ownership of the IB external parallel bus
+ *
+ * @v linda Linda device
+ */
+static void linda_ib_epb_release ( struct linda *linda ) {
+ struct QIB_7220_ibsd_epb_access_ctrl access;
+
+ memset ( &access, 0, sizeof ( access ) );
+ BIT_FILL_1 ( &access, sw_ib_epb_req, 0 );
+ linda_writeq ( linda, &access, QIB_7220_ibsd_epb_access_ctrl_offset );
+}
+
+/**
+ * Read data via IB external parallel bus
+ *
+ * @v linda Linda device
+ * @v location EPB location
+ * @ret data Data read, or negative error
+ *
+ * You must have already acquired ownership of the IB external
+ * parallel bus.
+ */
+static int linda_ib_epb_read ( struct linda *linda, unsigned int location ) {
+ struct QIB_7220_ibsd_epb_transaction_reg xact;
+ unsigned int data;
+ int rc;
+
+ /* Ensure no transaction is currently in progress */
+ if ( ( rc = linda_ib_epb_wait ( linda, &xact ) ) != 0 )
+ return rc;
+
+ /* Process data */
+ memset ( &xact, 0, sizeof ( xact ) );
+ BIT_FILL_3 ( &xact,
+ ib_epb_address, LINDA_EPB_LOC_ADDRESS ( location ),
+ ib_epb_read_write, LINDA_EPB_READ,
+ ib_epb_cs, LINDA_EPB_LOC_CS ( location ) );
+ linda_writeq ( linda, &xact,
+ QIB_7220_ibsd_epb_transaction_reg_offset );
+
+ /* Wait for transaction to complete */
+ if ( ( rc = linda_ib_epb_wait ( linda, &xact ) ) != 0 )
+ return rc;
+
+ data = BIT_GET ( &xact, ib_epb_data );
+ return data;
+}
+
+/**
+ * Write data via IB external parallel bus
+ *
+ * @v linda Linda device
+ * @v location EPB location
+ * @v data Data to write
+ * @ret rc Return status code
+ *
+ * You must have already acquired ownership of the IB external
+ * parallel bus.
+ */
+static int linda_ib_epb_write ( struct linda *linda, unsigned int location,
+ unsigned int data ) {
+ struct QIB_7220_ibsd_epb_transaction_reg xact;
+ int rc;
+
+ /* Ensure no transaction is currently in progress */
+ if ( ( rc = linda_ib_epb_wait ( linda, &xact ) ) != 0 )
+ return rc;
+
+ /* Process data */
+ memset ( &xact, 0, sizeof ( xact ) );
+ BIT_FILL_4 ( &xact,
+ ib_epb_data, data,
+ ib_epb_address, LINDA_EPB_LOC_ADDRESS ( location ),
+ ib_epb_read_write, LINDA_EPB_WRITE,
+ ib_epb_cs, LINDA_EPB_LOC_CS ( location ) );
+ linda_writeq ( linda, &xact,
+ QIB_7220_ibsd_epb_transaction_reg_offset );
+
+ /* Wait for transaction to complete */
+ if ( ( rc = linda_ib_epb_wait ( linda, &xact ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/**
+ * Read/modify/write EPB register
+ *
+ * @v linda Linda device
+ * @v cs Chip select
+ * @v channel Channel
+ * @v element Element
+ * @v reg Register
+ * @v value Value to set
+ * @v mask Mask to apply to old value
+ * @ret rc Return status code
+ */
+static int linda_ib_epb_mod_reg ( struct linda *linda, unsigned int cs,
+ unsigned int channel, unsigned int element,
+ unsigned int reg, unsigned int value,
+ unsigned int mask ) {
+ unsigned int location;
+ int old_value;
+ int rc;
+
+ DBG_DISABLE ( DBGLVL_IO );
+
+ /* Sanity check */
+ assert ( ( value & mask ) == value );
+
+ /* Acquire bus ownership */
+ if ( ( rc = linda_ib_epb_request ( linda ) ) != 0 )
+ goto out;
+
+ /* Read existing value, if necessary */
+ location = LINDA_EPB_LOC ( cs, channel, element, reg );
+ if ( (~mask) & 0xff ) {
+ old_value = linda_ib_epb_read ( linda, location );
+ if ( old_value < 0 ) {
+ rc = old_value;
+ goto out_release;
+ }
+ } else {
+ old_value = 0;
+ }
+
+ /* Update value */
+ value = ( ( old_value & ~mask ) | value );
+ DBGCP ( linda, "Linda %p CS %d EPB(%d,%d,%#02x) %#02x => %#02x\n",
+ linda, cs, channel, element, reg, old_value, value );
+ if ( ( rc = linda_ib_epb_write ( linda, location, value ) ) != 0 )
+ goto out_release;
+
+ out_release:
+ /* Release bus */
+ linda_ib_epb_release ( linda );
+ out:
+ DBG_ENABLE ( DBGLVL_IO );
+ return rc;
+}
+
+/**
+ * Transfer data to/from microcontroller RAM
+ *
+ * @v linda Linda device
+ * @v address Starting address
+ * @v write Data to write, or NULL
+ * @v read Data to read, or NULL
+ * @v len Length of data
+ * @ret rc Return status code
+ */
+static int linda_ib_epb_ram_xfer ( struct linda *linda, unsigned int address,
+ const void *write, void *read,
+ size_t len ) {
+ unsigned int control;
+ unsigned int address_hi;
+ unsigned int address_lo;
+ int data;
+ int rc;
+
+ DBG_DISABLE ( DBGLVL_IO );
+
+ assert ( ! ( write && read ) );
+ assert ( ( address % LINDA_EPB_UC_CHUNK_SIZE ) == 0 );
+ assert ( ( len % LINDA_EPB_UC_CHUNK_SIZE ) == 0 );
+
+ /* Acquire bus ownership */
+ if ( ( rc = linda_ib_epb_request ( linda ) ) != 0 )
+ goto out;
+
+ /* Process data */
+ while ( len ) {
+
+ /* Reset the address for each new chunk */
+ if ( ( address % LINDA_EPB_UC_CHUNK_SIZE ) == 0 ) {
+
+ /* Write the control register */
+ control = ( read ? LINDA_EPB_UC_CTL_READ :
+ LINDA_EPB_UC_CTL_WRITE );
+ if ( ( rc = linda_ib_epb_write ( linda,
+ LINDA_EPB_UC_CTL,
+ control ) ) != 0 )
+ break;
+
+ /* Write the address registers */
+ address_hi = ( address >> 8 );
+ if ( ( rc = linda_ib_epb_write ( linda,
+ LINDA_EPB_UC_ADDR_HI,
+ address_hi ) ) != 0 )
+ break;
+ address_lo = ( address & 0xff );
+ if ( ( rc = linda_ib_epb_write ( linda,
+ LINDA_EPB_UC_ADDR_LO,
+ address_lo ) ) != 0 )
+ break;
+ }
+
+ /* Read or write the data */
+ if ( read ) {
+ data = linda_ib_epb_read ( linda, LINDA_EPB_UC_DATA );
+ if ( data < 0 ) {
+ rc = data;
+ break;
+ }
+ *( ( uint8_t * ) read++ ) = data;
+ } else {
+ data = *( ( uint8_t * ) write++ );
+ if ( ( rc = linda_ib_epb_write ( linda,
+ LINDA_EPB_UC_DATA,
+ data ) ) != 0 )
+ break;
+ }
+ address++;
+ len--;
+
+ /* Reset the control byte after each chunk */
+ if ( ( address % LINDA_EPB_UC_CHUNK_SIZE ) == 0 ) {
+ if ( ( rc = linda_ib_epb_write ( linda,
+ LINDA_EPB_UC_CTL,
+ 0 ) ) != 0 )
+ break;
+ }
+ }
+
+ /* Release bus */
+ linda_ib_epb_release ( linda );
+
+ out:
+ DBG_ENABLE ( DBGLVL_IO );
+ return rc;
+}
+
+/***************************************************************************
+ *
+ * Infiniband SerDes initialisation
+ *
+ ***************************************************************************
+ */
+
+/** A Linda SerDes parameter */
+struct linda_serdes_param {
+ /** EPB address as constructed by LINDA_EPB_ADDRESS() */
+ uint16_t address;
+ /** Value to set */
+ uint8_t value;
+ /** Mask to apply to old value */
+ uint8_t mask;
+} __packed;
+
+/** Magic "all channels" channel number */
+#define LINDA_EPB_ALL_CHANNELS 31
+
+/** End of SerDes parameter list marker */
+#define LINDA_SERDES_PARAM_END { 0, 0, 0 }
+
+/**
+ * Program IB SerDes register(s)
+ *
+ * @v linda Linda device
+ * @v param SerDes parameter
+ * @ret rc Return status code
+ */
+static int linda_set_serdes_param ( struct linda *linda,
+ struct linda_serdes_param *param ) {
+ unsigned int channel;
+ unsigned int channel_start;
+ unsigned int channel_end;
+ unsigned int element;
+ unsigned int reg;
+ int rc;
+
+ /* Break down the EPB address and determine channels */
+ channel = LINDA_EPB_ADDRESS_CHANNEL ( param->address );
+ element = LINDA_EPB_ADDRESS_ELEMENT ( param->address );
+ reg = LINDA_EPB_ADDRESS_REG ( param->address );
+ if ( channel == LINDA_EPB_ALL_CHANNELS ) {
+ channel_start = 0;
+ channel_end = 3;
+ } else {
+ channel_start = channel_end = channel;
+ }
+
+ /* Modify register for each specified channel */
+ for ( channel = channel_start ; channel <= channel_end ; channel++ ) {
+ if ( ( rc = linda_ib_epb_mod_reg ( linda, LINDA_EPB_CS_SERDES,
+ channel, element, reg,
+ param->value,
+ param->mask ) ) != 0 )
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Program IB SerDes registers
+ *
+ * @v linda Linda device
+ * @v param SerDes parameters
+ * @v count Number of parameters
+ * @ret rc Return status code
+ */
+static int linda_set_serdes_params ( struct linda *linda,
+ struct linda_serdes_param *params ) {
+ int rc;
+
+ for ( ; params->mask != 0 ; params++ ){
+ if ( ( rc = linda_set_serdes_param ( linda,
+ params ) ) != 0 )
+ return rc;
+ }
+
+ return 0;
+}
+
+#define LINDA_DDS_VAL( amp_d, main_d, ipst_d, ipre_d, \
+ amp_s, main_s, ipst_s, ipre_s ) \
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 9, 0x00 ), \
+ ( ( ( amp_d & 0x1f ) << 1 ) | 1 ), 0xff }, \
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 9, 0x01 ), \
+ ( ( ( amp_s & 0x1f ) << 1 ) | 1 ), 0xff }, \
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 9, 0x09 ), \
+ ( ( main_d << 3 ) | 4 | ( ipre_d >> 2 ) ), 0xff }, \
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 9, 0x0a ), \
+ ( ( main_s << 3 ) | 4 | ( ipre_s >> 2 ) ), 0xff }, \
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 9, 0x06 ), \
+ ( ( ( ipst_d & 0xf ) << 1 ) | \
+ ( ( ipre_d & 3 ) << 6 ) | 0x21 ), 0xff }, \
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 9, 0x07 ), \
+ ( ( ( ipst_s & 0xf ) << 1 ) | \
+ ( ( ipre_s & 3 ) << 6) | 0x21 ), 0xff }
+
+/**
+ * Linda SerDes default parameters
+ *
+ * These magic start-of-day values are taken from the Linux driver.
+ */
+static struct linda_serdes_param linda_serdes_defaults1[] = {
+ /* RXHSCTRL0 */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 6, 0x00 ), 0xd4, 0xff },
+ /* VCDL_DAC2 */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 6, 0x05 ), 0x2d, 0xff },
+ /* VCDL_CTRL2 */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 6, 0x08 ), 0x03, 0x0f },
+ /* START_EQ1 */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x27 ), 0x10, 0xff },
+ /* START_EQ2 */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x28 ), 0x30, 0xff },
+ /* BACTRL */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 6, 0x0e ), 0x40, 0xff },
+ /* LDOUTCTRL1 */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x06 ), 0x04, 0xff },
+ /* RXHSSTATUS */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 6, 0x0f ), 0x04, 0xff },
+ /* End of this block */
+ LINDA_SERDES_PARAM_END
+};
+static struct linda_serdes_param linda_serdes_defaults2[] = {
+ /* LDOUTCTRL1 */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x06 ), 0x00, 0xff },
+ /* DDS values */
+ LINDA_DDS_VAL ( 31, 19, 12, 0, 29, 22, 9, 0 ),
+ /* Set Rcv Eq. to Preset node */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x27 ), 0x10, 0xff },
+ /* DFELTHFDR */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x08 ), 0x00, 0xff },
+ /* DFELTHHDR */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x21 ), 0x00, 0xff },
+ /* TLTHFDR */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x09 ), 0x02, 0xff },
+ /* TLTHHDR */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x23 ), 0x02, 0xff },
+ /* ZFR */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x1b ), 0x0c, 0xff },
+ /* ZCNT) */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x1c ), 0x0c, 0xff },
+ /* GFR */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x1e ), 0x10, 0xff },
+ /* GHR */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x1f ), 0x10, 0xff },
+ /* VCDL_CTRL0 toggle */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 6, 0x06 ), 0x20, 0xff },
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 6, 0x06 ), 0x00, 0xff },
+ /* CMUCTRL5 */
+ { LINDA_EPB_ADDRESS ( 7, 0, 0x15 ), 0x80, 0xff },
+ /* End of this block */
+ LINDA_SERDES_PARAM_END
+};
+static struct linda_serdes_param linda_serdes_defaults3[] = {
+ /* START_EQ1 */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x27 ), 0x00, 0x38 },
+ /* End of this block */
+ LINDA_SERDES_PARAM_END
+};
+
+/**
+ * Program the microcontroller RAM
+ *
+ * @v linda Linda device
+ * @ret rc Return status code
+ */
+static int linda_program_uc_ram ( struct linda *linda ) {
+ int rc;
+
+ if ( ( rc = linda_ib_epb_ram_xfer ( linda, 0, linda_ib_fw, NULL,
+ sizeof ( linda_ib_fw ) ) ) != 0 ){
+ DBGC ( linda, "Linda %p could not load IB firmware: %s\n",
+ linda, strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Verify the microcontroller RAM
+ *
+ * @v linda Linda device
+ * @ret rc Return status code
+ */
+static int linda_verify_uc_ram ( struct linda *linda ) {
+ uint8_t verify[LINDA_EPB_UC_CHUNK_SIZE];
+ unsigned int offset;
+ int rc;
+
+ for ( offset = 0 ; offset < sizeof ( linda_ib_fw );
+ offset += sizeof ( verify ) ) {
+ if ( ( rc = linda_ib_epb_ram_xfer ( linda, offset,
+ NULL, verify,
+ sizeof (verify) )) != 0 ){
+ DBGC ( linda, "Linda %p could not read back IB "
+ "firmware: %s\n", linda, strerror ( rc ) );
+ return rc;
+ }
+ if ( memcmp ( ( linda_ib_fw + offset ), verify,
+ sizeof ( verify ) ) != 0 ) {
+ DBGC ( linda, "Linda %p firmware verification failed "
+ "at offset %#x\n", linda, offset );
+ DBGC_HDA ( linda, offset, ( linda_ib_fw + offset ),
+ sizeof ( verify ) );
+ DBGC_HDA ( linda, offset, verify, sizeof ( verify ) );
+ return -EIO;
+ }
+ }
+
+ DBGC2 ( linda, "Linda %p firmware verified ok\n", linda );
+ return 0;
+}
+
+/**
+ * Use the microcontroller to trim the IB link
+ *
+ * @v linda Linda device
+ * @ret rc Return status code
+ */
+static int linda_trim_ib ( struct linda *linda ) {
+ struct QIB_7220_IBSerDesCtrl ctrl;
+ struct QIB_7220_IntStatus intstatus;
+ unsigned int i;
+ int rc;
+
+ /* Bring the microcontroller out of reset */
+ linda_readq ( linda, &ctrl, QIB_7220_IBSerDesCtrl_offset );
+ BIT_SET ( &ctrl, ResetIB_uC_Core, 0 );
+ linda_writeq ( linda, &ctrl, QIB_7220_IBSerDesCtrl_offset );
+
+ /* Wait for the "trim done" signal */
+ for ( i = 0 ; i < LINDA_TRIM_DONE_MAX_WAIT_MS ; i++ ) {
+ linda_readq ( linda, &intstatus, QIB_7220_IntStatus_offset );
+ if ( BIT_GET ( &intstatus, IBSerdesTrimDone ) ) {
+ rc = 0;
+ goto out_reset;
+ }
+ mdelay ( 1 );
+ }
+
+ DBGC ( linda, "Linda %p timed out waiting for trim done\n", linda );
+ rc = -ETIMEDOUT;
+ out_reset:
+ /* Put the microcontroller back into reset */
+ BIT_SET ( &ctrl, ResetIB_uC_Core, 1 );
+ linda_writeq ( linda, &ctrl, QIB_7220_IBSerDesCtrl_offset );
+
+ return rc;
+}
+
+/**
+ * Initialise the IB SerDes
+ *
+ * @v linda Linda device
+ * @ret rc Return status code
+ */
+static int linda_init_ib_serdes ( struct linda *linda ) {
+ struct QIB_7220_Control control;
+ struct QIB_7220_IBCCtrl ibcctrl;
+ struct QIB_7220_IBCDDRCtrl ibcddrctrl;
+ struct QIB_7220_XGXSCfg xgxscfg;
+ int rc;
+
+ /* Disable link */
+ linda_readq ( linda, &control, QIB_7220_Control_offset );
+ BIT_SET ( &control, LinkEn, 0 );
+ linda_writeq ( linda, &control, QIB_7220_Control_offset );
+
+ /* Configure sensible defaults for IBC */
+ memset ( &ibcctrl, 0, sizeof ( ibcctrl ) );
+ BIT_FILL_6 ( &ibcctrl, /* Tuning values taken from Linux driver */
+ FlowCtrlPeriod, 0x03,
+ FlowCtrlWaterMark, 0x05,
+ MaxPktLen, ( ( LINDA_RECV_HEADER_SIZE +
+ LINDA_RECV_PAYLOAD_SIZE +
+ 4 /* ICRC */ ) >> 2 ),
+ PhyerrThreshold, 0xf,
+ OverrunThreshold, 0xf,
+ CreditScale, 0x4 );
+ linda_writeq ( linda, &ibcctrl, QIB_7220_IBCCtrl_offset );
+
+ /* Force SDR only to avoid needing all the DDR tuning,
+ * Mellanox compatibiltiy hacks etc. SDR is plenty for
+ * boot-time operation.
+ */
+ linda_readq ( linda, &ibcddrctrl, QIB_7220_IBCDDRCtrl_offset );
+ BIT_SET ( &ibcddrctrl, IB_ENHANCED_MODE, 0 );
+ BIT_SET ( &ibcddrctrl, SD_SPEED_SDR, 1 );
+ BIT_SET ( &ibcddrctrl, SD_SPEED_DDR, 0 );
+ BIT_SET ( &ibcddrctrl, SD_SPEED_QDR, 0 );
+ BIT_SET ( &ibcddrctrl, HRTBT_ENB, 0 );
+ BIT_SET ( &ibcddrctrl, HRTBT_AUTO, 0 );
+ linda_writeq ( linda, &ibcddrctrl, QIB_7220_IBCDDRCtrl_offset );
+
+ /* Set default SerDes parameters */
+ if ( ( rc = linda_set_serdes_params ( linda,
+ linda_serdes_defaults1 ) ) != 0 )
+ return rc;
+ udelay ( 415 ); /* Magic delay while SerDes sorts itself out */
+ if ( ( rc = linda_set_serdes_params ( linda,
+ linda_serdes_defaults2 ) ) != 0 )
+ return rc;
+
+ /* Program the microcontroller RAM */
+ if ( ( rc = linda_program_uc_ram ( linda ) ) != 0 )
+ return rc;
+
+ /* Verify the microcontroller RAM contents */
+ if ( DBGLVL_LOG ) {
+ if ( ( rc = linda_verify_uc_ram ( linda ) ) != 0 )
+ return rc;
+ }
+
+ /* More SerDes tuning */
+ if ( ( rc = linda_set_serdes_params ( linda,
+ linda_serdes_defaults3 ) ) != 0 )
+ return rc;
+
+ /* Use the microcontroller to trim the IB link */
+ if ( ( rc = linda_trim_ib ( linda ) ) != 0 )
+ return rc;
+
+ /* Bring XGXS out of reset */
+ linda_readq ( linda, &xgxscfg, QIB_7220_XGXSCfg_offset );
+ BIT_SET ( &xgxscfg, tx_rx_reset, 0 );
+ BIT_SET ( &xgxscfg, xcv_reset, 0 );
+ linda_writeq ( linda, &xgxscfg, QIB_7220_XGXSCfg_offset );
+
+ return rc;
+}
+
+/***************************************************************************
+ *
+ * PCI layer interface
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Probe PCI device
+ *
+ * @v pci PCI device
+ * @v id PCI ID
+ * @ret rc Return status code
+ */
+static int linda_probe ( struct pci_device *pci,
+ const struct pci_device_id *id __unused ) {
+ struct ib_device *ibdev;
+ struct linda *linda;
+ struct QIB_7220_Revision revision;
+ int rc;
+
+ /* Allocate Infiniband device */
+ ibdev = alloc_ibdev ( sizeof ( *linda ) );
+ if ( ! ibdev ) {
+ rc = -ENOMEM;
+ goto err_alloc_ibdev;
+ }
+ pci_set_drvdata ( pci, ibdev );
+ linda = ib_get_drvdata ( ibdev );
+ ibdev->op = &linda_ib_operations;
+ ibdev->dev = &pci->dev;
+ ibdev->port = 1;
+
+ /* Fix up PCI device */
+ adjust_pci_device ( pci );
+
+ /* Get PCI BARs */
+ linda->regs = ioremap ( pci->membase, LINDA_BAR0_SIZE );
+ DBGC2 ( linda, "Linda %p has BAR at %08lx\n", linda, pci->membase );
+
+ /* Print some general data */
+ linda_readq ( linda, &revision, QIB_7220_Revision_offset );
+ DBGC2 ( linda, "Linda %p board %02lx v%ld.%ld.%ld.%ld\n", linda,
+ BIT_GET ( &revision, BoardID ),
+ BIT_GET ( &revision, R_SW ),
+ BIT_GET ( &revision, R_Arch ),
+ BIT_GET ( &revision, R_ChipRevMajor ),
+ BIT_GET ( &revision, R_ChipRevMinor ) );
+
+ /* Initialise I2C subsystem */
+ if ( ( rc = linda_init_i2c ( linda ) ) != 0 )
+ goto err_init_i2c;
+
+ /* Read EEPROM parameters */
+ if ( ( rc = linda_read_eeprom ( linda, &ibdev->gid.u.half[1] ) ) != 0 )
+ goto err_read_eeprom;
+
+ /* Initialise send datapath */
+ if ( ( rc = linda_init_send ( linda ) ) != 0 )
+ goto err_init_send;
+
+ /* Initialise receive datapath */
+ if ( ( rc = linda_init_recv ( linda ) ) != 0 )
+ goto err_init_recv;
+
+ /* Initialise the IB SerDes */
+ if ( ( rc = linda_init_ib_serdes ( linda ) ) != 0 )
+ goto err_init_ib_serdes;
+
+ /* Create the SMA */
+ if ( ( rc = ib_create_sma ( &linda->sma, ibdev,
+ &linda_sma_operations ) ) != 0 )
+ goto err_create_sma;
+ /* If the SMA doesn't get context 0, we're screwed */
+ assert ( linda_qpn_to_ctx ( linda->sma.qp->qpn ) == 0 );
+
+ /* Register Infiniband device */
+ if ( ( rc = register_ibdev ( ibdev ) ) != 0 ) {
+ DBGC ( linda, "Linda %p could not register IB "
+ "device: %s\n", linda, strerror ( rc ) );
+ goto err_register_ibdev;
+ }
+
+ return 0;
+
+ unregister_ibdev ( ibdev );
+ err_register_ibdev:
+ ib_destroy_sma ( &linda->sma );
+ err_create_sma:
+ linda_fini_recv ( linda );
+ err_init_recv:
+ linda_fini_send ( linda );
+ err_init_send:
+ err_init_ib_serdes:
+ err_read_eeprom:
+ err_init_i2c:
+ ibdev_put ( ibdev );
+ err_alloc_ibdev:
+ return rc;
+}
+
+/**
+ * Remove PCI device
+ *
+ * @v pci PCI device
+ */
+static void linda_remove ( struct pci_device *pci ) {
+ struct ib_device *ibdev = pci_get_drvdata ( pci );
+ struct linda *linda = ib_get_drvdata ( ibdev );
+
+ unregister_ibdev ( ibdev );
+ ib_destroy_sma ( &linda->sma );
+ linda_fini_recv ( linda );
+ linda_fini_send ( linda );
+ ibdev_put ( ibdev );
+}
+
+static struct pci_device_id linda_nics[] = {
+ PCI_ROM ( 0x1077, 0x7220, "iba7220", "QLE7240/7280 HCA driver" ),
+};
+
+struct pci_driver linda_driver __pci_driver = {
+ .ids = linda_nics,
+ .id_count = ( sizeof ( linda_nics ) / sizeof ( linda_nics[0] ) ),
+ .probe = linda_probe,
+ .remove = linda_remove,
+};
diff --git a/gpxe/src/drivers/infiniband/linda.h b/gpxe/src/drivers/infiniband/linda.h
new file mode 100644
index 00000000..dd1737a6
--- /dev/null
+++ b/gpxe/src/drivers/infiniband/linda.h
@@ -0,0 +1,271 @@
+#ifndef _LINDA_H
+#define _LINDA_H
+
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/**
+ * @file
+ *
+ * QLogic Linda Infiniband HCA
+ *
+ */
+
+#define BITOPS_LITTLE_ENDIAN
+#include <gpxe/bitops.h>
+#include "qib_7220_regs.h"
+
+struct ib_device;
+
+/** A Linda GPIO register */
+struct QIB_7220_GPIO_pb {
+ pseudo_bit_t GPIO[16];
+ pseudo_bit_t Reserved[48];
+};
+struct QIB_7220_GPIO {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_GPIO_pb );
+};
+
+/** A Linda general scalar register */
+struct QIB_7220_scalar_pb {
+ pseudo_bit_t Value[64];
+};
+struct QIB_7220_scalar {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_scalar_pb );
+};
+
+/** Linda send per-buffer control word */
+struct QIB_7220_SendPbc_pb {
+ pseudo_bit_t LengthP1_toibc[11];
+ pseudo_bit_t Reserved1[4];
+ pseudo_bit_t LengthP1_trigger[11];
+ pseudo_bit_t Reserved2[3];
+ pseudo_bit_t TestEbp[1];
+ pseudo_bit_t Test[1];
+ pseudo_bit_t Intr[1];
+ pseudo_bit_t Reserved3[31];
+ pseudo_bit_t VL15[1];
+};
+struct QIB_7220_SendPbc {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SendPbc_pb );
+};
+
+/** Linda send buffer availability */
+struct QIB_7220_SendBufAvail_pb {
+ pseudo_bit_t InUseCheck[144][2];
+ pseudo_bit_t Reserved[32];
+};
+struct QIB_7220_SendBufAvail {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SendBufAvail_pb );
+};
+
+/** DMA alignment for send buffer availability */
+#define LINDA_SENDBUFAVAIL_ALIGN 64
+
+/** A Linda eager receive descriptor */
+struct QIB_7220_RcvEgr_pb {
+ pseudo_bit_t Addr[37];
+ pseudo_bit_t BufSize[3];
+ pseudo_bit_t Reserved[24];
+};
+struct QIB_7220_RcvEgr {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvEgr_pb );
+};
+
+/** Linda receive header flags */
+struct QIB_7220_RcvHdrFlags_pb {
+ pseudo_bit_t PktLen[11];
+ pseudo_bit_t RcvType[3];
+ pseudo_bit_t SoftB[1];
+ pseudo_bit_t SoftA[1];
+ pseudo_bit_t EgrIndex[12];
+ pseudo_bit_t Reserved1[3];
+ pseudo_bit_t UseEgrBfr[1];
+ pseudo_bit_t RcvSeq[4];
+ pseudo_bit_t HdrqOffset[11];
+ pseudo_bit_t Reserved2[8];
+ pseudo_bit_t IBErr[1];
+ pseudo_bit_t MKErr[1];
+ pseudo_bit_t TIDErr[1];
+ pseudo_bit_t KHdrErr[1];
+ pseudo_bit_t MTUErr[1];
+ pseudo_bit_t LenErr[1];
+ pseudo_bit_t ParityErr[1];
+ pseudo_bit_t VCRCErr[1];
+ pseudo_bit_t ICRCErr[1];
+};
+struct QIB_7220_RcvHdrFlags {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrFlags_pb );
+};
+
+/** Linda memory BAR size */
+#define LINDA_BAR0_SIZE 0x400000
+
+/** Linda I2C SCL line GPIO number */
+#define LINDA_GPIO_SCL 0
+
+/** Linda I2C SDA line GPIO number */
+#define LINDA_GPIO_SDA 1
+
+/** GUID offset within EEPROM */
+#define LINDA_EEPROM_GUID_OFFSET 3
+
+/** GUID size within EEPROM */
+#define LINDA_EEPROM_GUID_SIZE 8
+
+/** Board serial number offset within EEPROM */
+#define LINDA_EEPROM_SERIAL_OFFSET 12
+
+/** Board serial number size within EEPROM */
+#define LINDA_EEPROM_SERIAL_SIZE 12
+
+/** Maximum number of send buffers used
+ *
+ * This is a policy decision. Must be less than or equal to the total
+ * number of send buffers supported by the hardware (128).
+ */
+#define LINDA_MAX_SEND_BUFS 32
+
+/** Linda send buffer size */
+#define LINDA_SEND_BUF_SIZE 4096
+
+/** Number of contexts (including kernel context)
+ *
+ * This is a policy decision. Must be 5, 9 or 17.
+ */
+#define LINDA_NUM_CONTEXTS 5
+
+/** PortCfg values for different numbers of contexts */
+enum linda_portcfg {
+ LINDA_PORTCFG_5CTX = 0,
+ LINDA_PORTCFG_9CTX = 1,
+ LINDA_PORTCFG_17CTX = 2,
+};
+
+/** PortCfg values for different numbers of contexts */
+#define LINDA_EAGER_ARRAY_SIZE_5CTX_0 2048
+#define LINDA_EAGER_ARRAY_SIZE_5CTX_OTHER 4096
+#define LINDA_EAGER_ARRAY_SIZE_9CTX_0 2048
+#define LINDA_EAGER_ARRAY_SIZE_9CTX_OTHER 2048
+#define LINDA_EAGER_ARRAY_SIZE_17CTX_0 2048
+#define LINDA_EAGER_ARRAY_SIZE_17CTX_OTHER 1024
+
+/** Eager buffer required alignment */
+#define LINDA_EAGER_BUFFER_ALIGN 2048
+
+/** Eager buffer size encodings */
+enum linda_eager_buffer_size {
+ LINDA_EAGER_BUFFER_NONE = 0,
+ LINDA_EAGER_BUFFER_2K = 1,
+ LINDA_EAGER_BUFFER_4K = 2,
+ LINDA_EAGER_BUFFER_8K = 3,
+ LINDA_EAGER_BUFFER_16K = 4,
+ LINDA_EAGER_BUFFER_32K = 5,
+ LINDA_EAGER_BUFFER_64K = 6,
+};
+
+/** Number of RX headers per context
+ *
+ * This is a policy decision.
+ */
+#define LINDA_RECV_HEADER_COUNT 8
+
+/** Maximum size of each RX header
+ *
+ * This is a policy decision. Must be divisible by 4.
+ */
+#define LINDA_RECV_HEADER_SIZE 96
+
+/** Total size of an RX header ring */
+#define LINDA_RECV_HEADERS_SIZE \
+ ( LINDA_RECV_HEADER_SIZE * LINDA_RECV_HEADER_COUNT )
+
+/** RX header alignment */
+#define LINDA_RECV_HEADERS_ALIGN 64
+
+/** RX payload size
+ *
+ * This is a policy decision. Must be a valid eager buffer size.
+ */
+#define LINDA_RECV_PAYLOAD_SIZE 2048
+
+/** QPN used for Infinipath Packets
+ *
+ * This is a policy decision. Must have bit 0 clear. Must not be a
+ * QPN that we will use.
+ */
+#define LINDA_QP_IDETH 0xdead0
+
+/** Maximum time for wait for external parallel bus request, in us */
+#define LINDA_EPB_REQUEST_MAX_WAIT_US 500
+
+/** Maximum time for wait for external parallel bus transaction, in us */
+#define LINDA_EPB_XACT_MAX_WAIT_US 500
+
+/** Linda external parallel bus chip selects */
+#define LINDA_EPB_CS_SERDES 1
+#define LINDA_EPB_CS_UC 2
+
+/** Linda external parallel bus read/write operations */
+#define LINDA_EPB_WRITE 0
+#define LINDA_EPB_READ 1
+
+/** Linda external parallel bus register addresses */
+#define LINDA_EPB_ADDRESS( _channel, _element, _reg ) \
+ ( (_element) | ( (_channel) << 4 ) | ( (_reg) << 9 ) )
+#define LINDA_EPB_ADDRESS_CHANNEL( _address ) ( ( (_address) >> 4 ) & 0x1f )
+#define LINDA_EPB_ADDRESS_ELEMENT( _address ) ( ( (_address) >> 0 ) & 0x0f )
+#define LINDA_EPB_ADDRESS_REG( _address ) ( ( (_address) >> 9 ) & 0x3f )
+
+/** Linda external parallel bus locations
+ *
+ * The location is used by the driver to encode both the chip select
+ * and the EPB address.
+ */
+#define LINDA_EPB_LOC( _cs, _channel, _element, _reg) \
+ ( ( (_cs) << 16 ) | LINDA_EPB_ADDRESS ( _channel, _element, _reg ) )
+#define LINDA_EPB_LOC_ADDRESS( _loc ) ( (_loc) & 0xffff )
+#define LINDA_EPB_LOC_CS( _loc ) ( (_loc) >> 16 )
+
+/** Linda external parallel bus microcontroller register addresses */
+#define LINDA_EPB_UC_CHANNEL 6
+#define LINDA_EPB_UC_LOC( _reg ) \
+ LINDA_EPB_LOC ( LINDA_EPB_CS_UC, LINDA_EPB_UC_CHANNEL, 0, (_reg) )
+#define LINDA_EPB_UC_CTL LINDA_EPB_UC_LOC ( 0 )
+#define LINDA_EPB_UC_CTL_WRITE 1
+#define LINDA_EPB_UC_CTL_READ 2
+#define LINDA_EPB_UC_ADDR_LO LINDA_EPB_UC_LOC ( 2 )
+#define LINDA_EPB_UC_ADDR_HI LINDA_EPB_UC_LOC ( 3 )
+#define LINDA_EPB_UC_DATA LINDA_EPB_UC_LOC ( 4 )
+#define LINDA_EPB_UC_CHUNK_SIZE 64
+
+extern uint8_t linda_ib_fw[8192];
+
+/** Maximum time to wait for "trim done" signal, in ms */
+#define LINDA_TRIM_DONE_MAX_WAIT_MS 1000
+
+/** Linda link states */
+enum linda_link_state {
+ LINDA_LINK_STATE_DOWN = 0,
+ LINDA_LINK_STATE_INIT = 1,
+ LINDA_LINK_STATE_ARM = 2,
+ LINDA_LINK_STATE_ACTIVE = 3,
+ LINDA_LINK_STATE_ACT_DEFER = 4,
+};
+
+#endif /* _LINDA_H */
diff --git a/gpxe/src/drivers/infiniband/linda_fw.c b/gpxe/src/drivers/infiniband/linda_fw.c
new file mode 100644
index 00000000..fc5ea077
--- /dev/null
+++ b/gpxe/src/drivers/infiniband/linda_fw.c
@@ -0,0 +1,1067 @@
+/*
+ * Copyright (c) 2007, 2008 QLogic Corporation. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*
+ * This file contains the memory image from the vendor, to be copied into
+ * the IB SERDES of the IBA7220 during initialization.
+ * The file also includes the two functions which use this image.
+ */
+
+#include <stdint.h>
+#include "linda.h"
+
+uint8_t linda_ib_fw[8192] = {
+/*0000*/0x02, 0x0A, 0x29, 0x02, 0x0A, 0x87, 0xE5, 0xE6,
+ 0x30, 0xE6, 0x04, 0x7F, 0x01, 0x80, 0x02, 0x7F,
+/*0010*/0x00, 0xE5, 0xE2, 0x30, 0xE4, 0x04, 0x7E, 0x01,
+ 0x80, 0x02, 0x7E, 0x00, 0xEE, 0x5F, 0x60, 0x08,
+/*0020*/0x53, 0xF9, 0xF7, 0xE4, 0xF5, 0xFE, 0x80, 0x08,
+ 0x7F, 0x0A, 0x12, 0x17, 0x31, 0x12, 0x0E, 0xA2,
+/*0030*/0x75, 0xFC, 0x08, 0xE4, 0xF5, 0xFD, 0xE5, 0xE7,
+ 0x20, 0xE7, 0x03, 0x43, 0xF9, 0x08, 0x22, 0x00,
+/*0040*/0x01, 0x20, 0x11, 0x00, 0x04, 0x20, 0x00, 0x75,
+ 0x51, 0x01, 0xE4, 0xF5, 0x52, 0xF5, 0x53, 0xF5,
+/*0050*/0x52, 0xF5, 0x7E, 0x7F, 0x04, 0x02, 0x04, 0x38,
+ 0xC2, 0x36, 0x05, 0x52, 0xE5, 0x52, 0xD3, 0x94,
+/*0060*/0x0C, 0x40, 0x05, 0x75, 0x52, 0x01, 0xD2, 0x36,
+ 0x90, 0x07, 0x0C, 0x74, 0x07, 0xF0, 0xA3, 0x74,
+/*0070*/0xFF, 0xF0, 0xE4, 0xF5, 0x0C, 0xA3, 0xF0, 0x90,
+ 0x07, 0x14, 0xF0, 0xA3, 0xF0, 0x75, 0x0B, 0x20,
+/*0080*/0xF5, 0x09, 0xE4, 0xF5, 0x08, 0xE5, 0x08, 0xD3,
+ 0x94, 0x30, 0x40, 0x03, 0x02, 0x04, 0x04, 0x12,
+/*0090*/0x00, 0x06, 0x15, 0x0B, 0xE5, 0x08, 0x70, 0x04,
+ 0x7F, 0x01, 0x80, 0x02, 0x7F, 0x00, 0xE5, 0x09,
+/*00A0*/0x70, 0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00,
+ 0xEE, 0x5F, 0x60, 0x05, 0x12, 0x18, 0x71, 0xD2,
+/*00B0*/0x35, 0x53, 0xE1, 0xF7, 0xE5, 0x08, 0x45, 0x09,
+ 0xFF, 0xE5, 0x0B, 0x25, 0xE0, 0x25, 0xE0, 0x24,
+/*00C0*/0x83, 0xF5, 0x82, 0xE4, 0x34, 0x07, 0xF5, 0x83,
+ 0xEF, 0xF0, 0x85, 0xE2, 0x20, 0xE5, 0x52, 0xD3,
+/*00D0*/0x94, 0x01, 0x40, 0x0D, 0x12, 0x19, 0xF3, 0xE0,
+ 0x54, 0xA0, 0x64, 0x40, 0x70, 0x03, 0x02, 0x03,
+/*00E0*/0xFB, 0x53, 0xF9, 0xF8, 0x90, 0x94, 0x70, 0xE4,
+ 0xF0, 0xE0, 0xF5, 0x10, 0xAF, 0x09, 0x12, 0x1E,
+/*00F0*/0xB3, 0xAF, 0x08, 0xEF, 0x44, 0x08, 0xF5, 0x82,
+ 0x75, 0x83, 0x80, 0xE0, 0xF5, 0x29, 0xEF, 0x44,
+/*0100*/0x07, 0x12, 0x1A, 0x3C, 0xF5, 0x22, 0x54, 0x40,
+ 0xD3, 0x94, 0x00, 0x40, 0x1E, 0xE5, 0x29, 0x54,
+/*0110*/0xF0, 0x70, 0x21, 0x12, 0x19, 0xF3, 0xE0, 0x44,
+ 0x80, 0xF0, 0xE5, 0x22, 0x54, 0x30, 0x65, 0x08,
+/*0120*/0x70, 0x09, 0x12, 0x19, 0xF3, 0xE0, 0x54, 0xBF,
+ 0xF0, 0x80, 0x09, 0x12, 0x19, 0xF3, 0x74, 0x40,
+/*0130*/0xF0, 0x02, 0x03, 0xFB, 0x12, 0x1A, 0x12, 0x75,
+ 0x83, 0xAE, 0x74, 0xFF, 0xF0, 0xAF, 0x08, 0x7E,
+/*0140*/0x00, 0xEF, 0x44, 0x07, 0xF5, 0x82, 0xE0, 0xFD,
+ 0xE5, 0x0B, 0x25, 0xE0, 0x25, 0xE0, 0x24, 0x81,
+/*0150*/0xF5, 0x82, 0xE4, 0x34, 0x07, 0xF5, 0x83, 0xED,
+ 0xF0, 0x90, 0x07, 0x0E, 0xE0, 0x04, 0xF0, 0xEF,
+/*0160*/0x44, 0x07, 0xF5, 0x82, 0x75, 0x83, 0x98, 0xE0,
+ 0xF5, 0x28, 0x12, 0x1A, 0x23, 0x40, 0x0C, 0x12,
+/*0170*/0x19, 0xF3, 0xE0, 0x44, 0x01, 0x12, 0x1A, 0x32,
+ 0x02, 0x03, 0xF6, 0xAF, 0x08, 0x7E, 0x00, 0x74,
+/*0180*/0x80, 0xCD, 0xEF, 0xCD, 0x8D, 0x82, 0xF5, 0x83,
+ 0xE0, 0x30, 0xE0, 0x0A, 0x12, 0x19, 0xF3, 0xE0,
+/*0190*/0x44, 0x20, 0xF0, 0x02, 0x03, 0xFB, 0x12, 0x19,
+ 0xF3, 0xE0, 0x54, 0xDF, 0xF0, 0xEE, 0x44, 0xAE,
+/*01A0*/0x12, 0x1A, 0x43, 0x30, 0xE4, 0x03, 0x02, 0x03,
+ 0xFB, 0x74, 0x9E, 0x12, 0x1A, 0x05, 0x20, 0xE0,
+/*01B0*/0x03, 0x02, 0x03, 0xFB, 0x8F, 0x82, 0x8E, 0x83,
+ 0xE0, 0x20, 0xE0, 0x03, 0x02, 0x03, 0xFB, 0x12,
+/*01C0*/0x19, 0xF3, 0xE0, 0x44, 0x10, 0xF0, 0xE5, 0xE3,
+ 0x20, 0xE7, 0x08, 0xE5, 0x08, 0x12, 0x1A, 0x3A,
+/*01D0*/0x44, 0x04, 0xF0, 0xAF, 0x08, 0x7E, 0x00, 0xEF,
+ 0x12, 0x1A, 0x3A, 0x20, 0xE2, 0x34, 0x12, 0x19,
+/*01E0*/0xF3, 0xE0, 0x44, 0x08, 0xF0, 0xE5, 0xE4, 0x30,
+ 0xE6, 0x04, 0x7D, 0x01, 0x80, 0x02, 0x7D, 0x00,
+/*01F0*/0xE5, 0x7E, 0xC3, 0x94, 0x04, 0x50, 0x04, 0x7C,
+ 0x01, 0x80, 0x02, 0x7C, 0x00, 0xEC, 0x4D, 0x60,
+/*0200*/0x05, 0xC2, 0x35, 0x02, 0x03, 0xFB, 0xEE, 0x44,
+ 0xD2, 0x12, 0x1A, 0x43, 0x44, 0x40, 0xF0, 0x02,
+/*0210*/0x03, 0xFB, 0x12, 0x19, 0xF3, 0xE0, 0x54, 0xF7,
+ 0xF0, 0x12, 0x1A, 0x12, 0x75, 0x83, 0xD2, 0xE0,
+/*0220*/0x54, 0xBF, 0xF0, 0x90, 0x07, 0x14, 0xE0, 0x04,
+ 0xF0, 0xE5, 0x7E, 0x70, 0x03, 0x75, 0x7E, 0x01,
+/*0230*/0xAF, 0x08, 0x7E, 0x00, 0x12, 0x1A, 0x23, 0x40,
+ 0x12, 0x12, 0x19, 0xF3, 0xE0, 0x44, 0x01, 0x12,
+/*0240*/0x19, 0xF2, 0xE0, 0x54, 0x02, 0x12, 0x1A, 0x32,
+ 0x02, 0x03, 0xFB, 0x12, 0x19, 0xF3, 0xE0, 0x44,
+/*0250*/0x02, 0x12, 0x19, 0xF2, 0xE0, 0x54, 0xFE, 0xF0,
+ 0xC2, 0x35, 0xEE, 0x44, 0x8A, 0x8F, 0x82, 0xF5,
+/*0260*/0x83, 0xE0, 0xF5, 0x17, 0x54, 0x8F, 0x44, 0x40,
+ 0xF0, 0x74, 0x90, 0xFC, 0xE5, 0x08, 0x44, 0x07,
+/*0270*/0xFD, 0xF5, 0x82, 0x8C, 0x83, 0xE0, 0x54, 0x3F,
+ 0x90, 0x07, 0x02, 0xF0, 0xE0, 0x54, 0xC0, 0x8D,
+/*0280*/0x82, 0x8C, 0x83, 0xF0, 0x74, 0x92, 0x12, 0x1A,
+ 0x05, 0x90, 0x07, 0x03, 0x12, 0x1A, 0x19, 0x74,
+/*0290*/0x82, 0x12, 0x1A, 0x05, 0x90, 0x07, 0x04, 0x12,
+ 0x1A, 0x19, 0x74, 0xB4, 0x12, 0x1A, 0x05, 0x90,
+/*02A0*/0x07, 0x05, 0x12, 0x1A, 0x19, 0x74, 0x94, 0xFE,
+ 0xE5, 0x08, 0x44, 0x06, 0x12, 0x1A, 0x0A, 0xF5,
+/*02B0*/0x10, 0x30, 0xE0, 0x04, 0xD2, 0x37, 0x80, 0x02,
+ 0xC2, 0x37, 0xE5, 0x10, 0x54, 0x7F, 0x8F, 0x82,
+/*02C0*/0x8E, 0x83, 0xF0, 0x30, 0x44, 0x30, 0x12, 0x1A,
+ 0x03, 0x54, 0x80, 0xD3, 0x94, 0x00, 0x40, 0x04,
+/*02D0*/0xD2, 0x39, 0x80, 0x02, 0xC2, 0x39, 0x8F, 0x82,
+ 0x8E, 0x83, 0xE0, 0x44, 0x80, 0xF0, 0x12, 0x1A,
+/*02E0*/0x03, 0x54, 0x40, 0xD3, 0x94, 0x00, 0x40, 0x04,
+ 0xD2, 0x3A, 0x80, 0x02, 0xC2, 0x3A, 0x8F, 0x82,
+/*02F0*/0x8E, 0x83, 0xE0, 0x44, 0x40, 0xF0, 0x74, 0x92,
+ 0xFE, 0xE5, 0x08, 0x44, 0x06, 0x12, 0x1A, 0x0A,
+/*0300*/0x30, 0xE7, 0x04, 0xD2, 0x38, 0x80, 0x02, 0xC2,
+ 0x38, 0x8F, 0x82, 0x8E, 0x83, 0xE0, 0x54, 0x7F,
+/*0310*/0xF0, 0x12, 0x1E, 0x46, 0xE4, 0xF5, 0x0A, 0x20,
+ 0x03, 0x02, 0x80, 0x03, 0x30, 0x43, 0x03, 0x12,
+/*0320*/0x19, 0x95, 0x20, 0x02, 0x02, 0x80, 0x03, 0x30,
+ 0x42, 0x03, 0x12, 0x0C, 0x8F, 0x30, 0x30, 0x06,
+/*0330*/0x12, 0x19, 0x95, 0x12, 0x0C, 0x8F, 0x12, 0x0D,
+ 0x47, 0x12, 0x19, 0xF3, 0xE0, 0x54, 0xFB, 0xF0,
+/*0340*/0xE5, 0x0A, 0xC3, 0x94, 0x01, 0x40, 0x46, 0x43,
+ 0xE1, 0x08, 0x12, 0x19, 0xF3, 0xE0, 0x44, 0x04,
+/*0350*/0xF0, 0xE5, 0xE4, 0x20, 0xE7, 0x2A, 0x12, 0x1A,
+ 0x12, 0x75, 0x83, 0xD2, 0xE0, 0x54, 0x08, 0xD3,
+/*0360*/0x94, 0x00, 0x40, 0x04, 0x7F, 0x01, 0x80, 0x02,
+ 0x7F, 0x00, 0xE5, 0x0A, 0xC3, 0x94, 0x01, 0x40,
+/*0370*/0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEF,
+ 0x5E, 0x60, 0x05, 0x12, 0x1D, 0xD7, 0x80, 0x17,
+/*0380*/0x12, 0x1A, 0x12, 0x75, 0x83, 0xD2, 0xE0, 0x44,
+ 0x08, 0xF0, 0x02, 0x03, 0xFB, 0x12, 0x1A, 0x12,
+/*0390*/0x75, 0x83, 0xD2, 0xE0, 0x54, 0xF7, 0xF0, 0x12,
+ 0x1E, 0x46, 0x7F, 0x08, 0x12, 0x17, 0x31, 0x74,
+/*03A0*/0x8E, 0xFE, 0x12, 0x1A, 0x12, 0x8E, 0x83, 0xE0,
+ 0xF5, 0x10, 0x54, 0xFE, 0xF0, 0xE5, 0x10, 0x44,
+/*03B0*/0x01, 0xFF, 0xE5, 0x08, 0xFD, 0xED, 0x44, 0x07,
+ 0xF5, 0x82, 0xEF, 0xF0, 0xE5, 0x10, 0x54, 0xFE,
+/*03C0*/0xFF, 0xED, 0x44, 0x07, 0xF5, 0x82, 0xEF, 0x12,
+ 0x1A, 0x11, 0x75, 0x83, 0x86, 0xE0, 0x44, 0x10,
+/*03D0*/0x12, 0x1A, 0x11, 0xE0, 0x44, 0x10, 0xF0, 0x12,
+ 0x19, 0xF3, 0xE0, 0x54, 0xFD, 0x44, 0x01, 0xFF,
+/*03E0*/0x12, 0x19, 0xF3, 0xEF, 0x12, 0x1A, 0x32, 0x30,
+ 0x32, 0x0C, 0xE5, 0x08, 0x44, 0x08, 0xF5, 0x82,
+/*03F0*/0x75, 0x83, 0x82, 0x74, 0x05, 0xF0, 0xAF, 0x0B,
+ 0x12, 0x18, 0xD7, 0x74, 0x10, 0x25, 0x08, 0xF5,
+/*0400*/0x08, 0x02, 0x00, 0x85, 0x05, 0x09, 0xE5, 0x09,
+ 0xD3, 0x94, 0x07, 0x50, 0x03, 0x02, 0x00, 0x82,
+/*0410*/0xE5, 0x7E, 0xD3, 0x94, 0x00, 0x40, 0x04, 0x7F,
+ 0x01, 0x80, 0x02, 0x7F, 0x00, 0xE5, 0x7E, 0xC3,
+/*0420*/0x94, 0xFA, 0x50, 0x04, 0x7E, 0x01, 0x80, 0x02,
+ 0x7E, 0x00, 0xEE, 0x5F, 0x60, 0x02, 0x05, 0x7E,
+/*0430*/0x30, 0x35, 0x0B, 0x43, 0xE1, 0x01, 0x7F, 0x09,
+ 0x12, 0x17, 0x31, 0x02, 0x00, 0x58, 0x53, 0xE1,
+/*0440*/0xFE, 0x02, 0x00, 0x58, 0x8E, 0x6A, 0x8F, 0x6B,
+ 0x8C, 0x6C, 0x8D, 0x6D, 0x75, 0x6E, 0x01, 0x75,
+/*0450*/0x6F, 0x01, 0x75, 0x70, 0x01, 0xE4, 0xF5, 0x73,
+ 0xF5, 0x74, 0xF5, 0x75, 0x90, 0x07, 0x2F, 0xF0,
+/*0460*/0xF5, 0x3C, 0xF5, 0x3E, 0xF5, 0x46, 0xF5, 0x47,
+ 0xF5, 0x3D, 0xF5, 0x3F, 0xF5, 0x6F, 0xE5, 0x6F,
+/*0470*/0x70, 0x0F, 0xE5, 0x6B, 0x45, 0x6A, 0x12, 0x07,
+ 0x2A, 0x75, 0x83, 0x80, 0x74, 0x3A, 0xF0, 0x80,
+/*0480*/0x09, 0x12, 0x07, 0x2A, 0x75, 0x83, 0x80, 0x74,
+ 0x1A, 0xF0, 0xE4, 0xF5, 0x6E, 0xC3, 0x74, 0x3F,
+/*0490*/0x95, 0x6E, 0xFF, 0x12, 0x08, 0x65, 0x75, 0x83,
+ 0x82, 0xEF, 0xF0, 0x12, 0x1A, 0x4D, 0x12, 0x08,
+/*04A0*/0xC6, 0xE5, 0x33, 0xF0, 0x12, 0x08, 0xFA, 0x12,
+ 0x08, 0xB1, 0x40, 0xE1, 0xE5, 0x6F, 0x70, 0x0B,
+/*04B0*/0x12, 0x07, 0x2A, 0x75, 0x83, 0x80, 0x74, 0x36,
+ 0xF0, 0x80, 0x09, 0x12, 0x07, 0x2A, 0x75, 0x83,
+/*04C0*/0x80, 0x74, 0x16, 0xF0, 0x75, 0x6E, 0x01, 0x12,
+ 0x07, 0x2A, 0x75, 0x83, 0xB4, 0xE5, 0x6E, 0xF0,
+/*04D0*/0x12, 0x1A, 0x4D, 0x74, 0x3F, 0x25, 0x6E, 0xF5,
+ 0x82, 0xE4, 0x34, 0x00, 0xF5, 0x83, 0xE5, 0x33,
+/*04E0*/0xF0, 0x74, 0xBF, 0x25, 0x6E, 0xF5, 0x82, 0xE4,
+ 0x34, 0x00, 0x12, 0x08, 0xB1, 0x40, 0xD8, 0xE4,
+/*04F0*/0xF5, 0x70, 0xF5, 0x46, 0xF5, 0x47, 0xF5, 0x6E,
+ 0x12, 0x08, 0xFA, 0xF5, 0x83, 0xE0, 0xFE, 0x12,
+/*0500*/0x08, 0xC6, 0xE0, 0x7C, 0x00, 0x24, 0x00, 0xFF,
+ 0xEC, 0x3E, 0xFE, 0xAD, 0x3B, 0xD3, 0xEF, 0x9D,
+/*0510*/0xEE, 0x9C, 0x50, 0x04, 0x7B, 0x01, 0x80, 0x02,
+ 0x7B, 0x00, 0xE5, 0x70, 0x70, 0x04, 0x7A, 0x01,
+/*0520*/0x80, 0x02, 0x7A, 0x00, 0xEB, 0x5A, 0x60, 0x06,
+ 0x85, 0x6E, 0x46, 0x75, 0x70, 0x01, 0xD3, 0xEF,
+/*0530*/0x9D, 0xEE, 0x9C, 0x50, 0x04, 0x7F, 0x01, 0x80,
+ 0x02, 0x7F, 0x00, 0xE5, 0x70, 0xB4, 0x01, 0x04,
+/*0540*/0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEF, 0x5E,
+ 0x60, 0x03, 0x85, 0x6E, 0x47, 0x05, 0x6E, 0xE5,
+/*0550*/0x6E, 0x64, 0x7F, 0x70, 0xA3, 0xE5, 0x46, 0x60,
+ 0x05, 0xE5, 0x47, 0xB4, 0x7E, 0x03, 0x85, 0x46,
+/*0560*/0x47, 0xE5, 0x6F, 0x70, 0x08, 0x85, 0x46, 0x76,
+ 0x85, 0x47, 0x77, 0x80, 0x0E, 0xC3, 0x74, 0x7F,
+/*0570*/0x95, 0x46, 0xF5, 0x78, 0xC3, 0x74, 0x7F, 0x95,
+ 0x47, 0xF5, 0x79, 0xE5, 0x6F, 0x70, 0x37, 0xE5,
+/*0580*/0x46, 0x65, 0x47, 0x70, 0x0C, 0x75, 0x73, 0x01,
+ 0x75, 0x74, 0x01, 0xF5, 0x3C, 0xF5, 0x3D, 0x80,
+/*0590*/0x35, 0xE4, 0xF5, 0x4E, 0xC3, 0xE5, 0x47, 0x95,
+ 0x46, 0xF5, 0x3C, 0xC3, 0x13, 0xF5, 0x71, 0x25,
+/*05A0*/0x46, 0xF5, 0x72, 0xC3, 0x94, 0x3F, 0x40, 0x05,
+ 0xE4, 0xF5, 0x3D, 0x80, 0x40, 0xC3, 0x74, 0x3F,
+/*05B0*/0x95, 0x72, 0xF5, 0x3D, 0x80, 0x37, 0xE5, 0x46,
+ 0x65, 0x47, 0x70, 0x0F, 0x75, 0x73, 0x01, 0x75,
+/*05C0*/0x75, 0x01, 0xF5, 0x3E, 0xF5, 0x3F, 0x75, 0x4E,
+ 0x01, 0x80, 0x22, 0xE4, 0xF5, 0x4E, 0xC3, 0xE5,
+/*05D0*/0x47, 0x95, 0x46, 0xF5, 0x3E, 0xC3, 0x13, 0xF5,
+ 0x71, 0x25, 0x46, 0xF5, 0x72, 0xD3, 0x94, 0x3F,
+/*05E0*/0x50, 0x05, 0xE4, 0xF5, 0x3F, 0x80, 0x06, 0xE5,
+ 0x72, 0x24, 0xC1, 0xF5, 0x3F, 0x05, 0x6F, 0xE5,
+/*05F0*/0x6F, 0xC3, 0x94, 0x02, 0x50, 0x03, 0x02, 0x04,
+ 0x6E, 0xE5, 0x6D, 0x45, 0x6C, 0x70, 0x02, 0x80,
+/*0600*/0x04, 0xE5, 0x74, 0x45, 0x75, 0x90, 0x07, 0x2F,
+ 0xF0, 0x7F, 0x01, 0xE5, 0x3E, 0x60, 0x04, 0xE5,
+/*0610*/0x3C, 0x70, 0x14, 0xE4, 0xF5, 0x3C, 0xF5, 0x3D,
+ 0xF5, 0x3E, 0xF5, 0x3F, 0x12, 0x08, 0xD2, 0x70,
+/*0620*/0x04, 0xF0, 0x02, 0x06, 0xA4, 0x80, 0x7A, 0xE5,
+ 0x3C, 0xC3, 0x95, 0x3E, 0x40, 0x07, 0xE5, 0x3C,
+/*0630*/0x95, 0x3E, 0xFF, 0x80, 0x06, 0xC3, 0xE5, 0x3E,
+ 0x95, 0x3C, 0xFF, 0xE5, 0x76, 0xD3, 0x95, 0x79,
+/*0640*/0x40, 0x05, 0x85, 0x76, 0x7A, 0x80, 0x03, 0x85,
+ 0x79, 0x7A, 0xE5, 0x77, 0xC3, 0x95, 0x78, 0x50,
+/*0650*/0x05, 0x85, 0x77, 0x7B, 0x80, 0x03, 0x85, 0x78,
+ 0x7B, 0xE5, 0x7B, 0xD3, 0x95, 0x7A, 0x40, 0x30,
+/*0660*/0xE5, 0x7B, 0x95, 0x7A, 0xF5, 0x3C, 0xF5, 0x3E,
+ 0xC3, 0xE5, 0x7B, 0x95, 0x7A, 0x90, 0x07, 0x19,
+/*0670*/0xF0, 0xE5, 0x3C, 0xC3, 0x13, 0xF5, 0x71, 0x25,
+ 0x7A, 0xF5, 0x72, 0xC3, 0x94, 0x3F, 0x40, 0x05,
+/*0680*/0xE4, 0xF5, 0x3D, 0x80, 0x1F, 0xC3, 0x74, 0x3F,
+ 0x95, 0x72, 0xF5, 0x3D, 0xF5, 0x3F, 0x80, 0x14,
+/*0690*/0xE4, 0xF5, 0x3C, 0xF5, 0x3E, 0x90, 0x07, 0x19,
+ 0xF0, 0x12, 0x08, 0xD2, 0x70, 0x03, 0xF0, 0x80,
+/*06A0*/0x03, 0x74, 0x01, 0xF0, 0x12, 0x08, 0x65, 0x75,
+ 0x83, 0xD0, 0xE0, 0x54, 0x0F, 0xFE, 0xAD, 0x3C,
+/*06B0*/0x70, 0x02, 0x7E, 0x07, 0xBE, 0x0F, 0x02, 0x7E,
+ 0x80, 0xEE, 0xFB, 0xEF, 0xD3, 0x9B, 0x74, 0x80,
+/*06C0*/0xF8, 0x98, 0x40, 0x1F, 0xE4, 0xF5, 0x3C, 0xF5,
+ 0x3E, 0x12, 0x08, 0xD2, 0x70, 0x03, 0xF0, 0x80,
+/*06D0*/0x12, 0x74, 0x01, 0xF0, 0xE5, 0x08, 0xFB, 0xEB,
+ 0x44, 0x07, 0xF5, 0x82, 0x75, 0x83, 0xD2, 0xE0,
+/*06E0*/0x44, 0x10, 0xF0, 0xE5, 0x08, 0xFB, 0xEB, 0x44,
+ 0x09, 0xF5, 0x82, 0x75, 0x83, 0x9E, 0xED, 0xF0,
+/*06F0*/0xEB, 0x44, 0x07, 0xF5, 0x82, 0x75, 0x83, 0xCA,
+ 0xED, 0xF0, 0x12, 0x08, 0x65, 0x75, 0x83, 0xCC,
+/*0700*/0xEF, 0xF0, 0x22, 0xE5, 0x08, 0x44, 0x07, 0xF5,
+ 0x82, 0x75, 0x83, 0xBC, 0xE0, 0x54, 0xF0, 0xF0,
+/*0710*/0xE5, 0x08, 0x44, 0x07, 0xF5, 0x82, 0x75, 0x83,
+ 0xBE, 0xE0, 0x54, 0xF0, 0xF0, 0xE5, 0x08, 0x44,
+/*0720*/0x07, 0xF5, 0x82, 0x75, 0x83, 0xC0, 0xE0, 0x54,
+ 0xF0, 0xF0, 0xE5, 0x08, 0x44, 0x07, 0xF5, 0x82,
+/*0730*/0x22, 0xF0, 0x90, 0x07, 0x28, 0xE0, 0xFE, 0xA3,
+ 0xE0, 0xF5, 0x82, 0x8E, 0x83, 0x22, 0x85, 0x42,
+/*0740*/0x42, 0x85, 0x41, 0x41, 0x85, 0x40, 0x40, 0x74,
+ 0xC0, 0x2F, 0xF5, 0x82, 0x74, 0x02, 0x3E, 0xF5,
+/*0750*/0x83, 0xE5, 0x42, 0xF0, 0x74, 0xE0, 0x2F, 0xF5,
+ 0x82, 0x74, 0x02, 0x3E, 0xF5, 0x83, 0x22, 0xE5,
+/*0760*/0x42, 0x29, 0xFD, 0xE4, 0x33, 0xFC, 0xE5, 0x3C,
+ 0xC3, 0x9D, 0xEC, 0x64, 0x80, 0xF8, 0x74, 0x80,
+/*0770*/0x98, 0x22, 0xF5, 0x83, 0xE0, 0x90, 0x07, 0x22,
+ 0x54, 0x1F, 0xFD, 0xE0, 0xFA, 0xA3, 0xE0, 0xF5,
+/*0780*/0x82, 0x8A, 0x83, 0xED, 0xF0, 0x22, 0x90, 0x07,
+ 0x22, 0xE0, 0xFC, 0xA3, 0xE0, 0xF5, 0x82, 0x8C,
+/*0790*/0x83, 0x22, 0x90, 0x07, 0x24, 0xFF, 0xED, 0x44,
+ 0x07, 0xCF, 0xF0, 0xA3, 0xEF, 0xF0, 0x22, 0x85,
+/*07A0*/0x38, 0x38, 0x85, 0x39, 0x39, 0x85, 0x3A, 0x3A,
+ 0x74, 0xC0, 0x2F, 0xF5, 0x82, 0x74, 0x02, 0x3E,
+/*07B0*/0xF5, 0x83, 0x22, 0x90, 0x07, 0x26, 0xFF, 0xED,
+ 0x44, 0x07, 0xCF, 0xF0, 0xA3, 0xEF, 0xF0, 0x22,
+/*07C0*/0xF0, 0x74, 0xA0, 0x2F, 0xF5, 0x82, 0x74, 0x02,
+ 0x3E, 0xF5, 0x83, 0x22, 0x74, 0xC0, 0x25, 0x11,
+/*07D0*/0xF5, 0x82, 0xE4, 0x34, 0x01, 0xF5, 0x83, 0x22,
+ 0x74, 0x00, 0x25, 0x11, 0xF5, 0x82, 0xE4, 0x34,
+/*07E0*/0x02, 0xF5, 0x83, 0x22, 0x74, 0x60, 0x25, 0x11,
+ 0xF5, 0x82, 0xE4, 0x34, 0x03, 0xF5, 0x83, 0x22,
+/*07F0*/0x74, 0x80, 0x25, 0x11, 0xF5, 0x82, 0xE4, 0x34,
+ 0x03, 0xF5, 0x83, 0x22, 0x74, 0xE0, 0x25, 0x11,
+/*0800*/0xF5, 0x82, 0xE4, 0x34, 0x03, 0xF5, 0x83, 0x22,
+ 0x74, 0x40, 0x25, 0x11, 0xF5, 0x82, 0xE4, 0x34,
+/*0810*/0x06, 0xF5, 0x83, 0x22, 0x74, 0x80, 0x2F, 0xF5,
+ 0x82, 0x74, 0x02, 0x3E, 0xF5, 0x83, 0x22, 0xAF,
+/*0820*/0x08, 0x7E, 0x00, 0xEF, 0x44, 0x07, 0xF5, 0x82,
+ 0x22, 0xF5, 0x83, 0xE5, 0x82, 0x44, 0x07, 0xF5,
+/*0830*/0x82, 0xE5, 0x40, 0xF0, 0x22, 0x74, 0x40, 0x25,
+ 0x11, 0xF5, 0x82, 0xE4, 0x34, 0x02, 0xF5, 0x83,
+/*0840*/0x22, 0x74, 0xC0, 0x25, 0x11, 0xF5, 0x82, 0xE4,
+ 0x34, 0x03, 0xF5, 0x83, 0x22, 0x74, 0x00, 0x25,
+/*0850*/0x11, 0xF5, 0x82, 0xE4, 0x34, 0x06, 0xF5, 0x83,
+ 0x22, 0x74, 0x20, 0x25, 0x11, 0xF5, 0x82, 0xE4,
+/*0860*/0x34, 0x06, 0xF5, 0x83, 0x22, 0xE5, 0x08, 0xFD,
+ 0xED, 0x44, 0x07, 0xF5, 0x82, 0x22, 0xE5, 0x41,
+/*0870*/0xF0, 0xE5, 0x65, 0x64, 0x01, 0x45, 0x64, 0x22,
+ 0x7E, 0x00, 0xFB, 0x7A, 0x00, 0xFD, 0x7C, 0x00,
+/*0880*/0x22, 0x74, 0x20, 0x25, 0x11, 0xF5, 0x82, 0xE4,
+ 0x34, 0x02, 0x22, 0x74, 0xA0, 0x25, 0x11, 0xF5,
+/*0890*/0x82, 0xE4, 0x34, 0x03, 0x22, 0x85, 0x3E, 0x42,
+ 0x85, 0x3F, 0x41, 0x8F, 0x40, 0x22, 0x85, 0x3C,
+/*08A0*/0x42, 0x85, 0x3D, 0x41, 0x8F, 0x40, 0x22, 0x75,
+ 0x45, 0x3F, 0x90, 0x07, 0x20, 0xE4, 0xF0, 0xA3,
+/*08B0*/0x22, 0xF5, 0x83, 0xE5, 0x32, 0xF0, 0x05, 0x6E,
+ 0xE5, 0x6E, 0xC3, 0x94, 0x40, 0x22, 0xF0, 0xE5,
+/*08C0*/0x08, 0x44, 0x06, 0xF5, 0x82, 0x22, 0x74, 0x00,
+ 0x25, 0x6E, 0xF5, 0x82, 0xE4, 0x34, 0x00, 0xF5,
+/*08D0*/0x83, 0x22, 0xE5, 0x6D, 0x45, 0x6C, 0x90, 0x07,
+ 0x2F, 0x22, 0xE4, 0xF9, 0xE5, 0x3C, 0xD3, 0x95,
+/*08E0*/0x3E, 0x22, 0x74, 0x80, 0x2E, 0xF5, 0x82, 0xE4,
+ 0x34, 0x02, 0xF5, 0x83, 0xE0, 0x22, 0x74, 0xA0,
+/*08F0*/0x2E, 0xF5, 0x82, 0xE4, 0x34, 0x02, 0xF5, 0x83,
+ 0xE0, 0x22, 0x74, 0x80, 0x25, 0x6E, 0xF5, 0x82,
+/*0900*/0xE4, 0x34, 0x00, 0x22, 0x25, 0x42, 0xFD, 0xE4,
+ 0x33, 0xFC, 0x22, 0x85, 0x42, 0x42, 0x85, 0x41,
+/*0910*/0x41, 0x85, 0x40, 0x40, 0x22, 0xED, 0x4C, 0x60,
+ 0x03, 0x02, 0x09, 0xE5, 0xEF, 0x4E, 0x70, 0x37,
+/*0920*/0x90, 0x07, 0x26, 0x12, 0x07, 0x89, 0xE0, 0xFD,
+ 0x12, 0x07, 0xCC, 0xED, 0xF0, 0x90, 0x07, 0x28,
+/*0930*/0x12, 0x07, 0x89, 0xE0, 0xFD, 0x12, 0x07, 0xD8,
+ 0xED, 0xF0, 0x12, 0x07, 0x86, 0xE0, 0x54, 0x1F,
+/*0940*/0xFD, 0x12, 0x08, 0x81, 0xF5, 0x83, 0xED, 0xF0,
+ 0x90, 0x07, 0x24, 0x12, 0x07, 0x89, 0xE0, 0x54,
+/*0950*/0x1F, 0xFD, 0x12, 0x08, 0x35, 0xED, 0xF0, 0xEF,
+ 0x64, 0x04, 0x4E, 0x70, 0x37, 0x90, 0x07, 0x26,
+/*0960*/0x12, 0x07, 0x89, 0xE0, 0xFD, 0x12, 0x07, 0xE4,
+ 0xED, 0xF0, 0x90, 0x07, 0x28, 0x12, 0x07, 0x89,
+/*0970*/0xE0, 0xFD, 0x12, 0x07, 0xF0, 0xED, 0xF0, 0x12,
+ 0x07, 0x86, 0xE0, 0x54, 0x1F, 0xFD, 0x12, 0x08,
+/*0980*/0x8B, 0xF5, 0x83, 0xED, 0xF0, 0x90, 0x07, 0x24,
+ 0x12, 0x07, 0x89, 0xE0, 0x54, 0x1F, 0xFD, 0x12,
+/*0990*/0x08, 0x41, 0xED, 0xF0, 0xEF, 0x64, 0x01, 0x4E,
+ 0x70, 0x04, 0x7D, 0x01, 0x80, 0x02, 0x7D, 0x00,
+/*09A0*/0xEF, 0x64, 0x02, 0x4E, 0x70, 0x04, 0x7F, 0x01,
+ 0x80, 0x02, 0x7F, 0x00, 0xEF, 0x4D, 0x60, 0x78,
+/*09B0*/0x90, 0x07, 0x26, 0x12, 0x07, 0x35, 0xE0, 0xFF,
+ 0x12, 0x07, 0xFC, 0xEF, 0x12, 0x07, 0x31, 0xE0,
+/*09C0*/0xFF, 0x12, 0x08, 0x08, 0xEF, 0xF0, 0x90, 0x07,
+ 0x22, 0x12, 0x07, 0x35, 0xE0, 0x54, 0x1F, 0xFF,
+/*09D0*/0x12, 0x08, 0x4D, 0xEF, 0xF0, 0x90, 0x07, 0x24,
+ 0x12, 0x07, 0x35, 0xE0, 0x54, 0x1F, 0xFF, 0x12,
+/*09E0*/0x08, 0x59, 0xEF, 0xF0, 0x22, 0x12, 0x07, 0xCC,
+ 0xE4, 0xF0, 0x12, 0x07, 0xD8, 0xE4, 0xF0, 0x12,
+/*09F0*/0x08, 0x81, 0xF5, 0x83, 0xE4, 0xF0, 0x12, 0x08,
+ 0x35, 0x74, 0x14, 0xF0, 0x12, 0x07, 0xE4, 0xE4,
+/*0A00*/0xF0, 0x12, 0x07, 0xF0, 0xE4, 0xF0, 0x12, 0x08,
+ 0x8B, 0xF5, 0x83, 0xE4, 0xF0, 0x12, 0x08, 0x41,
+/*0A10*/0x74, 0x14, 0xF0, 0x12, 0x07, 0xFC, 0xE4, 0xF0,
+ 0x12, 0x08, 0x08, 0xE4, 0xF0, 0x12, 0x08, 0x4D,
+/*0A20*/0xE4, 0xF0, 0x12, 0x08, 0x59, 0x74, 0x14, 0xF0,
+ 0x22, 0x53, 0xF9, 0xF7, 0x75, 0xFC, 0x10, 0xE4,
+/*0A30*/0xF5, 0xFD, 0x75, 0xFE, 0x30, 0xF5, 0xFF, 0xE5,
+ 0xE7, 0x20, 0xE7, 0x03, 0x43, 0xF9, 0x08, 0xE5,
+/*0A40*/0xE6, 0x20, 0xE7, 0x0B, 0x78, 0xFF, 0xE4, 0xF6,
+ 0xD8, 0xFD, 0x53, 0xE6, 0xFE, 0x80, 0x09, 0x78,
+/*0A50*/0x08, 0xE4, 0xF6, 0xD8, 0xFD, 0x53, 0xE6, 0xFE,
+ 0x75, 0x81, 0x80, 0xE4, 0xF5, 0xA8, 0xD2, 0xA8,
+/*0A60*/0xC2, 0xA9, 0xD2, 0xAF, 0xE5, 0xE2, 0x20, 0xE5,
+ 0x05, 0x20, 0xE6, 0x02, 0x80, 0x03, 0x43, 0xE1,
+/*0A70*/0x02, 0xE5, 0xE2, 0x20, 0xE0, 0x0E, 0x90, 0x00,
+ 0x00, 0x7F, 0x00, 0x7E, 0x08, 0xE4, 0xF0, 0xA3,
+/*0A80*/0xDF, 0xFC, 0xDE, 0xFA, 0x02, 0x0A, 0xDB, 0x43,
+ 0xFA, 0x01, 0xC0, 0xE0, 0xC0, 0xF0, 0xC0, 0x83,
+/*0A90*/0xC0, 0x82, 0xC0, 0xD0, 0x12, 0x1C, 0xE7, 0xD0,
+ 0xD0, 0xD0, 0x82, 0xD0, 0x83, 0xD0, 0xF0, 0xD0,
+/*0AA0*/0xE0, 0x53, 0xFA, 0xFE, 0x32, 0x02, 0x1B, 0x55,
+ 0xE4, 0x93, 0xA3, 0xF8, 0xE4, 0x93, 0xA3, 0xF6,
+/*0AB0*/0x08, 0xDF, 0xF9, 0x80, 0x29, 0xE4, 0x93, 0xA3,
+ 0xF8, 0x54, 0x07, 0x24, 0x0C, 0xC8, 0xC3, 0x33,
+/*0AC0*/0xC4, 0x54, 0x0F, 0x44, 0x20, 0xC8, 0x83, 0x40,
+ 0x04, 0xF4, 0x56, 0x80, 0x01, 0x46, 0xF6, 0xDF,
+/*0AD0*/0xE4, 0x80, 0x0B, 0x01, 0x02, 0x04, 0x08, 0x10,
+ 0x20, 0x40, 0x80, 0x90, 0x00, 0x3F, 0xE4, 0x7E,
+/*0AE0*/0x01, 0x93, 0x60, 0xC1, 0xA3, 0xFF, 0x54, 0x3F,
+ 0x30, 0xE5, 0x09, 0x54, 0x1F, 0xFE, 0xE4, 0x93,
+/*0AF0*/0xA3, 0x60, 0x01, 0x0E, 0xCF, 0x54, 0xC0, 0x25,
+ 0xE0, 0x60, 0xAD, 0x40, 0xB8, 0x80, 0xFE, 0x8C,
+/*0B00*/0x64, 0x8D, 0x65, 0x8A, 0x66, 0x8B, 0x67, 0xE4,
+ 0xF5, 0x69, 0xEF, 0x4E, 0x70, 0x03, 0x02, 0x1D,
+/*0B10*/0x55, 0xE4, 0xF5, 0x68, 0xE5, 0x67, 0x45, 0x66,
+ 0x70, 0x32, 0x12, 0x07, 0x2A, 0x75, 0x83, 0x90,
+/*0B20*/0xE4, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC2, 0xE4,
+ 0x12, 0x07, 0x29, 0x75, 0x83, 0xC4, 0xE4, 0x12,
+/*0B30*/0x08, 0x70, 0x70, 0x29, 0x12, 0x07, 0x2A, 0x75,
+ 0x83, 0x92, 0xE4, 0x12, 0x07, 0x29, 0x75, 0x83,
+/*0B40*/0xC6, 0xE4, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC8,
+ 0xE4, 0xF0, 0x80, 0x11, 0x90, 0x07, 0x26, 0x12,
+/*0B50*/0x07, 0x35, 0xE4, 0x12, 0x08, 0x70, 0x70, 0x05,
+ 0x12, 0x07, 0x32, 0xE4, 0xF0, 0x12, 0x1D, 0x55,
+/*0B60*/0x12, 0x1E, 0xBF, 0xE5, 0x67, 0x45, 0x66, 0x70,
+ 0x33, 0x12, 0x07, 0x2A, 0x75, 0x83, 0x90, 0xE5,
+/*0B70*/0x41, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC2, 0xE5,
+ 0x41, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC4, 0x12,
+/*0B80*/0x08, 0x6E, 0x70, 0x29, 0x12, 0x07, 0x2A, 0x75,
+ 0x83, 0x92, 0xE5, 0x40, 0x12, 0x07, 0x29, 0x75,
+/*0B90*/0x83, 0xC6, 0xE5, 0x40, 0x12, 0x07, 0x29, 0x75,
+ 0x83, 0xC8, 0x80, 0x0E, 0x90, 0x07, 0x26, 0x12,
+/*0BA0*/0x07, 0x35, 0x12, 0x08, 0x6E, 0x70, 0x06, 0x12,
+ 0x07, 0x32, 0xE5, 0x40, 0xF0, 0xAF, 0x69, 0x7E,
+/*0BB0*/0x00, 0xAD, 0x67, 0xAC, 0x66, 0x12, 0x04, 0x44,
+ 0x12, 0x07, 0x2A, 0x75, 0x83, 0xCA, 0xE0, 0xD3,
+/*0BC0*/0x94, 0x00, 0x50, 0x0C, 0x05, 0x68, 0xE5, 0x68,
+ 0xC3, 0x94, 0x05, 0x50, 0x03, 0x02, 0x0B, 0x14,
+/*0BD0*/0x22, 0x8C, 0x60, 0x8D, 0x61, 0x12, 0x08, 0xDA,
+ 0x74, 0x20, 0x40, 0x0D, 0x2F, 0xF5, 0x82, 0x74,
+/*0BE0*/0x03, 0x3E, 0xF5, 0x83, 0xE5, 0x3E, 0xF0, 0x80,
+ 0x0B, 0x2F, 0xF5, 0x82, 0x74, 0x03, 0x3E, 0xF5,
+/*0BF0*/0x83, 0xE5, 0x3C, 0xF0, 0xE5, 0x3C, 0xD3, 0x95,
+ 0x3E, 0x40, 0x3C, 0xE5, 0x61, 0x45, 0x60, 0x70,
+/*0C00*/0x10, 0xE9, 0x12, 0x09, 0x04, 0xE5, 0x3E, 0x12,
+ 0x07, 0x68, 0x40, 0x3B, 0x12, 0x08, 0x95, 0x80,
+/*0C10*/0x18, 0xE5, 0x3E, 0xC3, 0x95, 0x38, 0x40, 0x1D,
+ 0x85, 0x3E, 0x38, 0xE5, 0x3E, 0x60, 0x05, 0x85,
+/*0C20*/0x3F, 0x39, 0x80, 0x03, 0x85, 0x39, 0x39, 0x8F,
+ 0x3A, 0x12, 0x08, 0x14, 0xE5, 0x3E, 0x12, 0x07,
+/*0C30*/0xC0, 0xE5, 0x3F, 0xF0, 0x22, 0x80, 0x43, 0xE5,
+ 0x61, 0x45, 0x60, 0x70, 0x19, 0x12, 0x07, 0x5F,
+/*0C40*/0x40, 0x05, 0x12, 0x08, 0x9E, 0x80, 0x27, 0x12,
+ 0x09, 0x0B, 0x12, 0x08, 0x14, 0xE5, 0x42, 0x12,
+/*0C50*/0x07, 0xC0, 0xE5, 0x41, 0xF0, 0x22, 0xE5, 0x3C,
+ 0xC3, 0x95, 0x38, 0x40, 0x1D, 0x85, 0x3C, 0x38,
+/*0C60*/0xE5, 0x3C, 0x60, 0x05, 0x85, 0x3D, 0x39, 0x80,
+ 0x03, 0x85, 0x39, 0x39, 0x8F, 0x3A, 0x12, 0x08,
+/*0C70*/0x14, 0xE5, 0x3C, 0x12, 0x07, 0xC0, 0xE5, 0x3D,
+ 0xF0, 0x22, 0x85, 0x38, 0x38, 0x85, 0x39, 0x39,
+/*0C80*/0x85, 0x3A, 0x3A, 0x12, 0x08, 0x14, 0xE5, 0x38,
+ 0x12, 0x07, 0xC0, 0xE5, 0x39, 0xF0, 0x22, 0x7F,
+/*0C90*/0x06, 0x12, 0x17, 0x31, 0x12, 0x1D, 0x23, 0x12,
+ 0x0E, 0x04, 0x12, 0x0E, 0x33, 0xE0, 0x44, 0x0A,
+/*0CA0*/0xF0, 0x74, 0x8E, 0xFE, 0x12, 0x0E, 0x04, 0x12,
+ 0x0E, 0x0B, 0xEF, 0xF0, 0xE5, 0x28, 0x30, 0xE5,
+/*0CB0*/0x03, 0xD3, 0x80, 0x01, 0xC3, 0x40, 0x05, 0x75,
+ 0x14, 0x20, 0x80, 0x03, 0x75, 0x14, 0x08, 0x12,
+/*0CC0*/0x0E, 0x04, 0x75, 0x83, 0x8A, 0xE5, 0x14, 0xF0,
+ 0xB4, 0xFF, 0x05, 0x75, 0x12, 0x80, 0x80, 0x06,
+/*0CD0*/0xE5, 0x14, 0xC3, 0x13, 0xF5, 0x12, 0xE4, 0xF5,
+ 0x16, 0xF5, 0x7F, 0x12, 0x19, 0x36, 0x12, 0x13,
+/*0CE0*/0xA3, 0xE5, 0x0A, 0xC3, 0x94, 0x01, 0x50, 0x09,
+ 0x05, 0x16, 0xE5, 0x16, 0xC3, 0x94, 0x14, 0x40,
+/*0CF0*/0xEA, 0xE5, 0xE4, 0x20, 0xE7, 0x28, 0x12, 0x0E,
+ 0x04, 0x75, 0x83, 0xD2, 0xE0, 0x54, 0x08, 0xD3,
+/*0D00*/0x94, 0x00, 0x40, 0x04, 0x7F, 0x01, 0x80, 0x02,
+ 0x7F, 0x00, 0xE5, 0x0A, 0xC3, 0x94, 0x01, 0x40,
+/*0D10*/0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEF,
+ 0x5E, 0x60, 0x03, 0x12, 0x1D, 0xD7, 0xE5, 0x7F,
+/*0D20*/0xC3, 0x94, 0x11, 0x40, 0x14, 0x12, 0x0E, 0x04,
+ 0x75, 0x83, 0xD2, 0xE0, 0x44, 0x80, 0xF0, 0xE5,
+/*0D30*/0xE4, 0x20, 0xE7, 0x0F, 0x12, 0x1D, 0xD7, 0x80,
+ 0x0A, 0x12, 0x0E, 0x04, 0x75, 0x83, 0xD2, 0xE0,
+/*0D40*/0x54, 0x7F, 0xF0, 0x12, 0x1D, 0x23, 0x22, 0x74,
+ 0x8A, 0x85, 0x08, 0x82, 0xF5, 0x83, 0xE5, 0x17,
+/*0D50*/0xF0, 0x12, 0x0E, 0x3A, 0xE4, 0xF0, 0x90, 0x07,
+ 0x02, 0xE0, 0x12, 0x0E, 0x17, 0x75, 0x83, 0x90,
+/*0D60*/0xEF, 0xF0, 0x74, 0x92, 0xFE, 0xE5, 0x08, 0x44,
+ 0x07, 0xFF, 0xF5, 0x82, 0x8E, 0x83, 0xE0, 0x54,
+/*0D70*/0xC0, 0xFD, 0x90, 0x07, 0x03, 0xE0, 0x54, 0x3F,
+ 0x4D, 0x8F, 0x82, 0x8E, 0x83, 0xF0, 0x90, 0x07,
+/*0D80*/0x04, 0xE0, 0x12, 0x0E, 0x17, 0x75, 0x83, 0x82,
+ 0xEF, 0xF0, 0x90, 0x07, 0x05, 0xE0, 0xFF, 0xED,
+/*0D90*/0x44, 0x07, 0xF5, 0x82, 0x75, 0x83, 0xB4, 0xEF,
+ 0x12, 0x0E, 0x03, 0x75, 0x83, 0x80, 0xE0, 0x54,
+/*0DA0*/0xBF, 0xF0, 0x30, 0x37, 0x0A, 0x12, 0x0E, 0x91,
+ 0x75, 0x83, 0x94, 0xE0, 0x44, 0x80, 0xF0, 0x30,
+/*0DB0*/0x38, 0x0A, 0x12, 0x0E, 0x91, 0x75, 0x83, 0x92,
+ 0xE0, 0x44, 0x80, 0xF0, 0xE5, 0x28, 0x30, 0xE4,
+/*0DC0*/0x1A, 0x20, 0x39, 0x0A, 0x12, 0x0E, 0x04, 0x75,
+ 0x83, 0x88, 0xE0, 0x54, 0x7F, 0xF0, 0x20, 0x3A,
+/*0DD0*/0x0A, 0x12, 0x0E, 0x04, 0x75, 0x83, 0x88, 0xE0,
+ 0x54, 0xBF, 0xF0, 0x74, 0x8C, 0xFE, 0x12, 0x0E,
+/*0DE0*/0x04, 0x8E, 0x83, 0xE0, 0x54, 0x0F, 0x12, 0x0E,
+ 0x03, 0x75, 0x83, 0x86, 0xE0, 0x54, 0xBF, 0xF0,
+/*0DF0*/0xE5, 0x08, 0x44, 0x06, 0x12, 0x0D, 0xFD, 0x75,
+ 0x83, 0x8A, 0xE4, 0xF0, 0x22, 0xF5, 0x82, 0x75,
+/*0E00*/0x83, 0x82, 0xE4, 0xF0, 0xE5, 0x08, 0x44, 0x07,
+ 0xF5, 0x82, 0x22, 0x8E, 0x83, 0xE0, 0xF5, 0x10,
+/*0E10*/0x54, 0xFE, 0xF0, 0xE5, 0x10, 0x44, 0x01, 0xFF,
+ 0xE5, 0x08, 0xFD, 0xED, 0x44, 0x07, 0xF5, 0x82,
+/*0E20*/0x22, 0xE5, 0x15, 0xC4, 0x54, 0x07, 0xFF, 0xE5,
+ 0x08, 0xFD, 0xED, 0x44, 0x08, 0xF5, 0x82, 0x75,
+/*0E30*/0x83, 0x82, 0x22, 0x75, 0x83, 0x80, 0xE0, 0x44,
+ 0x40, 0xF0, 0xE5, 0x08, 0x44, 0x08, 0xF5, 0x82,
+/*0E40*/0x75, 0x83, 0x8A, 0x22, 0xE5, 0x16, 0x25, 0xE0,
+ 0x25, 0xE0, 0x24, 0xAF, 0xF5, 0x82, 0xE4, 0x34,
+/*0E50*/0x1A, 0xF5, 0x83, 0xE4, 0x93, 0xF5, 0x0D, 0x22,
+ 0x43, 0xE1, 0x10, 0x43, 0xE1, 0x80, 0x53, 0xE1,
+/*0E60*/0xFD, 0x85, 0xE1, 0x10, 0x22, 0xE5, 0x16, 0x25,
+ 0xE0, 0x25, 0xE0, 0x24, 0xB2, 0xF5, 0x82, 0xE4,
+/*0E70*/0x34, 0x1A, 0xF5, 0x83, 0xE4, 0x93, 0x22, 0x85,
+ 0x55, 0x82, 0x85, 0x54, 0x83, 0xE5, 0x15, 0xF0,
+/*0E80*/0x22, 0xE5, 0xE2, 0x54, 0x20, 0xD3, 0x94, 0x00,
+ 0x22, 0xE5, 0xE2, 0x54, 0x40, 0xD3, 0x94, 0x00,
+/*0E90*/0x22, 0xE5, 0x08, 0x44, 0x06, 0xF5, 0x82, 0x22,
+ 0xFD, 0xE5, 0x08, 0xFB, 0xEB, 0x44, 0x07, 0xF5,
+/*0EA0*/0x82, 0x22, 0x53, 0xF9, 0xF7, 0x75, 0xFE, 0x30,
+ 0x22, 0xEF, 0x4E, 0x70, 0x26, 0x12, 0x07, 0xCC,
+/*0EB0*/0xE0, 0xFD, 0x90, 0x07, 0x26, 0x12, 0x07, 0x7B,
+ 0x12, 0x07, 0xD8, 0xE0, 0xFD, 0x90, 0x07, 0x28,
+/*0EC0*/0x12, 0x07, 0x7B, 0x12, 0x08, 0x81, 0x12, 0x07,
+ 0x72, 0x12, 0x08, 0x35, 0xE0, 0x90, 0x07, 0x24,
+/*0ED0*/0x12, 0x07, 0x78, 0xEF, 0x64, 0x04, 0x4E, 0x70,
+ 0x29, 0x12, 0x07, 0xE4, 0xE0, 0xFD, 0x90, 0x07,
+/*0EE0*/0x26, 0x12, 0x07, 0x7B, 0x12, 0x07, 0xF0, 0xE0,
+ 0xFD, 0x90, 0x07, 0x28, 0x12, 0x07, 0x7B, 0x12,
+/*0EF0*/0x08, 0x8B, 0x12, 0x07, 0x72, 0x12, 0x08, 0x41,
+ 0xE0, 0x54, 0x1F, 0xFD, 0x90, 0x07, 0x24, 0x12,
+/*0F00*/0x07, 0x7B, 0xEF, 0x64, 0x01, 0x4E, 0x70, 0x04,
+ 0x7D, 0x01, 0x80, 0x02, 0x7D, 0x00, 0xEF, 0x64,
+/*0F10*/0x02, 0x4E, 0x70, 0x04, 0x7F, 0x01, 0x80, 0x02,
+ 0x7F, 0x00, 0xEF, 0x4D, 0x60, 0x35, 0x12, 0x07,
+/*0F20*/0xFC, 0xE0, 0xFF, 0x90, 0x07, 0x26, 0x12, 0x07,
+ 0x89, 0xEF, 0xF0, 0x12, 0x08, 0x08, 0xE0, 0xFF,
+/*0F30*/0x90, 0x07, 0x28, 0x12, 0x07, 0x89, 0xEF, 0xF0,
+ 0x12, 0x08, 0x4D, 0xE0, 0x54, 0x1F, 0xFF, 0x12,
+/*0F40*/0x07, 0x86, 0xEF, 0xF0, 0x12, 0x08, 0x59, 0xE0,
+ 0x54, 0x1F, 0xFF, 0x90, 0x07, 0x24, 0x12, 0x07,
+/*0F50*/0x89, 0xEF, 0xF0, 0x22, 0xE4, 0xF5, 0x53, 0x12,
+ 0x0E, 0x81, 0x40, 0x04, 0x7F, 0x01, 0x80, 0x02,
+/*0F60*/0x7F, 0x00, 0x12, 0x0E, 0x89, 0x40, 0x04, 0x7E,
+ 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE, 0x4F, 0x70,
+/*0F70*/0x03, 0x02, 0x0F, 0xF6, 0x85, 0xE1, 0x10, 0x43,
+ 0xE1, 0x02, 0x53, 0xE1, 0x0F, 0x85, 0xE1, 0x10,
+/*0F80*/0xE4, 0xF5, 0x51, 0xE5, 0xE3, 0x54, 0x3F, 0xF5,
+ 0x52, 0x12, 0x0E, 0x89, 0x40, 0x1D, 0xAD, 0x52,
+/*0F90*/0xAF, 0x51, 0x12, 0x11, 0x18, 0xEF, 0x60, 0x08,
+ 0x85, 0xE1, 0x10, 0x43, 0xE1, 0x40, 0x80, 0x0B,
+/*0FA0*/0x53, 0xE1, 0xBF, 0x12, 0x0E, 0x58, 0x12, 0x00,
+ 0x06, 0x80, 0xFB, 0xE5, 0xE3, 0x54, 0x3F, 0xF5,
+/*0FB0*/0x51, 0xE5, 0xE4, 0x54, 0x3F, 0xF5, 0x52, 0x12,
+ 0x0E, 0x81, 0x40, 0x1D, 0xAD, 0x52, 0xAF, 0x51,
+/*0FC0*/0x12, 0x11, 0x18, 0xEF, 0x60, 0x08, 0x85, 0xE1,
+ 0x10, 0x43, 0xE1, 0x20, 0x80, 0x0B, 0x53, 0xE1,
+/*0FD0*/0xDF, 0x12, 0x0E, 0x58, 0x12, 0x00, 0x06, 0x80,
+ 0xFB, 0x12, 0x0E, 0x81, 0x40, 0x04, 0x7F, 0x01,
+/*0FE0*/0x80, 0x02, 0x7F, 0x00, 0x12, 0x0E, 0x89, 0x40,
+ 0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE,
+/*0FF0*/0x4F, 0x60, 0x03, 0x12, 0x0E, 0x5B, 0x22, 0x12,
+ 0x0E, 0x21, 0xEF, 0xF0, 0x12, 0x10, 0x91, 0x22,
+/*1000*/0x02, 0x11, 0x00, 0x02, 0x10, 0x40, 0x02, 0x10,
+ 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1010*/0x01, 0x20, 0x01, 0x20, 0xE4, 0xF5, 0x57, 0x12,
+ 0x16, 0xBD, 0x12, 0x16, 0x44, 0xE4, 0x12, 0x10,
+/*1020*/0x56, 0x12, 0x14, 0xB7, 0x90, 0x07, 0x26, 0x12,
+ 0x07, 0x35, 0xE4, 0x12, 0x07, 0x31, 0xE4, 0xF0,
+/*1030*/0x12, 0x10, 0x56, 0x12, 0x14, 0xB7, 0x90, 0x07,
+ 0x26, 0x12, 0x07, 0x35, 0xE5, 0x41, 0x12, 0x07,
+/*1040*/0x31, 0xE5, 0x40, 0xF0, 0xAF, 0x57, 0x7E, 0x00,
+ 0xAD, 0x56, 0x7C, 0x00, 0x12, 0x04, 0x44, 0xAF,
+/*1050*/0x56, 0x7E, 0x00, 0x02, 0x11, 0xEE, 0xFF, 0x90,
+ 0x07, 0x20, 0xA3, 0xE0, 0xFD, 0xE4, 0xF5, 0x56,
+/*1060*/0xF5, 0x40, 0xFE, 0xFC, 0xAB, 0x56, 0xFA, 0x12,
+ 0x11, 0x51, 0x7F, 0x0F, 0x7D, 0x18, 0xE4, 0xF5,
+/*1070*/0x56, 0xF5, 0x40, 0xFE, 0xFC, 0xAB, 0x56, 0xFA,
+ 0x12, 0x15, 0x41, 0xAF, 0x56, 0x7E, 0x00, 0x12,
+/*1080*/0x1A, 0xFF, 0xE4, 0xFF, 0xF5, 0x56, 0x7D, 0x1F,
+ 0xF5, 0x40, 0xFE, 0xFC, 0xAB, 0x56, 0xFA, 0x22,
+/*1090*/0x22, 0xE4, 0xF5, 0x55, 0xE5, 0x08, 0xFD, 0x74,
+ 0xA0, 0xF5, 0x56, 0xED, 0x44, 0x07, 0xF5, 0x57,
+/*10A0*/0xE5, 0x28, 0x30, 0xE5, 0x03, 0xD3, 0x80, 0x01,
+ 0xC3, 0x40, 0x05, 0x7F, 0x28, 0xEF, 0x80, 0x04,
+/*10B0*/0x7F, 0x14, 0xEF, 0xC3, 0x13, 0xF5, 0x54, 0xE4,
+ 0xF9, 0x12, 0x0E, 0x18, 0x75, 0x83, 0x8E, 0xE0,
+/*10C0*/0xF5, 0x10, 0xCE, 0xEF, 0xCE, 0xEE, 0xD3, 0x94,
+ 0x00, 0x40, 0x26, 0xE5, 0x10, 0x54, 0xFE, 0x12,
+/*10D0*/0x0E, 0x98, 0x75, 0x83, 0x8E, 0xED, 0xF0, 0xE5,
+ 0x10, 0x44, 0x01, 0xFD, 0xEB, 0x44, 0x07, 0xF5,
+/*10E0*/0x82, 0xED, 0xF0, 0x85, 0x57, 0x82, 0x85, 0x56,
+ 0x83, 0xE0, 0x30, 0xE3, 0x01, 0x09, 0x1E, 0x80,
+/*10F0*/0xD4, 0xC2, 0x34, 0xE9, 0xC3, 0x95, 0x54, 0x40,
+ 0x02, 0xD2, 0x34, 0x22, 0x02, 0x00, 0x06, 0x22,
+/*1100*/0x30, 0x30, 0x11, 0x90, 0x10, 0x00, 0xE4, 0x93,
+ 0xF5, 0x10, 0x90, 0x10, 0x10, 0xE4, 0x93, 0xF5,
+/*1110*/0x10, 0x12, 0x10, 0x90, 0x12, 0x11, 0x50, 0x22,
+ 0xE4, 0xFC, 0xC3, 0xED, 0x9F, 0xFA, 0xEF, 0xF5,
+/*1120*/0x83, 0x75, 0x82, 0x00, 0x79, 0xFF, 0xE4, 0x93,
+ 0xCC, 0x6C, 0xCC, 0xA3, 0xD9, 0xF8, 0xDA, 0xF6,
+/*1130*/0xE5, 0xE2, 0x30, 0xE4, 0x02, 0x8C, 0xE5, 0xED,
+ 0x24, 0xFF, 0xFF, 0xEF, 0x75, 0x82, 0xFF, 0xF5,
+/*1140*/0x83, 0xE4, 0x93, 0x6C, 0x70, 0x03, 0x7F, 0x01,
+ 0x22, 0x7F, 0x00, 0x22, 0x22, 0x11, 0x00, 0x00,
+/*1150*/0x22, 0x8E, 0x58, 0x8F, 0x59, 0x8C, 0x5A, 0x8D,
+ 0x5B, 0x8A, 0x5C, 0x8B, 0x5D, 0x75, 0x5E, 0x01,
+/*1160*/0xE4, 0xF5, 0x5F, 0xF5, 0x60, 0xF5, 0x62, 0x12,
+ 0x07, 0x2A, 0x75, 0x83, 0xD0, 0xE0, 0xFF, 0xC4,
+/*1170*/0x54, 0x0F, 0xF5, 0x61, 0x12, 0x1E, 0xA5, 0x85,
+ 0x59, 0x5E, 0xD3, 0xE5, 0x5E, 0x95, 0x5B, 0xE5,
+/*1180*/0x5A, 0x12, 0x07, 0x6B, 0x50, 0x4B, 0x12, 0x07,
+ 0x03, 0x75, 0x83, 0xBC, 0xE0, 0x45, 0x5E, 0x12,
+/*1190*/0x07, 0x29, 0x75, 0x83, 0xBE, 0xE0, 0x45, 0x5E,
+ 0x12, 0x07, 0x29, 0x75, 0x83, 0xC0, 0xE0, 0x45,
+/*11A0*/0x5E, 0xF0, 0xAF, 0x5F, 0xE5, 0x60, 0x12, 0x08,
+ 0x78, 0x12, 0x0A, 0xFF, 0xAF, 0x62, 0x7E, 0x00,
+/*11B0*/0xAD, 0x5D, 0xAC, 0x5C, 0x12, 0x04, 0x44, 0xE5,
+ 0x61, 0xAF, 0x5E, 0x7E, 0x00, 0xB4, 0x03, 0x05,
+/*11C0*/0x12, 0x1E, 0x21, 0x80, 0x07, 0xAD, 0x5D, 0xAC,
+ 0x5C, 0x12, 0x13, 0x17, 0x05, 0x5E, 0x02, 0x11,
+/*11D0*/0x7A, 0x12, 0x07, 0x03, 0x75, 0x83, 0xBC, 0xE0,
+ 0x45, 0x40, 0x12, 0x07, 0x29, 0x75, 0x83, 0xBE,
+/*11E0*/0xE0, 0x45, 0x40, 0x12, 0x07, 0x29, 0x75, 0x83,
+ 0xC0, 0xE0, 0x45, 0x40, 0xF0, 0x22, 0x8E, 0x58,
+/*11F0*/0x8F, 0x59, 0x75, 0x5A, 0x01, 0x79, 0x01, 0x75,
+ 0x5B, 0x01, 0xE4, 0xFB, 0x12, 0x07, 0x2A, 0x75,
+/*1200*/0x83, 0xAE, 0xE0, 0x54, 0x1A, 0xFF, 0x12, 0x08,
+ 0x65, 0xE0, 0xC4, 0x13, 0x54, 0x07, 0xFE, 0xEF,
+/*1210*/0x70, 0x0C, 0xEE, 0x65, 0x35, 0x70, 0x07, 0x90,
+ 0x07, 0x2F, 0xE0, 0xB4, 0x01, 0x0D, 0xAF, 0x35,
+/*1220*/0x7E, 0x00, 0x12, 0x0E, 0xA9, 0xCF, 0xEB, 0xCF,
+ 0x02, 0x1E, 0x60, 0xE5, 0x59, 0x64, 0x02, 0x45,
+/*1230*/0x58, 0x70, 0x04, 0x7F, 0x01, 0x80, 0x02, 0x7F,
+ 0x00, 0xE5, 0x59, 0x45, 0x58, 0x70, 0x04, 0x7E,
+/*1240*/0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE, 0x4F, 0x60,
+ 0x23, 0x85, 0x41, 0x49, 0x85, 0x40, 0x4B, 0xE5,
+/*1250*/0x59, 0x45, 0x58, 0x70, 0x2C, 0xAF, 0x5A, 0xFE,
+ 0xCD, 0xE9, 0xCD, 0xFC, 0xAB, 0x59, 0xAA, 0x58,
+/*1260*/0x12, 0x0A, 0xFF, 0xAF, 0x5B, 0x7E, 0x00, 0x12,
+ 0x1E, 0x60, 0x80, 0x15, 0xAF, 0x5B, 0x7E, 0x00,
+/*1270*/0x12, 0x1E, 0x60, 0x90, 0x07, 0x26, 0x12, 0x07,
+ 0x35, 0xE5, 0x49, 0x12, 0x07, 0x31, 0xE5, 0x4B,
+/*1280*/0xF0, 0xE4, 0xFD, 0xAF, 0x35, 0xFE, 0xFC, 0x12,
+ 0x09, 0x15, 0x22, 0x8C, 0x64, 0x8D, 0x65, 0x12,
+/*1290*/0x08, 0xDA, 0x40, 0x3C, 0xE5, 0x65, 0x45, 0x64,
+ 0x70, 0x10, 0x12, 0x09, 0x04, 0xC3, 0xE5, 0x3E,
+/*12A0*/0x12, 0x07, 0x69, 0x40, 0x3B, 0x12, 0x08, 0x95,
+ 0x80, 0x18, 0xE5, 0x3E, 0xC3, 0x95, 0x38, 0x40,
+/*12B0*/0x1D, 0x85, 0x3E, 0x38, 0xE5, 0x3E, 0x60, 0x05,
+ 0x85, 0x3F, 0x39, 0x80, 0x03, 0x85, 0x39, 0x39,
+/*12C0*/0x8F, 0x3A, 0x12, 0x07, 0xA8, 0xE5, 0x3E, 0x12,
+ 0x07, 0x53, 0xE5, 0x3F, 0xF0, 0x22, 0x80, 0x3B,
+/*12D0*/0xE5, 0x65, 0x45, 0x64, 0x70, 0x11, 0x12, 0x07,
+ 0x5F, 0x40, 0x05, 0x12, 0x08, 0x9E, 0x80, 0x1F,
+/*12E0*/0x12, 0x07, 0x3E, 0xE5, 0x41, 0xF0, 0x22, 0xE5,
+ 0x3C, 0xC3, 0x95, 0x38, 0x40, 0x1D, 0x85, 0x3C,
+/*12F0*/0x38, 0xE5, 0x3C, 0x60, 0x05, 0x85, 0x3D, 0x39,
+ 0x80, 0x03, 0x85, 0x39, 0x39, 0x8F, 0x3A, 0x12,
+/*1300*/0x07, 0xA8, 0xE5, 0x3C, 0x12, 0x07, 0x53, 0xE5,
+ 0x3D, 0xF0, 0x22, 0x12, 0x07, 0x9F, 0xE5, 0x38,
+/*1310*/0x12, 0x07, 0x53, 0xE5, 0x39, 0xF0, 0x22, 0x8C,
+ 0x63, 0x8D, 0x64, 0x12, 0x08, 0xDA, 0x40, 0x3C,
+/*1320*/0xE5, 0x64, 0x45, 0x63, 0x70, 0x10, 0x12, 0x09,
+ 0x04, 0xC3, 0xE5, 0x3E, 0x12, 0x07, 0x69, 0x40,
+/*1330*/0x3B, 0x12, 0x08, 0x95, 0x80, 0x18, 0xE5, 0x3E,
+ 0xC3, 0x95, 0x38, 0x40, 0x1D, 0x85, 0x3E, 0x38,
+/*1340*/0xE5, 0x3E, 0x60, 0x05, 0x85, 0x3F, 0x39, 0x80,
+ 0x03, 0x85, 0x39, 0x39, 0x8F, 0x3A, 0x12, 0x07,
+/*1350*/0xA8, 0xE5, 0x3E, 0x12, 0x07, 0x53, 0xE5, 0x3F,
+ 0xF0, 0x22, 0x80, 0x3B, 0xE5, 0x64, 0x45, 0x63,
+/*1360*/0x70, 0x11, 0x12, 0x07, 0x5F, 0x40, 0x05, 0x12,
+ 0x08, 0x9E, 0x80, 0x1F, 0x12, 0x07, 0x3E, 0xE5,
+/*1370*/0x41, 0xF0, 0x22, 0xE5, 0x3C, 0xC3, 0x95, 0x38,
+ 0x40, 0x1D, 0x85, 0x3C, 0x38, 0xE5, 0x3C, 0x60,
+/*1380*/0x05, 0x85, 0x3D, 0x39, 0x80, 0x03, 0x85, 0x39,
+ 0x39, 0x8F, 0x3A, 0x12, 0x07, 0xA8, 0xE5, 0x3C,
+/*1390*/0x12, 0x07, 0x53, 0xE5, 0x3D, 0xF0, 0x22, 0x12,
+ 0x07, 0x9F, 0xE5, 0x38, 0x12, 0x07, 0x53, 0xE5,
+/*13A0*/0x39, 0xF0, 0x22, 0xE5, 0x0D, 0xFE, 0xE5, 0x08,
+ 0x8E, 0x54, 0x44, 0x05, 0xF5, 0x55, 0x75, 0x15,
+/*13B0*/0x0F, 0xF5, 0x82, 0x12, 0x0E, 0x7A, 0x12, 0x17,
+ 0xA3, 0x20, 0x31, 0x05, 0x75, 0x15, 0x03, 0x80,
+/*13C0*/0x03, 0x75, 0x15, 0x0B, 0xE5, 0x0A, 0xC3, 0x94,
+ 0x01, 0x50, 0x38, 0x12, 0x14, 0x20, 0x20, 0x31,
+/*13D0*/0x06, 0x05, 0x15, 0x05, 0x15, 0x80, 0x04, 0x15,
+ 0x15, 0x15, 0x15, 0xE5, 0x0A, 0xC3, 0x94, 0x01,
+/*13E0*/0x50, 0x21, 0x12, 0x14, 0x20, 0x20, 0x31, 0x04,
+ 0x05, 0x15, 0x80, 0x02, 0x15, 0x15, 0xE5, 0x0A,
+/*13F0*/0xC3, 0x94, 0x01, 0x50, 0x0E, 0x12, 0x0E, 0x77,
+ 0x12, 0x17, 0xA3, 0x20, 0x31, 0x05, 0x05, 0x15,
+/*1400*/0x12, 0x0E, 0x77, 0xE5, 0x15, 0xB4, 0x08, 0x04,
+ 0x7F, 0x01, 0x80, 0x02, 0x7F, 0x00, 0xE5, 0x15,
+/*1410*/0xB4, 0x07, 0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E,
+ 0x00, 0xEE, 0x4F, 0x60, 0x02, 0x05, 0x7F, 0x22,
+/*1420*/0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xE5, 0x15,
+ 0xF0, 0x12, 0x17, 0xA3, 0x22, 0x12, 0x07, 0x2A,
+/*1430*/0x75, 0x83, 0xAE, 0x74, 0xFF, 0x12, 0x07, 0x29,
+ 0xE0, 0x54, 0x1A, 0xF5, 0x34, 0xE0, 0xC4, 0x13,
+/*1440*/0x54, 0x07, 0xF5, 0x35, 0x24, 0xFE, 0x60, 0x24,
+ 0x24, 0xFE, 0x60, 0x3C, 0x24, 0x04, 0x70, 0x63,
+/*1450*/0x75, 0x31, 0x2D, 0xE5, 0x08, 0xFD, 0x74, 0xB6,
+ 0x12, 0x07, 0x92, 0x74, 0xBC, 0x90, 0x07, 0x22,
+/*1460*/0x12, 0x07, 0x95, 0x74, 0x90, 0x12, 0x07, 0xB3,
+ 0x74, 0x92, 0x80, 0x3C, 0x75, 0x31, 0x3A, 0xE5,
+/*1470*/0x08, 0xFD, 0x74, 0xBA, 0x12, 0x07, 0x92, 0x74,
+ 0xC0, 0x90, 0x07, 0x22, 0x12, 0x07, 0xB6, 0x74,
+/*1480*/0xC4, 0x12, 0x07, 0xB3, 0x74, 0xC8, 0x80, 0x20,
+ 0x75, 0x31, 0x35, 0xE5, 0x08, 0xFD, 0x74, 0xB8,
+/*1490*/0x12, 0x07, 0x92, 0x74, 0xBE, 0xFF, 0xED, 0x44,
+ 0x07, 0x90, 0x07, 0x22, 0xCF, 0xF0, 0xA3, 0xEF,
+/*14A0*/0xF0, 0x74, 0xC2, 0x12, 0x07, 0xB3, 0x74, 0xC6,
+ 0xFF, 0xED, 0x44, 0x07, 0xA3, 0xCF, 0xF0, 0xA3,
+/*14B0*/0xEF, 0xF0, 0x22, 0x75, 0x34, 0x01, 0x22, 0x8E,
+ 0x58, 0x8F, 0x59, 0x8C, 0x5A, 0x8D, 0x5B, 0x8A,
+/*14C0*/0x5C, 0x8B, 0x5D, 0x75, 0x5E, 0x01, 0xE4, 0xF5,
+ 0x5F, 0x12, 0x1E, 0xA5, 0x85, 0x59, 0x5E, 0xD3,
+/*14D0*/0xE5, 0x5E, 0x95, 0x5B, 0xE5, 0x5A, 0x12, 0x07,
+ 0x6B, 0x50, 0x57, 0xE5, 0x5D, 0x45, 0x5C, 0x70,
+/*14E0*/0x30, 0x12, 0x07, 0x2A, 0x75, 0x83, 0x92, 0xE5,
+ 0x5E, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC6, 0xE5,
+/*14F0*/0x5E, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC8, 0xE5,
+ 0x5E, 0x12, 0x07, 0x29, 0x75, 0x83, 0x90, 0xE5,
+/*1500*/0x5E, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC2, 0xE5,
+ 0x5E, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC4, 0x80,
+/*1510*/0x03, 0x12, 0x07, 0x32, 0xE5, 0x5E, 0xF0, 0xAF,
+ 0x5F, 0x7E, 0x00, 0xAD, 0x5D, 0xAC, 0x5C, 0x12,
+/*1520*/0x04, 0x44, 0xAF, 0x5E, 0x7E, 0x00, 0xAD, 0x5D,
+ 0xAC, 0x5C, 0x12, 0x0B, 0xD1, 0x05, 0x5E, 0x02,
+/*1530*/0x14, 0xCF, 0xAB, 0x5D, 0xAA, 0x5C, 0xAD, 0x5B,
+ 0xAC, 0x5A, 0xAF, 0x59, 0xAE, 0x58, 0x02, 0x1B,
+/*1540*/0xFB, 0x8C, 0x5C, 0x8D, 0x5D, 0x8A, 0x5E, 0x8B,
+ 0x5F, 0x75, 0x60, 0x01, 0xE4, 0xF5, 0x61, 0xF5,
+/*1550*/0x62, 0xF5, 0x63, 0x12, 0x1E, 0xA5, 0x8F, 0x60,
+ 0xD3, 0xE5, 0x60, 0x95, 0x5D, 0xE5, 0x5C, 0x12,
+/*1560*/0x07, 0x6B, 0x50, 0x61, 0xE5, 0x5F, 0x45, 0x5E,
+ 0x70, 0x27, 0x12, 0x07, 0x2A, 0x75, 0x83, 0xB6,
+/*1570*/0xE5, 0x60, 0x12, 0x07, 0x29, 0x75, 0x83, 0xB8,
+ 0xE5, 0x60, 0x12, 0x07, 0x29, 0x75, 0x83, 0xBA,
+/*1580*/0xE5, 0x60, 0xF0, 0xAF, 0x61, 0x7E, 0x00, 0xE5,
+ 0x62, 0x12, 0x08, 0x7A, 0x12, 0x0A, 0xFF, 0x80,
+/*1590*/0x19, 0x90, 0x07, 0x24, 0x12, 0x07, 0x35, 0xE5,
+ 0x60, 0x12, 0x07, 0x29, 0x75, 0x83, 0x8E, 0xE4,
+/*15A0*/0x12, 0x07, 0x29, 0x74, 0x01, 0x12, 0x07, 0x29,
+ 0xE4, 0xF0, 0xAF, 0x63, 0x7E, 0x00, 0xAD, 0x5F,
+/*15B0*/0xAC, 0x5E, 0x12, 0x04, 0x44, 0xAF, 0x60, 0x7E,
+ 0x00, 0xAD, 0x5F, 0xAC, 0x5E, 0x12, 0x12, 0x8B,
+/*15C0*/0x05, 0x60, 0x02, 0x15, 0x58, 0x22, 0x90, 0x11,
+ 0x4D, 0xE4, 0x93, 0x90, 0x07, 0x2E, 0xF0, 0x12,
+/*15D0*/0x08, 0x1F, 0x75, 0x83, 0xAE, 0xE0, 0x54, 0x1A,
+ 0xF5, 0x34, 0x70, 0x67, 0xEF, 0x44, 0x07, 0xF5,
+/*15E0*/0x82, 0x75, 0x83, 0xCE, 0xE0, 0xFF, 0x13, 0x13,
+ 0x13, 0x54, 0x07, 0xF5, 0x36, 0x54, 0x0F, 0xD3,
+/*15F0*/0x94, 0x00, 0x40, 0x06, 0x12, 0x14, 0x2D, 0x12,
+ 0x1B, 0xA9, 0xE5, 0x36, 0x54, 0x0F, 0x24, 0xFE,
+/*1600*/0x60, 0x0C, 0x14, 0x60, 0x0C, 0x14, 0x60, 0x19,
+ 0x24, 0x03, 0x70, 0x37, 0x80, 0x10, 0x02, 0x1E,
+/*1610*/0x91, 0x12, 0x1E, 0x91, 0x12, 0x07, 0x2A, 0x75,
+ 0x83, 0xCE, 0xE0, 0x54, 0xEF, 0xF0, 0x02, 0x1D,
+/*1620*/0xAE, 0x12, 0x10, 0x14, 0xE4, 0xF5, 0x55, 0x12,
+ 0x1D, 0x85, 0x05, 0x55, 0xE5, 0x55, 0xC3, 0x94,
+/*1630*/0x05, 0x40, 0xF4, 0x12, 0x07, 0x2A, 0x75, 0x83,
+ 0xCE, 0xE0, 0x54, 0xC7, 0x12, 0x07, 0x29, 0xE0,
+/*1640*/0x44, 0x08, 0xF0, 0x22, 0xE4, 0xF5, 0x58, 0xF5,
+ 0x59, 0xAF, 0x08, 0xEF, 0x44, 0x07, 0xF5, 0x82,
+/*1650*/0x75, 0x83, 0xD0, 0xE0, 0xFD, 0xC4, 0x54, 0x0F,
+ 0xF5, 0x5A, 0xEF, 0x44, 0x07, 0xF5, 0x82, 0x75,
+/*1660*/0x83, 0x80, 0x74, 0x01, 0xF0, 0x12, 0x08, 0x21,
+ 0x75, 0x83, 0x82, 0xE5, 0x45, 0xF0, 0xEF, 0x44,
+/*1670*/0x07, 0xF5, 0x82, 0x75, 0x83, 0x8A, 0x74, 0xFF,
+ 0xF0, 0x12, 0x1A, 0x4D, 0x12, 0x07, 0x2A, 0x75,
+/*1680*/0x83, 0xBC, 0xE0, 0x54, 0xEF, 0x12, 0x07, 0x29,
+ 0x75, 0x83, 0xBE, 0xE0, 0x54, 0xEF, 0x12, 0x07,
+/*1690*/0x29, 0x75, 0x83, 0xC0, 0xE0, 0x54, 0xEF, 0x12,
+ 0x07, 0x29, 0x75, 0x83, 0xBC, 0xE0, 0x44, 0x10,
+/*16A0*/0x12, 0x07, 0x29, 0x75, 0x83, 0xBE, 0xE0, 0x44,
+ 0x10, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC0, 0xE0,
+/*16B0*/0x44, 0x10, 0xF0, 0xAF, 0x58, 0xE5, 0x59, 0x12,
+ 0x08, 0x78, 0x02, 0x0A, 0xFF, 0xE4, 0xF5, 0x58,
+/*16C0*/0x7D, 0x01, 0xF5, 0x59, 0xAF, 0x35, 0xFE, 0xFC,
+ 0x12, 0x09, 0x15, 0x12, 0x07, 0x2A, 0x75, 0x83,
+/*16D0*/0xB6, 0x74, 0x10, 0x12, 0x07, 0x29, 0x75, 0x83,
+ 0xB8, 0x74, 0x10, 0x12, 0x07, 0x29, 0x75, 0x83,
+/*16E0*/0xBA, 0x74, 0x10, 0x12, 0x07, 0x29, 0x75, 0x83,
+ 0xBC, 0x74, 0x10, 0x12, 0x07, 0x29, 0x75, 0x83,
+/*16F0*/0xBE, 0x74, 0x10, 0x12, 0x07, 0x29, 0x75, 0x83,
+ 0xC0, 0x74, 0x10, 0x12, 0x07, 0x29, 0x75, 0x83,
+/*1700*/0x90, 0xE4, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC2,
+ 0xE4, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC4, 0xE4,
+/*1710*/0x12, 0x07, 0x29, 0x75, 0x83, 0x92, 0xE4, 0x12,
+ 0x07, 0x29, 0x75, 0x83, 0xC6, 0xE4, 0x12, 0x07,
+/*1720*/0x29, 0x75, 0x83, 0xC8, 0xE4, 0xF0, 0xAF, 0x58,
+ 0xFE, 0xE5, 0x59, 0x12, 0x08, 0x7A, 0x02, 0x0A,
+/*1730*/0xFF, 0xE5, 0xE2, 0x30, 0xE4, 0x6C, 0xE5, 0xE7,
+ 0x54, 0xC0, 0x64, 0x40, 0x70, 0x64, 0xE5, 0x09,
+/*1740*/0xC4, 0x54, 0x30, 0xFE, 0xE5, 0x08, 0x25, 0xE0,
+ 0x25, 0xE0, 0x54, 0xC0, 0x4E, 0xFE, 0xEF, 0x54,
+/*1750*/0x3F, 0x4E, 0xFD, 0xE5, 0x2B, 0xAE, 0x2A, 0x78,
+ 0x02, 0xC3, 0x33, 0xCE, 0x33, 0xCE, 0xD8, 0xF9,
+/*1760*/0xF5, 0x82, 0x8E, 0x83, 0xED, 0xF0, 0xE5, 0x2B,
+ 0xAE, 0x2A, 0x78, 0x02, 0xC3, 0x33, 0xCE, 0x33,
+/*1770*/0xCE, 0xD8, 0xF9, 0xFF, 0xF5, 0x82, 0x8E, 0x83,
+ 0xA3, 0xE5, 0xFE, 0xF0, 0x8F, 0x82, 0x8E, 0x83,
+/*1780*/0xA3, 0xA3, 0xE5, 0xFD, 0xF0, 0x8F, 0x82, 0x8E,
+ 0x83, 0xA3, 0xA3, 0xA3, 0xE5, 0xFC, 0xF0, 0xC3,
+/*1790*/0xE5, 0x2B, 0x94, 0xFA, 0xE5, 0x2A, 0x94, 0x00,
+ 0x50, 0x08, 0x05, 0x2B, 0xE5, 0x2B, 0x70, 0x02,
+/*17A0*/0x05, 0x2A, 0x22, 0xE4, 0xFF, 0xE4, 0xF5, 0x58,
+ 0xF5, 0x56, 0xF5, 0x57, 0x74, 0x82, 0xFC, 0x12,
+/*17B0*/0x0E, 0x04, 0x8C, 0x83, 0xE0, 0xF5, 0x10, 0x54,
+ 0x7F, 0xF0, 0xE5, 0x10, 0x44, 0x80, 0x12, 0x0E,
+/*17C0*/0x98, 0xED, 0xF0, 0x7E, 0x0A, 0x12, 0x0E, 0x04,
+ 0x75, 0x83, 0xA0, 0xE0, 0x20, 0xE0, 0x26, 0xDE,
+/*17D0*/0xF4, 0x05, 0x57, 0xE5, 0x57, 0x70, 0x02, 0x05,
+ 0x56, 0xE5, 0x14, 0x24, 0x01, 0xFD, 0xE4, 0x33,
+/*17E0*/0xFC, 0xD3, 0xE5, 0x57, 0x9D, 0xE5, 0x56, 0x9C,
+ 0x40, 0xD9, 0xE5, 0x0A, 0x94, 0x20, 0x50, 0x02,
+/*17F0*/0x05, 0x0A, 0x43, 0xE1, 0x08, 0xC2, 0x31, 0x12,
+ 0x0E, 0x04, 0x75, 0x83, 0xA6, 0xE0, 0x55, 0x12,
+/*1800*/0x65, 0x12, 0x70, 0x03, 0xD2, 0x31, 0x22, 0xC2,
+ 0x31, 0x22, 0x90, 0x07, 0x26, 0xE0, 0xFA, 0xA3,
+/*1810*/0xE0, 0xF5, 0x82, 0x8A, 0x83, 0xE0, 0xF5, 0x41,
+ 0xE5, 0x39, 0xC3, 0x95, 0x41, 0x40, 0x26, 0xE5,
+/*1820*/0x39, 0x95, 0x41, 0xC3, 0x9F, 0xEE, 0x12, 0x07,
+ 0x6B, 0x40, 0x04, 0x7C, 0x01, 0x80, 0x02, 0x7C,
+/*1830*/0x00, 0xE5, 0x41, 0x64, 0x3F, 0x60, 0x04, 0x7B,
+ 0x01, 0x80, 0x02, 0x7B, 0x00, 0xEC, 0x5B, 0x60,
+/*1840*/0x29, 0x05, 0x41, 0x80, 0x28, 0xC3, 0xE5, 0x41,
+ 0x95, 0x39, 0xC3, 0x9F, 0xEE, 0x12, 0x07, 0x6B,
+/*1850*/0x40, 0x04, 0x7F, 0x01, 0x80, 0x02, 0x7F, 0x00,
+ 0xE5, 0x41, 0x60, 0x04, 0x7E, 0x01, 0x80, 0x02,
+/*1860*/0x7E, 0x00, 0xEF, 0x5E, 0x60, 0x04, 0x15, 0x41,
+ 0x80, 0x03, 0x85, 0x39, 0x41, 0x85, 0x3A, 0x40,
+/*1870*/0x22, 0xE5, 0xE2, 0x30, 0xE4, 0x60, 0xE5, 0xE1,
+ 0x30, 0xE2, 0x5B, 0xE5, 0x09, 0x70, 0x04, 0x7F,
+/*1880*/0x01, 0x80, 0x02, 0x7F, 0x00, 0xE5, 0x08, 0x70,
+ 0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE,
+/*1890*/0x5F, 0x60, 0x43, 0x53, 0xF9, 0xF8, 0xE5, 0xE2,
+ 0x30, 0xE4, 0x3B, 0xE5, 0xE1, 0x30, 0xE2, 0x2E,
+/*18A0*/0x43, 0xFA, 0x02, 0x53, 0xFA, 0xFB, 0xE4, 0xF5,
+ 0x10, 0x90, 0x94, 0x70, 0xE5, 0x10, 0xF0, 0xE5,
+/*18B0*/0xE1, 0x30, 0xE2, 0xE7, 0x90, 0x94, 0x70, 0xE0,
+ 0x65, 0x10, 0x60, 0x03, 0x43, 0xFA, 0x04, 0x05,
+/*18C0*/0x10, 0x90, 0x94, 0x70, 0xE5, 0x10, 0xF0, 0x70,
+ 0xE6, 0x12, 0x00, 0x06, 0x80, 0xE1, 0x53, 0xFA,
+/*18D0*/0xFD, 0x53, 0xFA, 0xFB, 0x80, 0xC0, 0x22, 0x8F,
+ 0x54, 0x12, 0x00, 0x06, 0xE5, 0xE1, 0x30, 0xE0,
+/*18E0*/0x04, 0x7F, 0x01, 0x80, 0x02, 0x7F, 0x00, 0xE5,
+ 0x7E, 0xD3, 0x94, 0x05, 0x40, 0x04, 0x7E, 0x01,
+/*18F0*/0x80, 0x02, 0x7E, 0x00, 0xEE, 0x4F, 0x60, 0x3D,
+ 0x85, 0x54, 0x11, 0xE5, 0xE2, 0x20, 0xE1, 0x32,
+/*1900*/0x74, 0xCE, 0x12, 0x1A, 0x05, 0x30, 0xE7, 0x04,
+ 0x7D, 0x01, 0x80, 0x02, 0x7D, 0x00, 0x8F, 0x82,
+/*1910*/0x8E, 0x83, 0xE0, 0x30, 0xE6, 0x04, 0x7F, 0x01,
+ 0x80, 0x02, 0x7F, 0x00, 0xEF, 0x5D, 0x70, 0x15,
+/*1920*/0x12, 0x15, 0xC6, 0x74, 0xCE, 0x12, 0x1A, 0x05,
+ 0x30, 0xE6, 0x07, 0xE0, 0x44, 0x80, 0xF0, 0x43,
+/*1930*/0xF9, 0x80, 0x12, 0x18, 0x71, 0x22, 0x12, 0x0E,
+ 0x44, 0xE5, 0x16, 0x25, 0xE0, 0x25, 0xE0, 0x24,
+/*1940*/0xB0, 0xF5, 0x82, 0xE4, 0x34, 0x1A, 0xF5, 0x83,
+ 0xE4, 0x93, 0xF5, 0x0F, 0xE5, 0x16, 0x25, 0xE0,
+/*1950*/0x25, 0xE0, 0x24, 0xB1, 0xF5, 0x82, 0xE4, 0x34,
+ 0x1A, 0xF5, 0x83, 0xE4, 0x93, 0xF5, 0x0E, 0x12,
+/*1960*/0x0E, 0x65, 0xF5, 0x10, 0xE5, 0x0F, 0x54, 0xF0,
+ 0x12, 0x0E, 0x17, 0x75, 0x83, 0x8C, 0xEF, 0xF0,
+/*1970*/0xE5, 0x0F, 0x30, 0xE0, 0x0C, 0x12, 0x0E, 0x04,
+ 0x75, 0x83, 0x86, 0xE0, 0x44, 0x40, 0xF0, 0x80,
+/*1980*/0x0A, 0x12, 0x0E, 0x04, 0x75, 0x83, 0x86, 0xE0,
+ 0x54, 0xBF, 0xF0, 0x12, 0x0E, 0x91, 0x75, 0x83,
+/*1990*/0x82, 0xE5, 0x0E, 0xF0, 0x22, 0x7F, 0x05, 0x12,
+ 0x17, 0x31, 0x12, 0x0E, 0x04, 0x12, 0x0E, 0x33,
+/*19A0*/0x74, 0x02, 0xF0, 0x74, 0x8E, 0xFE, 0x12, 0x0E,
+ 0x04, 0x12, 0x0E, 0x0B, 0xEF, 0xF0, 0x75, 0x15,
+/*19B0*/0x70, 0x12, 0x0F, 0xF7, 0x20, 0x34, 0x05, 0x75,
+ 0x15, 0x10, 0x80, 0x03, 0x75, 0x15, 0x50, 0x12,
+/*19C0*/0x0F, 0xF7, 0x20, 0x34, 0x04, 0x74, 0x10, 0x80,
+ 0x02, 0x74, 0xF0, 0x25, 0x15, 0xF5, 0x15, 0x12,
+/*19D0*/0x0E, 0x21, 0xEF, 0xF0, 0x12, 0x10, 0x91, 0x20,
+ 0x34, 0x17, 0xE5, 0x15, 0x64, 0x30, 0x60, 0x0C,
+/*19E0*/0x74, 0x10, 0x25, 0x15, 0xF5, 0x15, 0xB4, 0x80,
+ 0x03, 0xE4, 0xF5, 0x15, 0x12, 0x0E, 0x21, 0xEF,
+/*19F0*/0xF0, 0x22, 0xF0, 0xE5, 0x0B, 0x25, 0xE0, 0x25,
+ 0xE0, 0x24, 0x82, 0xF5, 0x82, 0xE4, 0x34, 0x07,
+/*1A00*/0xF5, 0x83, 0x22, 0x74, 0x88, 0xFE, 0xE5, 0x08,
+ 0x44, 0x07, 0xFF, 0xF5, 0x82, 0x8E, 0x83, 0xE0,
+/*1A10*/0x22, 0xF0, 0xE5, 0x08, 0x44, 0x07, 0xF5, 0x82,
+ 0x22, 0xF0, 0xE0, 0x54, 0xC0, 0x8F, 0x82, 0x8E,
+/*1A20*/0x83, 0xF0, 0x22, 0xEF, 0x44, 0x07, 0xF5, 0x82,
+ 0x75, 0x83, 0x86, 0xE0, 0x54, 0x10, 0xD3, 0x94,
+/*1A30*/0x00, 0x22, 0xF0, 0x90, 0x07, 0x15, 0xE0, 0x04,
+ 0xF0, 0x22, 0x44, 0x06, 0xF5, 0x82, 0x75, 0x83,
+/*1A40*/0x9E, 0xE0, 0x22, 0xFE, 0xEF, 0x44, 0x07, 0xF5,
+ 0x82, 0x8E, 0x83, 0xE0, 0x22, 0xE4, 0x90, 0x07,
+/*1A50*/0x2A, 0xF0, 0xA3, 0xF0, 0x12, 0x07, 0x2A, 0x75,
+ 0x83, 0x82, 0xE0, 0x54, 0x7F, 0x12, 0x07, 0x29,
+/*1A60*/0xE0, 0x44, 0x80, 0xF0, 0x12, 0x10, 0xFC, 0x12,
+ 0x08, 0x1F, 0x75, 0x83, 0xA0, 0xE0, 0x20, 0xE0,
+/*1A70*/0x1A, 0x90, 0x07, 0x2B, 0xE0, 0x04, 0xF0, 0x70,
+ 0x06, 0x90, 0x07, 0x2A, 0xE0, 0x04, 0xF0, 0x90,
+/*1A80*/0x07, 0x2A, 0xE0, 0xB4, 0x10, 0xE1, 0xA3, 0xE0,
+ 0xB4, 0x00, 0xDC, 0xEE, 0x44, 0xA6, 0xFC, 0xEF,
+/*1A90*/0x44, 0x07, 0xF5, 0x82, 0x8C, 0x83, 0xE0, 0xF5,
+ 0x32, 0xEE, 0x44, 0xA8, 0xFE, 0xEF, 0x44, 0x07,
+/*1AA0*/0xF5, 0x82, 0x8E, 0x83, 0xE0, 0xF5, 0x33, 0x22,
+ 0x01, 0x20, 0x11, 0x00, 0x04, 0x20, 0x00, 0x90,
+/*1AB0*/0x00, 0x20, 0x0F, 0x92, 0x00, 0x21, 0x0F, 0x94,
+ 0x00, 0x22, 0x0F, 0x96, 0x00, 0x23, 0x0F, 0x98,
+/*1AC0*/0x00, 0x24, 0x0F, 0x9A, 0x00, 0x25, 0x0F, 0x9C,
+ 0x00, 0x26, 0x0F, 0x9E, 0x00, 0x27, 0x0F, 0xA0,
+/*1AD0*/0x01, 0x20, 0x01, 0xA2, 0x01, 0x21, 0x01, 0xA4,
+ 0x01, 0x22, 0x01, 0xA6, 0x01, 0x23, 0x01, 0xA8,
+/*1AE0*/0x01, 0x24, 0x01, 0xAA, 0x01, 0x25, 0x01, 0xAC,
+ 0x01, 0x26, 0x01, 0xAE, 0x01, 0x27, 0x01, 0xB0,
+/*1AF0*/0x01, 0x28, 0x01, 0xB4, 0x00, 0x28, 0x0F, 0xB6,
+ 0x40, 0x28, 0x0F, 0xB8, 0x61, 0x28, 0x01, 0xCB,
+/*1B00*/0xEF, 0xCB, 0xCA, 0xEE, 0xCA, 0x7F, 0x01, 0xE4,
+ 0xFD, 0xEB, 0x4A, 0x70, 0x24, 0xE5, 0x08, 0xF5,
+/*1B10*/0x82, 0x74, 0xB6, 0x12, 0x08, 0x29, 0xE5, 0x08,
+ 0xF5, 0x82, 0x74, 0xB8, 0x12, 0x08, 0x29, 0xE5,
+/*1B20*/0x08, 0xF5, 0x82, 0x74, 0xBA, 0x12, 0x08, 0x29,
+ 0x7E, 0x00, 0x7C, 0x00, 0x12, 0x0A, 0xFF, 0x80,
+/*1B30*/0x12, 0x90, 0x07, 0x26, 0x12, 0x07, 0x35, 0xE5,
+ 0x41, 0xF0, 0x90, 0x07, 0x24, 0x12, 0x07, 0x35,
+/*1B40*/0xE5, 0x40, 0xF0, 0x12, 0x07, 0x2A, 0x75, 0x83,
+ 0x8E, 0xE4, 0x12, 0x07, 0x29, 0x74, 0x01, 0x12,
+/*1B50*/0x07, 0x29, 0xE4, 0xF0, 0x22, 0xE4, 0xF5, 0x26,
+ 0xF5, 0x27, 0x53, 0xE1, 0xFE, 0xF5, 0x2A, 0x75,
+/*1B60*/0x2B, 0x01, 0xF5, 0x08, 0x7F, 0x01, 0x12, 0x17,
+ 0x31, 0x30, 0x30, 0x1C, 0x90, 0x1A, 0xA9, 0xE4,
+/*1B70*/0x93, 0xF5, 0x10, 0x90, 0x1F, 0xF9, 0xE4, 0x93,
+ 0xF5, 0x10, 0x90, 0x00, 0x41, 0xE4, 0x93, 0xF5,
+/*1B80*/0x10, 0x90, 0x1E, 0xCA, 0xE4, 0x93, 0xF5, 0x10,
+ 0x7F, 0x02, 0x12, 0x17, 0x31, 0x12, 0x0F, 0x54,
+/*1B90*/0x7F, 0x03, 0x12, 0x17, 0x31, 0x12, 0x00, 0x06,
+ 0xE5, 0xE2, 0x30, 0xE7, 0x09, 0x12, 0x10, 0x00,
+/*1BA0*/0x30, 0x30, 0x03, 0x12, 0x11, 0x00, 0x02, 0x00,
+ 0x47, 0x12, 0x08, 0x1F, 0x75, 0x83, 0xD0, 0xE0,
+/*1BB0*/0xC4, 0x54, 0x0F, 0xFD, 0x75, 0x43, 0x01, 0x75,
+ 0x44, 0xFF, 0x12, 0x08, 0xAA, 0x74, 0x04, 0xF0,
+/*1BC0*/0x75, 0x3B, 0x01, 0xED, 0x14, 0x60, 0x0C, 0x14,
+ 0x60, 0x0B, 0x14, 0x60, 0x0F, 0x24, 0x03, 0x70,
+/*1BD0*/0x0B, 0x80, 0x09, 0x80, 0x00, 0x12, 0x08, 0xA7,
+ 0x04, 0xF0, 0x80, 0x06, 0x12, 0x08, 0xA7, 0x74,
+/*1BE0*/0x04, 0xF0, 0xEE, 0x44, 0x82, 0xFE, 0xEF, 0x44,
+ 0x07, 0xF5, 0x82, 0x8E, 0x83, 0xE5, 0x45, 0x12,
+/*1BF0*/0x08, 0xBE, 0x75, 0x83, 0x82, 0xE5, 0x31, 0xF0,
+ 0x02, 0x11, 0x4C, 0x8E, 0x60, 0x8F, 0x61, 0x12,
+/*1C00*/0x1E, 0xA5, 0xE4, 0xFF, 0xCE, 0xED, 0xCE, 0xEE,
+ 0xD3, 0x95, 0x61, 0xE5, 0x60, 0x12, 0x07, 0x6B,
+/*1C10*/0x40, 0x39, 0x74, 0x20, 0x2E, 0xF5, 0x82, 0xE4,
+ 0x34, 0x03, 0xF5, 0x83, 0xE0, 0x70, 0x03, 0xFF,
+/*1C20*/0x80, 0x26, 0x12, 0x08, 0xE2, 0xFD, 0xC3, 0x9F,
+ 0x40, 0x1E, 0xCF, 0xED, 0xCF, 0xEB, 0x4A, 0x70,
+/*1C30*/0x0B, 0x8D, 0x42, 0x12, 0x08, 0xEE, 0xF5, 0x41,
+ 0x8E, 0x40, 0x80, 0x0C, 0x12, 0x08, 0xE2, 0xF5,
+/*1C40*/0x38, 0x12, 0x08, 0xEE, 0xF5, 0x39, 0x8E, 0x3A,
+ 0x1E, 0x80, 0xBC, 0x22, 0x75, 0x58, 0x01, 0xE5,
+/*1C50*/0x35, 0x70, 0x0C, 0x12, 0x07, 0xCC, 0xE0, 0xF5,
+ 0x4A, 0x12, 0x07, 0xD8, 0xE0, 0xF5, 0x4C, 0xE5,
+/*1C60*/0x35, 0xB4, 0x04, 0x0C, 0x12, 0x07, 0xE4, 0xE0,
+ 0xF5, 0x4A, 0x12, 0x07, 0xF0, 0xE0, 0xF5, 0x4C,
+/*1C70*/0xE5, 0x35, 0xB4, 0x01, 0x04, 0x7F, 0x01, 0x80,
+ 0x02, 0x7F, 0x00, 0xE5, 0x35, 0xB4, 0x02, 0x04,
+/*1C80*/0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE, 0x4F,
+ 0x60, 0x0C, 0x12, 0x07, 0xFC, 0xE0, 0xF5, 0x4A,
+/*1C90*/0x12, 0x08, 0x08, 0xE0, 0xF5, 0x4C, 0x85, 0x41,
+ 0x49, 0x85, 0x40, 0x4B, 0x22, 0x75, 0x5B, 0x01,
+/*1CA0*/0x90, 0x07, 0x24, 0x12, 0x07, 0x35, 0xE0, 0x54,
+ 0x1F, 0xFF, 0xD3, 0x94, 0x02, 0x50, 0x04, 0x8F,
+/*1CB0*/0x58, 0x80, 0x05, 0xEF, 0x24, 0xFE, 0xF5, 0x58,
+ 0xEF, 0xC3, 0x94, 0x18, 0x40, 0x05, 0x75, 0x59,
+/*1CC0*/0x18, 0x80, 0x04, 0xEF, 0x04, 0xF5, 0x59, 0x85,
+ 0x43, 0x5A, 0xAF, 0x58, 0x7E, 0x00, 0xAD, 0x59,
+/*1CD0*/0x7C, 0x00, 0xAB, 0x5B, 0x7A, 0x00, 0x12, 0x15,
+ 0x41, 0xAF, 0x5A, 0x7E, 0x00, 0x12, 0x18, 0x0A,
+/*1CE0*/0xAF, 0x5B, 0x7E, 0x00, 0x02, 0x1A, 0xFF, 0xE5,
+ 0xE2, 0x30, 0xE7, 0x0E, 0x12, 0x10, 0x03, 0xC2,
+/*1CF0*/0x30, 0x30, 0x30, 0x03, 0x12, 0x10, 0xFF, 0x20,
+ 0x33, 0x28, 0xE5, 0xE7, 0x30, 0xE7, 0x05, 0x12,
+/*1D00*/0x0E, 0xA2, 0x80, 0x0D, 0xE5, 0xFE, 0xC3, 0x94,
+ 0x20, 0x50, 0x06, 0x12, 0x0E, 0xA2, 0x43, 0xF9,
+/*1D10*/0x08, 0xE5, 0xF2, 0x30, 0xE7, 0x03, 0x53, 0xF9,
+ 0x7F, 0xE5, 0xF1, 0x54, 0x70, 0xD3, 0x94, 0x00,
+/*1D20*/0x50, 0xD8, 0x22, 0x12, 0x0E, 0x04, 0x75, 0x83,
+ 0x80, 0xE4, 0xF0, 0xE5, 0x08, 0x44, 0x07, 0x12,
+/*1D30*/0x0D, 0xFD, 0x75, 0x83, 0x84, 0x12, 0x0E, 0x02,
+ 0x75, 0x83, 0x86, 0x12, 0x0E, 0x02, 0x75, 0x83,
+/*1D40*/0x8C, 0xE0, 0x54, 0xF3, 0x12, 0x0E, 0x03, 0x75,
+ 0x83, 0x8E, 0x12, 0x0E, 0x02, 0x75, 0x83, 0x94,
+/*1D50*/0xE0, 0x54, 0xFB, 0xF0, 0x22, 0x12, 0x07, 0x2A,
+ 0x75, 0x83, 0x8E, 0xE4, 0x12, 0x07, 0x29, 0x74,
+/*1D60*/0x01, 0x12, 0x07, 0x29, 0xE4, 0x12, 0x08, 0xBE,
+ 0x75, 0x83, 0x8C, 0xE0, 0x44, 0x20, 0x12, 0x08,
+/*1D70*/0xBE, 0xE0, 0x54, 0xDF, 0xF0, 0x74, 0x84, 0x85,
+ 0x08, 0x82, 0xF5, 0x83, 0xE0, 0x54, 0x7F, 0xF0,
+/*1D80*/0xE0, 0x44, 0x80, 0xF0, 0x22, 0x75, 0x56, 0x01,
+ 0xE4, 0xFD, 0xF5, 0x57, 0xAF, 0x35, 0xFE, 0xFC,
+/*1D90*/0x12, 0x09, 0x15, 0x12, 0x1C, 0x9D, 0x12, 0x1E,
+ 0x7A, 0x12, 0x1C, 0x4C, 0xAF, 0x57, 0x7E, 0x00,
+/*1DA0*/0xAD, 0x56, 0x7C, 0x00, 0x12, 0x04, 0x44, 0xAF,
+ 0x56, 0x7E, 0x00, 0x02, 0x11, 0xEE, 0x75, 0x56,
+/*1DB0*/0x01, 0xE4, 0xFD, 0xF5, 0x57, 0xAF, 0x35, 0xFE,
+ 0xFC, 0x12, 0x09, 0x15, 0x12, 0x1C, 0x9D, 0x12,
+/*1DC0*/0x1E, 0x7A, 0x12, 0x1C, 0x4C, 0xAF, 0x57, 0x7E,
+ 0x00, 0xAD, 0x56, 0x7C, 0x00, 0x12, 0x04, 0x44,
+/*1DD0*/0xAF, 0x56, 0x7E, 0x00, 0x02, 0x11, 0xEE, 0xE4,
+ 0xF5, 0x16, 0x12, 0x0E, 0x44, 0xFE, 0xE5, 0x08,
+/*1DE0*/0x44, 0x05, 0xFF, 0x12, 0x0E, 0x65, 0x8F, 0x82,
+ 0x8E, 0x83, 0xF0, 0x05, 0x16, 0xE5, 0x16, 0xC3,
+/*1DF0*/0x94, 0x14, 0x40, 0xE6, 0xE5, 0x08, 0x12, 0x0E,
+ 0x2B, 0xE4, 0xF0, 0x22, 0xE4, 0xF5, 0x58, 0xF5,
+/*1E00*/0x59, 0xF5, 0x5A, 0xFF, 0xFE, 0xAD, 0x58, 0xFC,
+ 0x12, 0x09, 0x15, 0x7F, 0x04, 0x7E, 0x00, 0xAD,
+/*1E10*/0x58, 0x7C, 0x00, 0x12, 0x09, 0x15, 0x7F, 0x02,
+ 0x7E, 0x00, 0xAD, 0x58, 0x7C, 0x00, 0x02, 0x09,
+/*1E20*/0x15, 0xE5, 0x3C, 0x25, 0x3E, 0xFC, 0xE5, 0x42,
+ 0x24, 0x00, 0xFB, 0xE4, 0x33, 0xFA, 0xEC, 0xC3,
+/*1E30*/0x9B, 0xEA, 0x12, 0x07, 0x6B, 0x40, 0x0B, 0x8C,
+ 0x42, 0xE5, 0x3D, 0x25, 0x3F, 0xF5, 0x41, 0x8F,
+/*1E40*/0x40, 0x22, 0x12, 0x09, 0x0B, 0x22, 0x74, 0x84,
+ 0xF5, 0x18, 0x85, 0x08, 0x19, 0x85, 0x19, 0x82,
+/*1E50*/0x85, 0x18, 0x83, 0xE0, 0x54, 0x7F, 0xF0, 0xE0,
+ 0x44, 0x80, 0xF0, 0xE0, 0x44, 0x80, 0xF0, 0x22,
+/*1E60*/0xEF, 0x4E, 0x70, 0x0B, 0x12, 0x07, 0x2A, 0x75,
+ 0x83, 0xD2, 0xE0, 0x54, 0xDF, 0xF0, 0x22, 0x12,
+/*1E70*/0x07, 0x2A, 0x75, 0x83, 0xD2, 0xE0, 0x44, 0x20,
+ 0xF0, 0x22, 0x75, 0x58, 0x01, 0x90, 0x07, 0x26,
+/*1E80*/0x12, 0x07, 0x35, 0xE0, 0x54, 0x3F, 0xF5, 0x41,
+ 0x12, 0x07, 0x32, 0xE0, 0x54, 0x3F, 0xF5, 0x40,
+/*1E90*/0x22, 0x75, 0x56, 0x02, 0xE4, 0xF5, 0x57, 0x12,
+ 0x1D, 0xFC, 0xAF, 0x57, 0x7E, 0x00, 0xAD, 0x56,
+/*1EA0*/0x7C, 0x00, 0x02, 0x04, 0x44, 0xE4, 0xF5, 0x42,
+ 0xF5, 0x41, 0xF5, 0x40, 0xF5, 0x38, 0xF5, 0x39,
+/*1EB0*/0xF5, 0x3A, 0x22, 0xEF, 0x54, 0x07, 0xFF, 0xE5,
+ 0xF9, 0x54, 0xF8, 0x4F, 0xF5, 0xF9, 0x22, 0x7F,
+/*1EC0*/0x01, 0xE4, 0xFE, 0x0F, 0x0E, 0xBE, 0xFF, 0xFB,
+ 0x22, 0x01, 0x20, 0x00, 0x01, 0x04, 0x20, 0x00,
+/*1ED0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1EE0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1EF0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1F00*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1F10*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1F20*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1F30*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1F40*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1F50*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1F60*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1F70*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1F80*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1F90*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1FA0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1FB0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1FC0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1FD0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1FE0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1FF0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x20, 0x11, 0x00, 0x04, 0x20, 0x00, 0x81
+};
diff --git a/gpxe/src/drivers/infiniband/qib_7220_regs.h b/gpxe/src/drivers/infiniband/qib_7220_regs.h
new file mode 100644
index 00000000..0dd3c53d
--- /dev/null
+++ b/gpxe/src/drivers/infiniband/qib_7220_regs.h
@@ -0,0 +1,1763 @@
+/*
+ * Copyright (c) 2008 QLogic Corporation. All rights reserved.
+ *
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * This file is mechanically generated. Any hand-edits will be lost.
+ * If not now, soon.
+ */
+
+/* This file has been further processed by ./drivers/infiniband/qib_genbits.pl */
+
+
+#define QIB_7220_Revision_offset 0x00000000UL
+struct QIB_7220_Revision_pb {
+ pseudo_bit_t R_ChipRevMinor[8];
+ pseudo_bit_t R_ChipRevMajor[8];
+ pseudo_bit_t R_Arch[8];
+ pseudo_bit_t R_SW[8];
+ pseudo_bit_t BoardID[8];
+ pseudo_bit_t R_Palldium_Revcode[22];
+ pseudo_bit_t R_Palladium[1];
+ pseudo_bit_t R_Simulator[1];
+};
+struct QIB_7220_Revision {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_Revision_pb );
+};
+
+#define QIB_7220_Control_offset 0x00000008UL
+struct QIB_7220_Control_pb {
+ pseudo_bit_t SyncReset[1];
+ pseudo_bit_t FreezeMode[1];
+ pseudo_bit_t LinkEn[1];
+ pseudo_bit_t PCIERetryBufDiagEn[1];
+ pseudo_bit_t TxLatency[1];
+ pseudo_bit_t Reserved[1];
+ pseudo_bit_t PCIECplQDiagEn[1];
+ pseudo_bit_t SyncResetExceptPcieIRAMRST[1];
+ pseudo_bit_t _unused_0[56];
+};
+struct QIB_7220_Control {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_Control_pb );
+};
+
+#define QIB_7220_PageAlign_offset 0x00000010UL
+
+#define QIB_7220_PortCnt_offset 0x00000018UL
+
+#define QIB_7220_DbgPortSel_offset 0x00000020UL
+struct QIB_7220_DbgPortSel_pb {
+ pseudo_bit_t NibbleSel0[4];
+ pseudo_bit_t NibbleSel1[4];
+ pseudo_bit_t NibbleSel2[4];
+ pseudo_bit_t NibbleSel3[4];
+ pseudo_bit_t NibbleSel4[4];
+ pseudo_bit_t NibbleSel5[4];
+ pseudo_bit_t NibbleSel6[4];
+ pseudo_bit_t NibbleSel7[4];
+ pseudo_bit_t SrcMuxSel[14];
+ pseudo_bit_t DbgClkPortSel[5];
+ pseudo_bit_t EnDbgPort[1];
+ pseudo_bit_t EnEnhancedDebugMode[1];
+ pseudo_bit_t EnhMode_SrcMuxSelIndex[10];
+ pseudo_bit_t EnhMode_SrcMuxSelWrEn[1];
+};
+struct QIB_7220_DbgPortSel {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_DbgPortSel_pb );
+};
+
+#define QIB_7220_DebugSigsIntSel_offset 0x00000028UL
+struct QIB_7220_DebugSigsIntSel_pb {
+ pseudo_bit_t debug_port_sel_pcs_pipe_lane07[3];
+ pseudo_bit_t debug_port_sel_pcs_pipe_lane815[3];
+ pseudo_bit_t debug_port_sel_pcs_sdout[1];
+ pseudo_bit_t debug_port_sel_pcs_symlock_elfifo_lane[4];
+ pseudo_bit_t debug_port_sel_pcs_rxdet_encdec_lane[4];
+ pseudo_bit_t debug_port_sel_pcie_rx_tx[1];
+ pseudo_bit_t debug_port_sel_xgxs[4];
+ pseudo_bit_t debug_port_sel_epb_pcie[1];
+ pseudo_bit_t _unused_0[43];
+};
+struct QIB_7220_DebugSigsIntSel {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_DebugSigsIntSel_pb );
+};
+
+#define QIB_7220_SendRegBase_offset 0x00000030UL
+
+#define QIB_7220_UserRegBase_offset 0x00000038UL
+
+#define QIB_7220_CntrRegBase_offset 0x00000040UL
+
+#define QIB_7220_Scratch_offset 0x00000048UL
+
+#define QIB_7220_REG_000050_offset 0x00000050UL
+
+#define QIB_7220_IntBlocked_offset 0x00000060UL
+struct QIB_7220_IntBlocked_pb {
+ pseudo_bit_t RcvAvail0IntBlocked[1];
+ pseudo_bit_t RcvAvail1IntBlocked[1];
+ pseudo_bit_t RcvAvail2IntBlocked[1];
+ pseudo_bit_t RcvAvail3IntBlocked[1];
+ pseudo_bit_t RcvAvail4IntBlocked[1];
+ pseudo_bit_t RcvAvail5IntBlocked[1];
+ pseudo_bit_t RcvAvail6IntBlocked[1];
+ pseudo_bit_t RcvAvail7IntBlocked[1];
+ pseudo_bit_t RcvAvail8IntBlocked[1];
+ pseudo_bit_t RcvAvail9IntBlocked[1];
+ pseudo_bit_t RcvAvail10IntBlocked[1];
+ pseudo_bit_t RcvAvail11IntBlocked[1];
+ pseudo_bit_t RcvAvail12IntBlocked[1];
+ pseudo_bit_t RcvAvail13IntBlocked[1];
+ pseudo_bit_t RcvAvail14IntBlocked[1];
+ pseudo_bit_t RcvAvail15IntBlocked[1];
+ pseudo_bit_t RcvAvail16IntBlocked[1];
+ pseudo_bit_t Reserved1[9];
+ pseudo_bit_t JIntBlocked[1];
+ pseudo_bit_t IBSerdesTrimDoneIntBlocked[1];
+ pseudo_bit_t assertGPIOIntBlocked[1];
+ pseudo_bit_t PioBufAvailIntBlocked[1];
+ pseudo_bit_t PioSetIntBlocked[1];
+ pseudo_bit_t ErrorIntBlocked[1];
+ pseudo_bit_t RcvUrg0IntBlocked[1];
+ pseudo_bit_t RcvUrg1IntBlocked[1];
+ pseudo_bit_t RcvUrg2IntBlocked[1];
+ pseudo_bit_t RcvUrg3IntBlocked[1];
+ pseudo_bit_t RcvUrg4IntBlocked[1];
+ pseudo_bit_t RcvUrg5IntBlocked[1];
+ pseudo_bit_t RcvUrg6IntBlocked[1];
+ pseudo_bit_t RcvUrg7IntBlocked[1];
+ pseudo_bit_t RcvUrg8IntBlocked[1];
+ pseudo_bit_t RcvUrg9IntBlocked[1];
+ pseudo_bit_t RcvUrg10IntBlocked[1];
+ pseudo_bit_t RcvUrg11IntBlocked[1];
+ pseudo_bit_t RcvUrg12IntBlocked[1];
+ pseudo_bit_t RcvUrg13IntBlocked[1];
+ pseudo_bit_t RcvUrg14IntBlocked[1];
+ pseudo_bit_t RcvUrg15IntBlocked[1];
+ pseudo_bit_t RcvUrg16IntBlocked[1];
+ pseudo_bit_t Reserved[13];
+ pseudo_bit_t SDmaDisabledBlocked[1];
+ pseudo_bit_t SDmaIntBlocked[1];
+};
+struct QIB_7220_IntBlocked {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_IntBlocked_pb );
+};
+
+#define QIB_7220_IntMask_offset 0x00000068UL
+struct QIB_7220_IntMask_pb {
+ pseudo_bit_t RcvAvail0IntMask[1];
+ pseudo_bit_t RcvAvail1IntMask[1];
+ pseudo_bit_t RcvAvail2IntMask[1];
+ pseudo_bit_t RcvAvail3IntMask[1];
+ pseudo_bit_t RcvAvail4IntMask[1];
+ pseudo_bit_t RcvAvail5IntMask[1];
+ pseudo_bit_t RcvAvail6IntMask[1];
+ pseudo_bit_t RcvAvail7IntMask[1];
+ pseudo_bit_t RcvAvail8IntMask[1];
+ pseudo_bit_t RcvAvail9IntMask[1];
+ pseudo_bit_t RcvAvail10IntMask[1];
+ pseudo_bit_t RcvAvail11IntMask[1];
+ pseudo_bit_t RcvAvail12IntMask[1];
+ pseudo_bit_t RcvAvail13IntMask[1];
+ pseudo_bit_t RcvAvail14IntMask[1];
+ pseudo_bit_t RcvAvail15IntMask[1];
+ pseudo_bit_t RcvAvail16IntMask[1];
+ pseudo_bit_t Reserved1[9];
+ pseudo_bit_t JIntMask[1];
+ pseudo_bit_t IBSerdesTrimDoneIntMask[1];
+ pseudo_bit_t assertGPIOIntMask[1];
+ pseudo_bit_t PioBufAvailIntMask[1];
+ pseudo_bit_t PioSetIntMask[1];
+ pseudo_bit_t ErrorIntMask[1];
+ pseudo_bit_t RcvUrg0IntMask[1];
+ pseudo_bit_t RcvUrg1IntMask[1];
+ pseudo_bit_t RcvUrg2IntMask[1];
+ pseudo_bit_t RcvUrg3IntMask[1];
+ pseudo_bit_t RcvUrg4IntMask[1];
+ pseudo_bit_t RcvUrg5IntMask[1];
+ pseudo_bit_t RcvUrg6IntMask[1];
+ pseudo_bit_t RcvUrg7IntMask[1];
+ pseudo_bit_t RcvUrg8IntMask[1];
+ pseudo_bit_t RcvUrg9IntMask[1];
+ pseudo_bit_t RcvUrg10IntMask[1];
+ pseudo_bit_t RcvUrg11IntMask[1];
+ pseudo_bit_t RcvUrg12IntMask[1];
+ pseudo_bit_t RcvUrg13IntMask[1];
+ pseudo_bit_t RcvUrg14IntMask[1];
+ pseudo_bit_t RcvUrg15IntMask[1];
+ pseudo_bit_t RcvUrg16IntMask[1];
+ pseudo_bit_t Reserved[13];
+ pseudo_bit_t SDmaDisabledMasked[1];
+ pseudo_bit_t SDmaIntMask[1];
+};
+struct QIB_7220_IntMask {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_IntMask_pb );
+};
+
+#define QIB_7220_IntStatus_offset 0x00000070UL
+struct QIB_7220_IntStatus_pb {
+ pseudo_bit_t RcvAvail0[1];
+ pseudo_bit_t RcvAvail1[1];
+ pseudo_bit_t RcvAvail2[1];
+ pseudo_bit_t RcvAvail3[1];
+ pseudo_bit_t RcvAvail4[1];
+ pseudo_bit_t RcvAvail5[1];
+ pseudo_bit_t RcvAvail6[1];
+ pseudo_bit_t RcvAvail7[1];
+ pseudo_bit_t RcvAvail8[1];
+ pseudo_bit_t RcvAvail9[1];
+ pseudo_bit_t RcvAvail10[1];
+ pseudo_bit_t RcvAvail11[1];
+ pseudo_bit_t RcvAvail12[1];
+ pseudo_bit_t RcvAvail13[1];
+ pseudo_bit_t RcvAvail14[1];
+ pseudo_bit_t RcvAvail15[1];
+ pseudo_bit_t RcvAvail16[1];
+ pseudo_bit_t Reserved1[9];
+ pseudo_bit_t JInt[1];
+ pseudo_bit_t IBSerdesTrimDone[1];
+ pseudo_bit_t assertGPIO[1];
+ pseudo_bit_t PioBufAvail[1];
+ pseudo_bit_t PioSent[1];
+ pseudo_bit_t Error[1];
+ pseudo_bit_t RcvUrg0[1];
+ pseudo_bit_t RcvUrg1[1];
+ pseudo_bit_t RcvUrg2[1];
+ pseudo_bit_t RcvUrg3[1];
+ pseudo_bit_t RcvUrg4[1];
+ pseudo_bit_t RcvUrg5[1];
+ pseudo_bit_t RcvUrg6[1];
+ pseudo_bit_t RcvUrg7[1];
+ pseudo_bit_t RcvUrg8[1];
+ pseudo_bit_t RcvUrg9[1];
+ pseudo_bit_t RcvUrg10[1];
+ pseudo_bit_t RcvUrg11[1];
+ pseudo_bit_t RcvUrg12[1];
+ pseudo_bit_t RcvUrg13[1];
+ pseudo_bit_t RcvUrg14[1];
+ pseudo_bit_t RcvUrg15[1];
+ pseudo_bit_t RcvUrg16[1];
+ pseudo_bit_t Reserved[13];
+ pseudo_bit_t SDmaDisabled[1];
+ pseudo_bit_t SDmaInt[1];
+};
+struct QIB_7220_IntStatus {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_IntStatus_pb );
+};
+
+#define QIB_7220_IntClear_offset 0x00000078UL
+struct QIB_7220_IntClear_pb {
+ pseudo_bit_t RcvAvail0IntClear[1];
+ pseudo_bit_t RcvAvail1IntClear[1];
+ pseudo_bit_t RcvAvail2IntClear[1];
+ pseudo_bit_t RcvAvail3IntClear[1];
+ pseudo_bit_t RcvAvail4IntClear[1];
+ pseudo_bit_t RcvAvail5IntClear[1];
+ pseudo_bit_t RcvAvail6IntClear[1];
+ pseudo_bit_t RcvAvail7IntClear[1];
+ pseudo_bit_t RcvAvail8IntClear[1];
+ pseudo_bit_t RcvAvail9IntClear[1];
+ pseudo_bit_t RcvAvail10IntClear[1];
+ pseudo_bit_t RcvAvail11IntClear[1];
+ pseudo_bit_t RcvAvail12IntClear[1];
+ pseudo_bit_t RcvAvail13IntClear[1];
+ pseudo_bit_t RcvAvail14IntClear[1];
+ pseudo_bit_t RcvAvail15IntClear[1];
+ pseudo_bit_t RcvAvail16IntClear[1];
+ pseudo_bit_t Reserved1[9];
+ pseudo_bit_t JIntClear[1];
+ pseudo_bit_t IBSerdesTrimDoneClear[1];
+ pseudo_bit_t assertGPIOIntClear[1];
+ pseudo_bit_t PioBufAvailIntClear[1];
+ pseudo_bit_t PioSetIntClear[1];
+ pseudo_bit_t ErrorIntClear[1];
+ pseudo_bit_t RcvUrg0IntClear[1];
+ pseudo_bit_t RcvUrg1IntClear[1];
+ pseudo_bit_t RcvUrg2IntClear[1];
+ pseudo_bit_t RcvUrg3IntClear[1];
+ pseudo_bit_t RcvUrg4IntClear[1];
+ pseudo_bit_t RcvUrg5IntClear[1];
+ pseudo_bit_t RcvUrg6IntClear[1];
+ pseudo_bit_t RcvUrg7IntClear[1];
+ pseudo_bit_t RcvUrg8IntClear[1];
+ pseudo_bit_t RcvUrg9IntClear[1];
+ pseudo_bit_t RcvUrg10IntClear[1];
+ pseudo_bit_t RcvUrg11IntClear[1];
+ pseudo_bit_t RcvUrg12IntClear[1];
+ pseudo_bit_t RcvUrg13IntClear[1];
+ pseudo_bit_t RcvUrg14IntClear[1];
+ pseudo_bit_t RcvUrg15IntClear[1];
+ pseudo_bit_t RcvUrg16IntClear[1];
+ pseudo_bit_t Reserved[13];
+ pseudo_bit_t SDmaDisabledClear[1];
+ pseudo_bit_t SDmaIntClear[1];
+};
+struct QIB_7220_IntClear {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_IntClear_pb );
+};
+
+#define QIB_7220_ErrMask_offset 0x00000080UL
+struct QIB_7220_ErrMask_pb {
+ pseudo_bit_t RcvFormatErrMask[1];
+ pseudo_bit_t RcvVCRCErrMask[1];
+ pseudo_bit_t RcvICRCErrMask[1];
+ pseudo_bit_t RcvMinPktLenErrMask[1];
+ pseudo_bit_t RcvMaxPktLenErrMask[1];
+ pseudo_bit_t RcvLongPktLenErrMask[1];
+ pseudo_bit_t RcvShortPktLenErrMask[1];
+ pseudo_bit_t RcvUnexpectedCharErrMask[1];
+ pseudo_bit_t RcvUnsupportedVLErrMask[1];
+ pseudo_bit_t RcvEBPErrMask[1];
+ pseudo_bit_t RcvIBFlowErrMask[1];
+ pseudo_bit_t RcvBadVersionErrMask[1];
+ pseudo_bit_t RcvEgrFullErrMask[1];
+ pseudo_bit_t RcvHdrFullErrMask[1];
+ pseudo_bit_t RcvBadTidErrMask[1];
+ pseudo_bit_t RcvHdrLenErrMask[1];
+ pseudo_bit_t RcvHdrErrMask[1];
+ pseudo_bit_t RcvIBLostLinkErrMask[1];
+ pseudo_bit_t Reserved1[9];
+ pseudo_bit_t SendSpecialTriggerErrMask[1];
+ pseudo_bit_t SDmaDisabledErrMask[1];
+ pseudo_bit_t SendMinPktLenErrMask[1];
+ pseudo_bit_t SendMaxPktLenErrMask[1];
+ pseudo_bit_t SendUnderRunErrMask[1];
+ pseudo_bit_t SendPktLenErrMask[1];
+ pseudo_bit_t SendDroppedSmpPktErrMask[1];
+ pseudo_bit_t SendDroppedDataPktErrMask[1];
+ pseudo_bit_t SendPioArmLaunchErrMask[1];
+ pseudo_bit_t SendUnexpectedPktNumErrMask[1];
+ pseudo_bit_t SendUnsupportedVLErrMask[1];
+ pseudo_bit_t SendBufMisuseErrMask[1];
+ pseudo_bit_t SDmaGenMismatchErrMask[1];
+ pseudo_bit_t SDmaOutOfBoundErrMask[1];
+ pseudo_bit_t SDmaTailOutOfBoundErrMask[1];
+ pseudo_bit_t SDmaBaseErrMask[1];
+ pseudo_bit_t SDma1stDescErrMask[1];
+ pseudo_bit_t SDmaRpyTagErrMask[1];
+ pseudo_bit_t SDmaDwEnErrMask[1];
+ pseudo_bit_t SDmaMissingDwErrMask[1];
+ pseudo_bit_t SDmaUnexpDataErrMask[1];
+ pseudo_bit_t IBStatusChangedMask[1];
+ pseudo_bit_t InvalidAddrErrMask[1];
+ pseudo_bit_t ResetNegatedMask[1];
+ pseudo_bit_t HardwareErrMask[1];
+ pseudo_bit_t SDmaDescAddrMisalignErrMask[1];
+ pseudo_bit_t InvalidEEPCmdMask[1];
+ pseudo_bit_t Reserved[10];
+};
+struct QIB_7220_ErrMask {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_ErrMask_pb );
+};
+
+#define QIB_7220_ErrStatus_offset 0x00000088UL
+struct QIB_7220_ErrStatus_pb {
+ pseudo_bit_t RcvFormatErr[1];
+ pseudo_bit_t RcvVCRCErr[1];
+ pseudo_bit_t RcvICRCErr[1];
+ pseudo_bit_t RcvMinPktLenErr[1];
+ pseudo_bit_t RcvMaxPktLenErr[1];
+ pseudo_bit_t RcvLongPktLenErr[1];
+ pseudo_bit_t RcvShortPktLenErr[1];
+ pseudo_bit_t RcvUnexpectedCharErr[1];
+ pseudo_bit_t RcvUnsupportedVLErr[1];
+ pseudo_bit_t RcvEBPErr[1];
+ pseudo_bit_t RcvIBFlowErr[1];
+ pseudo_bit_t RcvBadVersionErr[1];
+ pseudo_bit_t RcvEgrFullErr[1];
+ pseudo_bit_t RcvHdrFullErr[1];
+ pseudo_bit_t RcvBadTidErr[1];
+ pseudo_bit_t RcvHdrLenErr[1];
+ pseudo_bit_t RcvHdrErr[1];
+ pseudo_bit_t RcvIBLostLinkErr[1];
+ pseudo_bit_t Reserved1[9];
+ pseudo_bit_t SendSpecialTriggerErr[1];
+ pseudo_bit_t SDmaDisabledErr[1];
+ pseudo_bit_t SendMinPktLenErr[1];
+ pseudo_bit_t SendMaxPktLenErr[1];
+ pseudo_bit_t SendUnderRunErr[1];
+ pseudo_bit_t SendPktLenErr[1];
+ pseudo_bit_t SendDroppedSmpPktErr[1];
+ pseudo_bit_t SendDroppedDataPktErr[1];
+ pseudo_bit_t SendPioArmLaunchErr[1];
+ pseudo_bit_t SendUnexpectedPktNumErr[1];
+ pseudo_bit_t SendUnsupportedVLErr[1];
+ pseudo_bit_t SendBufMisuseErr[1];
+ pseudo_bit_t SDmaGenMismatchErr[1];
+ pseudo_bit_t SDmaOutOfBoundErr[1];
+ pseudo_bit_t SDmaTailOutOfBoundErr[1];
+ pseudo_bit_t SDmaBaseErr[1];
+ pseudo_bit_t SDma1stDescErr[1];
+ pseudo_bit_t SDmaRpyTagErr[1];
+ pseudo_bit_t SDmaDwEnErr[1];
+ pseudo_bit_t SDmaMissingDwErr[1];
+ pseudo_bit_t SDmaUnexpDataErr[1];
+ pseudo_bit_t IBStatusChanged[1];
+ pseudo_bit_t InvalidAddrErr[1];
+ pseudo_bit_t ResetNegated[1];
+ pseudo_bit_t HardwareErr[1];
+ pseudo_bit_t SDmaDescAddrMisalignErr[1];
+ pseudo_bit_t InvalidEEPCmdErr[1];
+ pseudo_bit_t Reserved[10];
+};
+struct QIB_7220_ErrStatus {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_ErrStatus_pb );
+};
+
+#define QIB_7220_ErrClear_offset 0x00000090UL
+struct QIB_7220_ErrClear_pb {
+ pseudo_bit_t RcvFormatErrClear[1];
+ pseudo_bit_t RcvVCRCErrClear[1];
+ pseudo_bit_t RcvICRCErrClear[1];
+ pseudo_bit_t RcvMinPktLenErrClear[1];
+ pseudo_bit_t RcvMaxPktLenErrClear[1];
+ pseudo_bit_t RcvLongPktLenErrClear[1];
+ pseudo_bit_t RcvShortPktLenErrClear[1];
+ pseudo_bit_t RcvUnexpectedCharErrClear[1];
+ pseudo_bit_t RcvUnsupportedVLErrClear[1];
+ pseudo_bit_t RcvEBPErrClear[1];
+ pseudo_bit_t RcvIBFlowErrClear[1];
+ pseudo_bit_t RcvBadVersionErrClear[1];
+ pseudo_bit_t RcvEgrFullErrClear[1];
+ pseudo_bit_t RcvHdrFullErrClear[1];
+ pseudo_bit_t RcvBadTidErrClear[1];
+ pseudo_bit_t RcvHdrLenErrClear[1];
+ pseudo_bit_t RcvHdrErrClear[1];
+ pseudo_bit_t RcvIBLostLinkErrClear[1];
+ pseudo_bit_t Reserved1[9];
+ pseudo_bit_t SendSpecialTriggerErrClear[1];
+ pseudo_bit_t SDmaDisabledErrClear[1];
+ pseudo_bit_t SendMinPktLenErrClear[1];
+ pseudo_bit_t SendMaxPktLenErrClear[1];
+ pseudo_bit_t SendUnderRunErrClear[1];
+ pseudo_bit_t SendPktLenErrClear[1];
+ pseudo_bit_t SendDroppedSmpPktErrClear[1];
+ pseudo_bit_t SendDroppedDataPktErrClear[1];
+ pseudo_bit_t SendPioArmLaunchErrClear[1];
+ pseudo_bit_t SendUnexpectedPktNumErrClear[1];
+ pseudo_bit_t SendUnsupportedVLErrClear[1];
+ pseudo_bit_t SendBufMisuseErrClear[1];
+ pseudo_bit_t SDmaGenMismatchErrClear[1];
+ pseudo_bit_t SDmaOutOfBoundErrClear[1];
+ pseudo_bit_t SDmaTailOutOfBoundErrClear[1];
+ pseudo_bit_t SDmaBaseErrClear[1];
+ pseudo_bit_t SDma1stDescErrClear[1];
+ pseudo_bit_t SDmaRpyTagErrClear[1];
+ pseudo_bit_t SDmaDwEnErrClear[1];
+ pseudo_bit_t SDmaMissingDwErrClear[1];
+ pseudo_bit_t SDmaUnexpDataErrClear[1];
+ pseudo_bit_t IBStatusChangedClear[1];
+ pseudo_bit_t InvalidAddrErrClear[1];
+ pseudo_bit_t ResetNegatedClear[1];
+ pseudo_bit_t HardwareErrClear[1];
+ pseudo_bit_t SDmaDescAddrMisalignErrClear[1];
+ pseudo_bit_t InvalidEEPCmdErrClear[1];
+ pseudo_bit_t Reserved[10];
+};
+struct QIB_7220_ErrClear {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_ErrClear_pb );
+};
+
+#define QIB_7220_HwErrMask_offset 0x00000098UL
+struct QIB_7220_HwErrMask_pb {
+ pseudo_bit_t PCIeMemParityErrMask[8];
+ pseudo_bit_t Reserved3[20];
+ pseudo_bit_t SDmaMemReadErrMask[1];
+ pseudo_bit_t PoisonedTLPMask[1];
+ pseudo_bit_t PcieCplTimeoutMask[1];
+ pseudo_bit_t PCIeBusParityErrMask[3];
+ pseudo_bit_t Reserved2[2];
+ pseudo_bit_t PCIEOct0_uC_MemoryParityErrMask[1];
+ pseudo_bit_t PCIEOct1_uC_MemoryParityErrMask[1];
+ pseudo_bit_t IB_uC_MemoryParityErrMask[1];
+ pseudo_bit_t DDSRXEQMemoryParityErrMask[1];
+ pseudo_bit_t TXEMemParityErrMask[4];
+ pseudo_bit_t RXEMemParityErrMask[7];
+ pseudo_bit_t Reserved1[3];
+ pseudo_bit_t PowerOnBISTFailedMask[1];
+ pseudo_bit_t Reserved[1];
+ pseudo_bit_t PCIESerdesQ0PClkNotDetectMask[1];
+ pseudo_bit_t PCIESerdesQ1PClkNotDetectMask[1];
+ pseudo_bit_t PCIESerdesQ2PClkNotDetectMask[1];
+ pseudo_bit_t PCIESerdesQ3PClkNotDetectMask[1];
+ pseudo_bit_t IBSerdesPClkNotDetectMask[1];
+ pseudo_bit_t Clk_uC_PLLNotLockedMask[1];
+ pseudo_bit_t IBCBusToSPCParityErrMask[1];
+ pseudo_bit_t IBCBusFromSPCParityErrMask[1];
+};
+struct QIB_7220_HwErrMask {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_HwErrMask_pb );
+};
+
+#define QIB_7220_HwErrStatus_offset 0x000000a0UL
+struct QIB_7220_HwErrStatus_pb {
+ pseudo_bit_t PCIeMemParity[8];
+ pseudo_bit_t Reserved3[20];
+ pseudo_bit_t SDmaMemReadErr[1];
+ pseudo_bit_t PoisenedTLP[1];
+ pseudo_bit_t PcieCplTimeout[1];
+ pseudo_bit_t PCIeBusParity[3];
+ pseudo_bit_t Reserved2[2];
+ pseudo_bit_t PCIE_uC_Oct0MemoryParityErr[1];
+ pseudo_bit_t PCIE_uC_Oct1MemoryParityErr[1];
+ pseudo_bit_t IB_uC_MemoryParityErr[1];
+ pseudo_bit_t DDSRXEQMemoryParityErr[1];
+ pseudo_bit_t TXEMemParity[4];
+ pseudo_bit_t RXEMemParity[7];
+ pseudo_bit_t Reserved1[3];
+ pseudo_bit_t PowerOnBISTFailed[1];
+ pseudo_bit_t Reserved[1];
+ pseudo_bit_t PCIESerdesQ0PClkNotDetect[1];
+ pseudo_bit_t PCIESerdesQ1PClkNotDetect[1];
+ pseudo_bit_t PCIESerdesQ2PClkNotDetect[1];
+ pseudo_bit_t PCIESerdesQ3PClkNotDetect[1];
+ pseudo_bit_t IBSerdesPClkNotDetect[1];
+ pseudo_bit_t Clk_uC_PLLNotLocked[1];
+ pseudo_bit_t IBCBusToSPCParityErr[1];
+ pseudo_bit_t IBCBusFromSPCParityErr[1];
+};
+struct QIB_7220_HwErrStatus {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_HwErrStatus_pb );
+};
+
+#define QIB_7220_HwErrClear_offset 0x000000a8UL
+struct QIB_7220_HwErrClear_pb {
+ pseudo_bit_t PCIeMemParityClr[8];
+ pseudo_bit_t Reserved3[20];
+ pseudo_bit_t SDmaMemReadErrClear[1];
+ pseudo_bit_t PoisonedTLPClear[1];
+ pseudo_bit_t PcieCplTimeoutClear[1];
+ pseudo_bit_t PCIeBusParityClr[3];
+ pseudo_bit_t Reserved2[2];
+ pseudo_bit_t PCIE_uC_Oct0MemoryParityErrClear[1];
+ pseudo_bit_t PCIE_uC_Oct1MemoryParityErrClear[1];
+ pseudo_bit_t IB_uC_MemoryParityErrClear[1];
+ pseudo_bit_t DDSRXEQMemoryParityErrClear[1];
+ pseudo_bit_t TXEMemParityClear[4];
+ pseudo_bit_t RXEMemParityClear[7];
+ pseudo_bit_t Reserved1[3];
+ pseudo_bit_t PowerOnBISTFailedClear[1];
+ pseudo_bit_t Reserved[1];
+ pseudo_bit_t PCIESerdesQ0PClkNotDetectClear[1];
+ pseudo_bit_t PCIESerdesQ1PClkNotDetectClear[1];
+ pseudo_bit_t PCIESerdesQ2PClkNotDetectClear[1];
+ pseudo_bit_t PCIESerdesQ3PClkNotDetectClear[1];
+ pseudo_bit_t IBSerdesPClkNotDetectClear[1];
+ pseudo_bit_t Clk_uC_PLLNotLockedClear[1];
+ pseudo_bit_t IBCBusToSPCparityErrClear[1];
+ pseudo_bit_t IBCBusFromSPCParityErrClear[1];
+};
+struct QIB_7220_HwErrClear {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_HwErrClear_pb );
+};
+
+#define QIB_7220_HwDiagCtrl_offset 0x000000b0UL
+struct QIB_7220_HwDiagCtrl_pb {
+ pseudo_bit_t forcePCIeMemParity[8];
+ pseudo_bit_t Reserved2[23];
+ pseudo_bit_t forcePCIeBusParity[4];
+ pseudo_bit_t Reserved1[1];
+ pseudo_bit_t ForcePCIE_uC_Oct0MemoryParityErr[1];
+ pseudo_bit_t ForcePCIE_uC_Oct1MemoryParityErr[1];
+ pseudo_bit_t ForceIB_uC_MemoryParityErr[1];
+ pseudo_bit_t ForceDDSRXEQMemoryParityErr[1];
+ pseudo_bit_t ForceTxMemparityErr[4];
+ pseudo_bit_t ForceRxMemParityErr[7];
+ pseudo_bit_t Reserved[9];
+ pseudo_bit_t CounterDisable[1];
+ pseudo_bit_t CounterWrEnable[1];
+ pseudo_bit_t ForceIBCBusToSPCParityErr[1];
+ pseudo_bit_t ForceIBCBusFromSPCParityErr[1];
+};
+struct QIB_7220_HwDiagCtrl {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_HwDiagCtrl_pb );
+};
+
+#define QIB_7220_REG_0000B8_offset 0x000000b8UL
+
+#define QIB_7220_IBCStatus_offset 0x000000c0UL
+struct QIB_7220_IBCStatus_pb {
+ pseudo_bit_t LinkTrainingState[5];
+ pseudo_bit_t LinkState[3];
+ pseudo_bit_t LinkSpeedActive[1];
+ pseudo_bit_t LinkWidthActive[1];
+ pseudo_bit_t DDS_RXEQ_FAIL[1];
+ pseudo_bit_t IB_SERDES_TRIM_DONE[1];
+ pseudo_bit_t IBRxLaneReversed[1];
+ pseudo_bit_t IBTxLaneReversed[1];
+ pseudo_bit_t Reserved[16];
+ pseudo_bit_t TxReady[1];
+ pseudo_bit_t TxCreditOk[1];
+ pseudo_bit_t _unused_0[32];
+};
+struct QIB_7220_IBCStatus {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_IBCStatus_pb );
+};
+
+#define QIB_7220_IBCCtrl_offset 0x000000c8UL
+struct QIB_7220_IBCCtrl_pb {
+ pseudo_bit_t FlowCtrlPeriod[8];
+ pseudo_bit_t FlowCtrlWaterMark[8];
+ pseudo_bit_t LinkInitCmd[3];
+ pseudo_bit_t LinkCmd[2];
+ pseudo_bit_t MaxPktLen[11];
+ pseudo_bit_t PhyerrThreshold[4];
+ pseudo_bit_t OverrunThreshold[4];
+ pseudo_bit_t CreditScale[3];
+ pseudo_bit_t Reserved[19];
+ pseudo_bit_t LinkDownDefaultState[1];
+ pseudo_bit_t Loopback[1];
+};
+struct QIB_7220_IBCCtrl {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_IBCCtrl_pb );
+};
+
+#define QIB_7220_EXTStatus_offset 0x000000d0UL
+struct QIB_7220_EXTStatus_pb {
+ pseudo_bit_t Reserved2[14];
+ pseudo_bit_t MemBISTEndTest[1];
+ pseudo_bit_t MemBISTDisabled[1];
+ pseudo_bit_t Reserved1[16];
+ pseudo_bit_t Reserved[16];
+ pseudo_bit_t GPIOIn[16];
+};
+struct QIB_7220_EXTStatus {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_EXTStatus_pb );
+};
+
+#define QIB_7220_EXTCtrl_offset 0x000000d8UL
+struct QIB_7220_EXTCtrl_pb {
+ pseudo_bit_t LEDGblErrRedOff[1];
+ pseudo_bit_t LEDGblOkGreenOn[1];
+ pseudo_bit_t LEDPriPortYellowOn[1];
+ pseudo_bit_t LEDPriPortGreenOn[1];
+ pseudo_bit_t Reserved[28];
+ pseudo_bit_t GPIOInvert[16];
+ pseudo_bit_t GPIOOe[16];
+};
+struct QIB_7220_EXTCtrl {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_EXTCtrl_pb );
+};
+
+#define QIB_7220_GPIOOut_offset 0x000000e0UL
+
+#define QIB_7220_GPIOMask_offset 0x000000e8UL
+
+#define QIB_7220_GPIOStatus_offset 0x000000f0UL
+
+#define QIB_7220_GPIOClear_offset 0x000000f8UL
+
+#define QIB_7220_RcvCtrl_offset 0x00000100UL
+struct QIB_7220_RcvCtrl_pb {
+ pseudo_bit_t PortEnable[17];
+ pseudo_bit_t IntrAvail[17];
+ pseudo_bit_t RcvPartitionKeyDisable[1];
+ pseudo_bit_t TailUpd[1];
+ pseudo_bit_t PortCfg[2];
+ pseudo_bit_t RcvQPMapEnable[1];
+ pseudo_bit_t Reserved[25];
+};
+struct QIB_7220_RcvCtrl {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvCtrl_pb );
+};
+
+#define QIB_7220_RcvBTHQP_offset 0x00000108UL
+struct QIB_7220_RcvBTHQP_pb {
+ pseudo_bit_t RcvBTHQP[24];
+ pseudo_bit_t Reserved[8];
+ pseudo_bit_t _unused_0[32];
+};
+struct QIB_7220_RcvBTHQP {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvBTHQP_pb );
+};
+
+#define QIB_7220_RcvHdrSize_offset 0x00000110UL
+
+#define QIB_7220_RcvHdrCnt_offset 0x00000118UL
+
+#define QIB_7220_RcvHdrEntSize_offset 0x00000120UL
+
+#define QIB_7220_RcvTIDBase_offset 0x00000128UL
+
+#define QIB_7220_RcvTIDCnt_offset 0x00000130UL
+
+#define QIB_7220_RcvEgrBase_offset 0x00000138UL
+
+#define QIB_7220_RcvEgrCnt_offset 0x00000140UL
+
+#define QIB_7220_RcvBufBase_offset 0x00000148UL
+
+#define QIB_7220_RcvBufSize_offset 0x00000150UL
+
+#define QIB_7220_RxIntMemBase_offset 0x00000158UL
+
+#define QIB_7220_RxIntMemSize_offset 0x00000160UL
+
+#define QIB_7220_RcvPartitionKey_offset 0x00000168UL
+
+#define QIB_7220_RcvQPMulticastPort_offset 0x00000170UL
+struct QIB_7220_RcvQPMulticastPort_pb {
+ pseudo_bit_t RcvQpMcPort[5];
+ pseudo_bit_t Reserved[59];
+};
+struct QIB_7220_RcvQPMulticastPort {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvQPMulticastPort_pb );
+};
+
+#define QIB_7220_RcvPktLEDCnt_offset 0x00000178UL
+struct QIB_7220_RcvPktLEDCnt_pb {
+ pseudo_bit_t OFFperiod[32];
+ pseudo_bit_t ONperiod[32];
+};
+struct QIB_7220_RcvPktLEDCnt {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvPktLEDCnt_pb );
+};
+
+#define QIB_7220_IBCDDRCtrl_offset 0x00000180UL
+struct QIB_7220_IBCDDRCtrl_pb {
+ pseudo_bit_t IB_ENHANCED_MODE[1];
+ pseudo_bit_t SD_SPEED[1];
+ pseudo_bit_t SD_SPEED_SDR[1];
+ pseudo_bit_t SD_SPEED_DDR[1];
+ pseudo_bit_t SD_SPEED_QDR[1];
+ pseudo_bit_t IB_NUM_CHANNELS[2];
+ pseudo_bit_t IB_POLARITY_REV_SUPP[1];
+ pseudo_bit_t IB_LANE_REV_SUPPORTED[1];
+ pseudo_bit_t SD_RX_EQUAL_ENABLE[1];
+ pseudo_bit_t SD_ADD_ENB[1];
+ pseudo_bit_t SD_DDSV[1];
+ pseudo_bit_t SD_DDS[4];
+ pseudo_bit_t HRTBT_ENB[1];
+ pseudo_bit_t HRTBT_AUTO[1];
+ pseudo_bit_t HRTBT_PORT[8];
+ pseudo_bit_t HRTBT_REQ[1];
+ pseudo_bit_t Reserved[5];
+ pseudo_bit_t IB_DLID[16];
+ pseudo_bit_t IB_DLID_MASK[16];
+};
+struct QIB_7220_IBCDDRCtrl {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_IBCDDRCtrl_pb );
+};
+
+#define QIB_7220_HRTBT_GUID_offset 0x00000188UL
+
+#define QIB_7220_IB_SDTEST_IF_TX_offset 0x00000190UL
+struct QIB_7220_IB_SDTEST_IF_TX_pb {
+ pseudo_bit_t TS_T_TX_VALID[1];
+ pseudo_bit_t TS_3_TX_VALID[1];
+ pseudo_bit_t Reserved1[9];
+ pseudo_bit_t TS_TX_OPCODE[2];
+ pseudo_bit_t TS_TX_SPEED[3];
+ pseudo_bit_t Reserved[16];
+ pseudo_bit_t TS_TX_TX_CFG[16];
+ pseudo_bit_t TS_TX_RX_CFG[16];
+};
+struct QIB_7220_IB_SDTEST_IF_TX {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_IB_SDTEST_IF_TX_pb );
+};
+
+#define QIB_7220_IB_SDTEST_IF_RX_offset 0x00000198UL
+struct QIB_7220_IB_SDTEST_IF_RX_pb {
+ pseudo_bit_t TS_T_RX_VALID[1];
+ pseudo_bit_t TS_3_RX_VALID[1];
+ pseudo_bit_t Reserved[14];
+ pseudo_bit_t TS_RX_A[8];
+ pseudo_bit_t TS_RX_B[8];
+ pseudo_bit_t TS_RX_TX_CFG[16];
+ pseudo_bit_t TS_RX_RX_CFG[16];
+};
+struct QIB_7220_IB_SDTEST_IF_RX {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_IB_SDTEST_IF_RX_pb );
+};
+
+#define QIB_7220_IBCDDRCtrl2_offset 0x000001a0UL
+struct QIB_7220_IBCDDRCtrl2_pb {
+ pseudo_bit_t IB_FRONT_PORCH[5];
+ pseudo_bit_t IB_BACK_PORCH[5];
+ pseudo_bit_t _unused_0[54];
+};
+struct QIB_7220_IBCDDRCtrl2 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_IBCDDRCtrl2_pb );
+};
+
+#define QIB_7220_IBCDDRStatus_offset 0x000001a8UL
+struct QIB_7220_IBCDDRStatus_pb {
+ pseudo_bit_t LinkRoundTripLatency[26];
+ pseudo_bit_t ReqDDSLocalFromRmt[4];
+ pseudo_bit_t RxEqLocalDevice[2];
+ pseudo_bit_t heartbeat_crosstalk[4];
+ pseudo_bit_t heartbeat_timed_out[1];
+ pseudo_bit_t _unused_0[27];
+};
+struct QIB_7220_IBCDDRStatus {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_IBCDDRStatus_pb );
+};
+
+#define QIB_7220_JIntReload_offset 0x000001b0UL
+struct QIB_7220_JIntReload_pb {
+ pseudo_bit_t J_reload[16];
+ pseudo_bit_t J_limit_reload[16];
+ pseudo_bit_t _unused_0[32];
+};
+struct QIB_7220_JIntReload {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_JIntReload_pb );
+};
+
+#define QIB_7220_IBNCModeCtrl_offset 0x000001b8UL
+struct QIB_7220_IBNCModeCtrl_pb {
+ pseudo_bit_t TSMEnable_send_TS1[1];
+ pseudo_bit_t TSMEnable_send_TS2[1];
+ pseudo_bit_t TSMEnable_ignore_TSM_on_rx[1];
+ pseudo_bit_t Reserved1[5];
+ pseudo_bit_t TSMCode_TS1[9];
+ pseudo_bit_t TSMCode_TS2[9];
+ pseudo_bit_t Reserved[38];
+};
+struct QIB_7220_IBNCModeCtrl {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_IBNCModeCtrl_pb );
+};
+
+#define QIB_7220_SendCtrl_offset 0x000001c0UL
+struct QIB_7220_SendCtrl_pb {
+ pseudo_bit_t Abort[1];
+ pseudo_bit_t SendIntBufAvail[1];
+ pseudo_bit_t SendBufAvailUpd[1];
+ pseudo_bit_t SPioEnable[1];
+ pseudo_bit_t SSpecialTriggerEn[1];
+ pseudo_bit_t Reserved2[4];
+ pseudo_bit_t SDmaIntEnable[1];
+ pseudo_bit_t SDmaSingleDescriptor[1];
+ pseudo_bit_t SDmaEnable[1];
+ pseudo_bit_t SDmaHalt[1];
+ pseudo_bit_t Reserved1[3];
+ pseudo_bit_t DisarmPIOBuf[8];
+ pseudo_bit_t AvailUpdThld[5];
+ pseudo_bit_t Reserved[2];
+ pseudo_bit_t Disarm[1];
+ pseudo_bit_t _unused_0[32];
+};
+struct QIB_7220_SendCtrl {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SendCtrl_pb );
+};
+
+#define QIB_7220_SendBufBase_offset 0x000001c8UL
+struct QIB_7220_SendBufBase_pb {
+ pseudo_bit_t BaseAddr_SmallPIO[21];
+ pseudo_bit_t Reserved1[11];
+ pseudo_bit_t BaseAddr_LargePIO[21];
+ pseudo_bit_t Reserved[11];
+};
+struct QIB_7220_SendBufBase {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SendBufBase_pb );
+};
+
+#define QIB_7220_SendBufSize_offset 0x000001d0UL
+struct QIB_7220_SendBufSize_pb {
+ pseudo_bit_t Size_SmallPIO[12];
+ pseudo_bit_t Reserved1[20];
+ pseudo_bit_t Size_LargePIO[13];
+ pseudo_bit_t Reserved[19];
+};
+struct QIB_7220_SendBufSize {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SendBufSize_pb );
+};
+
+#define QIB_7220_SendBufCnt_offset 0x000001d8UL
+struct QIB_7220_SendBufCnt_pb {
+ pseudo_bit_t Num_SmallBuffers[9];
+ pseudo_bit_t Reserved1[23];
+ pseudo_bit_t Num_LargeBuffers[4];
+ pseudo_bit_t Reserved[28];
+};
+struct QIB_7220_SendBufCnt {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SendBufCnt_pb );
+};
+
+#define QIB_7220_SendBufAvailAddr_offset 0x000001e0UL
+struct QIB_7220_SendBufAvailAddr_pb {
+ pseudo_bit_t Reserved[6];
+ pseudo_bit_t SendBufAvailAddr[34];
+ pseudo_bit_t _unused_0[24];
+};
+struct QIB_7220_SendBufAvailAddr {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SendBufAvailAddr_pb );
+};
+
+#define QIB_7220_TxIntMemBase_offset 0x000001e8UL
+
+#define QIB_7220_TxIntMemSize_offset 0x000001f0UL
+
+#define QIB_7220_SendDmaBase_offset 0x000001f8UL
+struct QIB_7220_SendDmaBase_pb {
+ pseudo_bit_t SendDmaBase[48];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_SendDmaBase {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaBase_pb );
+};
+
+#define QIB_7220_SendDmaLenGen_offset 0x00000200UL
+struct QIB_7220_SendDmaLenGen_pb {
+ pseudo_bit_t Length[16];
+ pseudo_bit_t Generation[3];
+ pseudo_bit_t Reserved[45];
+};
+struct QIB_7220_SendDmaLenGen {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaLenGen_pb );
+};
+
+#define QIB_7220_SendDmaTail_offset 0x00000208UL
+struct QIB_7220_SendDmaTail_pb {
+ pseudo_bit_t SendDmaTail[16];
+ pseudo_bit_t Reserved[48];
+};
+struct QIB_7220_SendDmaTail {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaTail_pb );
+};
+
+#define QIB_7220_SendDmaHead_offset 0x00000210UL
+struct QIB_7220_SendDmaHead_pb {
+ pseudo_bit_t SendDmaHead[16];
+ pseudo_bit_t Reserved1[16];
+ pseudo_bit_t InternalSendDmaHead[16];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_SendDmaHead {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaHead_pb );
+};
+
+#define QIB_7220_SendDmaHeadAddr_offset 0x00000218UL
+struct QIB_7220_SendDmaHeadAddr_pb {
+ pseudo_bit_t SendDmaHeadAddr[48];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_SendDmaHeadAddr {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaHeadAddr_pb );
+};
+
+#define QIB_7220_SendDmaBufMask0_offset 0x00000220UL
+struct QIB_7220_SendDmaBufMask0_pb {
+ pseudo_bit_t BufMask_63_0[0];
+ pseudo_bit_t _unused_0[64];
+};
+struct QIB_7220_SendDmaBufMask0 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaBufMask0_pb );
+};
+
+#define QIB_7220_SendDmaStatus_offset 0x00000238UL
+struct QIB_7220_SendDmaStatus_pb {
+ pseudo_bit_t SplFifoDescIndex[16];
+ pseudo_bit_t SplFifoBufNum[8];
+ pseudo_bit_t SplFifoFull[1];
+ pseudo_bit_t SplFifoEmpty[1];
+ pseudo_bit_t SplFifoDisarmed[1];
+ pseudo_bit_t SplFifoReadyToGo[1];
+ pseudo_bit_t ScbFetchDescFlag[1];
+ pseudo_bit_t ScbEntryValid[1];
+ pseudo_bit_t ScbEmpty[1];
+ pseudo_bit_t ScbFull[1];
+ pseudo_bit_t RpyTag_7_0[8];
+ pseudo_bit_t RpyLowAddr_6_0[7];
+ pseudo_bit_t ScbDescIndex_13_0[14];
+ pseudo_bit_t InternalSDmaEnable[1];
+ pseudo_bit_t AbortInProg[1];
+ pseudo_bit_t ScoreBoardDrainInProg[1];
+};
+struct QIB_7220_SendDmaStatus {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaStatus_pb );
+};
+
+#define QIB_7220_SendBufErr0_offset 0x00000240UL
+struct QIB_7220_SendBufErr0_pb {
+ pseudo_bit_t SendBufErr_63_0[0];
+ pseudo_bit_t _unused_0[64];
+};
+struct QIB_7220_SendBufErr0 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SendBufErr0_pb );
+};
+
+#define QIB_7220_REG_000258_offset 0x00000258UL
+
+#define QIB_7220_AvailUpdCount_offset 0x00000268UL
+struct QIB_7220_AvailUpdCount_pb {
+ pseudo_bit_t AvailUpdCount[5];
+ pseudo_bit_t _unused_0[59];
+};
+struct QIB_7220_AvailUpdCount {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_AvailUpdCount_pb );
+};
+
+#define QIB_7220_RcvHdrAddr0_offset 0x00000270UL
+struct QIB_7220_RcvHdrAddr0_pb {
+ pseudo_bit_t Reserved[2];
+ pseudo_bit_t RcvHdrAddr0[38];
+ pseudo_bit_t _unused_0[24];
+};
+struct QIB_7220_RcvHdrAddr0 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrAddr0_pb );
+};
+
+#define QIB_7220_REG_0002F8_offset 0x000002f8UL
+
+#define QIB_7220_RcvHdrTailAddr0_offset 0x00000300UL
+struct QIB_7220_RcvHdrTailAddr0_pb {
+ pseudo_bit_t Reserved[2];
+ pseudo_bit_t RcvHdrTailAddr0[38];
+ pseudo_bit_t _unused_0[24];
+};
+struct QIB_7220_RcvHdrTailAddr0 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrTailAddr0_pb );
+};
+
+#define QIB_7220_REG_000388_offset 0x00000388UL
+
+#define QIB_7220_ibsd_epb_access_ctrl_offset 0x000003c0UL
+struct QIB_7220_ibsd_epb_access_ctrl_pb {
+ pseudo_bit_t sw_ib_epb_req[1];
+ pseudo_bit_t Reserved[7];
+ pseudo_bit_t sw_ib_epb_req_granted[1];
+ pseudo_bit_t _unused_0[55];
+};
+struct QIB_7220_ibsd_epb_access_ctrl {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_ibsd_epb_access_ctrl_pb );
+};
+
+#define QIB_7220_ibsd_epb_transaction_reg_offset 0x000003c8UL
+struct QIB_7220_ibsd_epb_transaction_reg_pb {
+ pseudo_bit_t ib_epb_data[8];
+ pseudo_bit_t ib_epb_address[15];
+ pseudo_bit_t Reserved2[1];
+ pseudo_bit_t ib_epb_read_write[1];
+ pseudo_bit_t ib_epb_cs[2];
+ pseudo_bit_t Reserved1[1];
+ pseudo_bit_t mem_data_parity[1];
+ pseudo_bit_t Reserved[1];
+ pseudo_bit_t ib_epb_req_error[1];
+ pseudo_bit_t ib_epb_rdy[1];
+ pseudo_bit_t _unused_0[32];
+};
+struct QIB_7220_ibsd_epb_transaction_reg {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_ibsd_epb_transaction_reg_pb );
+};
+
+#define QIB_7220_REG_0003D0_offset 0x000003d0UL
+
+#define QIB_7220_XGXSCfg_offset 0x000003d8UL
+struct QIB_7220_XGXSCfg_pb {
+ pseudo_bit_t tx_rx_reset[1];
+ pseudo_bit_t Reserved2[1];
+ pseudo_bit_t xcv_reset[1];
+ pseudo_bit_t Reserved1[6];
+ pseudo_bit_t link_sync_mask[10];
+ pseudo_bit_t Reserved[44];
+ pseudo_bit_t sel_link_down_for_fctrl_lane_sync_reset[1];
+};
+struct QIB_7220_XGXSCfg {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_XGXSCfg_pb );
+};
+
+#define QIB_7220_IBSerDesCtrl_offset 0x000003e0UL
+struct QIB_7220_IBSerDesCtrl_pb {
+ pseudo_bit_t ResetIB_uC_Core[1];
+ pseudo_bit_t Reserved2[7];
+ pseudo_bit_t NumSerDesRegsToWrForDDS[5];
+ pseudo_bit_t NumSerDesRegsToWrForRXEQ[5];
+ pseudo_bit_t Reserved1[14];
+ pseudo_bit_t TXINV[1];
+ pseudo_bit_t RXINV[1];
+ pseudo_bit_t RXIDLE[1];
+ pseudo_bit_t TWC[1];
+ pseudo_bit_t TXOBPD[1];
+ pseudo_bit_t PLLM[3];
+ pseudo_bit_t PLLN[2];
+ pseudo_bit_t CKSEL_uC[2];
+ pseudo_bit_t INT_uC[1];
+ pseudo_bit_t Reserved[19];
+};
+struct QIB_7220_IBSerDesCtrl {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_IBSerDesCtrl_pb );
+};
+
+#define QIB_7220_EEPCtlStat_offset 0x000003e8UL
+struct QIB_7220_EEPCtlStat_pb {
+ pseudo_bit_t EPAccEn[2];
+ pseudo_bit_t EPReset[1];
+ pseudo_bit_t ByteProg[1];
+ pseudo_bit_t PageMode[1];
+ pseudo_bit_t LstDatWr[1];
+ pseudo_bit_t CmdWrErr[1];
+ pseudo_bit_t Reserved[24];
+ pseudo_bit_t CtlrStat[1];
+ pseudo_bit_t _unused_0[32];
+};
+struct QIB_7220_EEPCtlStat {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_EEPCtlStat_pb );
+};
+
+#define QIB_7220_EEPAddrCmd_offset 0x000003f0UL
+struct QIB_7220_EEPAddrCmd_pb {
+ pseudo_bit_t EPAddr[24];
+ pseudo_bit_t EPCmd[8];
+ pseudo_bit_t _unused_0[32];
+};
+struct QIB_7220_EEPAddrCmd {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_EEPAddrCmd_pb );
+};
+
+#define QIB_7220_EEPData_offset 0x000003f8UL
+
+#define QIB_7220_pciesd_epb_access_ctrl_offset 0x00000400UL
+struct QIB_7220_pciesd_epb_access_ctrl_pb {
+ pseudo_bit_t sw_pcie_epb_req[1];
+ pseudo_bit_t sw_pcieepb_star_en[2];
+ pseudo_bit_t Reserved[5];
+ pseudo_bit_t sw_pcie_epb_req_granted[1];
+ pseudo_bit_t _unused_0[55];
+};
+struct QIB_7220_pciesd_epb_access_ctrl {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_pciesd_epb_access_ctrl_pb );
+};
+
+#define QIB_7220_pciesd_epb_transaction_reg_offset 0x00000408UL
+struct QIB_7220_pciesd_epb_transaction_reg_pb {
+ pseudo_bit_t pcie_epb_data[8];
+ pseudo_bit_t pcie_epb_address[15];
+ pseudo_bit_t Reserved1[1];
+ pseudo_bit_t pcie_epb_read_write[1];
+ pseudo_bit_t pcie_epb_cs[3];
+ pseudo_bit_t mem_data_parity[1];
+ pseudo_bit_t Reserved[1];
+ pseudo_bit_t pcie_epb_req_error[1];
+ pseudo_bit_t pcie_epb_rdy[1];
+ pseudo_bit_t _unused_0[32];
+};
+struct QIB_7220_pciesd_epb_transaction_reg {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_pciesd_epb_transaction_reg_pb );
+};
+
+#define QIB_7220_efuse_control_reg_offset 0x00000410UL
+struct QIB_7220_efuse_control_reg_pb {
+ pseudo_bit_t start_op[1];
+ pseudo_bit_t operation[1];
+ pseudo_bit_t read_valid[1];
+ pseudo_bit_t req_error[1];
+ pseudo_bit_t Reserved[27];
+ pseudo_bit_t rdy[1];
+ pseudo_bit_t _unused_0[32];
+};
+struct QIB_7220_efuse_control_reg {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_efuse_control_reg_pb );
+};
+
+#define QIB_7220_efuse_rddata0_reg_offset 0x00000418UL
+
+#define QIB_7220_procmon_register_offset 0x00000438UL
+struct QIB_7220_procmon_register_pb {
+ pseudo_bit_t interval_time[12];
+ pseudo_bit_t Reserved1[2];
+ pseudo_bit_t clear_counter[1];
+ pseudo_bit_t start_counter[1];
+ pseudo_bit_t procmon_count[9];
+ pseudo_bit_t Reserved[6];
+ pseudo_bit_t procmon_count_valid[1];
+ pseudo_bit_t _unused_0[32];
+};
+struct QIB_7220_procmon_register {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_procmon_register_pb );
+};
+
+#define QIB_7220_PcieRbufTestReg0_offset 0x00000440UL
+
+#define QIB_7220_PcieRBufTestReg1_offset 0x00000448UL
+
+#define QIB_7220_SPC_JTAG_ACCESS_REG_offset 0x00000460UL
+struct QIB_7220_SPC_JTAG_ACCESS_REG_pb {
+ pseudo_bit_t rdy[1];
+ pseudo_bit_t tdo[1];
+ pseudo_bit_t tdi[1];
+ pseudo_bit_t opcode[2];
+ pseudo_bit_t bist_en[5];
+ pseudo_bit_t SPC_JTAG_ACCESS_EN[1];
+ pseudo_bit_t _unused_0[53];
+};
+struct QIB_7220_SPC_JTAG_ACCESS_REG {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SPC_JTAG_ACCESS_REG_pb );
+};
+
+#define QIB_7220_LAControlReg_offset 0x00000468UL
+struct QIB_7220_LAControlReg_pb {
+ pseudo_bit_t Finished[1];
+ pseudo_bit_t Address[8];
+ pseudo_bit_t Mode[2];
+ pseudo_bit_t Delay[20];
+ pseudo_bit_t Reserved[1];
+ pseudo_bit_t _unused_0[32];
+};
+struct QIB_7220_LAControlReg {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_LAControlReg_pb );
+};
+
+#define QIB_7220_GPIODebugSelReg_offset 0x00000470UL
+struct QIB_7220_GPIODebugSelReg_pb {
+ pseudo_bit_t GPIOSourceSelDebug[16];
+ pseudo_bit_t SelPulse[16];
+ pseudo_bit_t _unused_0[32];
+};
+struct QIB_7220_GPIODebugSelReg {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_GPIODebugSelReg_pb );
+};
+
+#define QIB_7220_DebugPortValueReg_offset 0x00000478UL
+
+#define QIB_7220_SendDmaBufUsed0_offset 0x00000480UL
+struct QIB_7220_SendDmaBufUsed0_pb {
+ pseudo_bit_t BufUsed_63_0[0];
+ pseudo_bit_t _unused_0[64];
+};
+struct QIB_7220_SendDmaBufUsed0 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaBufUsed0_pb );
+};
+
+#define QIB_7220_SendDmaReqTagUsed_offset 0x00000498UL
+struct QIB_7220_SendDmaReqTagUsed_pb {
+ pseudo_bit_t ReqTagUsed_7_0[8];
+ pseudo_bit_t _unused_0[8];
+ pseudo_bit_t Reserved[48];
+ pseudo_bit_t _unused_1[8];
+};
+struct QIB_7220_SendDmaReqTagUsed {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaReqTagUsed_pb );
+};
+
+#define QIB_7220_efuse_pgm_data0_offset 0x000004a0UL
+
+#define QIB_7220_MEM_0004B0_offset 0x000004b0UL
+
+#define QIB_7220_SerDes_DDSRXEQ0_offset 0x00000500UL
+struct QIB_7220_SerDes_DDSRXEQ0_pb {
+ pseudo_bit_t element_num[4];
+ pseudo_bit_t reg_addr[6];
+ pseudo_bit_t _unused_0[54];
+};
+struct QIB_7220_SerDes_DDSRXEQ0 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SerDes_DDSRXEQ0_pb );
+};
+
+#define QIB_7220_MEM_0005F0_offset 0x000005f0UL
+
+#define QIB_7220_LAMemory_offset 0x00000600UL
+
+#define QIB_7220_MEM_0007F0_offset 0x000007f0UL
+
+#define QIB_7220_SendBufAvail0_offset 0x00001000UL
+struct QIB_7220_SendBufAvail0_pb {
+ pseudo_bit_t SendBuf_31_0[0];
+ pseudo_bit_t _unused_0[64];
+};
+struct QIB_7220_SendBufAvail0 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SendBufAvail0_pb );
+};
+
+#define QIB_7220_MEM_001028_offset 0x00001028UL
+
+#define QIB_7220_LBIntCnt_offset 0x00013000UL
+
+#define QIB_7220_LBFlowStallCnt_offset 0x00013008UL
+
+#define QIB_7220_TxSDmaDescCnt_offset 0x00013010UL
+
+#define QIB_7220_TxUnsupVLErrCnt_offset 0x00013018UL
+
+#define QIB_7220_TxDataPktCnt_offset 0x00013020UL
+
+#define QIB_7220_TxFlowPktCnt_offset 0x00013028UL
+
+#define QIB_7220_TxDwordCnt_offset 0x00013030UL
+
+#define QIB_7220_TxLenErrCnt_offset 0x00013038UL
+
+#define QIB_7220_TxMaxMinLenErrCnt_offset 0x00013040UL
+
+#define QIB_7220_TxUnderrunCnt_offset 0x00013048UL
+
+#define QIB_7220_TxFlowStallCnt_offset 0x00013050UL
+
+#define QIB_7220_TxDroppedPktCnt_offset 0x00013058UL
+
+#define QIB_7220_RxDroppedPktCnt_offset 0x00013060UL
+
+#define QIB_7220_RxDataPktCnt_offset 0x00013068UL
+
+#define QIB_7220_RxFlowPktCnt_offset 0x00013070UL
+
+#define QIB_7220_RxDwordCnt_offset 0x00013078UL
+
+#define QIB_7220_RxLenErrCnt_offset 0x00013080UL
+
+#define QIB_7220_RxMaxMinLenErrCnt_offset 0x00013088UL
+
+#define QIB_7220_RxICRCErrCnt_offset 0x00013090UL
+
+#define QIB_7220_RxVCRCErrCnt_offset 0x00013098UL
+
+#define QIB_7220_RxFlowCtrlViolCnt_offset 0x000130a0UL
+
+#define QIB_7220_RxVersionErrCnt_offset 0x000130a8UL
+
+#define QIB_7220_RxLinkMalformCnt_offset 0x000130b0UL
+
+#define QIB_7220_RxEBPCnt_offset 0x000130b8UL
+
+#define QIB_7220_RxLPCRCErrCnt_offset 0x000130c0UL
+
+#define QIB_7220_RxBufOvflCnt_offset 0x000130c8UL
+
+#define QIB_7220_RxTIDFullErrCnt_offset 0x000130d0UL
+
+#define QIB_7220_RxTIDValidErrCnt_offset 0x000130d8UL
+
+#define QIB_7220_RxPKeyMismatchCnt_offset 0x000130e0UL
+
+#define QIB_7220_RxP0HdrEgrOvflCnt_offset 0x000130e8UL
+
+#define QIB_7220_IBStatusChangeCnt_offset 0x00013170UL
+
+#define QIB_7220_IBLinkErrRecoveryCnt_offset 0x00013178UL
+
+#define QIB_7220_IBLinkDownedCnt_offset 0x00013180UL
+
+#define QIB_7220_IBSymbolErrCnt_offset 0x00013188UL
+
+#define QIB_7220_RxVL15DroppedPktCnt_offset 0x00013190UL
+
+#define QIB_7220_RxOtherLocalPhyErrCnt_offset 0x00013198UL
+
+#define QIB_7220_PcieRetryBufDiagQwordCnt_offset 0x000131a0UL
+
+#define QIB_7220_ExcessBufferOvflCnt_offset 0x000131a8UL
+
+#define QIB_7220_LocalLinkIntegrityErrCnt_offset 0x000131b0UL
+
+#define QIB_7220_RxVlErrCnt_offset 0x000131b8UL
+
+#define QIB_7220_RxDlidFltrCnt_offset 0x000131c0UL
+
+#define QIB_7220_CNT_0131C8_offset 0x000131c8UL
+
+#define QIB_7220_PSStat_offset 0x00013200UL
+
+#define QIB_7220_PSStart_offset 0x00013208UL
+
+#define QIB_7220_PSInterval_offset 0x00013210UL
+
+#define QIB_7220_PSRcvDataCount_offset 0x00013218UL
+
+#define QIB_7220_PSRcvPktsCount_offset 0x00013220UL
+
+#define QIB_7220_PSXmitDataCount_offset 0x00013228UL
+
+#define QIB_7220_PSXmitPktsCount_offset 0x00013230UL
+
+#define QIB_7220_PSXmitWaitCount_offset 0x00013238UL
+
+#define QIB_7220_CNT_013240_offset 0x00013240UL
+
+#define QIB_7220_RcvEgrArray_offset 0x00014000UL
+
+#define QIB_7220_MEM_038000_offset 0x00038000UL
+
+#define QIB_7220_RcvTIDArray0_offset 0x00053000UL
+
+#define QIB_7220_PIOLaunchFIFO_offset 0x00064000UL
+
+#define QIB_7220_MEM_064480_offset 0x00064480UL
+
+#define QIB_7220_SendPIOpbcCache_offset 0x00064800UL
+
+#define QIB_7220_MEM_064C80_offset 0x00064c80UL
+
+#define QIB_7220_PreLaunchFIFO_offset 0x00065000UL
+
+#define QIB_7220_MEM_065080_offset 0x00065080UL
+
+#define QIB_7220_ScoreBoard_offset 0x00065400UL
+
+#define QIB_7220_MEM_065440_offset 0x00065440UL
+
+#define QIB_7220_DescriptorFIFO_offset 0x00065800UL
+
+#define QIB_7220_MEM_065880_offset 0x00065880UL
+
+#define QIB_7220_RcvBuf1_offset 0x00072000UL
+
+#define QIB_7220_MEM_074800_offset 0x00074800UL
+
+#define QIB_7220_RcvBuf2_offset 0x00075000UL
+
+#define QIB_7220_MEM_076400_offset 0x00076400UL
+
+#define QIB_7220_RcvFlags_offset 0x00077000UL
+
+#define QIB_7220_MEM_078400_offset 0x00078400UL
+
+#define QIB_7220_RcvLookupBuf1_offset 0x00079000UL
+
+#define QIB_7220_MEM_07A400_offset 0x0007a400UL
+
+#define QIB_7220_RcvDMADatBuf_offset 0x0007b000UL
+
+#define QIB_7220_RcvDMAHdrBuf_offset 0x0007b800UL
+
+#define QIB_7220_MiscRXEIntMem_offset 0x0007c000UL
+
+#define QIB_7220_MEM_07D400_offset 0x0007d400UL
+
+#define QIB_7220_PCIERcvBuf_offset 0x00080000UL
+
+#define QIB_7220_PCIERetryBuf_offset 0x00084000UL
+
+#define QIB_7220_PCIERcvBufRdToWrAddr_offset 0x00088000UL
+
+#define QIB_7220_PCIECplBuf_offset 0x00090000UL
+
+#define QIB_7220_IBSerDesMappTable_offset 0x00094000UL
+
+#define QIB_7220_MEM_095000_offset 0x00095000UL
+
+#define QIB_7220_SendBuf0_MA_offset 0x00100000UL
+
+#define QIB_7220_MEM_1A0000_offset 0x001a0000UL
+
+#define QIB_7220_RcvHdrTail0_offset 0x00200000UL
+
+#define QIB_7220_RcvHdrHead0_offset 0x00200008UL
+struct QIB_7220_RcvHdrHead0_pb {
+ pseudo_bit_t RcvHeadPointer[32];
+ pseudo_bit_t counter[16];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead0 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead0_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail0_offset 0x00200010UL
+
+#define QIB_7220_RcvEgrIndexHead0_offset 0x00200018UL
+
+#define QIB_7220_MEM_200020_offset 0x00200020UL
+
+#define QIB_7220_RcvHdrTail1_offset 0x00210000UL
+
+#define QIB_7220_RcvHdrHead1_offset 0x00210008UL
+struct QIB_7220_RcvHdrHead1_pb {
+ pseudo_bit_t RcvHeadPointer[32];
+ pseudo_bit_t counter[16];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead1 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead1_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail1_offset 0x00210010UL
+
+#define QIB_7220_RcvEgrIndexHead1_offset 0x00210018UL
+
+#define QIB_7220_MEM_210020_offset 0x00210020UL
+
+#define QIB_7220_RcvHdrTail2_offset 0x00220000UL
+
+#define QIB_7220_RcvHdrHead2_offset 0x00220008UL
+struct QIB_7220_RcvHdrHead2_pb {
+ pseudo_bit_t RcvHeadPointer[32];
+ pseudo_bit_t counter[16];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead2 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead2_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail2_offset 0x00220010UL
+
+#define QIB_7220_RcvEgrIndexHead2_offset 0x00220018UL
+
+#define QIB_7220_MEM_220020_offset 0x00220020UL
+
+#define QIB_7220_RcvHdrTail3_offset 0x00230000UL
+
+#define QIB_7220_RcvHdrHead3_offset 0x00230008UL
+struct QIB_7220_RcvHdrHead3_pb {
+ pseudo_bit_t RcvHeadPointer[32];
+ pseudo_bit_t counter[16];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead3 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead3_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail3_offset 0x00230010UL
+
+#define QIB_7220_RcvEgrIndexHead3_offset 0x00230018UL
+
+#define QIB_7220_MEM_230020_offset 0x00230020UL
+
+#define QIB_7220_RcvHdrTail4_offset 0x00240000UL
+
+#define QIB_7220_RcvHdrHead4_offset 0x00240008UL
+struct QIB_7220_RcvHdrHead4_pb {
+ pseudo_bit_t RcvHeadPointer[32];
+ pseudo_bit_t counter[16];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead4 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead4_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail4_offset 0x00240010UL
+
+#define QIB_7220_RcvEgrIndexHead4_offset 0x00240018UL
+
+#define QIB_7220_MEM_240020_offset 0x00240020UL
+
+#define QIB_7220_RcvHdrTail5_offset 0x00250000UL
+
+#define QIB_7220_RcvHdrHead5_offset 0x00250008UL
+struct QIB_7220_RcvHdrHead5_pb {
+ pseudo_bit_t RcvHeadPointer[32];
+ pseudo_bit_t counter[16];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead5 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead5_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail5_offset 0x00250010UL
+
+#define QIB_7220_RcvEgrIndexHead5_offset 0x00250018UL
+
+#define QIB_7220_MEM_250020_offset 0x00250020UL
+
+#define QIB_7220_RcvHdrTail6_offset 0x00260000UL
+
+#define QIB_7220_RcvHdrHead6_offset 0x00260008UL
+struct QIB_7220_RcvHdrHead6_pb {
+ pseudo_bit_t RcvHeadPointer[32];
+ pseudo_bit_t counter[16];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead6 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead6_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail6_offset 0x00260010UL
+
+#define QIB_7220_RcvEgrIndexHead6_offset 0x00260018UL
+
+#define QIB_7220_MEM_260020_offset 0x00260020UL
+
+#define QIB_7220_RcvHdrTail7_offset 0x00270000UL
+
+#define QIB_7220_RcvHdrHead7_offset 0x00270008UL
+struct QIB_7220_RcvHdrHead7_pb {
+ pseudo_bit_t RcvHeadPointer[32];
+ pseudo_bit_t counter[16];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead7 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead7_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail7_offset 0x00270010UL
+
+#define QIB_7220_RcvEgrIndexHead7_offset 0x00270018UL
+
+#define QIB_7220_MEM_270020_offset 0x00270020UL
+
+#define QIB_7220_RcvHdrTail8_offset 0x00280000UL
+
+#define QIB_7220_RcvHdrHead8_offset 0x00280008UL
+struct QIB_7220_RcvHdrHead8_pb {
+ pseudo_bit_t RcvHeadPointer[32];
+ pseudo_bit_t counter[16];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead8 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead8_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail8_offset 0x00280010UL
+
+#define QIB_7220_RcvEgrIndexHead8_offset 0x00280018UL
+
+#define QIB_7220_MEM_280020_offset 0x00280020UL
+
+#define QIB_7220_RcvHdrTail9_offset 0x00290000UL
+
+#define QIB_7220_RcvHdrHead9_offset 0x00290008UL
+struct QIB_7220_RcvHdrHead9_pb {
+ pseudo_bit_t RcvHeadPointer[32];
+ pseudo_bit_t counter[16];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead9 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead9_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail9_offset 0x00290010UL
+
+#define QIB_7220_RcvEgrIndexHead9_offset 0x00290018UL
+
+#define QIB_7220_MEM_290020_offset 0x00290020UL
+
+#define QIB_7220_RcvHdrTail10_offset 0x002a0000UL
+
+#define QIB_7220_RcvHdrHead10_offset 0x002a0008UL
+struct QIB_7220_RcvHdrHead10_pb {
+ pseudo_bit_t RcvHeadPointer[32];
+ pseudo_bit_t counter[16];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead10 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead10_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail10_offset 0x002a0010UL
+
+#define QIB_7220_RcvEgrIndexHead10_offset 0x002a0018UL
+
+#define QIB_7220_MEM_2A0020_offset 0x002a0020UL
+
+#define QIB_7220_RcvHdrTail11_offset 0x002b0000UL
+
+#define QIB_7220_RcvHdrHead11_offset 0x002b0008UL
+struct QIB_7220_RcvHdrHead11_pb {
+ pseudo_bit_t RcvHeadPointer[32];
+ pseudo_bit_t counter[16];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead11 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead11_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail11_offset 0x002b0010UL
+
+#define QIB_7220_RcvEgrIndexHead11_offset 0x002b0018UL
+
+#define QIB_7220_MEM_2B0020_offset 0x002b0020UL
+
+#define QIB_7220_RcvHdrTail12_offset 0x002c0000UL
+
+#define QIB_7220_RcvHdrHead12_offset 0x002c0008UL
+struct QIB_7220_RcvHdrHead12_pb {
+ pseudo_bit_t RcvHeadPointer[32];
+ pseudo_bit_t counter[16];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead12 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead12_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail12_offset 0x002c0010UL
+
+#define QIB_7220_RcvEgrIndexHead12_offset 0x002c0018UL
+
+#define QIB_7220_MEM_2C0020_offset 0x002c0020UL
+
+#define QIB_7220_RcvHdrTail13_offset 0x002d0000UL
+
+#define QIB_7220_RcvHdrHead13_offset 0x002d0008UL
+struct QIB_7220_RcvHdrHead13_pb {
+ pseudo_bit_t RcvHeadPointer[32];
+ pseudo_bit_t counter[16];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead13 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead13_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail13_offset 0x002d0010UL
+
+#define QIB_7220_RcvEgrIndexHead13_offset 0x002d0018UL
+
+#define QIB_7220_MEM_2D0020_offset 0x002d0020UL
+
+#define QIB_7220_RcvHdrTail14_offset 0x002e0000UL
+
+#define QIB_7220_RcvHdrHead14_offset 0x002e0008UL
+struct QIB_7220_RcvHdrHead14_pb {
+ pseudo_bit_t RcvHeadPointer[32];
+ pseudo_bit_t counter[16];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead14 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead14_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail14_offset 0x002e0010UL
+
+#define QIB_7220_RcvEgrIndexHead14_offset 0x002e0018UL
+
+#define QIB_7220_MEM_2E0020_offset 0x002e0020UL
+
+#define QIB_7220_RcvHdrTail15_offset 0x002f0000UL
+
+#define QIB_7220_RcvHdrHead15_offset 0x002f0008UL
+struct QIB_7220_RcvHdrHead15_pb {
+ pseudo_bit_t RcvHeadPointer[32];
+ pseudo_bit_t counter[16];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead15 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead15_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail15_offset 0x002f0010UL
+
+#define QIB_7220_RcvEgrIndexHead15_offset 0x002f0018UL
+
+#define QIB_7220_MEM_2F0020_offset 0x002f0020UL
+
+#define QIB_7220_RcvHdrTail16_offset 0x00300000UL
+
+#define QIB_7220_RcvHdrHead16_offset 0x00300008UL
+struct QIB_7220_RcvHdrHead16_pb {
+ pseudo_bit_t RcvHeadPointer[32];
+ pseudo_bit_t counter[16];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead16 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead16_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail16_offset 0x00300010UL
+
+#define QIB_7220_RcvEgrIndexHead16_offset 0x00300018UL
+
+#define QIB_7220_MEM_300020_offset 0x00300020UL
+
diff --git a/gpxe/src/drivers/infiniband/qib_genbits.pl b/gpxe/src/drivers/infiniband/qib_genbits.pl
new file mode 100644
index 00000000..9eba4da5
--- /dev/null
+++ b/gpxe/src/drivers/infiniband/qib_genbits.pl
@@ -0,0 +1,95 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of the
+# License, or any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+use strict;
+use warnings;
+
+my $offsets = {};
+my $structures = {};
+my $structure = "";
+
+while ( <> ) {
+ chomp;
+ if ( /^\#define (\S+)_OFFS (\S+)$/ ) {
+ $structure = $1;
+ $offsets->{$structure} = $2;
+ } elsif ( /^\#define ${structure}_(\S+)_LSB (\S+)$/ ) {
+ $structures->{$structure}->{$1}->{LSB} = $2;
+ } elsif ( /^\#define ${structure}_(\S+)_RMASK (\S+)$/ ) {
+ $structures->{$structure}->{$1}->{RMASK} = $2;
+ } elsif ( /^\s*$/ ) {
+ # Do nothing
+ } else {
+ print "$_\n";
+ }
+}
+
+my $data = [ map { { name => $_, offset => $offsets->{$_} }; }
+ sort { hex ( $offsets->{$a} ) <=> hex ( $offsets->{$b} ) }
+ keys %$offsets ];
+
+foreach my $datum ( @$data ) {
+ next unless exists $structures->{$datum->{name}};
+ $structure = $structures->{$datum->{name}};
+ my $fields = [ map { { name => $_, lsb => $structure->{$_}->{LSB},
+ rmask => $structure->{$_}->{RMASK} }; }
+ sort { hex ( $structure->{$a}->{LSB} ) <=>
+ hex ( $structure->{$b}->{LSB} ) }
+ keys %$structure ];
+ $datum->{fields} = $fields;
+}
+
+print "\n/* This file has been further processed by $0 */\n\n\n";
+
+foreach my $datum ( @$data ) {
+ printf "#define %s_offset 0x%08xUL\n",
+ $datum->{name}, hex ( $datum->{offset} );
+ if ( exists $datum->{fields} ) {
+ my $lsb = 0;
+ my $reserved_idx = 0;
+ printf "struct %s_pb {\n", $datum->{name};
+ foreach my $field ( @{$datum->{fields}} ) {
+ my $pad_width = ( hex ( $field->{lsb} ) - $lsb );
+ die "Inconsistent LSB/RMASK in $datum->{name}\n" if $pad_width < 0;
+ printf "\tpseudo_bit_t _unused_%u[%u];\n", $reserved_idx++, $pad_width
+ if $pad_width;
+ # Damn Perl can't cope with 64-bit hex constants
+ my $width = 0;
+ my $rmask = $field->{rmask};
+ while ( $rmask =~ /^(0x.+)f$/i ) {
+ $width += 4;
+ $rmask = $1;
+ }
+ $rmask = hex ( $rmask );
+ while ( $rmask ) {
+ $width++;
+ $rmask >>= 1;
+ }
+ printf "\tpseudo_bit_t %s[%u];\n", $field->{name}, $width;
+ $lsb += $width;
+ }
+ my $pad_width = ( 64 - $lsb );
+ die "Inconsistent LSB/RMASK in $datum->{name}\n" if $pad_width < 0;
+ printf "\tpseudo_bit_t _unused_%u[%u];\n", $reserved_idx++, $pad_width
+ if $pad_width;
+ printf "};\n";
+ printf "struct %s {\n\tPSEUDO_BIT_STRUCT ( struct %s_pb );\n};\n",
+ $datum->{name}, $datum->{name};
+ }
+ print "\n";
+}
diff --git a/gpxe/src/drivers/net/3c509.c b/gpxe/src/drivers/net/3c509.c
index 8a15aff2..ecfdec55 100644
--- a/gpxe/src/drivers/net/3c509.c
+++ b/gpxe/src/drivers/net/3c509.c
@@ -8,7 +8,7 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
-#include <io.h>
+#include <gpxe/io.h>
#include <unistd.h>
#include <gpxe/device.h>
#include <gpxe/isa.h>
diff --git a/gpxe/src/drivers/net/3c515.c b/gpxe/src/drivers/net/3c515.c
index 02f03dc7..dcfe66ba 100644
--- a/gpxe/src/drivers/net/3c515.c
+++ b/gpxe/src/drivers/net/3c515.c
@@ -640,7 +640,7 @@ static int t515_probe ( struct nic *nic, struct isapnp_device *isapnp ) {
}
}
- DBG ( "3c515 Resource configuration register 0x%lX, DCR 0x%hX.\n",
+ DBG ( "3c515 Resource configuration register 0x%X, DCR 0x%hX.\n",
inl(nic->ioaddr + 0x2002), inw(nic->ioaddr + 0x2000) );
corkscrew_found_device(nic->ioaddr, nic->irqno, CORKSCREW_ID,
options, nic);
diff --git a/gpxe/src/drivers/net/3c595.c b/gpxe/src/drivers/net/3c595.c
index 7138f936..198e12e7 100644
--- a/gpxe/src/drivers/net/3c595.c
+++ b/gpxe/src/drivers/net/3c595.c
@@ -363,7 +363,7 @@ vxgetlink(void)
if (n > 0) {
printf("/");
}
- printf(conn_tab[k].name);
+ printf("%s", conn_tab[k].name );
n++;
}
}
diff --git a/gpxe/src/drivers/net/3c90x.c b/gpxe/src/drivers/net/3c90x.c
index 8158239d..a98e6628 100644
--- a/gpxe/src/drivers/net/3c90x.c
+++ b/gpxe/src/drivers/net/3c90x.c
@@ -497,7 +497,7 @@ a3c90x_transmit(struct nic *nic __unused, const char *d, unsigned int t,
unsigned char status;
unsigned i, retries;
- tick_t ct;
+ unsigned long ct;
for (retries=0; retries < XMIT_RETRIES ; retries++)
{
@@ -543,7 +543,7 @@ a3c90x_transmit(struct nic *nic __unused, const char *d, unsigned int t,
ct = currticks();
while (!(inw(INF_3C90X.IOAddr + regCommandIntStatus_w)&0x0004) &&
- ct + 10*USECS_IN_MSEC < currticks());
+ ct + 10*1000 < currticks());
;
if (!(inw(INF_3C90X.IOAddr + regCommandIntStatus_w)&0x0004))
diff --git a/gpxe/src/drivers/net/b44.c b/gpxe/src/drivers/net/b44.c
new file mode 100644
index 00000000..4c9c8e6e
--- /dev/null
+++ b/gpxe/src/drivers/net/b44.c
@@ -0,0 +1,949 @@
+/*
+ * Copyright (c) 2008 Stefan Hajnoczi <stefanha@gmail.com>
+ * Copyright (c) 2008 Pantelis Koukousoulas <pktoss@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * This driver is a port of the b44 linux driver version 1.01
+ *
+ * Copyright (c) 2002 David S. Miller <davem@redhat.com>
+ * Copyright (c) Pekka Pietikainen <pp@ee.oulu.fi>
+ * Copyright (C) 2006 Broadcom Corporation.
+ *
+ * Some ssb bits copied from version 2.0 of the b44 driver
+ * Copyright (c) Michael Buesch
+ *
+ * Copyright (c) a lot of people too. Please respect their work.
+ */
+
+#include <errno.h>
+#include <assert.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <byteswap.h>
+#include <gpxe/io.h>
+#include <mii.h>
+#include <gpxe/iobuf.h>
+#include <gpxe/malloc.h>
+#include <gpxe/pci.h>
+#include <gpxe/netdevice.h>
+#include <gpxe/ethernet.h>
+#include <gpxe/if_ether.h>
+#include <gpxe/memmap.h>
+#include "b44.h"
+
+
+static inline int ring_next(int index)
+{
+ /* B44_RING_SIZE is a power of 2 :) */
+ return (index + 1) & (B44_RING_SIZE - 1);
+}
+
+
+/* Memory-mapped I/O wrappers */
+
+static inline u32 br32(const struct b44_private *bp, u32 reg)
+{
+ return readl(bp->regs + reg);
+}
+
+
+static inline void bw32(const struct b44_private *bp, u32 reg, u32 val)
+{
+ writel(val, bp->regs + reg);
+}
+
+
+static inline void bflush(const struct b44_private *bp, u32 reg, u32 timeout)
+{
+ readl(bp->regs + reg);
+ udelay(timeout);
+}
+
+
+#define VIRT_TO_B44(addr) ( virt_to_bus(addr) + SB_PCI_DMA )
+
+
+/**
+ * Return non-zero if the installed RAM is within
+ * the limit given and zero if it is outside.
+ * Hopefully will be removed soon.
+ */
+int phys_ram_within_limit(u64 limit)
+{
+ struct memory_map memmap;
+ struct memory_region *highest = NULL;
+ get_memmap(&memmap);
+
+ highest = &memmap.regions[memmap.count - 1];
+
+ return (highest->end < limit);
+}
+
+
+/**
+ * Ring cells waiting to be processed are between 'tx_cur' and 'pending'
+ * indexes in the ring.
+ */
+static u32 pending_tx_index(struct b44_private *bp)
+{
+ u32 pending = br32(bp, B44_DMATX_STAT);
+ pending &= DMATX_STAT_CDMASK;
+
+ pending /= sizeof(struct dma_desc);
+ return pending & (B44_RING_SIZE - 1);
+}
+
+
+/**
+ * Ring cells waiting to be processed are between 'rx_cur' and 'pending'
+ * indexes in the ring.
+ */
+static u32 pending_rx_index(struct b44_private *bp)
+{
+ u32 pending = br32(bp, B44_DMARX_STAT);
+ pending &= DMARX_STAT_CDMASK;
+
+ pending /= sizeof(struct dma_desc);
+ return pending & (B44_RING_SIZE - 1);
+}
+
+
+/**
+ * Wait until the given bit is set/cleared.
+ */
+static int b44_wait_bit(struct b44_private *bp, unsigned long reg, u32 bit,
+ unsigned long timeout, const int clear)
+{
+ unsigned long i;
+
+ for (i = 0; i < timeout; i++) {
+ u32 val = br32(bp, reg);
+
+ if (clear && !(val & bit))
+ break;
+
+ if (!clear && (val & bit))
+ break;
+
+ udelay(10);
+ }
+ if (i == timeout) {
+ return -ENODEV;
+ }
+ return 0;
+}
+
+
+/*
+ * Sonics Silicon Backplane support. SSB is a mini-bus interconnecting
+ * so-called IP Cores. One of those cores implements the Fast Ethernet
+ * functionality and another one the PCI engine.
+ *
+ * You need to switch to the core you want to talk to before actually
+ * sending commands.
+ *
+ * See: http://bcm-v4.sipsolutions.net/Backplane for (reverse-engineered)
+ * specs.
+ */
+
+static inline u32 ssb_get_core_rev(struct b44_private *bp)
+{
+ return (br32(bp, B44_SBIDHIGH) & SBIDHIGH_RC_MASK);
+}
+
+
+static inline int ssb_is_core_up(struct b44_private *bp)
+{
+ return ((br32(bp, B44_SBTMSLOW) & (SSB_CORE_DOWN | SBTMSLOW_CLOCK))
+ == SBTMSLOW_CLOCK);
+}
+
+
+static u32 ssb_pci_setup(struct b44_private *bp, u32 cores)
+{
+ u32 bar_orig, pci_rev, val;
+
+ pci_read_config_dword(bp->pci, SSB_BAR0_WIN, &bar_orig);
+ pci_write_config_dword(bp->pci, SSB_BAR0_WIN,
+ BCM4400_PCI_CORE_ADDR);
+ pci_rev = ssb_get_core_rev(bp);
+
+ val = br32(bp, B44_SBINTVEC);
+ val |= cores;
+ bw32(bp, B44_SBINTVEC, val);
+
+ val = br32(bp, SSB_PCI_TRANS_2);
+ val |= SSB_PCI_PREF | SSB_PCI_BURST;
+ bw32(bp, SSB_PCI_TRANS_2, val);
+
+ pci_write_config_dword(bp->pci, SSB_BAR0_WIN, bar_orig);
+
+ return pci_rev;
+}
+
+
+static void ssb_core_disable(struct b44_private *bp)
+{
+ if (br32(bp, B44_SBTMSLOW) & SBTMSLOW_RESET)
+ return;
+
+ bw32(bp, B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_CLOCK));
+ b44_wait_bit(bp, B44_SBTMSLOW, SBTMSLOW_REJECT, 100000, 0);
+ b44_wait_bit(bp, B44_SBTMSHIGH, SBTMSHIGH_BUSY, 100000, 1);
+
+ bw32(bp, B44_SBTMSLOW, (SBTMSLOW_FGC | SBTMSLOW_CLOCK |
+ SSB_CORE_DOWN));
+ bflush(bp, B44_SBTMSLOW, 1);
+
+ bw32(bp, B44_SBTMSLOW, SSB_CORE_DOWN);
+ bflush(bp, B44_SBTMSLOW, 1);
+}
+
+
+static void ssb_core_reset(struct b44_private *bp)
+{
+ u32 val;
+ const u32 mask = (SBTMSLOW_CLOCK | SBTMSLOW_FGC | SBTMSLOW_RESET);
+
+ ssb_core_disable(bp);
+
+ bw32(bp, B44_SBTMSLOW, mask);
+ bflush(bp, B44_SBTMSLOW, 1);
+
+ /* Clear SERR if set, this is a hw bug workaround. */
+ if (br32(bp, B44_SBTMSHIGH) & SBTMSHIGH_SERR)
+ bw32(bp, B44_SBTMSHIGH, 0);
+
+ val = br32(bp, B44_SBIMSTATE);
+ if (val & (SBIMSTATE_BAD)) {
+ bw32(bp, B44_SBIMSTATE, val & ~SBIMSTATE_BAD);
+ }
+
+ bw32(bp, B44_SBTMSLOW, (SBTMSLOW_CLOCK | SBTMSLOW_FGC));
+ bflush(bp, B44_SBTMSLOW, 1);
+
+ bw32(bp, B44_SBTMSLOW, (SBTMSLOW_CLOCK));
+ bflush(bp, B44_SBTMSLOW, 1);
+}
+
+
+/*
+ * Driver helper functions
+ */
+
+/*
+ * Chip reset provides power to the b44 MAC & PCI cores, which
+ * is necessary for MAC register access. We only do a partial
+ * reset in case of transmit/receive errors (ISTAT_ERRORS) to
+ * avoid the chip being hung for an unnecessary long time in
+ * this case.
+ *
+ * Called-by: b44_close, b44_halt, b44_inithw(b44_open), b44_probe
+ */
+static void b44_chip_reset(struct b44_private *bp, int reset_kind)
+{
+ if (ssb_is_core_up(bp)) {
+ bw32(bp, B44_RCV_LAZY, 0);
+
+ bw32(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE);
+
+ b44_wait_bit(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE, 200, 1);
+
+ bw32(bp, B44_DMATX_CTRL, 0);
+
+ bp->tx_dirty = bp->tx_cur = 0;
+
+ if (br32(bp, B44_DMARX_STAT) & DMARX_STAT_EMASK)
+ b44_wait_bit(bp, B44_DMARX_STAT, DMARX_STAT_SIDLE,
+ 100, 0);
+
+ bw32(bp, B44_DMARX_CTRL, 0);
+
+ bp->rx_cur = 0;
+ } else {
+ ssb_pci_setup(bp, SBINTVEC_ENET0);
+ }
+
+ ssb_core_reset(bp);
+
+ /* Don't enable PHY if we are only doing a partial reset. */
+ if (reset_kind == B44_CHIP_RESET_PARTIAL)
+ return;
+
+ /* Make PHY accessible. */
+ bw32(bp, B44_MDIO_CTRL,
+ (MDIO_CTRL_PREAMBLE | (0x0d & MDIO_CTRL_MAXF_MASK)));
+ bflush(bp, B44_MDIO_CTRL, 1);
+
+ /* Enable internal or external PHY */
+ if (!(br32(bp, B44_DEVCTRL) & DEVCTRL_IPP)) {
+ bw32(bp, B44_ENET_CTRL, ENET_CTRL_EPSEL);
+ bflush(bp, B44_ENET_CTRL, 1);
+ } else {
+ u32 val = br32(bp, B44_DEVCTRL);
+ if (val & DEVCTRL_EPR) {
+ bw32(bp, B44_DEVCTRL, (val & ~DEVCTRL_EPR));
+ bflush(bp, B44_DEVCTRL, 100);
+ }
+ }
+}
+
+
+/**
+ * called by b44_poll in the error path
+ */
+static void b44_halt(struct b44_private *bp)
+{
+ /* disable ints */
+ bw32(bp, B44_IMASK, 0);
+ bflush(bp, B44_IMASK, 1);
+
+ DBG("b44: powering down PHY\n");
+ bw32(bp, B44_MAC_CTRL, MAC_CTRL_PHY_PDOWN);
+
+ /*
+ * Now reset the chip, but without enabling
+ * the MAC&PHY part of it.
+ * This has to be done _after_ we shut down the PHY
+ */
+ b44_chip_reset(bp, B44_CHIP_RESET_PARTIAL);
+}
+
+
+
+/*
+ * Called at device open time to get the chip ready for
+ * packet processing.
+ *
+ * Called-by: b44_open
+ */
+static void b44_init_hw(struct b44_private *bp, int reset_kind)
+{
+ u32 val;
+#define CTRL_MASK (DMARX_CTRL_ENABLE | (RX_PKT_OFFSET << DMARX_CTRL_ROSHIFT))
+
+ b44_chip_reset(bp, B44_CHIP_RESET_FULL);
+ if (reset_kind == B44_FULL_RESET) {
+ b44_phy_reset(bp);
+ }
+
+ /* Enable CRC32, set proper LED modes and power on PHY */
+ bw32(bp, B44_MAC_CTRL, MAC_CTRL_CRC32_ENAB | MAC_CTRL_PHY_LEDCTRL);
+ bw32(bp, B44_RCV_LAZY, (1 << RCV_LAZY_FC_SHIFT));
+
+ /* This sets the MAC address too. */
+ b44_set_rx_mode(bp->netdev);
+
+ /* MTU + eth header + possible VLAN tag + struct rx_header */
+ bw32(bp, B44_RXMAXLEN, B44_MAX_MTU + ETH_HLEN + 8 + RX_HEADER_LEN);
+ bw32(bp, B44_TXMAXLEN, B44_MAX_MTU + ETH_HLEN + 8 + RX_HEADER_LEN);
+
+ bw32(bp, B44_TX_HIWMARK, TX_HIWMARK_DEFLT);
+ if (reset_kind == B44_PARTIAL_RESET) {
+ bw32(bp, B44_DMARX_CTRL, CTRL_MASK);
+ } else {
+ bw32(bp, B44_DMATX_CTRL, DMATX_CTRL_ENABLE);
+ bw32(bp, B44_DMATX_ADDR, VIRT_TO_B44(bp->tx));
+
+ bw32(bp, B44_DMARX_CTRL, CTRL_MASK);
+ bw32(bp, B44_DMARX_ADDR, VIRT_TO_B44(bp->rx));
+ bw32(bp, B44_DMARX_PTR, B44_RX_RING_LEN_BYTES);
+
+ bw32(bp, B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ);
+ }
+
+ val = br32(bp, B44_ENET_CTRL);
+ bw32(bp, B44_ENET_CTRL, (val | ENET_CTRL_ENABLE));
+#undef CTRL_MASK
+}
+
+
+/*** Management of ring descriptors ***/
+
+
+static void b44_populate_rx_descriptor(struct b44_private *bp, u32 idx)
+{
+ struct rx_header *rh;
+ u32 ctrl, addr;
+
+ rh = bp->rx_iobuf[idx]->data;
+ rh->len = 0;
+ rh->flags = 0;
+ ctrl = DESC_CTRL_LEN & (RX_PKT_BUF_SZ - RX_PKT_OFFSET);
+ if (idx == B44_RING_LAST) {
+ ctrl |= DESC_CTRL_EOT;
+ }
+ addr = VIRT_TO_B44(bp->rx_iobuf[idx]->data);
+
+ bp->rx[idx].ctrl = cpu_to_le32(ctrl);
+ bp->rx[idx].addr = cpu_to_le32(addr);
+ bw32(bp, B44_DMARX_PTR, idx * sizeof(struct dma_desc));
+}
+
+
+/*
+ * Refill RX ring descriptors with buffers. This is needed
+ * because during rx we are passing ownership of descriptor
+ * buffers to the network stack.
+ */
+static void b44_rx_refill(struct b44_private *bp, u32 pending)
+{
+ u32 i;
+
+ // skip pending
+ for (i = pending + 1; i != bp->rx_cur; i = ring_next(i)) {
+ if (bp->rx_iobuf[i] != NULL)
+ continue;
+
+ bp->rx_iobuf[i] = alloc_iob(RX_PKT_BUF_SZ);
+ if (!bp->rx_iobuf[i]) {
+ DBG("Refill rx ring failed!!\n");
+ break;
+ }
+
+ b44_populate_rx_descriptor(bp, i);
+ }
+}
+
+
+static void b44_free_rx_ring(struct b44_private *bp)
+{
+ u32 i;
+
+ if (bp->rx) {
+ for (i = 0; i < B44_RING_SIZE; i++) {
+ free_iob(bp->rx_iobuf[i]);
+ bp->rx_iobuf[i] = NULL;
+ }
+ free_dma(bp->rx, B44_RX_RING_LEN_BYTES);
+ bp->rx = NULL;
+ }
+}
+
+
+static int b44_init_rx_ring(struct b44_private *bp)
+{
+ b44_free_rx_ring(bp);
+
+ bp->rx = malloc_dma(B44_RX_RING_LEN_BYTES, B44_DMA_ALIGNMENT);
+ if (!bp->rx)
+ return -ENOMEM;
+
+ memset(bp->rx_iobuf, 0, sizeof(bp->rx_iobuf));
+
+ bp->rx_iobuf[0] = alloc_iob(RX_PKT_BUF_SZ);
+ b44_populate_rx_descriptor(bp, 0);
+ b44_rx_refill(bp, 0);
+
+ DBG("Init RX rings: rx=0x%08lx\n", VIRT_TO_B44(bp->rx));
+ return 0;
+}
+
+
+static void b44_free_tx_ring(struct b44_private *bp)
+{
+ if (bp->tx) {
+ free_dma(bp->tx, B44_TX_RING_LEN_BYTES);
+ bp->tx = NULL;
+ }
+}
+
+
+static int b44_init_tx_ring(struct b44_private *bp)
+{
+ b44_free_tx_ring(bp);
+
+ bp->tx = malloc_dma(B44_TX_RING_LEN_BYTES, B44_DMA_ALIGNMENT);
+ if (!bp->tx)
+ return -ENOMEM;
+
+ memset(bp->tx, 0, B44_TX_RING_LEN_BYTES);
+ memset(bp->tx_iobuf, 0, sizeof(bp->tx_iobuf));
+
+ DBG("Init TX rings: tx=0x%08lx\n", VIRT_TO_B44(bp->tx));
+ return 0;
+}
+
+
+/*** Interaction with the PHY ***/
+
+
+static int b44_phy_read(struct b44_private *bp, int reg, u32 * val)
+{
+ int err;
+
+ u32 arg1 = (MDIO_OP_READ << MDIO_DATA_OP_SHIFT);
+ u32 arg2 = (bp->phy_addr << MDIO_DATA_PMD_SHIFT);
+ u32 arg3 = (reg << MDIO_DATA_RA_SHIFT);
+ u32 arg4 = (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT);
+ u32 argv = arg1 | arg2 | arg3 | arg4;
+
+ bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII);
+ bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START | argv));
+ err = b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0);
+ *val = br32(bp, B44_MDIO_DATA) & MDIO_DATA_DATA;
+
+ return err;
+}
+
+
+static int b44_phy_write(struct b44_private *bp, int reg, u32 val)
+{
+ u32 arg1 = (MDIO_OP_WRITE << MDIO_DATA_OP_SHIFT);
+ u32 arg2 = (bp->phy_addr << MDIO_DATA_PMD_SHIFT);
+ u32 arg3 = (reg << MDIO_DATA_RA_SHIFT);
+ u32 arg4 = (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT);
+ u32 arg5 = (val & MDIO_DATA_DATA);
+ u32 argv = arg1 | arg2 | arg3 | arg4 | arg5;
+
+
+ bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII);
+ bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START | argv));
+ return b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0);
+}
+
+
+static int b44_phy_reset(struct b44_private *bp)
+{
+ u32 val;
+ int err;
+
+ err = b44_phy_write(bp, MII_BMCR, BMCR_RESET);
+ if (err)
+ return err;
+
+ udelay(100);
+ err = b44_phy_read(bp, MII_BMCR, &val);
+ if (!err) {
+ if (val & BMCR_RESET) {
+ return -ENODEV;
+ }
+ }
+
+ return 0;
+}
+
+
+/*
+ * The BCM44xx CAM (Content Addressable Memory) stores the MAC
+ * and PHY address.
+ */
+static void b44_cam_write(struct b44_private *bp, unsigned char *data,
+ int index)
+{
+ u32 val;
+
+ val = ((u32) data[2]) << 24;
+ val |= ((u32) data[3]) << 16;
+ val |= ((u32) data[4]) << 8;
+ val |= ((u32) data[5]) << 0;
+ bw32(bp, B44_CAM_DATA_LO, val);
+
+
+ val = (CAM_DATA_HI_VALID |
+ (((u32) data[0]) << 8) | (((u32) data[1]) << 0));
+
+ bw32(bp, B44_CAM_DATA_HI, val);
+
+ val = CAM_CTRL_WRITE | (index << CAM_CTRL_INDEX_SHIFT);
+ bw32(bp, B44_CAM_CTRL, val);
+
+ b44_wait_bit(bp, B44_CAM_CTRL, CAM_CTRL_BUSY, 100, 1);
+}
+
+
+static void b44_set_mac_addr(struct b44_private *bp)
+{
+ u32 val;
+ bw32(bp, B44_CAM_CTRL, 0);
+ b44_cam_write(bp, bp->netdev->ll_addr, 0);
+ val = br32(bp, B44_CAM_CTRL);
+ bw32(bp, B44_CAM_CTRL, val | CAM_CTRL_ENABLE);
+}
+
+
+/* Read 128-bytes of EEPROM. */
+static void b44_read_eeprom(struct b44_private *bp, u8 * data)
+{
+ long i;
+ u16 *ptr = (u16 *) data;
+
+ for (i = 0; i < 128; i += 2)
+ ptr[i / 2] = cpu_to_le16(readw(bp->regs + 4096 + i));
+}
+
+
+static void b44_load_mac_and_phy_addr(struct b44_private *bp)
+{
+ u8 eeprom[128];
+
+ /* Load MAC address, note byteswapping */
+ b44_read_eeprom(bp, &eeprom[0]);
+ bp->netdev->ll_addr[0] = eeprom[79];
+ bp->netdev->ll_addr[1] = eeprom[78];
+ bp->netdev->ll_addr[2] = eeprom[81];
+ bp->netdev->ll_addr[3] = eeprom[80];
+ bp->netdev->ll_addr[4] = eeprom[83];
+ bp->netdev->ll_addr[5] = eeprom[82];
+
+ /* Load PHY address */
+ bp->phy_addr = eeprom[90] & 0x1f;
+}
+
+
+static void b44_set_rx_mode(struct net_device *netdev)
+{
+ struct b44_private *bp = netdev_priv(netdev);
+ unsigned char zero[6] = { 0, 0, 0, 0, 0, 0 };
+ u32 val;
+ int i;
+
+ val = br32(bp, B44_RXCONFIG);
+ val &= ~RXCONFIG_PROMISC;
+ val |= RXCONFIG_ALLMULTI;
+
+ b44_set_mac_addr(bp);
+
+ for (i = 1; i < 64; i++)
+ b44_cam_write(bp, zero, i);
+
+ bw32(bp, B44_RXCONFIG, val);
+ val = br32(bp, B44_CAM_CTRL);
+ bw32(bp, B44_CAM_CTRL, val | CAM_CTRL_ENABLE);
+}
+
+
+/*** Implementation of gPXE driver callbacks ***/
+
+/**
+ * Probe device
+ *
+ * @v pci PCI device
+ * @v id Matching entry in ID table
+ * @ret rc Return status code
+ */
+static int b44_probe(struct pci_device *pci, const struct pci_device_id *id)
+{
+ struct net_device *netdev;
+ struct b44_private *bp;
+ int rc;
+
+ /*
+ * Bail out if more than 1GB of physical RAM is installed.
+ * This limitation will be removed later when dma mapping
+ * is merged into mainline.
+ */
+ if (!phys_ram_within_limit(B44_30BIT_DMA_MASK)) {
+ DBG("Sorry, this version of the driver does not\n"
+ "support systems with more than 1GB of RAM.\n");
+ return -ENOMEM;
+ }
+
+ /* Set up netdev */
+ netdev = alloc_etherdev(sizeof(*bp));
+ if (!netdev)
+ return -ENOMEM;
+
+ netdev_init(netdev, &b44_operations);
+ pci_set_drvdata(pci, netdev);
+ netdev->dev = &pci->dev;
+
+ /* Set up private data */
+ bp = netdev_priv(netdev);
+ memset(bp, 0, sizeof(*bp));
+ bp->netdev = netdev;
+ bp->pci = pci;
+
+ /* Map device registers */
+ bp->regs = ioremap(pci->membase, B44_REGS_SIZE);
+ if (!bp->regs) {
+ netdev_put(netdev);
+ return -ENOMEM;
+ }
+
+ /* Enable PCI bus mastering */
+ adjust_pci_device(pci);
+
+ b44_load_mac_and_phy_addr(bp);
+
+ /* Link management currently not implemented */
+ netdev_link_up(netdev);
+
+ rc = register_netdev(netdev);
+ if (rc != 0) {
+ iounmap(bp->regs);
+ netdev_put(netdev);
+ return rc;
+ }
+
+ b44_chip_reset(bp, B44_CHIP_RESET_FULL);
+
+ DBG("b44 %s (%04x:%04x) regs=%p MAC=%s\n", id->name, id->vendor,
+ id->device, bp->regs, eth_ntoa(netdev->ll_addr));
+
+ return 0;
+}
+
+
+/**
+ * Remove device
+ *
+ * @v pci PCI device
+ */
+static void b44_remove(struct pci_device *pci)
+{
+ struct net_device *netdev = pci_get_drvdata(pci);
+ struct b44_private *bp = netdev_priv(netdev);
+
+ ssb_core_disable(bp);
+ unregister_netdev(netdev);
+ iounmap(bp->regs);
+ netdev_nullify(netdev);
+ netdev_put(netdev);
+}
+
+
+/** Enable or disable interrupts
+ *
+ * @v netdev Network device
+ * @v enable Interrupts should be enabled
+ */
+static void b44_irq(struct net_device *netdev, int enable)
+{
+ struct b44_private *bp = netdev_priv(netdev);
+
+ /* Interrupt mask specifies which events generate interrupts */
+ bw32(bp, B44_IMASK, enable ? IMASK_DEF : IMASK_DISABLE);
+}
+
+
+/** Open network device
+ *
+ * @v netdev Network device
+ * @ret rc Return status code
+ */
+static int b44_open(struct net_device *netdev)
+{
+ struct b44_private *bp = netdev_priv(netdev);
+ int rc;
+
+ rc = b44_init_tx_ring(bp);
+ if (rc != 0)
+ return rc;
+
+ rc = b44_init_rx_ring(bp);
+ if (rc != 0)
+ return rc;
+
+ b44_init_hw(bp, B44_FULL_RESET);
+
+ /* Disable interrupts */
+ b44_irq(netdev, 0);
+
+ return 0;
+}
+
+
+/** Close network device
+ *
+ * @v netdev Network device
+ */
+static void b44_close(struct net_device *netdev)
+{
+ struct b44_private *bp = netdev_priv(netdev);
+
+ b44_chip_reset(bp, B44_FULL_RESET);
+ b44_free_tx_ring(bp);
+ b44_free_rx_ring(bp);
+}
+
+
+/** Transmit packet
+ *
+ * @v netdev Network device
+ * @v iobuf I/O buffer
+ * @ret rc Return status code
+ */
+static int b44_transmit(struct net_device *netdev, struct io_buffer *iobuf)
+{
+ struct b44_private *bp = netdev_priv(netdev);
+ u32 cur = bp->tx_cur;
+ u32 ctrl;
+
+ /* Check for TX ring overflow */
+ if (bp->tx[cur].ctrl) {
+ DBG("tx overflow\n");
+ return -ENOBUFS;
+ }
+
+ /* Will call netdev_tx_complete() on the iobuf later */
+ bp->tx_iobuf[cur] = iobuf;
+
+ /* Set up TX descriptor */
+ ctrl = (iob_len(iobuf) & DESC_CTRL_LEN) |
+ DESC_CTRL_IOC | DESC_CTRL_SOF | DESC_CTRL_EOF;
+
+ if (cur == B44_RING_LAST)
+ ctrl |= DESC_CTRL_EOT;
+
+ bp->tx[cur].ctrl = cpu_to_le32(ctrl);
+ bp->tx[cur].addr = cpu_to_le32(VIRT_TO_B44(iobuf->data));
+
+ /* Update next available descriptor index */
+ cur = ring_next(cur);
+ bp->tx_cur = cur;
+ wmb();
+
+ /* Tell card that a new TX descriptor is ready */
+ bw32(bp, B44_DMATX_PTR, cur * sizeof(struct dma_desc));
+ return 0;
+}
+
+
+/** Recycles sent TX descriptors and notifies network stack
+ *
+ * @v bp Driver state
+ */
+static void b44_tx_complete(struct b44_private *bp)
+{
+ u32 cur, i;
+
+ cur = pending_tx_index(bp);
+
+ for (i = bp->tx_dirty; i != cur; i = ring_next(i)) {
+ /* Free finished frame */
+ netdev_tx_complete(bp->netdev, bp->tx_iobuf[i]);
+ bp->tx_iobuf[i] = NULL;
+
+ /* Clear TX descriptor */
+ bp->tx[i].ctrl = 0;
+ bp->tx[i].addr = 0;
+ }
+ bp->tx_dirty = cur;
+}
+
+
+static void b44_process_rx_packets(struct b44_private *bp)
+{
+ struct io_buffer *iob; /* received data */
+ struct rx_header *rh;
+ u32 pending, i;
+ u16 len;
+
+ pending = pending_rx_index(bp);
+
+ for (i = bp->rx_cur; i != pending; i = ring_next(i)) {
+ iob = bp->rx_iobuf[i];
+ if (iob == NULL)
+ break;
+
+ rh = iob->data;
+ len = le16_to_cpu(rh->len);
+
+ /*
+ * Guard against incompletely written RX descriptors.
+ * Without this, things can get really slow!
+ */
+ if (len == 0)
+ break;
+
+ /* Discard CRC that is generated by the card */
+ len -= 4;
+
+ /* Check for invalid packets and errors */
+ if (len > RX_PKT_BUF_SZ - RX_PKT_OFFSET ||
+ (rh->flags & cpu_to_le16(RX_FLAG_ERRORS))) {
+ DBG("rx error len=%d flags=%04x\n", len,
+ cpu_to_le16(rh->flags));
+ rh->len = 0;
+ rh->flags = 0;
+ netdev_rx_err(bp->netdev, iob, -EINVAL);
+ continue;
+ }
+
+ /* Clear RX descriptor */
+ rh->len = 0;
+ rh->flags = 0;
+ bp->rx_iobuf[i] = NULL;
+
+ /* Hand off the IO buffer to the network stack */
+ iob_reserve(iob, RX_PKT_OFFSET);
+ iob_put(iob, len);
+ netdev_rx(bp->netdev, iob);
+ }
+ bp->rx_cur = i;
+ b44_rx_refill(bp, pending_rx_index(bp));
+}
+
+
+/** Poll for completed and received packets
+ *
+ * @v netdev Network device
+ */
+static void b44_poll(struct net_device *netdev)
+{
+ struct b44_private *bp = netdev_priv(netdev);
+ u32 istat;
+
+ /* Interrupt status */
+ istat = br32(bp, B44_ISTAT);
+ istat &= IMASK_DEF; /* only the events we care about */
+
+ if (!istat)
+ return;
+ if (istat & ISTAT_TX)
+ b44_tx_complete(bp);
+ if (istat & ISTAT_RX)
+ b44_process_rx_packets(bp);
+ if (istat & ISTAT_ERRORS) {
+ DBG("b44 error istat=0x%08x\n", istat);
+
+ /* Reset B44 core partially to avoid long waits */
+ b44_irq(bp->netdev, 0);
+ b44_halt(bp);
+ b44_init_tx_ring(bp);
+ b44_init_rx_ring(bp);
+ b44_init_hw(bp, B44_FULL_RESET_SKIP_PHY);
+ }
+
+ /* Acknowledge interrupt */
+ bw32(bp, B44_ISTAT, 0);
+ bflush(bp, B44_ISTAT, 1);
+}
+
+
+static struct net_device_operations b44_operations = {
+ .open = b44_open,
+ .close = b44_close,
+ .transmit = b44_transmit,
+ .poll = b44_poll,
+ .irq = b44_irq,
+};
+
+
+static struct pci_device_id b44_nics[] = {
+ PCI_ROM(0x14e4, 0x4401, "BCM4401", "BCM4401"),
+ PCI_ROM(0x14e4, 0x170c, "BCM4401-B0", "BCM4401-B0"),
+ PCI_ROM(0x14e4, 0x4402, "BCM4401-B1", "BCM4401-B1"),
+};
+
+
+struct pci_driver b44_driver __pci_driver = {
+ .ids = b44_nics,
+ .id_count = sizeof b44_nics / sizeof b44_nics[0],
+ .probe = b44_probe,
+ .remove = b44_remove,
+};
diff --git a/gpxe/src/drivers/net/b44.h b/gpxe/src/drivers/net/b44.h
new file mode 100644
index 00000000..fb36757f
--- /dev/null
+++ b/gpxe/src/drivers/net/b44.h
@@ -0,0 +1,467 @@
+/*
+ * Copyright (c) 2008 Stefan Hajnoczi <stefanha@gmail.com>
+ * Copyright (c) 2008 Pantelis Koukousoulas <pktoss@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * This driver is a port of the b44 linux driver version 1.01
+ *
+ * Copyright (c) 2002 David S. Miller <davem@redhat.com>
+ * Copyright (c) Pekka Pietikainen <pp@ee.oulu.fi>
+ * Copyright (C) 2006 Broadcom Corporation.
+ *
+ * Some ssb bits copied from version 2.0 of the b44 driver
+ * Copyright (c) Michael Buesch
+ *
+ * Copyright (c) a lot of people too. Please respect their work.
+ */
+#ifndef _B44_H
+#define _B44_H
+
+/* BCM44xx Register layout */
+#define B44_DEVCTRL 0x0000UL /* Device Control */
+#define DEVCTRL_MPM 0x00000040 /* MP PME Enable (B0 only) */
+#define DEVCTRL_PFE 0x00000080 /* Pattern Filtering Enable */
+#define DEVCTRL_IPP 0x00000400 /* Internal EPHY Present */
+#define DEVCTRL_EPR 0x00008000 /* EPHY Reset */
+#define DEVCTRL_PME 0x00001000 /* PHY Mode Enable */
+#define DEVCTRL_PMCE 0x00002000 /* PHY Mode Clocks Enable */
+#define DEVCTRL_PADDR 0x0007c000 /* PHY Address */
+#define DEVCTRL_PADDR_SHIFT 18
+#define B44_BIST_STAT 0x000CUL /* Built-In Self-Test Status */
+#define B44_WKUP_LEN 0x0010UL /* Wakeup Length */
+#define WKUP_LEN_P0_MASK 0x0000007f /* Pattern 0 */
+#define WKUP_LEN_D0 0x00000080
+#define WKUP_LEN_P1_MASK 0x00007f00 /* Pattern 1 */
+#define WKUP_LEN_P1_SHIFT 8
+#define WKUP_LEN_D1 0x00008000
+#define WKUP_LEN_P2_MASK 0x007f0000 /* Pattern 2 */
+#define WKUP_LEN_P2_SHIFT 16
+#define WKUP_LEN_D2 0x00000000
+#define WKUP_LEN_P3_MASK 0x7f000000 /* Pattern 3 */
+#define WKUP_LEN_P3_SHIFT 24
+#define WKUP_LEN_D3 0x80000000
+#define WKUP_LEN_DISABLE 0x80808080
+#define WKUP_LEN_ENABLE_TWO 0x80800000
+#define WKUP_LEN_ENABLE_THREE 0x80000000
+#define B44_ISTAT 0x0020UL /* Interrupt Status */
+#define ISTAT_LS 0x00000020 /* Link Change (B0 only) */
+#define ISTAT_PME 0x00000040 /* Power Management Event */
+#define ISTAT_TO 0x00000080 /* General Purpose Timeout */
+#define ISTAT_DSCE 0x00000400 /* Descriptor Error */
+#define ISTAT_DATAE 0x00000800 /* Data Error */
+#define ISTAT_DPE 0x00001000 /* Descr. Protocol Error */
+#define ISTAT_RDU 0x00002000 /* Receive Descr. Underflow */
+#define ISTAT_RFO 0x00004000 /* Receive FIFO Overflow */
+#define ISTAT_TFU 0x00008000 /* Transmit FIFO Underflow */
+#define ISTAT_RX 0x00010000 /* RX Interrupt */
+#define ISTAT_TX 0x01000000 /* TX Interrupt */
+#define ISTAT_EMAC 0x04000000 /* EMAC Interrupt */
+#define ISTAT_MII_WRITE 0x08000000 /* MII Write Interrupt */
+#define ISTAT_MII_READ 0x10000000 /* MII Read Interrupt */
+#define ISTAT_ERRORS (ISTAT_DSCE|ISTAT_DATAE|ISTAT_DPE|\
+ ISTAT_RDU|ISTAT_RFO|ISTAT_TFU)
+#define B44_IMASK 0x0024UL /* Interrupt Mask */
+#define IMASK_DEF (ISTAT_ERRORS | ISTAT_RX | ISTAT_TX)
+#define IMASK_DISABLE 0
+#define B44_GPTIMER 0x0028UL /* General Purpose Timer */
+#define B44_ADDR_LO 0x0088UL /* ENET Address Lo (B0 only) */
+#define B44_ADDR_HI 0x008CUL /* ENET Address Hi (B0 only) */
+#define B44_FILT_ADDR 0x0090UL /* ENET Filter Address */
+#define B44_FILT_DATA 0x0094UL /* ENET Filter Data */
+#define B44_TXBURST 0x00A0UL /* TX Max Burst Length */
+#define B44_RXBURST 0x00A4UL /* RX Max Burst Length */
+#define B44_MAC_CTRL 0x00A8UL /* MAC Control */
+#define MAC_CTRL_CRC32_ENAB 0x00000001 /* CRC32 Generation Enable */
+#define MAC_CTRL_PHY_PDOWN 0x00000004 /* Onchip EPHY Powerdown */
+#define MAC_CTRL_PHY_EDET 0x00000008 /* Onchip EPHY Energy Detected*/
+#define MAC_CTRL_PHY_LEDCTRL 0x000000e0 /* Onchip EPHY LED Control */
+#define MAC_CTRL_PHY_LEDCTRL_SHIFT 5
+#define B44_MAC_FLOW 0x00ACUL /* MAC Flow Control */
+#define MAC_FLOW_RX_HI_WATER 0x000000ff /* Receive FIFO HI Water Mark */
+#define MAC_FLOW_PAUSE_ENAB 0x00008000 /* Enbl Pause Frm Generation */
+#define B44_RCV_LAZY 0x0100UL /* Lazy Interrupt Control */
+#define RCV_LAZY_TO_MASK 0x00ffffff /* Timeout */
+#define RCV_LAZY_FC_MASK 0xff000000 /* Frame Count */
+#define RCV_LAZY_FC_SHIFT 24
+#define B44_DMATX_CTRL 0x0200UL /* DMA TX Control */
+#define DMATX_CTRL_ENABLE 0x00000001 /* Enable */
+#define DMATX_CTRL_SUSPEND 0x00000002 /* Suepend Request */
+#define DMATX_CTRL_LPBACK 0x00000004 /* Loopback Enable */
+#define DMATX_CTRL_FAIRPRIOR 0x00000008 /* Fair Priority */
+#define DMATX_CTRL_FLUSH 0x00000010 /* Flush Request */
+#define B44_DMATX_ADDR 0x0204UL /* DMA TX Descriptor Ring Addr */
+#define B44_DMATX_PTR 0x0208UL /* DMA TX Last Posted Desc. */
+#define B44_DMATX_STAT 0x020CUL /* DMA TX Cur Actve Desc. + Sts */
+#define DMATX_STAT_CDMASK 0x00000fff /* Current Descriptor Mask */
+#define DMATX_STAT_SMASK 0x0000f000 /* State Mask */
+#define DMATX_STAT_SDISABLED 0x00000000 /* State Disabled */
+#define DMATX_STAT_SACTIVE 0x00001000 /* State Active */
+#define DMATX_STAT_SIDLE 0x00002000 /* State Idle Wait */
+#define DMATX_STAT_SSTOPPED 0x00003000 /* State Stopped */
+#define DMATX_STAT_SSUSP 0x00004000 /* State Suspend Pending */
+#define DMATX_STAT_EMASK 0x000f0000 /* Error Mask */
+#define DMATX_STAT_ENONE 0x00000000 /* Error None */
+#define DMATX_STAT_EDPE 0x00010000 /* Error Desc. Protocol Error */
+#define DMATX_STAT_EDFU 0x00020000 /* Error Data FIFO Underrun */
+#define DMATX_STAT_EBEBR 0x00030000 /* Bus Error on Buffer Read */
+#define DMATX_STAT_EBEDA 0x00040000 /* Bus Error on Desc. Access */
+#define DMATX_STAT_FLUSHED 0x00100000 /* Flushed */
+#define B44_DMARX_CTRL 0x0210UL /* DMA RX Control */
+#define DMARX_CTRL_ENABLE 0x00000001 /* Enable */
+#define DMARX_CTRL_ROMASK 0x000000fe /* Receive Offset Mask */
+#define DMARX_CTRL_ROSHIFT 1 /* Receive Offset Shift */
+#define B44_DMARX_ADDR 0x0214UL /* DMA RX Descriptor Ring Addr */
+#define B44_DMARX_PTR 0x0218UL /* DMA RX Last Posted Desc */
+#define B44_DMARX_STAT 0x021CUL /* Cur Active Desc. + Status */
+#define DMARX_STAT_CDMASK 0x00000fff /* Current Descriptor Mask */
+#define DMARX_STAT_SMASK 0x0000f000 /* State Mask */
+#define DMARX_STAT_SDISABLED 0x00000000 /* State Disbaled */
+#define DMARX_STAT_SACTIVE 0x00001000 /* State Active */
+#define DMARX_STAT_SIDLE 0x00002000 /* State Idle Wait */
+#define DMARX_STAT_SSTOPPED 0x00003000 /* State Stopped */
+#define DMARX_STAT_EMASK 0x000f0000 /* Error Mask */
+#define DMARX_STAT_ENONE 0x00000000 /* Error None */
+#define DMARX_STAT_EDPE 0x00010000 /* Error Desc. Protocol Error */
+#define DMARX_STAT_EDFO 0x00020000 /* Error Data FIFO Overflow */
+#define DMARX_STAT_EBEBW 0x00030000 /* Error on Buffer Write */
+#define DMARX_STAT_EBEDA 0x00040000 /* Bus Error on Desc. Access */
+#define B44_DMAFIFO_AD 0x0220UL /* DMA FIFO Diag Address */
+#define DMAFIFO_AD_OMASK 0x0000ffff /* Offset Mask */
+#define DMAFIFO_AD_SMASK 0x000f0000 /* Select Mask */
+#define DMAFIFO_AD_SXDD 0x00000000 /* Select Transmit DMA Data */
+#define DMAFIFO_AD_SXDP 0x00010000 /* Sel Transmit DMA Pointers */
+#define DMAFIFO_AD_SRDD 0x00040000 /* Select Receive DMA Data */
+#define DMAFIFO_AD_SRDP 0x00050000 /* Sel Receive DMA Pointers */
+#define DMAFIFO_AD_SXFD 0x00080000 /* Select Transmit FIFO Data */
+#define DMAFIFO_AD_SXFP 0x00090000 /* Sel Transmit FIFO Pointers */
+#define DMAFIFO_AD_SRFD 0x000c0000 /* Select Receive FIFO Data */
+#define DMAFIFO_AD_SRFP 0x000c0000 /* Sel Receive FIFO Pointers */
+#define B44_DMAFIFO_LO 0x0224UL /* DMA FIFO Diag Low Data */
+#define B44_DMAFIFO_HI 0x0228UL /* DMA FIFO Diag High Data */
+#define B44_RXCONFIG 0x0400UL /* EMAC RX Config */
+#define RXCONFIG_DBCAST 0x00000001 /* Disable Broadcast */
+#define RXCONFIG_ALLMULTI 0x00000002 /* Accept All Multicast */
+#define RXCONFIG_NORX_WHILE_TX 0x00000004 /* Rcv Disble While TX */
+#define RXCONFIG_PROMISC 0x00000008 /* Promiscuous Enable */
+#define RXCONFIG_LPBACK 0x00000010 /* Loopback Enable */
+#define RXCONFIG_FLOW 0x00000020 /* Flow Control Enable */
+#define RXCONFIG_FLOW_ACCEPT 0x00000040 /* Accept UFC Frame */
+#define RXCONFIG_RFILT 0x00000080 /* Reject Filter */
+#define B44_RXMAXLEN 0x0404UL /* EMAC RX Max Packet Length */
+#define B44_TXMAXLEN 0x0408UL /* EMAC TX Max Packet Length */
+#define B44_MDIO_CTRL 0x0410UL /* EMAC MDIO Control */
+#define MDIO_CTRL_MAXF_MASK 0x0000007f /* MDC Frequency */
+#define MDIO_CTRL_PREAMBLE 0x00000080 /* MII Preamble Enable */
+#define B44_MDIO_DATA 0x0414UL /* EMAC MDIO Data */
+#define MDIO_DATA_DATA 0x0000ffff /* R/W Data */
+#define MDIO_DATA_TA_MASK 0x00030000 /* Turnaround Value */
+#define MDIO_DATA_TA_SHIFT 16
+#define MDIO_TA_VALID 2
+#define MDIO_DATA_RA_MASK 0x007c0000 /* Register Address */
+#define MDIO_DATA_RA_SHIFT 18
+#define MDIO_DATA_PMD_MASK 0x0f800000 /* Physical Media Device */
+#define MDIO_DATA_PMD_SHIFT 23
+#define MDIO_DATA_OP_MASK 0x30000000 /* Opcode */
+#define MDIO_DATA_OP_SHIFT 28
+#define MDIO_OP_WRITE 1
+#define MDIO_OP_READ 2
+#define MDIO_DATA_SB_MASK 0xc0000000 /* Start Bits */
+#define MDIO_DATA_SB_SHIFT 30
+#define MDIO_DATA_SB_START 0x40000000 /* Start Of Frame */
+#define B44_EMAC_IMASK 0x0418UL /* EMAC Interrupt Mask */
+#define B44_EMAC_ISTAT 0x041CUL /* EMAC Interrupt Status */
+#define EMAC_INT_MII 0x00000001 /* MII MDIO Interrupt */
+#define EMAC_INT_MIB 0x00000002 /* MIB Interrupt */
+#define EMAC_INT_FLOW 0x00000003 /* Flow Control Interrupt */
+#define B44_CAM_DATA_LO 0x0420UL /* EMAC CAM Data Low */
+#define B44_CAM_DATA_HI 0x0424UL /* EMAC CAM Data High */
+#define CAM_DATA_HI_VALID 0x00010000 /* Valid Bit */
+#define B44_CAM_CTRL 0x0428UL /* EMAC CAM Control */
+#define CAM_CTRL_ENABLE 0x00000001 /* CAM Enable */
+#define CAM_CTRL_MSEL 0x00000002 /* Mask Select */
+#define CAM_CTRL_READ 0x00000004 /* Read */
+#define CAM_CTRL_WRITE 0x00000008 /* Read */
+#define CAM_CTRL_INDEX_MASK 0x003f0000 /* Index Mask */
+#define CAM_CTRL_INDEX_SHIFT 16
+#define CAM_CTRL_BUSY 0x80000000 /* CAM Busy */
+#define B44_ENET_CTRL 0x042CUL /* EMAC ENET Control */
+#define ENET_CTRL_ENABLE 0x00000001 /* EMAC Enable */
+#define ENET_CTRL_DISABLE 0x00000002 /* EMAC Disable */
+#define ENET_CTRL_SRST 0x00000004 /* EMAC Soft Reset */
+#define ENET_CTRL_EPSEL 0x00000008 /* External PHY Select */
+#define B44_TX_CTRL 0x0430UL /* EMAC TX Control */
+#define TX_CTRL_DUPLEX 0x00000001 /* Full Duplex */
+#define TX_CTRL_FMODE 0x00000002 /* Flow Mode */
+#define TX_CTRL_SBENAB 0x00000004 /* Single Backoff Enable */
+#define TX_CTRL_SMALL_SLOT 0x00000008 /* Small Slottime */
+#define B44_TX_HIWMARK 0x0434UL /* EMAC TX High Watermark */
+#define TX_HIWMARK_DEFLT 56 /* Default used in all drivers */
+#define B44_MIB_CTRL 0x0438UL /* EMAC MIB Control */
+#define MIB_CTRL_CLR_ON_READ 0x00000001 /* Autoclear on Read */
+#define B44_TX_GOOD_O 0x0500UL /* MIB TX Good Octets */
+#define B44_TX_GOOD_P 0x0504UL /* MIB TX Good Packets */
+#define B44_TX_O 0x0508UL /* MIB TX Octets */
+#define B44_TX_P 0x050CUL /* MIB TX Packets */
+#define B44_TX_BCAST 0x0510UL /* MIB TX Broadcast Packets */
+#define B44_TX_MCAST 0x0514UL /* MIB TX Multicast Packets */
+#define B44_TX_64 0x0518UL /* MIB TX <= 64 byte Packets */
+#define B44_TX_65_127 0x051CUL /* MIB TX 65 to 127 byte Pkts */
+#define B44_TX_128_255 0x0520UL /* MIB TX 128 to 255 byte Pkts */
+#define B44_TX_256_511 0x0524UL /* MIB TX 256 to 511 byte Pkts */
+#define B44_TX_512_1023 0x0528UL /* MIB TX 512 to 1023 byte Pkts */
+#define B44_TX_1024_MAX 0x052CUL /* MIB TX 1024 to max byte Pkts */
+#define B44_TX_JABBER 0x0530UL /* MIB TX Jabber Packets */
+#define B44_TX_OSIZE 0x0534UL /* MIB TX Oversize Packets */
+#define B44_TX_FRAG 0x0538UL /* MIB TX Fragment Packets */
+#define B44_TX_URUNS 0x053CUL /* MIB TX Underruns */
+#define B44_TX_TCOLS 0x0540UL /* MIB TX Total Collisions */
+#define B44_TX_SCOLS 0x0544UL /* MIB TX Single Collisions */
+#define B44_TX_MCOLS 0x0548UL /* MIB TX Multiple Collisions */
+#define B44_TX_ECOLS 0x054CUL /* MIB TX Excessive Collisions */
+#define B44_TX_LCOLS 0x0550UL /* MIB TX Late Collisions */
+#define B44_TX_DEFERED 0x0554UL /* MIB TX Defered Packets */
+#define B44_TX_CLOST 0x0558UL /* MIB TX Carrier Lost */
+#define B44_TX_PAUSE 0x055CUL /* MIB TX Pause Packets */
+#define B44_RX_GOOD_O 0x0580UL /* MIB RX Good Octets */
+#define B44_RX_GOOD_P 0x0584UL /* MIB RX Good Packets */
+#define B44_RX_O 0x0588UL /* MIB RX Octets */
+#define B44_RX_P 0x058CUL /* MIB RX Packets */
+#define B44_RX_BCAST 0x0590UL /* MIB RX Broadcast Packets */
+#define B44_RX_MCAST 0x0594UL /* MIB RX Multicast Packets */
+#define B44_RX_64 0x0598UL /* MIB RX <= 64 byte Packets */
+#define B44_RX_65_127 0x059CUL /* MIB RX 65 to 127 byte Pkts */
+#define B44_RX_128_255 0x05A0UL /* MIB RX 128 to 255 byte Pkts */
+#define B44_RX_256_511 0x05A4UL /* MIB RX 256 to 511 byte Pkts */
+#define B44_RX_512_1023 0x05A8UL /* MIB RX 512 to 1023 byte Pkts */
+#define B44_RX_1024_MAX 0x05ACUL /* MIB RX 1024 to max byte Pkts */
+#define B44_RX_JABBER 0x05B0UL /* MIB RX Jabber Packets */
+#define B44_RX_OSIZE 0x05B4UL /* MIB RX Oversize Packets */
+#define B44_RX_FRAG 0x05B8UL /* MIB RX Fragment Packets */
+#define B44_RX_MISS 0x05BCUL /* MIB RX Missed Packets */
+#define B44_RX_CRCA 0x05C0UL /* MIB RX CRC Align Errors */
+#define B44_RX_USIZE 0x05C4UL /* MIB RX Undersize Packets */
+#define B44_RX_CRC 0x05C8UL /* MIB RX CRC Errors */
+#define B44_RX_ALIGN 0x05CCUL /* MIB RX Align Errors */
+#define B44_RX_SYM 0x05D0UL /* MIB RX Symbol Errors */
+#define B44_RX_PAUSE 0x05D4UL /* MIB RX Pause Packets */
+#define B44_RX_NPAUSE 0x05D8UL /* MIB RX Non-Pause Packets */
+
+/* Sonics Silicon backplane register definitions */
+#define B44_SBIMSTATE 0x0F90UL /* SB Initiator Agent State */
+#define SBIMSTATE_PC 0x0000000f /* Pipe Count */
+#define SBIMSTATE_AP_MASK 0x00000030 /* Arbitration Priority */
+#define SBIMSTATE_AP_BOTH 0x00000000 /* both timeslices and token */
+#define SBIMSTATE_AP_TS 0x00000010 /* Use timeslices only */
+#define SBIMSTATE_AP_TK 0x00000020 /* Use token only */
+#define SBIMSTATE_AP_RSV 0x00000030 /* Reserved */
+#define SBIMSTATE_IBE 0x00020000 /* In Band Error */
+#define SBIMSTATE_TO 0x00040000 /* Timeout */
+#define SBIMSTATE_BAD ( SBIMSTATE_IBE | SBIMSTATE_TO )
+#define B44_SBINTVEC 0x0F94UL /* SB Interrupt Mask */
+#define SBINTVEC_PCI 0x00000001 /* Enable interrupts for PCI */
+#define SBINTVEC_ENET0 0x00000002 /* Enable ints for enet 0 */
+#define SBINTVEC_ILINE20 0x00000004 /* Enable ints for iline20 */
+#define SBINTVEC_CODEC 0x00000008 /* Enable ints for v90 codec */
+#define SBINTVEC_USB 0x00000010 /* Enable intts for usb */
+#define SBINTVEC_EXTIF 0x00000020 /* Enable ints for ext i/f */
+#define SBINTVEC_ENET1 0x00000040 /* Enable ints for enet 1 */
+#define B44_SBTMSLOW 0x0F98UL /* SB Target State Low */
+#define SBTMSLOW_RESET 0x00000001 /* Reset */
+#define SBTMSLOW_REJECT 0x00000002 /* Reject */
+#define SBTMSLOW_CLOCK 0x00010000 /* Clock Enable */
+#define SBTMSLOW_FGC 0x00020000 /* Force Gated Clocks On */
+#define SBTMSLOW_PE 0x40000000 /* Power Management Enable */
+#define SBTMSLOW_BE 0x80000000 /* BIST Enable */
+#define B44_SBTMSHIGH 0x0F9CUL /* SB Target State High */
+#define SBTMSHIGH_SERR 0x00000001 /* S-error */
+#define SBTMSHIGH_INT 0x00000002 /* Interrupt */
+#define SBTMSHIGH_BUSY 0x00000004 /* Busy */
+#define SBTMSHIGH_GCR 0x20000000 /* Gated Clock Request */
+#define SBTMSHIGH_BISTF 0x40000000 /* BIST Failed */
+#define SBTMSHIGH_BISTD 0x80000000 /* BIST Done */
+#define B44_SBIDHIGH 0x0FFCUL /* SB Identification High */
+#define SBIDHIGH_RC_MASK 0x0000000f /* Revision Code */
+#define SBIDHIGH_CC_MASK 0x0000fff0 /* Core Code */
+#define SBIDHIGH_CC_SHIFT 4
+#define SBIDHIGH_VC_MASK 0xffff0000 /* Vendor Code */
+#define SBIDHIGH_VC_SHIFT 16
+
+/* SSB PCI config space registers. */
+#define SSB_PMCSR 0x44
+#define SSB_PE 0x100
+#define SSB_BAR0_WIN 0x80
+#define SSB_BAR1_WIN 0x84
+#define SSB_SPROM_CONTROL 0x88
+#define SSB_BAR1_CONTROL 0x8c
+
+/* SSB core and host control registers. */
+#define SSB_CONTROL 0x0000UL
+#define SSB_ARBCONTROL 0x0010UL
+#define SSB_ISTAT 0x0020UL
+#define SSB_IMASK 0x0024UL
+#define SSB_MBOX 0x0028UL
+#define SSB_BCAST_ADDR 0x0050UL
+#define SSB_BCAST_DATA 0x0054UL
+#define SSB_PCI_TRANS_0 0x0100UL
+#define SSB_PCI_TRANS_1 0x0104UL
+#define SSB_PCI_TRANS_2 0x0108UL
+#define SSB_SPROM 0x0800UL
+
+#define SSB_PCI_MEM 0x00000000
+#define SSB_PCI_IO 0x00000001
+#define SSB_PCI_CFG0 0x00000002
+#define SSB_PCI_CFG1 0x00000003
+#define SSB_PCI_PREF 0x00000004
+#define SSB_PCI_BURST 0x00000008
+#define SSB_PCI_MASK0 0xfc000000
+#define SSB_PCI_MASK1 0xfc000000
+#define SSB_PCI_MASK2 0xc0000000
+
+/* 4400 PHY registers */
+#define B44_MII_AUXCTRL 24 /* Auxiliary Control */
+#define MII_AUXCTRL_DUPLEX 0x0001 /* Full Duplex */
+#define MII_AUXCTRL_SPEED 0x0002 /* 1=100Mbps, 0=10Mbps */
+#define MII_AUXCTRL_FORCED 0x0004 /* Forced 10/100 */
+#define B44_MII_ALEDCTRL 26 /* Activity LED */
+#define MII_ALEDCTRL_ALLMSK 0x7fff
+#define B44_MII_TLEDCTRL 27 /* Traffic Meter LED */
+#define MII_TLEDCTRL_ENABLE 0x0040
+
+/* RX/TX descriptor */
+struct dma_desc {
+ u32 ctrl; /* length of data and flags */
+ u32 addr; /* address of data */
+};
+
+/* There are only 12 bits in the DMA engine for descriptor offsetting
+ * so the table must be aligned on a boundary of this.
+ */
+#define B44_DMA_ALIGNMENT 4096
+
+/* The DMA engine can only address the first gigabyte of address space
+ */
+#define B44_30BIT_DMA_MASK 0x3fffffff
+
+#define DESC_CTRL_LEN 0x00001fff
+#define DESC_CTRL_CMASK 0x0ff00000 /* Core specific bits */
+#define DESC_CTRL_EOT 0x10000000 /* End of Table */
+#define DESC_CTRL_IOC 0x20000000 /* Interrupt On Completion */
+#define DESC_CTRL_EOF 0x40000000 /* End of Frame */
+#define DESC_CTRL_SOF 0x80000000 /* Start of Frame */
+
+struct rx_header {
+ u16 len;
+ u16 flags;
+ u16 pad[12];
+};
+#define RX_HEADER_LEN 28
+
+#define RX_FLAG_OFIFO 0x00000001 /* FIFO Overflow */
+#define RX_FLAG_CRCERR 0x00000002 /* CRC Error */
+#define RX_FLAG_SERR 0x00000004 /* Receive Symbol Error */
+#define RX_FLAG_ODD 0x00000008 /* Frame has odd number of nibbles */
+#define RX_FLAG_LARGE 0x00000010 /* Frame is > RX MAX Length */
+#define RX_FLAG_MCAST 0x00000020 /* Dest is Multicast Address */
+#define RX_FLAG_BCAST 0x00000040 /* Dest is Broadcast Address */
+#define RX_FLAG_MISS 0x00000080 /* Received due to promisc mode */
+#define RX_FLAG_LAST 0x00000800 /* Last buffer in frame */
+#define RX_FLAG_ERRORS (RX_FLAG_ODD | RX_FLAG_SERR |\
+ RX_FLAG_CRCERR | RX_FLAG_OFIFO)
+
+/* Client Mode PCI memory access space (1 GB) */
+#define SB_PCI_DMA 0x40000000
+
+ /* Address of PCI core on BCM4400 cards */
+#define BCM4400_PCI_CORE_ADDR 0x18002000
+
+/* Hardware minimum and maximum for a single frame's data payload */
+#define B44_MIN_MTU 60
+#define B44_MAX_MTU 1500
+
+#define B44_RING_SIZE 8
+#define B44_RING_LAST ( B44_RING_SIZE - 1 )
+
+#define B44_RX_RING_LEN_BYTES ( sizeof bp->rx[0] * B44_RING_SIZE )
+#define B44_TX_RING_LEN_BYTES ( sizeof bp->tx[0] * B44_RING_SIZE )
+
+#define RX_PKT_OFFSET 30
+#define RX_PKT_BUF_SZ (1536 + RX_PKT_OFFSET + 64)
+
+#define B44_FULL_RESET 1
+#define B44_FULL_RESET_SKIP_PHY 2
+#define B44_PARTIAL_RESET 3
+#define B44_CHIP_RESET_FULL 4
+#define B44_CHIP_RESET_PARTIAL 5
+
+#define SSB_CORE_DOWN ( SBTMSLOW_RESET | SBTMSLOW_REJECT )
+
+#define B44_REGS_SIZE 8192
+
+/** Driver private state */
+struct b44_private {
+ struct net_device *netdev;
+ struct pci_device *pci;
+ u8 *regs; /* memory-mapped registers */
+ u8 phy_addr;
+
+ struct dma_desc *tx;
+ struct io_buffer *tx_iobuf[B44_RING_SIZE];
+ u32 tx_cur; /* next available descriptor */
+ u32 tx_dirty; /* oldest pending descriptor */
+
+ struct dma_desc *rx;
+ struct io_buffer *rx_iobuf[B44_RING_SIZE];
+ u32 rx_cur; /* next descriptor to read */
+};
+
+
+static void ssb_core_reset ( struct b44_private *bp );
+static void ssb_core_disable ( struct b44_private *bp );
+static u32 ssb_pci_setup ( struct b44_private *bp, u32 cores );
+
+static void b44_chip_reset ( struct b44_private *bp, int reset_kind );
+static void b44_init_hw ( struct b44_private *bp, int reset_kind );
+static void b44_cam_write ( struct b44_private *bp, u8 *data, int index );
+static void b44_set_mac_addr ( struct b44_private *bp );
+static void b44_set_rx_mode ( struct net_device *netdev );
+static void b44_halt(struct b44_private *);
+
+static int b44_phy_reset ( struct b44_private *bp );
+static int b44_phy_write ( struct b44_private *bp, int reg, u32 val );
+static int b44_phy_read ( struct b44_private *bp, int reg, u32 *val );
+
+static int b44_init_tx_ring ( struct b44_private *bp );
+static void b44_free_tx_ring ( struct b44_private *bp );
+static int b44_init_rx_ring ( struct b44_private *bp );
+static void b44_free_rx_ring ( struct b44_private *bp );
+static void b44_rx_refill ( struct b44_private *bp, u32 pending );
+static void b44_populate_rx_descriptor (struct b44_private *bp, u32 index);
+
+static int b44_probe ( struct pci_device *pci,
+ const struct pci_device_id *id );
+static void b44_remove ( struct pci_device *pci );
+
+static int b44_open ( struct net_device *netdev );
+static void b44_close ( struct net_device *netdev );
+static void b44_irq ( struct net_device *netdev, int enable );
+static void b44_poll ( struct net_device *netdev );
+static void b44_process_rx_packets ( struct b44_private *bp );
+static int b44_transmit ( struct net_device *netdev,
+ struct io_buffer *iobuf );
+
+static struct net_device_operations b44_operations;
+
+#endif /* _B44_H */
diff --git a/gpxe/src/drivers/net/cs89x0.c b/gpxe/src/drivers/net/cs89x0.c
index 11988add..1f647a8e 100644
--- a/gpxe/src/drivers/net/cs89x0.c
+++ b/gpxe/src/drivers/net/cs89x0.c
@@ -419,8 +419,8 @@ retry:
ETH_ALEN/2);
outw(((t >> 8)&0xFF)|(t << 8), eth_nic_base + TX_FRAME_PORT);
outsw(eth_nic_base + TX_FRAME_PORT, p, (s+1)/2);
- for (sr = sr/2 - (s+1)/2 - ETH_ALEN - 1; sr-- > 0;
- outw(0, eth_nic_base + TX_FRAME_PORT));
+ for (sr = sr/2 - (s+1)/2 - ETH_ALEN - 1; sr > 0; sr--)
+ outw(0, eth_nic_base + TX_FRAME_PORT);
/* wait for transfer to succeed */
for (tmo = currticks()+5*TICKS_PER_SEC;
diff --git a/gpxe/src/drivers/net/davicom.c b/gpxe/src/drivers/net/davicom.c
index 079e647e..bb6d7e96 100644
--- a/gpxe/src/drivers/net/davicom.c
+++ b/gpxe/src/drivers/net/davicom.c
@@ -630,7 +630,7 @@ static void davicom_disable ( struct nic *nic ) {
outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6);
/* Clear the missed-packet counter. */
- (volatile unsigned long)inl(ioaddr + CSR8);
+ inl(ioaddr + CSR8);
}
@@ -676,7 +676,7 @@ static int davicom_probe ( struct nic *nic, struct pci_device *pci ) {
outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6);
/* Clear the missed-packet counter. */
- (volatile unsigned long)inl(ioaddr + CSR8);
+ inl(ioaddr + CSR8);
/* Get MAC Address */
/* read EEPROM data */
diff --git a/gpxe/src/drivers/net/dmfe.c b/gpxe/src/drivers/net/dmfe.c
index 9cf50418..26021e6b 100644
--- a/gpxe/src/drivers/net/dmfe.c
+++ b/gpxe/src/drivers/net/dmfe.c
@@ -133,14 +133,14 @@
/* Structure/enum declaration ------------------------------- */
struct tx_desc {
u32 tdes0, tdes1, tdes2, tdes3; /* Data for the card */
- u32 tx_buf_ptr; /* Data for us */
- u32 /* struct tx_desc * */ next_tx_desc;
+ void * tx_buf_ptr; /* Data for us */
+ struct tx_desc * next_tx_desc;
} __attribute__ ((aligned(32)));
struct rx_desc {
u32 rdes0, rdes1, rdes2, rdes3; /* Data for the card */
- u32 rx_skb_ptr; /* Data for us */
- u32 /* struct rx_desc * */ next_rx_desc;
+ void * rx_skb_ptr; /* Data for us */
+ struct rx_desc * next_rx_desc;
} __attribute__ ((aligned(32)));
static struct dmfe_private {
@@ -522,30 +522,30 @@ static void dmfe_descriptor_init(struct nic *nic __unused, unsigned long ioaddr)
/* Init Transmit chain */
for (i = 0; i < TX_DESC_CNT; i++) {
- txd[i].tx_buf_ptr = (u32) & txb[i];
+ txd[i].tx_buf_ptr = &txb[i];
txd[i].tdes0 = cpu_to_le32(0);
txd[i].tdes1 = cpu_to_le32(0x81000000); /* IC, chain */
txd[i].tdes2 = cpu_to_le32(virt_to_bus(&txb[i]));
txd[i].tdes3 = cpu_to_le32(virt_to_bus(&txd[i + 1]));
- txd[i].next_tx_desc = virt_to_le32desc(&txd[i + 1]);
+ txd[i].next_tx_desc = &txd[i + 1];
}
/* Mark the last entry as wrapping the ring */
txd[i - 1].tdes3 = virt_to_le32desc(&txd[0]);
- txd[i - 1].next_tx_desc = (u32) & txd[0];
+ txd[i - 1].next_tx_desc = &txd[0];
/* receive descriptor chain */
for (i = 0; i < RX_DESC_CNT; i++) {
- rxd[i].rx_skb_ptr = (u32) & rxb[i * RX_ALLOC_SIZE];
+ rxd[i].rx_skb_ptr = &rxb[i * RX_ALLOC_SIZE];
rxd[i].rdes0 = cpu_to_le32(0x80000000);
rxd[i].rdes1 = cpu_to_le32(0x01000600);
rxd[i].rdes2 =
cpu_to_le32(virt_to_bus(&rxb[i * RX_ALLOC_SIZE]));
rxd[i].rdes3 = cpu_to_le32(virt_to_bus(&rxd[i + 1]));
- rxd[i].next_rx_desc = virt_to_le32desc(&rxd[i + 1]);
+ rxd[i].next_rx_desc = &rxd[i + 1];
}
/* Mark the last entry as wrapping the ring */
rxd[i - 1].rdes3 = cpu_to_le32(virt_to_bus(&rxd[0]));
- rxd[i - 1].next_rx_desc = virt_to_le32desc(&rxd[0]);
+ rxd[i - 1].next_rx_desc = &rxd[0];
}
diff --git a/gpxe/src/drivers/net/e1000/e1000.c b/gpxe/src/drivers/net/e1000/e1000.c
index a9aa508a..c1a4a52d 100644
--- a/gpxe/src/drivers/net/e1000/e1000.c
+++ b/gpxe/src/drivers/net/e1000/e1000.c
@@ -258,8 +258,8 @@ e1000_configure_tx ( struct e1000_adapter *adapter )
E1000_WRITE_REG ( hw, TDBAL, virt_to_bus ( adapter->tx_base ) );
E1000_WRITE_REG ( hw, TDLEN, adapter->tx_ring_size );
- DBG ( "TDBAL: %#08lx\n", E1000_READ_REG ( hw, TDBAL ) );
- DBG ( "TDLEN: %ld\n", E1000_READ_REG ( hw, TDLEN ) );
+ DBG ( "TDBAL: %#08x\n", E1000_READ_REG ( hw, TDBAL ) );
+ DBG ( "TDLEN: %d\n", E1000_READ_REG ( hw, TDLEN ) );
/* Setup the HW Tx Head and Tail descriptor pointers */
E1000_WRITE_REG ( hw, TDH, 0 );
@@ -385,9 +385,9 @@ e1000_configure_rx ( struct e1000_adapter *adapter )
E1000_WRITE_REG ( hw, RCTL, rctl );
E1000_WRITE_FLUSH ( hw );
- DBG ( "RDBAL: %#08lx\n", E1000_READ_REG ( hw, RDBAL ) );
- DBG ( "RDLEN: %ld\n", E1000_READ_REG ( hw, RDLEN ) );
- DBG ( "RCTL: %#08lx\n", E1000_READ_REG ( hw, RCTL ) );
+ DBG ( "RDBAL: %#08x\n", E1000_READ_REG ( hw, RDBAL ) );
+ DBG ( "RDLEN: %d\n", E1000_READ_REG ( hw, RDLEN ) );
+ DBG ( "RCTL: %#08x\n", E1000_READ_REG ( hw, RCTL ) );
}
/**
@@ -577,7 +577,7 @@ e1000_transmit ( struct net_device *netdev, struct io_buffer *iobuf )
E1000_TXD_CMD_IFCS | iob_len ( iobuf );
tx_curr_desc->upper.data = 0;
- DBG ( "TX fill: %ld tx_curr: %ld addr: %#08lx len: %zd\n", adapter->tx_fill_ctr,
+ DBG ( "TX fill: %d tx_curr: %d addr: %#08lx len: %zd\n", adapter->tx_fill_ctr,
tx_curr, virt_to_bus ( iobuf->data ), iob_len ( iobuf ) );
/* Point to next free descriptor */
@@ -620,7 +620,7 @@ e1000_poll ( struct net_device *netdev )
if ( ! icr )
return;
- DBG ( "e1000_poll: intr_status = %#08lx\n", icr );
+ DBG ( "e1000_poll: intr_status = %#08x\n", icr );
/* Check status of transmitted packets
*/
@@ -635,17 +635,17 @@ e1000_poll ( struct net_device *netdev )
if ( ! ( tx_status & E1000_TXD_STAT_DD ) )
break;
- DBG ( "Sent packet. tx_head: %ld tx_tail: %ld tx_status: %#08lx\n",
+ DBG ( "Sent packet. tx_head: %d tx_tail: %d tx_status: %#08x\n",
adapter->tx_head, adapter->tx_tail, tx_status );
if ( tx_status & ( E1000_TXD_STAT_EC | E1000_TXD_STAT_LC |
E1000_TXD_STAT_TU ) ) {
netdev_tx_complete_err ( netdev, adapter->tx_iobuf[i], -EINVAL );
- DBG ( "Error transmitting packet, tx_status: %#08lx\n",
+ DBG ( "Error transmitting packet, tx_status: %#08x\n",
tx_status );
} else {
netdev_tx_complete ( netdev, adapter->tx_iobuf[i] );
- DBG ( "Success transmitting packet, tx_status: %#08lx\n",
+ DBG ( "Success transmitting packet, tx_status: %#08x\n",
tx_status );
}
@@ -667,16 +667,16 @@ e1000_poll ( struct net_device *netdev )
( i * sizeof ( *adapter->rx_base ) );
rx_status = rx_curr_desc->status;
- DBG2 ( "Before DD Check RX_status: %#08lx\n", rx_status );
+ DBG2 ( "Before DD Check RX_status: %#08x\n", rx_status );
if ( ! ( rx_status & E1000_RXD_STAT_DD ) )
break;
- DBG ( "RCTL = %#08lx\n", E1000_READ_REG ( &adapter->hw, RCTL ) );
+ DBG ( "RCTL = %#08x\n", E1000_READ_REG ( &adapter->hw, RCTL ) );
rx_len = rx_curr_desc->length;
- DBG ( "Received packet, rx_curr: %ld rx_status: %#08lx rx_len: %ld\n",
+ DBG ( "Received packet, rx_curr: %d rx_status: %#08x rx_len: %d\n",
i, rx_status, rx_len );
rx_err = rx_curr_desc->errors;
@@ -685,7 +685,7 @@ e1000_poll ( struct net_device *netdev )
netdev_rx_err ( netdev, NULL, -EINVAL );
DBG ( "e1000_poll: Corrupted packet received!"
- " rx_err: %#08lx\n", rx_err );
+ " rx_err: %#08x\n", rx_err );
} else {
/* If unable allocate space for this packet,
@@ -818,8 +818,8 @@ e1000_probe ( struct pci_device *pdev,
* because it depends on mac_type
*/
if ( ( adapter->hw.mac_type == e1000_ich8lan ) && ( pdev->ioaddr ) ) {
- flash_start = pci_bar_start ( pdev, 1 );
- flash_len = pci_bar_size ( pdev, 1 );
+ flash_start = pci_bar_start ( pdev, PCI_BASE_ADDRESS_1 );
+ flash_len = pci_bar_size ( pdev, PCI_BASE_ADDRESS_1 );
adapter->hw.flash_address = ioremap ( flash_start, flash_len );
if ( ! adapter->hw.flash_address )
goto err_flashmap;
@@ -962,7 +962,7 @@ e1000_open ( struct net_device *netdev )
e1000_configure_rx ( adapter );
- DBG ( "RXDCTL: %#08lx\n", E1000_READ_REG ( &adapter->hw, RXDCTL ) );
+ DBG ( "RXDCTL: %#08x\n", E1000_READ_REG ( &adapter->hw, RXDCTL ) );
return 0;
diff --git a/gpxe/src/drivers/net/e1000/e1000.h b/gpxe/src/drivers/net/e1000/e1000.h
index 4ae41451..77a09ef1 100644
--- a/gpxe/src/drivers/net/e1000/e1000.h
+++ b/gpxe/src/drivers/net/e1000/e1000.h
@@ -34,7 +34,8 @@
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
-#include <io.h>
+#include <string.h>
+#include <gpxe/io.h>
#include <errno.h>
#include <byteswap.h>
#include <gpxe/pci.h>
diff --git a/gpxe/src/drivers/net/e1000/e1000_hw.c b/gpxe/src/drivers/net/e1000/e1000_hw.c
index 0667ad61..1054b90a 100644
--- a/gpxe/src/drivers/net/e1000/e1000_hw.c
+++ b/gpxe/src/drivers/net/e1000/e1000_hw.c
@@ -1429,7 +1429,7 @@ e1000_copper_link_preconfig(struct e1000_hw *hw)
DEBUGOUT("Error, did not detect valid phy.\n");
return ret_val;
}
- DEBUGOUT1("Phy ID = %#08lx \n", hw->phy_id);
+ DEBUGOUT1("Phy ID = %#08x \n", hw->phy_id);
/* Set PHY to class A mode (if necessary) */
ret_val = e1000_set_phy_mode(hw);
@@ -3551,7 +3551,7 @@ e1000_read_phy_reg_ex(struct e1000_hw *hw, uint32_t reg_addr,
DEBUGFUNC("e1000_read_phy_reg_ex");
if (reg_addr > MAX_PHY_REG_ADDRESS) {
- DEBUGOUT1("PHY Address %ld is out of range\n", reg_addr);
+ DEBUGOUT1("PHY Address %d is out of range\n", reg_addr);
return -E1000_ERR_PARAM;
}
@@ -3689,7 +3689,7 @@ e1000_write_phy_reg_ex(struct e1000_hw *hw, uint32_t reg_addr,
DEBUGFUNC("e1000_write_phy_reg_ex");
if (reg_addr > MAX_PHY_REG_ADDRESS) {
- DEBUGOUT1("PHY Address %ld is out of range\n", reg_addr);
+ DEBUGOUT1("PHY Address %d is out of range\n", reg_addr);
return -E1000_ERR_PARAM;
}
@@ -4141,10 +4141,10 @@ e1000_detect_gig_phy(struct e1000_hw *hw)
phy_init_status = e1000_set_phy_type(hw);
if ((match) && (phy_init_status == E1000_SUCCESS)) {
- DEBUGOUT1("PHY ID %#08lx detected\n", hw->phy_id);
+ DEBUGOUT1("PHY ID %#08x detected\n", hw->phy_id);
return E1000_SUCCESS;
}
- DEBUGOUT1("Invalid PHY ID %#08lx\n", hw->phy_id);
+ DEBUGOUT1("Invalid PHY ID %#08x\n", hw->phy_id);
return -E1000_ERR_PHY;
}
@@ -8795,13 +8795,13 @@ e1000_verify_write_ich8_byte(struct e1000_hw *hw, uint32_t index, uint8_t byte)
int32_t error = E1000_SUCCESS;
int32_t program_retries = 0;
- DEBUGOUT2("Byte := %2.2X Offset := %ld\n", byte, index);
+ DEBUGOUT2("Byte := %2.2X Offset := %d\n", byte, index);
error = e1000_write_ich8_byte(hw, index, byte);
if (error != E1000_SUCCESS) {
for (program_retries = 0; program_retries < 100; program_retries++) {
- DEBUGOUT2("Retrying \t Byte := %2.2X Offset := %ld\n", byte, index);
+ DEBUGOUT2("Retrying \t Byte := %2.2X Offset := %d\n", byte, index);
error = e1000_write_ich8_byte(hw, index, byte);
udelay(100);
if (error == E1000_SUCCESS)
diff --git a/gpxe/src/drivers/net/e1000/e1000_osdep.h b/gpxe/src/drivers/net/e1000/e1000_osdep.h
index 7df9b5e9..c2d9eb9c 100644
--- a/gpxe/src/drivers/net/e1000/e1000_osdep.h
+++ b/gpxe/src/drivers/net/e1000/e1000_osdep.h
@@ -37,7 +37,7 @@
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
-#include <io.h>
+#include <gpxe/io.h>
#include <errno.h>
#include <unistd.h>
#include <byteswap.h>
@@ -74,60 +74,60 @@ typedef enum {
#define DEBUGOUT3 DEBUGOUT1
#define DEBUGOUT7 DEBUGOUT1
-#define E1000_WRITE_REG(a, reg, value) ( \
+#define E1000_WRITE_REG(a, reg, value) \
writel((value), ((a)->hw_addr + \
- (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg))))
+ (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg)))
-#define E1000_READ_REG(a, reg) ( \
+#define E1000_READ_REG(a, reg) \
readl((a)->hw_addr + \
- (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg)))
+ (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg))
-#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) ( \
+#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) \
writel((value), ((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
- ((offset) << 2))))
+ ((offset) << 2)))
-#define E1000_READ_REG_ARRAY(a, reg, offset) ( \
+#define E1000_READ_REG_ARRAY(a, reg, offset) \
readl((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
- ((offset) << 2)))
+ ((offset) << 2))
#define E1000_READ_REG_ARRAY_DWORD E1000_READ_REG_ARRAY
#define E1000_WRITE_REG_ARRAY_DWORD E1000_WRITE_REG_ARRAY
-#define E1000_WRITE_REG_ARRAY_WORD(a, reg, offset, value) ( \
+#define E1000_WRITE_REG_ARRAY_WORD(a, reg, offset, value) \
writew((value), ((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
- ((offset) << 1))))
+ ((offset) << 1)))
-#define E1000_READ_REG_ARRAY_WORD(a, reg, offset) ( \
+#define E1000_READ_REG_ARRAY_WORD(a, reg, offset) \
readw((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
- ((offset) << 1)))
+ ((offset) << 1))
-#define E1000_WRITE_REG_ARRAY_BYTE(a, reg, offset, value) ( \
+#define E1000_WRITE_REG_ARRAY_BYTE(a, reg, offset, value) \
writeb((value), ((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
- (offset))))
+ (offset)))
-#define E1000_READ_REG_ARRAY_BYTE(a, reg, offset) ( \
+#define E1000_READ_REG_ARRAY_BYTE(a, reg, offset) \
readb((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
- (offset)))
+ (offset))
#define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, STATUS)
-#define E1000_WRITE_ICH_FLASH_REG(a, reg, value) ( \
- writel((value), ((a)->flash_address + reg)))
+#define E1000_WRITE_ICH_FLASH_REG(a, reg, value) \
+ writel((value), ((a)->flash_address + reg))
-#define E1000_READ_ICH_FLASH_REG(a, reg) ( \
- readl((a)->flash_address + reg))
+#define E1000_READ_ICH_FLASH_REG(a, reg) \
+ readl((a)->flash_address + reg)
-#define E1000_WRITE_ICH_FLASH_REG16(a, reg, value) ( \
- writew((value), ((a)->flash_address + reg)))
+#define E1000_WRITE_ICH_FLASH_REG16(a, reg, value) \
+ writew((value), ((a)->flash_address + reg))
-#define E1000_READ_ICH_FLASH_REG16(a, reg) ( \
- readw((a)->flash_address + reg))
+#define E1000_READ_ICH_FLASH_REG16(a, reg) \
+ readw((a)->flash_address + reg)
#define msleep(n) mdelay(n)
diff --git a/gpxe/src/drivers/net/eepro100.c b/gpxe/src/drivers/net/eepro100.c
index f746976a..e6e7db49 100644
--- a/gpxe/src/drivers/net/eepro100.c
+++ b/gpxe/src/drivers/net/eepro100.c
@@ -407,7 +407,7 @@ static void eepro100_transmit(struct nic *nic, const char *d, unsigned int t, un
} hdr;
unsigned short status;
int s1, s2;
- tick_t ct;
+ unsigned long ct;
status = inw(ioaddr + SCBStatus);
/* Acknowledge all of the current interrupt sources ASAP. */
@@ -448,7 +448,7 @@ static void eepro100_transmit(struct nic *nic, const char *d, unsigned int t, un
ct = currticks();
/* timeout 10 ms for transmit */
- while (!txfd.status && ct + 10*USECS_IN_MSEC)
+ while (!txfd.status && ct + 10*1000)
/* Wait */;
s2 = inw (ioaddr + SCBStatus);
@@ -608,7 +608,7 @@ static int eepro100_probe ( struct nic *nic, struct pci_device *pci ) {
int read_cmd, ee_size;
int options;
int rx_mode;
- tick_t ct;
+ unsigned long ct;
/* we cache only the first few words of the EEPROM data
be careful not to access beyond this array */
@@ -753,7 +753,7 @@ static int eepro100_probe ( struct nic *nic, struct pci_device *pci ) {
whereami ("started TX thingy (config, iasetup).");
ct = currticks();
- while (!txfd.status && ct + 10*USECS_IN_MSEC < currticks())
+ while (!txfd.status && ct + 10*1000 < currticks())
/* Wait */;
/* Read the status register once to disgard stale data */
diff --git a/gpxe/src/drivers/net/epic100.c b/gpxe/src/drivers/net/epic100.c
index 67b4f0fb..1e36a680 100644
--- a/gpxe/src/drivers/net/epic100.c
+++ b/gpxe/src/drivers/net/epic100.c
@@ -309,7 +309,7 @@ epic100_transmit(struct nic *nic, const char *destaddr, unsigned int type,
unsigned short nstype;
unsigned char *txp;
int entry;
- tick_t ct;
+ unsigned long ct;
/* Calculate the next Tx descriptor entry. */
entry = cur_tx % TX_RING_SIZE;
@@ -352,7 +352,7 @@ epic100_transmit(struct nic *nic, const char *destaddr, unsigned int type,
ct = currticks();
/* timeout 10 ms for transmit */
while ((le32_to_cpu(tx_ring[entry].status) & (TRING_OWN)) &&
- ct + 10*USECS_IN_MSEC < currticks())
+ ct + 10*1000 < currticks())
/* Wait */;
if ((le32_to_cpu(tx_ring[entry].status) & TRING_OWN) != 0)
diff --git a/gpxe/src/drivers/net/etherfabric.c b/gpxe/src/drivers/net/etherfabric.c
index 8a6b1a17..704ce98b 100644
--- a/gpxe/src/drivers/net/etherfabric.c
+++ b/gpxe/src/drivers/net/etherfabric.c
@@ -15,17 +15,22 @@
*
**************************************************************************
*/
-
-#include "etherboot.h"
-#include "nic.h"
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
#include <errno.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <console.h>
+#include <gpxe/io.h>
#include <gpxe/pci.h>
-#include <gpxe/bitbash.h>
-#include <gpxe/i2c.h>
-#include <gpxe/spi.h>
-#include <gpxe/nvo.h>
-#define dma_addr_t unsigned long
+#include <gpxe/malloc.h>
+#include <gpxe/ethernet.h>
+#include <gpxe/iobuf.h>
+#include <gpxe/netdevice.h>
+#include <gpxe/timer.h>
#include "etherfabric.h"
+#include "etherfabric_nic.h"
/**************************************************************************
*
@@ -34,193 +39,35 @@
**************************************************************************
*/
-#define EFAB_ASSERT(x) \
- do { \
- if ( ! (x) ) { \
- DBG ( "ASSERT(%s) failed at %s line %d [%s]\n", #x, \
- __FILE__, __LINE__, __FUNCTION__ ); \
- } \
- } while (0)
-
-#define EFAB_TRACE(...) DBG ( __VA_ARGS__ )
-
#define EFAB_REGDUMP(...)
+#define EFAB_TRACE(...) DBGP(__VA_ARGS__)
-#define EFAB_LOG(...) printf ( __VA_ARGS__ )
-#define EFAB_ERR(...) printf ( __VA_ARGS__ )
-
-#define FALCON_USE_IO_BAR 1
+// printf() is not allowed within drivers. Use DBG() instead.
+#define EFAB_LOG(...) DBG(__VA_ARGS__)
+#define EFAB_ERR(...) DBG(__VA_ARGS__)
-/*
- * EtherFabric constants
- *
- */
+#define FALCON_USE_IO_BAR 0
-/* PCI Definitions */
-#define EFAB_VENDID_LEVEL5 0x1924
-#define FALCON_P_DEVID 0x0703 /* Temporary PCI ID */
-#define EF1002_DEVID 0xC101
+#define HZ 100
+#define EFAB_BYTE 1
/**************************************************************************
*
- * Data structures
+ * Hardware data structures and sizing
*
**************************************************************************
*/
+extern int __invalid_queue_size;
+#define FQS(_prefix, _x) \
+ ( ( (_x) == 512 ) ? _prefix ## _SIZE_512 : \
+ ( ( (_x) == 1024 ) ? _prefix ## _SIZE_1K : \
+ ( ( (_x) == 2048 ) ? _prefix ## _SIZE_2K : \
+ ( ( (_x) == 4096) ? _prefix ## _SIZE_4K : \
+ __invalid_queue_size ) ) ) )
-/*
- * Buffers used for TX, RX and event queue
- *
- */
-#define EFAB_BUF_ALIGN 4096
-#define EFAB_DATA_BUF_SIZE 2048
-#define EFAB_RX_BUFS 16
-#define EFAB_RXD_SIZE 512
-#define EFAB_TXD_SIZE 512
-#define EFAB_EVQ_SIZE 512
-struct efab_buffers {
- uint8_t eventq[4096];
- uint8_t rxd[4096];
- uint8_t txd[4096];
- uint8_t tx_buf[EFAB_DATA_BUF_SIZE];
- uint8_t rx_buf[EFAB_RX_BUFS][EFAB_DATA_BUF_SIZE];
- uint8_t padding[EFAB_BUF_ALIGN-1];
-};
-static struct efab_buffers efab_buffers;
-
-/** An RX buffer */
-struct efab_rx_buf {
- uint8_t *addr;
- unsigned int len;
- int id;
-};
-
-/** A TX buffer */
-struct efab_tx_buf {
- uint8_t *addr;
- unsigned int len;
- int id;
-};
-
-/** Etherfabric event type */
-enum efab_event_type {
- EFAB_EV_NONE = 0,
- EFAB_EV_TX,
- EFAB_EV_RX,
-};
-
-/** Etherfabric event */
-struct efab_event {
- /** Event type */
- enum efab_event_type type;
- /** RX buffer ID */
- int rx_id;
- /** RX length */
- unsigned int rx_len;
- /** Packet should be dropped */
- int drop;
-};
-
-/*
- * Etherfabric abstraction layer
- *
- */
-struct efab_nic;
-struct efab_operations {
- void ( * get_membase ) ( struct efab_nic *efab );
- int ( * reset ) ( struct efab_nic *efab );
- int ( * init_nic ) ( struct efab_nic *efab );
- int ( * read_eeprom ) ( struct efab_nic *efab );
- void ( * build_rx_desc ) ( struct efab_nic *efab,
- struct efab_rx_buf *rx_buf );
- void ( * notify_rx_desc ) ( struct efab_nic *efab );
- void ( * build_tx_desc ) ( struct efab_nic *efab,
- struct efab_tx_buf *tx_buf );
- void ( * notify_tx_desc ) ( struct efab_nic *efab );
- int ( * fetch_event ) ( struct efab_nic *efab,
- struct efab_event *event );
- void ( * mask_irq ) ( struct efab_nic *efab, int enabled );
- void ( * generate_irq ) ( struct efab_nic *efab );
- void ( * mdio_write ) ( struct efab_nic *efab, int location,
- int value );
- int ( * mdio_read ) ( struct efab_nic *efab, int location );
-};
-
-struct efab_mac_operations {
- void ( * mac_writel ) ( struct efab_nic *efab, efab_dword_t *value,
- unsigned int mac_reg );
- void ( * mac_readl ) ( struct efab_nic *efab, efab_dword_t *value,
- unsigned int mac_reg );
- int ( * init ) ( struct efab_nic *efab );
- int ( * reset ) ( struct efab_nic *efab );
-};
-
-/*
- * Driver private data structure
- *
- */
-struct efab_nic {
-
- /** PCI device */
- struct pci_device *pci;
-
- /** Operations table */
- struct efab_operations *op;
-
- /** MAC operations table */
- struct efab_mac_operations *mac_op;
- /** Memory base */
- void *membase;
-
- /** I/O base */
- unsigned int iobase;
-
- /** Buffers */
- uint8_t *eventq; /* Falcon only */
- uint8_t *txd; /* Falcon only */
- uint8_t *rxd; /* Falcon only */
- struct efab_tx_buf tx_buf;
- struct efab_rx_buf rx_bufs[EFAB_RX_BUFS];
-
- /** Buffer pointers */
- unsigned int eventq_read_ptr; /* Falcon only */
- unsigned int tx_write_ptr;
- unsigned int rx_write_ptr;
-
- /** Port 0/1 on the NIC */
- int port;
-
- /** MAC address */
- uint8_t mac_addr[ETH_ALEN];
- /** GMII link options */
- unsigned int link_options;
- /** Link status */
- int link_up;
-
- /* Nic type fields */
- int has_flash : 1;
- int has_eeprom : 1;
- int is_10g : 1;
- int is_dual : 1;
- int is_asic : 1;
-
- /** INT_REG_KER for Falcon */
- efab_oword_t int_ker __attribute__ (( aligned ( 16 ) ));
-
- /** I2C access */
- struct i2c_bit_basher ef1002_i2c;
- unsigned long ef1002_i2c_outputs;
- struct i2c_device ef1002_eeprom;
-
- /** SPI access */
- struct spi_bus spi;
- struct spi_device falcon_flash;
- struct spi_device falcon_eeprom;
-
- /** Non-volatile options */
- struct nvo_block nvo;
-};
+#define EFAB_MAX_FRAME_LEN(mtu) \
+ ( ( ( ( mtu ) + 4/* FCS */ ) + 7 ) & ~7 )
/**************************************************************************
*
@@ -229,6 +76,10 @@ struct efab_nic {
**************************************************************************
*/
+static void falcon_mdio_write (struct efab_nic *efab, int device,
+ int location, int value );
+static int falcon_mdio_read ( struct efab_nic *efab, int device, int location );
+
/* GMII registers */
#define MII_BMSR 0x01 /* Basic mode status register */
#define MII_ADVERTISE 0x04 /* Advertisement control register */
@@ -257,7 +108,8 @@ struct efab_nic {
#define LPA_100 (LPA_100FULL | LPA_100HALF | LPA_100BASE4)
#define LPA_1000 ( LPA_1000FULL | LPA_1000HALF )
#define LPA_10000 ( LPA_10000FULL | LPA_10000HALF )
-#define LPA_DUPLEX ( LPA_10FULL | LPA_100FULL | LPA_1000FULL )
+#define LPA_DUPLEX ( LPA_10FULL | LPA_100FULL | LPA_1000FULL | \
+ LPA_10000FULL )
/* Mask of bits not associated with speed or duplexity. */
#define LPA_OTHER ~( LPA_10FULL | LPA_10HALF | LPA_100FULL | \
@@ -270,13 +122,15 @@ struct efab_nic {
* Retrieve GMII autonegotiation advertised abilities
*
*/
-static unsigned int gmii_autoneg_advertised ( struct efab_nic *efab ) {
+static unsigned int
+gmii_autoneg_advertised ( struct efab_nic *efab )
+{
unsigned int mii_advertise;
unsigned int gmii_advertise;
-
+
/* Extended bits are in bits 8 and 9 of GMII_GTCR */
- mii_advertise = efab->op->mdio_read ( efab, MII_ADVERTISE );
- gmii_advertise = ( ( efab->op->mdio_read ( efab, GMII_GTCR ) >> 8 )
+ mii_advertise = falcon_mdio_read ( efab, 0, MII_ADVERTISE );
+ gmii_advertise = ( ( falcon_mdio_read ( efab, 0, GMII_GTCR ) >> 8 )
& 0x03 );
return ( ( gmii_advertise << 16 ) | mii_advertise );
}
@@ -285,13 +139,15 @@ static unsigned int gmii_autoneg_advertised ( struct efab_nic *efab ) {
* Retrieve GMII autonegotiation link partner abilities
*
*/
-static unsigned int gmii_autoneg_lpa ( struct efab_nic *efab ) {
+static unsigned int
+gmii_autoneg_lpa ( struct efab_nic *efab )
+{
unsigned int mii_lpa;
unsigned int gmii_lpa;
-
+
/* Extended bits are in bits 10 and 11 of GMII_GTSR */
- mii_lpa = efab->op->mdio_read ( efab, MII_LPA );
- gmii_lpa = ( efab->op->mdio_read ( efab, GMII_GTSR ) >> 10 ) & 0x03;
+ mii_lpa = falcon_mdio_read ( efab, 0, MII_LPA );
+ gmii_lpa = ( falcon_mdio_read ( efab, 0, GMII_GTSR ) >> 10 ) & 0x03;
return ( ( gmii_lpa << 16 ) | mii_lpa );
}
@@ -299,7 +155,9 @@ static unsigned int gmii_autoneg_lpa ( struct efab_nic *efab ) {
* Calculate GMII autonegotiated link technology
*
*/
-static unsigned int gmii_nway_result ( unsigned int negotiated ) {
+static unsigned int
+gmii_nway_result ( unsigned int negotiated )
+{
unsigned int other_bits;
/* Mask out the speed and duplexity bits */
@@ -324,1167 +182,244 @@ static unsigned int gmii_nway_result ( unsigned int negotiated ) {
* Check GMII PHY link status
*
*/
-static int gmii_link_ok ( struct efab_nic *efab ) {
+static int
+gmii_link_ok ( struct efab_nic *efab )
+{
int status;
int phy_status;
-
+
/* BMSR is latching - it returns "link down" if the link has
* been down at any point since the last read. To get a
* real-time status, we therefore read the register twice and
* use the result of the second read.
*/
- efab->op->mdio_read ( efab, MII_BMSR );
- status = efab->op->mdio_read ( efab, MII_BMSR );
+ (void) falcon_mdio_read ( efab, 0, MII_BMSR );
+ status = falcon_mdio_read ( efab, 0, MII_BMSR );
/* Read the PHY-specific Status Register. This is
* non-latching, so we need do only a single read.
*/
- phy_status = efab->op->mdio_read ( efab, GMII_PSSR );
+ phy_status = falcon_mdio_read ( efab, 0, GMII_PSSR );
return ( ( status & BMSR_LSTATUS ) && ( phy_status & PSSR_LSTATUS ) );
}
/**************************************************************************
*
- * Alaska PHY
+ * MDIO routines
*
**************************************************************************
*/
-/**
- * Initialise Alaska PHY
- *
- */
-static void alaska_init ( struct efab_nic *efab ) {
- unsigned int advertised, lpa;
-
- /* Read link up status */
- efab->link_up = gmii_link_ok ( efab );
-
- if ( ! efab->link_up )
- return;
-
- /* Determine link options from PHY. */
- advertised = gmii_autoneg_advertised ( efab );
- lpa = gmii_autoneg_lpa ( efab );
- efab->link_options = gmii_nway_result ( advertised & lpa );
-
- /* print out the link speed */
- EFAB_LOG ( "%dMbps %s-duplex (%04x,%04x)\n",
- ( efab->link_options & LPA_10000 ? 1000 :
- ( efab->link_options & LPA_1000 ? 1000 :
- ( efab->link_options & LPA_100 ? 100 : 10 ) ) ),
- ( efab->link_options & LPA_DUPLEX ? "full" : "half" ),
- advertised, lpa );
-}
-
-
-/**************************************************************************
- *
- * Mentor MAC
- *
- **************************************************************************
- */
-
-/* GMAC configuration register 1 */
-#define GM_CFG1_REG_MAC 0x00
-#define GM_SW_RST_LBN 31
-#define GM_SW_RST_WIDTH 1
-#define GM_RX_FC_EN_LBN 5
-#define GM_RX_FC_EN_WIDTH 1
-#define GM_TX_FC_EN_LBN 4
-#define GM_TX_FC_EN_WIDTH 1
-#define GM_RX_EN_LBN 2
-#define GM_RX_EN_WIDTH 1
-#define GM_TX_EN_LBN 0
-#define GM_TX_EN_WIDTH 1
-
-/* GMAC configuration register 2 */
-#define GM_CFG2_REG_MAC 0x01
-#define GM_PAMBL_LEN_LBN 12
-#define GM_PAMBL_LEN_WIDTH 4
-#define GM_IF_MODE_LBN 8
-#define GM_IF_MODE_WIDTH 2
-#define GM_PAD_CRC_EN_LBN 2
-#define GM_PAD_CRC_EN_WIDTH 1
-#define GM_FD_LBN 0
-#define GM_FD_WIDTH 1
-
-/* GMAC maximum frame length register */
-#define GM_MAX_FLEN_REG_MAC 0x04
-#define GM_MAX_FLEN_LBN 0
-#define GM_MAX_FLEN_WIDTH 16
-
-/* GMAC MII management configuration register */
-#define GM_MII_MGMT_CFG_REG_MAC 0x08
-#define GM_MGMT_CLK_SEL_LBN 0
-#define GM_MGMT_CLK_SEL_WIDTH 3
-
-/* GMAC MII management command register */
-#define GM_MII_MGMT_CMD_REG_MAC 0x09
-#define GM_MGMT_SCAN_CYC_LBN 1
-#define GM_MGMT_SCAN_CYC_WIDTH 1
-#define GM_MGMT_RD_CYC_LBN 0
-#define GM_MGMT_RD_CYC_WIDTH 1
-
-/* GMAC MII management address register */
-#define GM_MII_MGMT_ADR_REG_MAC 0x0a
-#define GM_MGMT_PHY_ADDR_LBN 8
-#define GM_MGMT_PHY_ADDR_WIDTH 5
-#define GM_MGMT_REG_ADDR_LBN 0
-#define GM_MGMT_REG_ADDR_WIDTH 5
-
-/* GMAC MII management control register */
-#define GM_MII_MGMT_CTL_REG_MAC 0x0b
-#define GM_MGMT_CTL_LBN 0
-#define GM_MGMT_CTL_WIDTH 16
-
-/* GMAC MII management status register */
-#define GM_MII_MGMT_STAT_REG_MAC 0x0c
-#define GM_MGMT_STAT_LBN 0
-#define GM_MGMT_STAT_WIDTH 16
-
-/* GMAC MII management indicators register */
-#define GM_MII_MGMT_IND_REG_MAC 0x0d
-#define GM_MGMT_BUSY_LBN 0
-#define GM_MGMT_BUSY_WIDTH 1
-
-/* GMAC station address register 1 */
-#define GM_ADR1_REG_MAC 0x10
-#define GM_HWADDR_5_LBN 24
-#define GM_HWADDR_5_WIDTH 8
-#define GM_HWADDR_4_LBN 16
-#define GM_HWADDR_4_WIDTH 8
-#define GM_HWADDR_3_LBN 8
-#define GM_HWADDR_3_WIDTH 8
-#define GM_HWADDR_2_LBN 0
-#define GM_HWADDR_2_WIDTH 8
-
-/* GMAC station address register 2 */
-#define GM_ADR2_REG_MAC 0x11
-#define GM_HWADDR_1_LBN 24
-#define GM_HWADDR_1_WIDTH 8
-#define GM_HWADDR_0_LBN 16
-#define GM_HWADDR_0_WIDTH 8
-
-/* GMAC FIFO configuration register 0 */
-#define GMF_CFG0_REG_MAC 0x12
-#define GMF_FTFENREQ_LBN 12
-#define GMF_FTFENREQ_WIDTH 1
-#define GMF_STFENREQ_LBN 11
-#define GMF_STFENREQ_WIDTH 1
-#define GMF_FRFENREQ_LBN 10
-#define GMF_FRFENREQ_WIDTH 1
-#define GMF_SRFENREQ_LBN 9
-#define GMF_SRFENREQ_WIDTH 1
-#define GMF_WTMENREQ_LBN 8
-#define GMF_WTMENREQ_WIDTH 1
-
-/* GMAC FIFO configuration register 1 */
-#define GMF_CFG1_REG_MAC 0x13
-#define GMF_CFGFRTH_LBN 16
-#define GMF_CFGFRTH_WIDTH 5
-#define GMF_CFGXOFFRTX_LBN 0
-#define GMF_CFGXOFFRTX_WIDTH 16
-
-/* GMAC FIFO configuration register 2 */
-#define GMF_CFG2_REG_MAC 0x14
-#define GMF_CFGHWM_LBN 16
-#define GMF_CFGHWM_WIDTH 6
-#define GMF_CFGLWM_LBN 0
-#define GMF_CFGLWM_WIDTH 6
-
-/* GMAC FIFO configuration register 3 */
-#define GMF_CFG3_REG_MAC 0x15
-#define GMF_CFGHWMFT_LBN 16
-#define GMF_CFGHWMFT_WIDTH 6
-#define GMF_CFGFTTH_LBN 0
-#define GMF_CFGFTTH_WIDTH 6
-
-/* GMAC FIFO configuration register 4 */
-#define GMF_CFG4_REG_MAC 0x16
-#define GMF_HSTFLTRFRM_PAUSE_LBN 12
-#define GMF_HSTFLTRFRM_PAUSE_WIDTH 12
-
-/* GMAC FIFO configuration register 5 */
-#define GMF_CFG5_REG_MAC 0x17
-#define GMF_CFGHDPLX_LBN 22
-#define GMF_CFGHDPLX_WIDTH 1
-#define GMF_CFGBYTMODE_LBN 19
-#define GMF_CFGBYTMODE_WIDTH 1
-#define GMF_HSTDRPLT64_LBN 18
-#define GMF_HSTDRPLT64_WIDTH 1
-#define GMF_HSTFLTRFRMDC_PAUSE_LBN 12
-#define GMF_HSTFLTRFRMDC_PAUSE_WIDTH 1
-
-struct efab_mentormac_parameters {
- int gmf_cfgfrth;
- int gmf_cfgftth;
- int gmf_cfghwmft;
- int gmf_cfghwm;
- int gmf_cfglwm;
-};
-
-/**
- * Reset Mentor MAC
- *
- */
-static void mentormac_reset ( struct efab_nic *efab ) {
- efab_dword_t reg;
- int save_port;
-
- /* Take into reset */
- EFAB_POPULATE_DWORD_1 ( reg, GM_SW_RST, 1 );
- efab->mac_op->mac_writel ( efab, &reg, GM_CFG1_REG_MAC );
- udelay ( 1000 );
-
- /* Take out of reset */
- EFAB_POPULATE_DWORD_1 ( reg, GM_SW_RST, 0 );
- efab->mac_op->mac_writel ( efab, &reg, GM_CFG1_REG_MAC );
- udelay ( 1000 );
-
- /* Mentor MAC connects both PHYs to MAC 0 */
- save_port = efab->port;
- efab->port = 0;
- /* Configure GMII interface so PHY is accessible. Note that
- * GMII interface is connected only to port 0, and that on
- * Falcon this is a no-op.
- */
- EFAB_POPULATE_DWORD_1 ( reg, GM_MGMT_CLK_SEL, 0x4 );
- efab->mac_op->mac_writel ( efab, &reg, GM_MII_MGMT_CFG_REG_MAC );
- udelay ( 10 );
- efab->port = save_port;
-}
-
-/**
- * Initialise Mentor MAC
- *
- */
-static void mentormac_init ( struct efab_nic *efab,
- struct efab_mentormac_parameters *params ) {
- int pause, if_mode, full_duplex, bytemode, half_duplex;
- efab_dword_t reg;
-
- /* Configuration register 1 */
- pause = ( efab->link_options & LPA_PAUSE ) ? 1 : 0;
- if ( ! ( efab->link_options & LPA_DUPLEX ) ) {
- /* Half-duplex operation requires TX flow control */
- pause = 1;
+/* Numbering of the MDIO Manageable Devices (MMDs) */
+/* Physical Medium Attachment/ Physical Medium Dependent sublayer */
+#define MDIO_MMD_PMAPMD (1)
+/* WAN Interface Sublayer */
+#define MDIO_MMD_WIS (2)
+/* Physical Coding Sublayer */
+#define MDIO_MMD_PCS (3)
+/* PHY Extender Sublayer */
+#define MDIO_MMD_PHYXS (4)
+/* Extender Sublayer */
+#define MDIO_MMD_DTEXS (5)
+/* Transmission convergence */
+#define MDIO_MMD_TC (6)
+/* Auto negotiation */
+#define MDIO_MMD_AN (7)
+
+/* Generic register locations */
+#define MDIO_MMDREG_CTRL1 (0)
+#define MDIO_MMDREG_STAT1 (1)
+#define MDIO_MMDREG_DEVS0 (5)
+#define MDIO_MMDREG_STAT2 (8)
+
+/* Bits in MMDREG_CTRL1 */
+/* Reset */
+#define MDIO_MMDREG_CTRL1_RESET_LBN (15)
+#define MDIO_MMDREG_CTRL1_RESET_WIDTH (1)
+
+/* Bits in MMDREG_STAT1 */
+#define MDIO_MMDREG_STAT1_FAULT_LBN (7)
+#define MDIO_MMDREG_STAT1_FAULT_WIDTH (1)
+
+/* Link state */
+#define MDIO_MMDREG_STAT1_LINK_LBN (2)
+#define MDIO_MMDREG_STAT1_LINK_WIDTH (1)
+
+/* Bits in MMDREG_DEVS0. */
+#define DEV_PRESENT_BIT(_b) (1 << _b)
+
+#define MDIO_MMDREG_DEVS0_DTEXS DEV_PRESENT_BIT(MDIO_MMD_DTEXS)
+#define MDIO_MMDREG_DEVS0_PHYXS DEV_PRESENT_BIT(MDIO_MMD_PHYXS)
+#define MDIO_MMDREG_DEVS0_PCS DEV_PRESENT_BIT(MDIO_MMD_PCS)
+#define MDIO_MMDREG_DEVS0_WIS DEV_PRESENT_BIT(MDIO_MMD_WIS)
+#define MDIO_MMDREG_DEVS0_PMAPMD DEV_PRESENT_BIT(MDIO_MMD_PMAPMD)
+
+#define MDIO_MMDREG_DEVS0_AN DEV_PRESENT_BIT(MDIO_MMD_AN)
+
+/* Bits in MMDREG_STAT2 */
+#define MDIO_MMDREG_STAT2_PRESENT_VAL (2)
+#define MDIO_MMDREG_STAT2_PRESENT_LBN (14)
+#define MDIO_MMDREG_STAT2_PRESENT_WIDTH (2)
+
+/* PHY XGXS lane state */
+#define MDIO_PHYXS_LANE_STATE (0x18)
+#define MDIO_PHYXS_LANE_ALIGNED_LBN (12)
+#define MDIO_PHYXS_LANE_SYNC0_LBN (0)
+#define MDIO_PHYXS_LANE_SYNC1_LBN (1)
+#define MDIO_PHYXS_LANE_SYNC2_LBN (2)
+#define MDIO_PHYXS_LANE_SYNC3_LBN (3)
+
+/* This ought to be ridiculous overkill. We expect it to fail rarely */
+#define MDIO45_RESET_TRIES 100
+#define MDIO45_RESET_SPINTIME 10
+
+static int
+mdio_clause45_wait_reset_mmds ( struct efab_nic* efab )
+{
+ int tries = MDIO45_RESET_TRIES;
+ int in_reset;
+
+ while(tries) {
+ int mask = efab->phy_op->mmds;
+ int mmd = 0;
+ in_reset = 0;
+ while(mask) {
+ if (mask & 1) {
+ int stat = falcon_mdio_read ( efab, mmd,
+ MDIO_MMDREG_CTRL1 );
+ if (stat < 0) {
+ EFAB_ERR("Failed to read status of MMD %d\n",
+ mmd );
+ in_reset = 1;
+ break;
+ }
+ if (stat & (1 << MDIO_MMDREG_CTRL1_RESET_LBN))
+ in_reset |= (1 << mmd);
+ }
+ mask = mask >> 1;
+ mmd++;
+ }
+ if (!in_reset)
+ break;
+ tries--;
+ mdelay ( MDIO45_RESET_SPINTIME );
}
- EFAB_POPULATE_DWORD_4 ( reg,
- GM_TX_EN, 1,
- GM_TX_FC_EN, pause,
- GM_RX_EN, 1,
- GM_RX_FC_EN, 1 );
- efab->mac_op->mac_writel ( efab, &reg, GM_CFG1_REG_MAC );
- udelay ( 10 );
-
- /* Configuration register 2 */
- if_mode = ( efab->link_options & LPA_1000 ) ? 2 : 1;
- full_duplex = ( efab->link_options & LPA_DUPLEX ) ? 1 : 0;
- EFAB_POPULATE_DWORD_4 ( reg,
- GM_IF_MODE, if_mode,
- GM_PAD_CRC_EN, 1,
- GM_FD, full_duplex,
- GM_PAMBL_LEN, 0x7 /* ? */ );
- efab->mac_op->mac_writel ( efab, &reg, GM_CFG2_REG_MAC );
- udelay ( 10 );
-
- /* Max frame len register */
- EFAB_POPULATE_DWORD_1 ( reg, GM_MAX_FLEN, ETH_FRAME_LEN + 4 /* FCS */);
- efab->mac_op->mac_writel ( efab, &reg, GM_MAX_FLEN_REG_MAC );
- udelay ( 10 );
-
- /* FIFO configuration register 0 */
- EFAB_POPULATE_DWORD_5 ( reg,
- GMF_FTFENREQ, 1,
- GMF_STFENREQ, 1,
- GMF_FRFENREQ, 1,
- GMF_SRFENREQ, 1,
- GMF_WTMENREQ, 1 );
- efab->mac_op->mac_writel ( efab, &reg, GMF_CFG0_REG_MAC );
- udelay ( 10 );
-
- /* FIFO configuration register 1 */
- EFAB_POPULATE_DWORD_2 ( reg,
- GMF_CFGFRTH, params->gmf_cfgfrth,
- GMF_CFGXOFFRTX, 0xffff );
- efab->mac_op->mac_writel ( efab, &reg, GMF_CFG1_REG_MAC );
- udelay ( 10 );
-
- /* FIFO configuration register 2 */
- EFAB_POPULATE_DWORD_2 ( reg,
- GMF_CFGHWM, params->gmf_cfghwm,
- GMF_CFGLWM, params->gmf_cfglwm );
- efab->mac_op->mac_writel ( efab, &reg, GMF_CFG2_REG_MAC );
- udelay ( 10 );
-
- /* FIFO configuration register 3 */
- EFAB_POPULATE_DWORD_2 ( reg,
- GMF_CFGHWMFT, params->gmf_cfghwmft,
- GMF_CFGFTTH, params->gmf_cfgftth );
- efab->mac_op->mac_writel ( efab, &reg, GMF_CFG3_REG_MAC );
- udelay ( 10 );
-
- /* FIFO configuration register 4 */
- EFAB_POPULATE_DWORD_1 ( reg, GMF_HSTFLTRFRM_PAUSE, 1 );
- efab->mac_op->mac_writel ( efab, &reg, GMF_CFG4_REG_MAC );
- udelay ( 10 );
-
- /* FIFO configuration register 5 */
- bytemode = ( efab->link_options & LPA_1000 ) ? 1 : 0;
- half_duplex = ( efab->link_options & LPA_DUPLEX ) ? 0 : 1;
- efab->mac_op->mac_readl ( efab, &reg, GMF_CFG5_REG_MAC );
- EFAB_SET_DWORD_FIELD ( reg, GMF_CFGBYTMODE, bytemode );
- EFAB_SET_DWORD_FIELD ( reg, GMF_CFGHDPLX, half_duplex );
- EFAB_SET_DWORD_FIELD ( reg, GMF_HSTDRPLT64, half_duplex );
- EFAB_SET_DWORD_FIELD ( reg, GMF_HSTFLTRFRMDC_PAUSE, 0 );
- efab->mac_op->mac_writel ( efab, &reg, GMF_CFG5_REG_MAC );
- udelay ( 10 );
-
- /* MAC address */
- EFAB_POPULATE_DWORD_4 ( reg,
- GM_HWADDR_5, efab->mac_addr[5],
- GM_HWADDR_4, efab->mac_addr[4],
- GM_HWADDR_3, efab->mac_addr[3],
- GM_HWADDR_2, efab->mac_addr[2] );
- efab->mac_op->mac_writel ( efab, &reg, GM_ADR1_REG_MAC );
- udelay ( 10 );
- EFAB_POPULATE_DWORD_2 ( reg,
- GM_HWADDR_1, efab->mac_addr[1],
- GM_HWADDR_0, efab->mac_addr[0] );
- efab->mac_op->mac_writel ( efab, &reg, GM_ADR2_REG_MAC );
- udelay ( 10 );
-}
-
-/**
- * Wait for GMII access to complete
- *
- */
-static int mentormac_gmii_wait ( struct efab_nic *efab ) {
- int count;
- efab_dword_t indicator;
-
- for ( count = 0 ; count < 1000 ; count++ ) {
- udelay ( 10 );
- efab->mac_op->mac_readl ( efab, &indicator,
- GM_MII_MGMT_IND_REG_MAC );
- if ( EFAB_DWORD_FIELD ( indicator, GM_MGMT_BUSY ) == 0 )
- return 1;
+ if (in_reset != 0) {
+ EFAB_ERR("Not all MMDs came out of reset in time. MMDs "
+ "still in reset: %x\n", in_reset);
+ return -ETIMEDOUT;
}
- EFAB_ERR ( "Timed out waiting for GMII\n" );
return 0;
}
-/**
- * Write a GMII register
- *
- */
-static void mentormac_mdio_write ( struct efab_nic *efab, int phy_id,
- int location, int value ) {
- efab_dword_t reg;
- int save_port;
-
- EFAB_TRACE ( "Writing GMII %d register %02x with %04x\n", phy_id,
- location, value );
-
- /* Mentor MAC connects both PHYs to MAC 0 */
- save_port = efab->port;
- efab->port = 0;
-
- /* Check MII not currently being accessed */
- if ( ! mentormac_gmii_wait ( efab ) )
- goto out;
-
- /* Write the address register */
- EFAB_POPULATE_DWORD_2 ( reg,
- GM_MGMT_PHY_ADDR, phy_id,
- GM_MGMT_REG_ADDR, location );
- efab->mac_op->mac_writel ( efab, &reg, GM_MII_MGMT_ADR_REG_MAC );
- udelay ( 10 );
-
- /* Write data */
- EFAB_POPULATE_DWORD_1 ( reg, GM_MGMT_CTL, value );
- efab->mac_op->mac_writel ( efab, &reg, GM_MII_MGMT_CTL_REG_MAC );
-
- /* Wait for data to be written */
- mentormac_gmii_wait ( efab );
-
- out:
- /* Restore efab->port */
- efab->port = save_port;
-}
-
-/**
- * Read a GMII register
- *
- */
-static int mentormac_mdio_read ( struct efab_nic *efab, int phy_id,
- int location ) {
- efab_dword_t reg;
- int value = 0xffff;
- int save_port;
-
- /* Mentor MAC connects both PHYs to MAC 0 */
- save_port = efab->port;
- efab->port = 0;
-
- /* Check MII not currently being accessed */
- if ( ! mentormac_gmii_wait ( efab ) )
- goto out;
-
- /* Write the address register */
- EFAB_POPULATE_DWORD_2 ( reg,
- GM_MGMT_PHY_ADDR, phy_id,
- GM_MGMT_REG_ADDR, location );
- efab->mac_op->mac_writel ( efab, &reg, GM_MII_MGMT_ADR_REG_MAC );
- udelay ( 10 );
-
- /* Request data to be read */
- EFAB_POPULATE_DWORD_1 ( reg, GM_MGMT_RD_CYC, 1 );
- efab->mac_op->mac_writel ( efab, &reg, GM_MII_MGMT_CMD_REG_MAC );
-
- /* Wait for data to be become available */
- if ( mentormac_gmii_wait ( efab ) ) {
- /* Read data */
- efab->mac_op->mac_readl ( efab, &reg, GM_MII_MGMT_STAT_REG_MAC );
- value = EFAB_DWORD_FIELD ( reg, GM_MGMT_STAT );
- EFAB_TRACE ( "Read from GMII %d register %02x, got %04x\n",
- phy_id, location, value );
- }
-
- /* Signal completion */
- EFAB_ZERO_DWORD ( reg );
- efab->mac_op->mac_writel ( efab, &reg, GM_MII_MGMT_CMD_REG_MAC );
- udelay ( 10 );
-
- out:
- /* Restore efab->port */
- efab->port = save_port;
-
- return value;
-}
-
-/**************************************************************************
- *
- * EF1002 routines
- *
- **************************************************************************
- */
-
-/** Control and General Status */
-#define EF1_CTR_GEN_STATUS0_REG 0x0
-#define EF1_MASTER_EVENTS_LBN 12
-#define EF1_MASTER_EVENTS_WIDTH 1
-#define EF1_TX_ENGINE_EN_LBN 19
-#define EF1_TX_ENGINE_EN_WIDTH 1
-#define EF1_RX_ENGINE_EN_LBN 18
-#define EF1_RX_ENGINE_EN_WIDTH 1
-#define EF1_TURBO2_LBN 17
-#define EF1_TURBO2_WIDTH 1
-#define EF1_TURBO1_LBN 16
-#define EF1_TURBO1_WIDTH 1
-#define EF1_TURBO3_LBN 14
-#define EF1_TURBO3_WIDTH 1
-#define EF1_LB_RESET_LBN 3
-#define EF1_LB_RESET_WIDTH 1
-#define EF1_MAC_RESET_LBN 2
-#define EF1_MAC_RESET_WIDTH 1
-#define EF1_CAM_ENABLE_LBN 1
-#define EF1_CAM_ENABLE_WIDTH 1
-
-/** IRQ sources */
-#define EF1_IRQ_SRC_REG 0x0008
-
-/** IRQ mask */
-#define EF1_IRQ_MASK_REG 0x000c
-#define EF1_IRQ_PHY1_LBN 11
-#define EF1_IRQ_PHY1_WIDTH 1
-#define EF1_IRQ_PHY0_LBN 10
-#define EF1_IRQ_PHY0_WIDTH 1
-#define EF1_IRQ_SERR_LBN 7
-#define EF1_IRQ_SERR_WIDTH 1
-#define EF1_IRQ_EVQ_LBN 3
-#define EF1_IRQ_EVQ_WIDTH 1
-
-/** Event generation */
-#define EF1_EVT3_REG 0x38
-
-/** EEPROMaccess */
-#define EF1_EEPROM_REG 0x40
-#define EF1_EEPROM_SDA_LBN 31
-#define EF1_EEPROM_SDA_WIDTH 1
-#define EF1_EEPROM_SCL_LBN 30
-#define EF1_EEPROM_SCL_WIDTH 1
-#define EF1_JTAG_DISCONNECT_LBN 17
-#define EF1_JTAG_DISCONNECT_WIDTH 1
-#define EF1_EEPROM_LBN 0
-#define EF1_EEPROM_WIDTH 32
-
-/** Control register 2 */
-#define EF1_CTL2_REG 0x4c
-#define EF1_PLL_TRAP_LBN 31
-#define EF1_PLL_TRAP_WIDTH 1
-#define EF1_MEM_MAP_4MB_LBN 11
-#define EF1_MEM_MAP_4MB_WIDTH 1
-#define EF1_EV_INTR_CLR_WRITE_LBN 6
-#define EF1_EV_INTR_CLR_WRITE_WIDTH 1
-#define EF1_BURST_MERGE_LBN 5
-#define EF1_BURST_MERGE_WIDTH 1
-#define EF1_CLEAR_NULL_PAD_LBN 4
-#define EF1_CLEAR_NULL_PAD_WIDTH 1
-#define EF1_SW_RESET_LBN 2
-#define EF1_SW_RESET_WIDTH 1
-#define EF1_INTR_AFTER_EVENT_LBN 1
-#define EF1_INTR_AFTER_EVENT_WIDTH 1
-
-/** Event FIFO */
-#define EF1_EVENT_FIFO_REG 0x50
-
-/** Event FIFO count */
-#define EF1_EVENT_FIFO_COUNT_REG 0x5c
-#define EF1_EV_COUNT_LBN 0
-#define EF1_EV_COUNT_WIDTH 16
-
-/** TX DMA control and status */
-#define EF1_DMA_TX_CSR_REG 0x80
-#define EF1_DMA_TX_CSR_CHAIN_EN_LBN 8
-#define EF1_DMA_TX_CSR_CHAIN_EN_WIDTH 1
-#define EF1_DMA_TX_CSR_ENABLE_LBN 4
-#define EF1_DMA_TX_CSR_ENABLE_WIDTH 1
-#define EF1_DMA_TX_CSR_INT_EN_LBN 0
-#define EF1_DMA_TX_CSR_INT_EN_WIDTH 1
-
-/** RX DMA control and status */
-#define EF1_DMA_RX_CSR_REG 0xa0
-#define EF1_DMA_RX_ABOVE_1GB_EN_LBN 6
-#define EF1_DMA_RX_ABOVE_1GB_EN_WIDTH 1
-#define EF1_DMA_RX_BELOW_1MB_EN_LBN 5
-#define EF1_DMA_RX_BELOW_1MB_EN_WIDTH 1
-#define EF1_DMA_RX_CSR_ENABLE_LBN 0
-#define EF1_DMA_RX_CSR_ENABLE_WIDTH 1
-
-/** Level 5 watermark register (in MAC space) */
-#define EF1_GMF_L5WM_REG_MAC 0x20
-#define EF1_L5WM_LBN 0
-#define EF1_L5WM_WIDTH 32
-
-/** MAC clock */
-#define EF1_GM_MAC_CLK_REG 0x112000
-#define EF1_GM_PORT0_MAC_CLK_LBN 0
-#define EF1_GM_PORT0_MAC_CLK_WIDTH 1
-#define EF1_GM_PORT1_MAC_CLK_LBN 1
-#define EF1_GM_PORT1_MAC_CLK_WIDTH 1
-
-/** TX descriptor FIFO */
-#define EF1_TX_DESC_FIFO 0x141000
-#define EF1_TX_KER_EVQ_LBN 80
-#define EF1_TX_KER_EVQ_WIDTH 12
-#define EF1_TX_KER_IDX_LBN 64
-#define EF1_TX_KER_IDX_WIDTH 16
-#define EF1_TX_KER_MODE_LBN 63
-#define EF1_TX_KER_MODE_WIDTH 1
-#define EF1_TX_KER_PORT_LBN 60
-#define EF1_TX_KER_PORT_WIDTH 1
-#define EF1_TX_KER_CONT_LBN 56
-#define EF1_TX_KER_CONT_WIDTH 1
-#define EF1_TX_KER_BYTE_CNT_LBN 32
-#define EF1_TX_KER_BYTE_CNT_WIDTH 24
-#define EF1_TX_KER_BUF_ADR_LBN 0
-#define EF1_TX_KER_BUF_ADR_WIDTH 32
-
-/** TX descriptor FIFO flush */
-#define EF1_TX_DESC_FIFO_FLUSH 0x141ffc
-
-/** RX descriptor FIFO */
-#define EF1_RX_DESC_FIFO 0x145000
-#define EF1_RX_KER_EVQ_LBN 48
-#define EF1_RX_KER_EVQ_WIDTH 12
-#define EF1_RX_KER_IDX_LBN 32
-#define EF1_RX_KER_IDX_WIDTH 16
-#define EF1_RX_KER_BUF_ADR_LBN 0
-#define EF1_RX_KER_BUF_ADR_WIDTH 32
-
-/** RX descriptor FIFO flush */
-#define EF1_RX_DESC_FIFO_FLUSH 0x145ffc
-
-/** CAM */
-#define EF1_CAM_BASE 0x1c0000
-#define EF1_CAM_WTF_DOES_THIS_DO_LBN 0
-#define EF1_CAM_WTF_DOES_THIS_DO_WIDTH 32
-
-/** Event queue pointers */
-#define EF1_EVQ_PTR_BASE 0x260000
-#define EF1_EVQ_SIZE_LBN 29
-#define EF1_EVQ_SIZE_WIDTH 2
-#define EF1_EVQ_SIZE_4K 3
-#define EF1_EVQ_SIZE_2K 2
-#define EF1_EVQ_SIZE_1K 1
-#define EF1_EVQ_SIZE_512 0
-#define EF1_EVQ_BUF_BASE_ID_LBN 0
-#define EF1_EVQ_BUF_BASE_ID_WIDTH 29
-
-/* MAC registers */
-#define EF1002_MAC_REGBANK 0x110000
-#define EF1002_MAC_REGBANK_SIZE 0x1000
-#define EF1002_MAC_REG_SIZE 0x08
-
-/** Offset of a MAC register within EF1002 */
-#define EF1002_MAC_REG( efab, mac_reg ) \
- ( EF1002_MAC_REGBANK + \
- ( (efab)->port * EF1002_MAC_REGBANK_SIZE ) + \
- ( (mac_reg) * EF1002_MAC_REG_SIZE ) )
-
-/* Event queue entries */
-#define EF1_EV_CODE_LBN 20
-#define EF1_EV_CODE_WIDTH 8
-#define EF1_RX_EV_DECODE 0x01
-#define EF1_TX_EV_DECODE 0x02
-#define EF1_TIMER_EV_DECODE 0x0b
-#define EF1_DRV_GEN_EV_DECODE 0x0f
-
-/* Receive events */
-#define EF1_RX_EV_LEN_LBN 48
-#define EF1_RX_EV_LEN_WIDTH 16
-#define EF1_RX_EV_PORT_LBN 17
-#define EF1_RX_EV_PORT_WIDTH 3
-#define EF1_RX_EV_OK_LBN 16
-#define EF1_RX_EV_OK_WIDTH 1
-#define EF1_RX_EV_IDX_LBN 0
-#define EF1_RX_EV_IDX_WIDTH 16
-
-/* Transmit events */
-#define EF1_TX_EV_PORT_LBN 17
-#define EF1_TX_EV_PORT_WIDTH 3
-#define EF1_TX_EV_OK_LBN 16
-#define EF1_TX_EV_OK_WIDTH 1
-#define EF1_TX_EV_IDX_LBN 0
-#define EF1_TX_EV_IDX_WIDTH 16
-
-/* forward decleration */
-static struct efab_mac_operations ef1002_mac_operations;
-
-/* I2C ID of the EEPROM */
-#define EF1_EEPROM_I2C_ID 0x50
-
-/* Offset of MAC address within EEPROM */
-#define EF1_EEPROM_HWADDR_OFFSET 0x0
-
-/**
- * Write dword to EF1002 register
- *
- */
-static inline void ef1002_writel ( struct efab_nic *efab, efab_dword_t *value,
- unsigned int reg ) {
- EFAB_REGDUMP ( "Writing register %x with " EFAB_DWORD_FMT "\n",
- reg, EFAB_DWORD_VAL ( *value ) );
- writel ( value->u32[0], efab->membase + reg );
-}
-
-/**
- * Read dword from an EF1002 register
- *
- */
-static inline void ef1002_readl ( struct efab_nic *efab, efab_dword_t *value,
- unsigned int reg ) {
- value->u32[0] = readl ( efab->membase + reg );
- EFAB_REGDUMP ( "Read from register %x, got " EFAB_DWORD_FMT "\n",
- reg, EFAB_DWORD_VAL ( *value ) );
-}
-
-/**
- * Read dword from an EF1002 register, silently
- *
- */
-static inline void ef1002_readl_silent ( struct efab_nic *efab,
- efab_dword_t *value,
- unsigned int reg ) {
- value->u32[0] = readl ( efab->membase + reg );
-}
-
-/**
- * Get memory base
- *
- */
-static void ef1002_get_membase ( struct efab_nic *efab ) {
- unsigned long membase_phys;
-
- membase_phys = pci_bar_start ( efab->pci, PCI_BASE_ADDRESS_0 );
- efab->membase = ioremap ( membase_phys, 0x800000 );
-}
-
-/** PCI registers to backup/restore over a device reset */
-static const unsigned int efab_pci_reg_addr[] = {
- PCI_COMMAND, 0x0c /* PCI_CACHE_LINE_SIZE */,
- PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, PCI_BASE_ADDRESS_2,
- PCI_BASE_ADDRESS_3, PCI_ROM_ADDRESS, PCI_INTERRUPT_LINE,
-};
-/** Number of registers in efab_pci_reg_addr */
-#define EFAB_NUM_PCI_REG \
- ( sizeof ( efab_pci_reg_addr ) / sizeof ( efab_pci_reg_addr[0] ) )
-/** PCI configuration space backup */
-struct efab_pci_reg {
- uint32_t reg[EFAB_NUM_PCI_REG];
-};
-
-/*
- * I2C interface and EEPROM
- *
- */
-
-static unsigned long ef1002_i2c_bits[] = {
- [I2C_BIT_SCL] = ( 1 << 30 ),
- [I2C_BIT_SDA] = ( 1 << 31 ),
-};
-
-static void ef1002_i2c_write_bit ( struct bit_basher *basher,
- unsigned int bit_id, unsigned long data ) {
- struct efab_nic *efab = container_of ( basher, struct efab_nic,
- ef1002_i2c.basher );
- unsigned long mask;
- efab_dword_t reg;
+static int
+mdio_clause45_reset_mmd ( struct efab_nic *efab, int mmd )
+{
+ int tries = MDIO45_RESET_TRIES;
+ int ctrl;
- mask = ef1002_i2c_bits[bit_id];
- efab->ef1002_i2c_outputs &= ~mask;
- efab->ef1002_i2c_outputs |= ( data & mask );
- EFAB_POPULATE_DWORD_1 ( reg, EF1_EEPROM, efab->ef1002_i2c_outputs );
- ef1002_writel ( efab, &reg, EF1_EEPROM_REG );
-}
+ falcon_mdio_write ( efab, mmd, MDIO_MMDREG_CTRL1,
+ ( 1 << MDIO_MMDREG_CTRL1_RESET_LBN ) );
-static int ef1002_i2c_read_bit ( struct bit_basher *basher,
- unsigned int bit_id ) {
- struct efab_nic *efab = container_of ( basher, struct efab_nic,
- ef1002_i2c.basher );
- unsigned long mask;
- efab_dword_t reg;
+ /* Wait for the reset bit to clear. */
+ do {
+ mdelay ( MDIO45_RESET_SPINTIME );
- mask = ef1002_i2c_bits[bit_id];
- ef1002_readl ( efab, &reg, EF1_EEPROM_REG );
- return ( EFAB_DWORD_FIELD ( reg, EF1_EEPROM ) & mask );
-}
+ ctrl = falcon_mdio_read ( efab, mmd, MDIO_MMDREG_CTRL1 );
+ if ( ~ctrl & ( 1 << MDIO_MMDREG_CTRL1_RESET_LBN ) )
+ return 0;
+ } while ( --tries );
-static struct bit_basher_operations ef1002_basher_ops = {
- .read = ef1002_i2c_read_bit,
- .write = ef1002_i2c_write_bit,
-};
+ EFAB_ERR ( "Failed to reset mmd %d\n", mmd );
-static void ef1002_init_eeprom ( struct efab_nic *efab ) {
- efab->ef1002_i2c.basher.op = &ef1002_basher_ops;
- init_i2c_bit_basher ( &efab->ef1002_i2c );
- efab->ef1002_eeprom.address = EF1_EEPROM_I2C_ID;
+ return -ETIMEDOUT;
}
-/**
- * Reset device
- *
- */
-static int ef1002_reset ( struct efab_nic *efab ) {
- struct efab_pci_reg pci_reg;
- struct pci_device *pci_dev = efab->pci;
- efab_dword_t reg;
- unsigned int i;
- uint32_t tmp;
-
- /* Back up PCI configuration registers */
- for ( i = 0 ; i < EFAB_NUM_PCI_REG ; i++ ) {
- pci_read_config_dword ( pci_dev, efab_pci_reg_addr[i],
- &pci_reg.reg[i] );
- }
-
- /* Reset the whole device. */
- EFAB_POPULATE_DWORD_1 ( reg, EF1_SW_RESET, 1 );
- ef1002_writel ( efab, &reg, EF1_CTL2_REG );
- mdelay ( 200 );
-
- /* Restore PCI configuration space */
- for ( i = 0 ; i < EFAB_NUM_PCI_REG ; i++ ) {
- pci_write_config_dword ( pci_dev, efab_pci_reg_addr[i],
- pci_reg.reg[i] );
- }
-
- /* Verify PCI configuration space */
- for ( i = 0 ; i < EFAB_NUM_PCI_REG ; i++ ) {
- pci_read_config_dword ( pci_dev, efab_pci_reg_addr[i], &tmp );
- if ( tmp != pci_reg.reg[i] ) {
- EFAB_LOG ( "PCI restore failed on register %02x "
- "(is %08lx, should be %08lx); reboot\n",
- i, tmp, pci_reg.reg[i] );
- return 0;
+static int
+mdio_clause45_links_ok(struct efab_nic *efab )
+{
+ int status, good;
+ int ok = 1;
+ int mmd = 0;
+ int mmd_mask = efab->phy_op->mmds;
+
+ while (mmd_mask) {
+ if (mmd_mask & 1) {
+ /* Double reads because link state is latched, and a
+ * read moves the current state into the register */
+ status = falcon_mdio_read ( efab, mmd,
+ MDIO_MMDREG_STAT1 );
+ status = falcon_mdio_read ( efab, mmd,
+ MDIO_MMDREG_STAT1 );
+
+ good = status & (1 << MDIO_MMDREG_STAT1_LINK_LBN);
+ ok = ok && good;
}
+ mmd_mask = (mmd_mask >> 1);
+ mmd++;
}
-
- /* Verify device reset complete */
- ef1002_readl ( efab, &reg, EF1_CTR_GEN_STATUS0_REG );
- if ( EFAB_DWORD_IS_ALL_ONES ( reg ) ) {
- EFAB_ERR ( "Reset failed\n" );
- return 0;
- }
-
- return 1;
-}
-
-/**
- * Initialise NIC
- *
- */
-static int ef1002_init_nic ( struct efab_nic *efab ) {
- efab_dword_t reg;
-
- /* patch in the MAC operations */
- efab->mac_op = &ef1002_mac_operations;
-
- /* No idea what CAM is, but the 'datasheet' says that we have
- * to write these values in at start of day
- */
- EFAB_POPULATE_DWORD_1 ( reg, EF1_CAM_WTF_DOES_THIS_DO, 0x6 );
- ef1002_writel ( efab, &reg, EF1_CAM_BASE + 0x20018 );
- udelay ( 1000 );
- EFAB_POPULATE_DWORD_1 ( reg, EF1_CAM_WTF_DOES_THIS_DO, 0x01000000 );
- ef1002_writel ( efab, &reg, EF1_CAM_BASE + 0x00018 );
- udelay ( 1000 );
-
- /* General control register 0 */
- ef1002_readl ( efab, &reg, EF1_CTR_GEN_STATUS0_REG );
- EFAB_SET_DWORD_FIELD ( reg, EF1_MASTER_EVENTS, 0 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_TX_ENGINE_EN, 0 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_RX_ENGINE_EN, 0 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_TURBO2, 1 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_TURBO1, 1 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_TURBO3, 1 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_CAM_ENABLE, 1 );
- ef1002_writel ( efab, &reg, EF1_CTR_GEN_STATUS0_REG );
- udelay ( 1000 );
-
- /* General control register 2 */
- ef1002_readl ( efab, &reg, EF1_CTL2_REG );
- EFAB_SET_DWORD_FIELD ( reg, EF1_PLL_TRAP, 1 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_MEM_MAP_4MB, 0 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_EV_INTR_CLR_WRITE, 0 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_BURST_MERGE, 0 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_CLEAR_NULL_PAD, 1 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_INTR_AFTER_EVENT, 1 );
- ef1002_writel ( efab, &reg, EF1_CTL2_REG );
- udelay ( 1000 );
-
- /* Enable RX DMA */
- ef1002_readl ( efab, &reg, EF1_DMA_RX_CSR_REG );
- EFAB_SET_DWORD_FIELD ( reg, EF1_DMA_RX_CSR_ENABLE, 1 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_DMA_RX_BELOW_1MB_EN, 1 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_DMA_RX_ABOVE_1GB_EN, 1 );
- ef1002_writel ( efab, &reg, EF1_DMA_RX_CSR_REG );
- udelay ( 1000 );
-
- /* Enable TX DMA */
- ef1002_readl ( efab, &reg, EF1_DMA_TX_CSR_REG );
- EFAB_SET_DWORD_FIELD ( reg, EF1_DMA_TX_CSR_CHAIN_EN, 1 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_DMA_TX_CSR_ENABLE, 0 /* ?? */ );
- EFAB_SET_DWORD_FIELD ( reg, EF1_DMA_TX_CSR_INT_EN, 0 /* ?? */ );
- ef1002_writel ( efab, &reg, EF1_DMA_TX_CSR_REG );
- udelay ( 1000 );
-
- /* Disconnect the JTAG chain. Read-modify-write is impossible
- * on the I2C control bits, since reading gives the state of
- * the line inputs rather than the last written state.
- */
- ef1002_readl ( efab, &reg, EF1_EEPROM_REG );
- EFAB_SET_DWORD_FIELD ( reg, EF1_EEPROM_SDA, 1 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_EEPROM_SCL, 1 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_JTAG_DISCONNECT, 1 );
- ef1002_writel ( efab, &reg, EF1_EEPROM_REG );
- udelay ( 10 );
-
- /* Flush descriptor queues */
- EFAB_ZERO_DWORD ( reg );
- ef1002_writel ( efab, &reg, EF1_RX_DESC_FIFO_FLUSH );
- ef1002_writel ( efab, &reg, EF1_TX_DESC_FIFO_FLUSH );
- wmb();
- udelay ( 10000 );
-
- /* Reset MAC */
- efab->mac_op->reset ( efab );
-
- /* Attach I2C bus */
- ef1002_init_eeprom ( efab );
-
- return 1;
-}
-
-/**
- * Read MAC address from EEPROM
- *
- */
-static int ef1002_read_eeprom ( struct efab_nic *efab ) {
- struct i2c_interface *i2c = &efab->ef1002_i2c.i2c;
- struct i2c_device *i2cdev = &efab->ef1002_eeprom;
-
- if ( i2c->read ( i2c, i2cdev, EF1_EEPROM_HWADDR_OFFSET,
- efab->mac_addr, sizeof ( efab->mac_addr ) ) != 0 )
- return 0;
-
- efab->mac_addr[ETH_ALEN-1] += efab->port;
-
- return 1;
-}
-
-/** RX descriptor */
-typedef efab_qword_t ef1002_rx_desc_t;
-
-/**
- * Build RX descriptor
- *
- */
-static void ef1002_build_rx_desc ( struct efab_nic *efab,
- struct efab_rx_buf *rx_buf ) {
- ef1002_rx_desc_t rxd;
-
- EFAB_POPULATE_QWORD_3 ( rxd,
- EF1_RX_KER_EVQ, 0,
- EF1_RX_KER_IDX, rx_buf->id,
- EF1_RX_KER_BUF_ADR,
- virt_to_bus ( rx_buf->addr ) );
- ef1002_writel ( efab, &rxd.dword[0], EF1_RX_DESC_FIFO + 0 );
- wmb();
- ef1002_writel ( efab, &rxd.dword[1], EF1_RX_DESC_FIFO + 4 );
- udelay ( 10 );
-}
-
-/**
- * Update RX descriptor write pointer
- *
- */
-static void ef1002_notify_rx_desc ( struct efab_nic *efab __unused ) {
- /* Nothing to do */
+ return ok;
}
-/** TX descriptor */
-typedef efab_oword_t ef1002_tx_desc_t;
-
-/**
- * Build TX descriptor
- *
- */
-static void ef1002_build_tx_desc ( struct efab_nic *efab,
- struct efab_tx_buf *tx_buf ) {
- ef1002_tx_desc_t txd;
-
- EFAB_POPULATE_OWORD_7 ( txd,
- EF1_TX_KER_EVQ, 0,
- EF1_TX_KER_IDX, tx_buf->id,
- EF1_TX_KER_MODE, 0 /* IP mode */,
- EF1_TX_KER_PORT, efab->port,
- EF1_TX_KER_CONT, 0,
- EF1_TX_KER_BYTE_CNT, tx_buf->len,
- EF1_TX_KER_BUF_ADR,
- virt_to_bus ( tx_buf->addr ) );
-
- ef1002_writel ( efab, &txd.dword[0], EF1_TX_DESC_FIFO + 0 );
- ef1002_writel ( efab, &txd.dword[1], EF1_TX_DESC_FIFO + 4 );
- wmb();
- ef1002_writel ( efab, &txd.dword[2], EF1_TX_DESC_FIFO + 8 );
- udelay ( 10 );
-}
-
-/**
- * Update TX descriptor write pointer
- *
- */
-static void ef1002_notify_tx_desc ( struct efab_nic *efab __unused ) {
- /* Nothing to do */
-}
-
-/** An event */
-typedef efab_qword_t ef1002_event_t;
-
-/**
- * Retrieve event from event queue
- *
- */
-static int ef1002_fetch_event ( struct efab_nic *efab,
- struct efab_event *event ) {
- efab_dword_t reg;
- int ev_code;
- int words;
-
- /* Check event FIFO depth */
- ef1002_readl_silent ( efab, &reg, EF1_EVENT_FIFO_COUNT_REG );
- words = EFAB_DWORD_FIELD ( reg, EF1_EV_COUNT );
- if ( ! words )
- return 0;
-
- /* Read event data */
- ef1002_readl ( efab, &reg, EF1_EVENT_FIFO_REG );
- DBG ( "Event is " EFAB_DWORD_FMT "\n", EFAB_DWORD_VAL ( reg ) );
-
- /* Decode event */
- ev_code = EFAB_DWORD_FIELD ( reg, EF1_EV_CODE );
- event->drop = 0;
- switch ( ev_code ) {
- case EF1_TX_EV_DECODE:
- event->type = EFAB_EV_TX;
- break;
- case EF1_RX_EV_DECODE:
- event->type = EFAB_EV_RX;
- event->rx_id = EFAB_DWORD_FIELD ( reg, EF1_RX_EV_IDX );
- /* RX len not available via event FIFO */
- event->rx_len = ETH_FRAME_LEN;
- break;
- case EF1_TIMER_EV_DECODE:
- /* These are safe to ignore. We seem to get some at
- * start of day, presumably due to the timers starting
- * up with random contents.
- */
- event->type = EFAB_EV_NONE;
- break;
- default:
- EFAB_ERR ( "Unknown event type %d\n", ev_code );
- event->type = EFAB_EV_NONE;
+static int
+mdio_clause45_check_mmds ( struct efab_nic *efab )
+{
+ int mmd = 0;
+ int devices = falcon_mdio_read ( efab, MDIO_MMD_PHYXS,
+ MDIO_MMDREG_DEVS0 );
+ int mmd_mask = efab->phy_op->mmds;
+
+ /* Check all the expected MMDs are present */
+ if ( devices < 0 ) {
+ EFAB_ERR ( "Failed to read devices present\n" );
+ return -EIO;
}
-
- /* Clear any pending interrupts */
- ef1002_readl ( efab, &reg, EF1_IRQ_SRC_REG );
-
- return 1;
-}
-
-/**
- * Enable/disable interrupts
- *
- */
-static void ef1002_mask_irq ( struct efab_nic *efab, int enabled ) {
- efab_dword_t irq_mask;
-
- EFAB_POPULATE_DWORD_2 ( irq_mask,
- EF1_IRQ_SERR, enabled,
- EF1_IRQ_EVQ, enabled );
- ef1002_writel ( efab, &irq_mask, EF1_IRQ_MASK_REG );
-}
-
-/**
- * Generate interrupt
- *
- */
-static void ef1002_generate_irq ( struct efab_nic *efab ) {
- ef1002_event_t test_event;
-
- EFAB_POPULATE_QWORD_1 ( test_event,
- EF1_EV_CODE, EF1_DRV_GEN_EV_DECODE );
- ef1002_writel ( efab, &test_event.dword[0], EF1_EVT3_REG );
-}
-
-/**
- * Write dword to an EF1002 MAC register
- *
- */
-static void ef1002_mac_writel ( struct efab_nic *efab,
- efab_dword_t *value, unsigned int mac_reg ) {
- ef1002_writel ( efab, value, EF1002_MAC_REG ( efab, mac_reg ) );
-}
-
-/**
- * Read dword from an EF1002 MAC register
- *
- */
-static void ef1002_mac_readl ( struct efab_nic *efab,
- efab_dword_t *value, unsigned int mac_reg ) {
- ef1002_readl ( efab, value, EF1002_MAC_REG ( efab, mac_reg ) );
-}
-
-/**
- * Initialise MAC
- *
- */
-static int ef1002_init_mac ( struct efab_nic *efab ) {
- static struct efab_mentormac_parameters ef1002_mentormac_params = {
- .gmf_cfgfrth = 0x13,
- .gmf_cfgftth = 0x10,
- .gmf_cfghwmft = 0x555,
- .gmf_cfghwm = 0x2a,
- .gmf_cfglwm = 0x15,
- };
- efab_dword_t reg;
- unsigned int mac_clk;
-
- /* Initialise PHY */
- alaska_init ( efab );
-
- /* Initialise MAC */
- mentormac_init ( efab, &ef1002_mentormac_params );
-
- /* Write Level 5 watermark register */
- EFAB_POPULATE_DWORD_1 ( reg, EF1_L5WM, 0x10040000 );
- efab->mac_op->mac_writel ( efab, &reg, EF1_GMF_L5WM_REG_MAC );
- udelay ( 10 );
-
- /* Set MAC clock speed */
- ef1002_readl ( efab, &reg, EF1_GM_MAC_CLK_REG );
- mac_clk = ( efab->link_options & LPA_1000 ) ? 0 : 1;
- if ( efab->port == 0 ) {
- EFAB_SET_DWORD_FIELD ( reg, EF1_GM_PORT0_MAC_CLK, mac_clk );
- } else {
- EFAB_SET_DWORD_FIELD ( reg, EF1_GM_PORT1_MAC_CLK, mac_clk );
+ if ( ( devices & mmd_mask ) != mmd_mask ) {
+ EFAB_ERR ( "required MMDs not present: got %x, wanted %x\n",
+ devices, mmd_mask );
+ return -EIO;
}
- ef1002_writel ( efab, &reg, EF1_GM_MAC_CLK_REG );
- udelay ( 10 );
- return 1;
-}
+ /* Check all required MMDs are responding and happy. */
+ while ( mmd_mask ) {
+ if ( mmd_mask & 1 ) {
+ efab_dword_t reg;
+ int status;
+ reg.opaque = falcon_mdio_read ( efab, mmd,
+ MDIO_MMDREG_STAT2 );
+ status = EFAB_DWORD_FIELD ( reg,
+ MDIO_MMDREG_STAT2_PRESENT );
+ if ( status != MDIO_MMDREG_STAT2_PRESENT_VAL ) {
-/**
- * Reset MAC
- *
- */
-static int ef1002_reset_mac ( struct efab_nic *efab ) {
- mentormac_reset ( efab );
- return 1;
-}
-/** MDIO write */
-static void ef1002_mdio_write ( struct efab_nic *efab, int location,
- int value ) {
- mentormac_mdio_write ( efab, efab->port + 2, location, value );
-}
+ return -EIO;
+ }
+ }
+ mmd_mask >>= 1;
+ mmd++;
+ }
-/** MDIO read */
-static int ef1002_mdio_read ( struct efab_nic *efab, int location ) {
- return mentormac_mdio_read ( efab, efab->port + 2, location );
+ return 0;
}
-static struct efab_operations ef1002_operations = {
- .get_membase = ef1002_get_membase,
- .reset = ef1002_reset,
- .init_nic = ef1002_init_nic,
- .read_eeprom = ef1002_read_eeprom,
- .build_rx_desc = ef1002_build_rx_desc,
- .notify_rx_desc = ef1002_notify_rx_desc,
- .build_tx_desc = ef1002_build_tx_desc,
- .notify_tx_desc = ef1002_notify_tx_desc,
- .fetch_event = ef1002_fetch_event,
- .mask_irq = ef1002_mask_irq,
- .generate_irq = ef1002_generate_irq,
- .mdio_write = ef1002_mdio_write,
- .mdio_read = ef1002_mdio_read,
-};
-
-static struct efab_mac_operations ef1002_mac_operations = {
- .mac_writel = ef1002_mac_writel,
- .mac_readl = ef1002_mac_readl,
- .init = ef1002_init_mac,
- .reset = ef1002_reset_mac,
-};
-
-/**************************************************************************
- *
- * Falcon routines
- *
- **************************************************************************
- */
-
/* I/O BAR address register */
#define FCN_IOM_IND_ADR_REG 0x0
/* I/O BAR data register */
#define FCN_IOM_IND_DAT_REG 0x4
+/* Address region register */
+#define FCN_ADR_REGION_REG_KER 0x00
+#define FCN_ADR_REGION0_LBN 0
+#define FCN_ADR_REGION0_WIDTH 18
+#define FCN_ADR_REGION1_LBN 32
+#define FCN_ADR_REGION1_WIDTH 18
+#define FCN_ADR_REGION2_LBN 64
+#define FCN_ADR_REGION2_WIDTH 18
+#define FCN_ADR_REGION3_LBN 96
+#define FCN_ADR_REGION3_WIDTH 18
+
/* Interrupt enable register */
#define FCN_INT_EN_REG_KER 0x0010
#define FCN_MEM_PERR_INT_EN_KER_LBN 5
@@ -1505,11 +440,25 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_INT_ADR_KER_LBN 0
#define FCN_INT_ADR_KER_WIDTH EFAB_DMA_TYPE_WIDTH ( 64 )
-/* Interrupt acknowledge register */
-#define FCN_INT_ACK_KER_REG 0x0050
+/* Interrupt status register (B0 only) */
+#define INT_ISR0_B0 0x90
+#define INT_ISR1_B0 0xA0
+
+/* Interrupt acknowledge register (A0/A1 only) */
+#define FCN_INT_ACK_KER_REG_A1 0x0050
+#define INT_ACK_DUMMY_DATA_LBN 0
+#define INT_ACK_DUMMY_DATA_WIDTH 32
+
+/* Interrupt acknowledge work-around register (A0/A1 only )*/
+#define WORK_AROUND_BROKEN_PCI_READS_REG_KER_A1 0x0070
+
+/* Hardware initialisation register */
+#define FCN_HW_INIT_REG_KER 0x00c0
+#define FCN_BCSR_TARGET_MASK_LBN 101
+#define FCN_BCSR_TARGET_MASK_WIDTH 4
/* SPI host command register */
-#define FCN_EE_SPI_HCMD_REG_KER 0x0100
+#define FCN_EE_SPI_HCMD_REG 0x0100
#define FCN_EE_SPI_HCMD_CMD_EN_LBN 31
#define FCN_EE_SPI_HCMD_CMD_EN_WIDTH 1
#define FCN_EE_WR_TIMER_ACTIVE_LBN 28
@@ -1532,14 +481,14 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_EE_SPI_HCMD_ENC_WIDTH 8
/* SPI host address register */
-#define FCN_EE_SPI_HADR_REG_KER 0x0110
+#define FCN_EE_SPI_HADR_REG 0x0110
#define FCN_EE_SPI_HADR_DUBYTE_LBN 24
#define FCN_EE_SPI_HADR_DUBYTE_WIDTH 8
#define FCN_EE_SPI_HADR_ADR_LBN 0
#define FCN_EE_SPI_HADR_ADR_WIDTH 24
/* SPI host data register */
-#define FCN_EE_SPI_HDATA_REG_KER 0x0120
+#define FCN_EE_SPI_HDATA_REG 0x0120
#define FCN_EE_SPI_HDATA3_LBN 96
#define FCN_EE_SPI_HDATA3_WIDTH 32
#define FCN_EE_SPI_HDATA2_LBN 64
@@ -1549,89 +498,130 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_EE_SPI_HDATA0_LBN 0
#define FCN_EE_SPI_HDATA0_WIDTH 32
-/* VPI configuration register */
-#define FCN_VPD_CONFIG_REG_KER 0x0140
-#define FCN_VPD_9BIT_LBN 1
-#define FCN_VPD_9BIT_WIDTH 1
+/* VPD Config 0 Register register */
+#define FCN_EE_VPD_CFG_REG 0x0140
+#define FCN_EE_VPD_EN_LBN 0
+#define FCN_EE_VPD_EN_WIDTH 1
+#define FCN_EE_VPD_EN_AD9_MODE_LBN 1
+#define FCN_EE_VPD_EN_AD9_MODE_WIDTH 1
+#define FCN_EE_EE_CLOCK_DIV_LBN 112
+#define FCN_EE_EE_CLOCK_DIV_WIDTH 7
+#define FCN_EE_SF_CLOCK_DIV_LBN 120
+#define FCN_EE_SF_CLOCK_DIV_WIDTH 7
+
/* NIC status register */
#define FCN_NIC_STAT_REG 0x0200
-#define ONCHIP_SRAM_LBN 16
-#define ONCHIP_SRAM_WIDTH 1
-#define SF_PRST_LBN 9
-#define SF_PRST_WIDTH 1
-#define EE_PRST_LBN 8
-#define EE_PRST_WIDTH 1
-#define EE_STRAP_LBN 7
-#define EE_STRAP_WIDTH 1
-#define PCI_PCIX_MODE_LBN 4
-#define PCI_PCIX_MODE_WIDTH 3
-#define PCI_PCIX_MODE_PCI33_DECODE 0
-#define PCI_PCIX_MODE_PCI66_DECODE 1
-#define PCI_PCIX_MODE_PCIX66_DECODE 5
-#define PCI_PCIX_MODE_PCIX100_DECODE 6
-#define PCI_PCIX_MODE_PCIX133_DECODE 7
-#define STRAP_ISCSI_EN_LBN 3
-#define STRAP_ISCSI_EN_WIDTH 1
-#define STRAP_PINS_LBN 0
-#define STRAP_PINS_WIDTH 3
-/* These bit definitions are extrapolated from the list of numerical
- * values for STRAP_PINS. If you want a laugh, read the datasheet's
- * definition for when bits 2:0 are set to 7.
- */
-#define STRAP_10G_LBN 2
-#define STRAP_10G_WIDTH 1
-#define STRAP_DUAL_PORT_LBN 1
-#define STRAP_DUAL_PORT_WIDTH 1
-#define STRAP_PCIE_LBN 0
-#define STRAP_PCIE_WIDTH 1
+#define FCN_ONCHIP_SRAM_LBN 16
+#define FCN_ONCHIP_SRAM_WIDTH 1
+#define FCN_SF_PRST_LBN 9
+#define FCN_SF_PRST_WIDTH 1
+#define FCN_EE_PRST_LBN 8
+#define FCN_EE_PRST_WIDTH 1
+#define FCN_EE_STRAP_LBN 7
+#define FCN_EE_STRAP_WIDTH 1
+#define FCN_PCI_PCIX_MODE_LBN 4
+#define FCN_PCI_PCIX_MODE_WIDTH 3
+#define FCN_PCI_PCIX_MODE_PCI33_DECODE 0
+#define FCN_PCI_PCIX_MODE_PCI66_DECODE 1
+#define FCN_PCI_PCIX_MODE_PCIX66_DECODE 5
+#define FCN_PCI_PCIX_MODE_PCIX100_DECODE 6
+#define FCN_PCI_PCIX_MODE_PCIX133_DECODE 7
+#define FCN_STRAP_ISCSI_EN_LBN 3
+#define FCN_STRAP_ISCSI_EN_WIDTH 1
+#define FCN_STRAP_PINS_LBN 0
+#define FCN_STRAP_PINS_WIDTH 3
+#define FCN_STRAP_10G_LBN 2
+#define FCN_STRAP_10G_WIDTH 1
+#define FCN_STRAP_DUAL_PORT_LBN 1
+#define FCN_STRAP_DUAL_PORT_WIDTH 1
+#define FCN_STRAP_PCIE_LBN 0
+#define FCN_STRAP_PCIE_WIDTH 1
+
+/* Falcon revisions */
+#define FALCON_REV_A0 0
+#define FALCON_REV_A1 1
+#define FALCON_REV_B0 2
/* GPIO control register */
#define FCN_GPIO_CTL_REG_KER 0x0210
+#define FCN_GPIO_CTL_REG_KER 0x0210
+
+#define FCN_GPIO3_OEN_LBN 27
+#define FCN_GPIO3_OEN_WIDTH 1
+#define FCN_GPIO2_OEN_LBN 26
+#define FCN_GPIO2_OEN_WIDTH 1
+#define FCN_GPIO1_OEN_LBN 25
+#define FCN_GPIO1_OEN_WIDTH 1
+#define FCN_GPIO0_OEN_LBN 24
+#define FCN_GPIO0_OEN_WIDTH 1
+
+#define FCN_GPIO3_OUT_LBN 19
+#define FCN_GPIO3_OUT_WIDTH 1
+#define FCN_GPIO2_OUT_LBN 18
+#define FCN_GPIO2_OUT_WIDTH 1
+#define FCN_GPIO1_OUT_LBN 17
+#define FCN_GPIO1_OUT_WIDTH 1
+#define FCN_GPIO0_OUT_LBN 16
+#define FCN_GPIO0_OUT_WIDTH 1
+
+#define FCN_GPIO3_IN_LBN 11
+#define FCN_GPIO3_IN_WIDTH 1
+#define FCN_GPIO2_IN_LBN 10
+#define FCN_GPIO2_IN_WIDTH 1
+#define FCN_GPIO1_IN_LBN 9
+#define FCN_GPIO1_IN_WIDTH 1
+#define FCN_GPIO0_IN_LBN 8
+#define FCN_GPIO0_IN_WIDTH 1
+
#define FCN_FLASH_PRESENT_LBN 7
#define FCN_FLASH_PRESENT_WIDTH 1
#define FCN_EEPROM_PRESENT_LBN 6
#define FCN_EEPROM_PRESENT_WIDTH 1
+#define FCN_BOOTED_USING_NVDEVICE_LBN 3
+#define FCN_BOOTED_USING_NVDEVICE_WIDTH 1
+
+/* Defines for extra non-volatile storage */
+#define FCN_NV_MAGIC_NUMBER 0xFA1C
/* Global control register */
#define FCN_GLB_CTL_REG_KER 0x0220
-#define EXT_PHY_RST_CTL_LBN 63
-#define EXT_PHY_RST_CTL_WIDTH 1
-#define PCIE_SD_RST_CTL_LBN 61
-#define PCIE_SD_RST_CTL_WIDTH 1
-#define PCIX_RST_CTL_LBN 60
-#define PCIX_RST_CTL_WIDTH 1
-#define PCIE_STCK_RST_CTL_LBN 59
-#define PCIE_STCK_RST_CTL_WIDTH 1
-#define PCIE_NSTCK_RST_CTL_LBN 58
-#define PCIE_NSTCK_RST_CTL_WIDTH 1
-#define PCIE_CORE_RST_CTL_LBN 57
-#define PCIE_CORE_RST_CTL_WIDTH 1
-#define EE_RST_CTL_LBN 49
-#define EE_RST_CTL_WIDTH 1
-#define CS_RST_CTL_LBN 48
-#define CS_RST_CTL_WIDTH 1
-#define RST_EXT_PHY_LBN 31
-#define RST_EXT_PHY_WIDTH 1
-#define INT_RST_DUR_LBN 4
-#define INT_RST_DUR_WIDTH 3
-#define EXT_PHY_RST_DUR_LBN 1
-#define EXT_PHY_RST_DUR_WIDTH 3
-#define SWRST_LBN 0
-#define SWRST_WIDTH 1
+#define FCN_EXT_PHY_RST_CTL_LBN 63
+#define FCN_EXT_PHY_RST_CTL_WIDTH 1
+#define FCN_PCIE_SD_RST_CTL_LBN 61
+#define FCN_PCIE_SD_RST_CTL_WIDTH 1
+#define FCN_PCIE_STCK_RST_CTL_LBN 59
+#define FCN_PCIE_STCK_RST_CTL_WIDTH 1
+#define FCN_PCIE_NSTCK_RST_CTL_LBN 58
+#define FCN_PCIE_NSTCK_RST_CTL_WIDTH 1
+#define FCN_PCIE_CORE_RST_CTL_LBN 57
+#define FCN_PCIE_CORE_RST_CTL_WIDTH 1
+#define FCN_EE_RST_CTL_LBN 49
+#define FCN_EE_RST_CTL_WIDTH 1
+#define FCN_RST_EXT_PHY_LBN 31
+#define FCN_RST_EXT_PHY_WIDTH 1
+#define FCN_EXT_PHY_RST_DUR_LBN 1
+#define FCN_EXT_PHY_RST_DUR_WIDTH 3
+#define FCN_SWRST_LBN 0
+#define FCN_SWRST_WIDTH 1
#define INCLUDE_IN_RESET 0
#define EXCLUDE_FROM_RESET 1
/* FPGA build version */
-#define ALTERA_BUILD_REG_KER 0x0300
-#define VER_MAJOR_LBN 24
-#define VER_MAJOR_WIDTH 8
-#define VER_MINOR_LBN 16
-#define VER_MINOR_WIDTH 8
-#define VER_BUILD_LBN 0
-#define VER_BUILD_WIDTH 16
-#define VER_ALL_LBN 0
-#define VER_ALL_WIDTH 32
+#define FCN_ALTERA_BUILD_REG_KER 0x0300
+#define FCN_VER_MAJOR_LBN 24
+#define FCN_VER_MAJOR_WIDTH 8
+#define FCN_VER_MINOR_LBN 16
+#define FCN_VER_MINOR_WIDTH 8
+#define FCN_VER_BUILD_LBN 0
+#define FCN_VER_BUILD_WIDTH 16
+#define FCN_VER_ALL_LBN 0
+#define FCN_VER_ALL_WIDTH 32
+
+/* Spare EEPROM bits register (flash 0x390) */
+#define FCN_SPARE_REG_KER 0x310
+#define FCN_MEM_PERR_EN_TX_DATA_LBN 72
+#define FCN_MEM_PERR_EN_TX_DATA_WIDTH 2
/* Timer table for kernel access */
#define FCN_TIMER_CMD_REG_KER 0x420
@@ -1657,10 +647,65 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_SRM_TX_DC_BASE_ADR_LBN 0
#define FCN_SRM_TX_DC_BASE_ADR_WIDTH 21
+/* SRAM configuration register */
+#define FCN_SRM_CFG_REG_KER 0x630
+#define FCN_SRAM_OOB_ADR_INTEN_LBN 5
+#define FCN_SRAM_OOB_ADR_INTEN_WIDTH 1
+#define FCN_SRAM_OOB_BUF_INTEN_LBN 4
+#define FCN_SRAM_OOB_BUF_INTEN_WIDTH 1
+#define FCN_SRAM_OOB_BT_INIT_EN_LBN 3
+#define FCN_SRAM_OOB_BT_INIT_EN_WIDTH 1
+#define FCN_SRM_NUM_BANK_LBN 2
+#define FCN_SRM_NUM_BANK_WIDTH 1
+#define FCN_SRM_BANK_SIZE_LBN 0
+#define FCN_SRM_BANK_SIZE_WIDTH 2
+#define FCN_SRM_NUM_BANKS_AND_BANK_SIZE_LBN 0
+#define FCN_SRM_NUM_BANKS_AND_BANK_SIZE_WIDTH 3
+
+#define FCN_RX_CFG_REG_KER 0x800
+#define FCN_RX_INGR_EN_B0_LBN 47
+#define FCN_RX_INGR_EN_B0_WIDTH 1
+#define FCN_RX_USR_BUF_SIZE_B0_LBN 19
+#define FCN_RX_USR_BUF_SIZE_B0_WIDTH 9
+#define FCN_RX_XON_MAC_TH_B0_LBN 10
+#define FCN_RX_XON_MAC_TH_B0_WIDTH 9
+#define FCN_RX_XOFF_MAC_TH_B0_LBN 1
+#define FCN_RX_XOFF_MAC_TH_B0_WIDTH 9
+#define FCN_RX_XOFF_MAC_EN_B0_LBN 0
+#define FCN_RX_XOFF_MAC_EN_B0_WIDTH 1
+#define FCN_RX_USR_BUF_SIZE_A1_LBN 11
+#define FCN_RX_USR_BUF_SIZE_A1_WIDTH 9
+#define FCN_RX_XON_MAC_TH_A1_LBN 6
+#define FCN_RX_XON_MAC_TH_A1_WIDTH 5
+#define FCN_RX_XOFF_MAC_TH_A1_LBN 1
+#define FCN_RX_XOFF_MAC_TH_A1_WIDTH 5
+#define FCN_RX_XOFF_MAC_EN_A1_LBN 0
+#define FCN_RX_XOFF_MAC_EN_A1_WIDTH 1
+
+#define FCN_RX_USR_BUF_SIZE_A1_LBN 11
+#define FCN_RX_USR_BUF_SIZE_A1_WIDTH 9
+#define FCN_RX_XOFF_MAC_EN_A1_LBN 0
+#define FCN_RX_XOFF_MAC_EN_A1_WIDTH 1
+
/* Receive filter control register */
#define FCN_RX_FILTER_CTL_REG_KER 0x810
+#define FCN_UDP_FULL_SRCH_LIMIT_LBN 32
+#define FCN_UDP_FULL_SRCH_LIMIT_WIDTH 8
#define FCN_NUM_KER_LBN 24
#define FCN_NUM_KER_WIDTH 2
+#define FCN_UDP_WILD_SRCH_LIMIT_LBN 16
+#define FCN_UDP_WILD_SRCH_LIMIT_WIDTH 8
+#define FCN_TCP_WILD_SRCH_LIMIT_LBN 8
+#define FCN_TCP_WILD_SRCH_LIMIT_WIDTH 8
+#define FCN_TCP_FULL_SRCH_LIMIT_LBN 0
+#define FCN_TCP_FULL_SRCH_LIMIT_WIDTH 8
+
+/* RX queue flush register */
+#define FCN_RX_FLUSH_DESCQ_REG_KER 0x0820
+#define FCN_RX_FLUSH_DESCQ_CMD_LBN 24
+#define FCN_RX_FLUSH_DESCQ_CMD_WIDTH 1
+#define FCN_RX_FLUSH_DESCQ_LBN 0
+#define FCN_RX_FLUSH_DESCQ_WIDTH 12
/* Receive descriptor update register */
#define FCN_RX_DESC_UPD_REG_KER 0x0830
@@ -1675,6 +720,26 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_RX_DC_SIZE_LBN 0
#define FCN_RX_DC_SIZE_WIDTH 2
+#define FCN_RX_SELF_RST_REG_KER 0x890
+#define FCN_RX_ISCSI_DIS_LBN 17
+#define FCN_RX_ISCSI_DIS_WIDTH 1
+#define FCN_RX_NODESC_WAIT_DIS_LBN 9
+#define FCN_RX_NODESC_WAIT_DIS_WIDTH 1
+#define FCN_RX_RECOVERY_EN_LBN 8
+#define FCN_RX_RECOVERY_EN_WIDTH 1
+
+/* TX queue flush register */
+#define FCN_TX_FLUSH_DESCQ_REG_KER 0x0a00
+#define FCN_TX_FLUSH_DESCQ_CMD_LBN 12
+#define FCN_TX_FLUSH_DESCQ_CMD_WIDTH 1
+#define FCN_TX_FLUSH_DESCQ_LBN 0
+#define FCN_TX_FLUSH_DESCQ_WIDTH 12
+
+/* Transmit configuration register 2 */
+#define FCN_TX_CFG2_REG_KER 0xa80
+#define FCN_TX_DIS_NON_IP_EV_LBN 17
+#define FCN_TX_DIS_NON_IP_EV_WIDTH 1
+
/* Transmit descriptor update register */
#define FCN_TX_DESC_UPD_REG_KER 0x0a10
#define FCN_TX_DESC_WPTR_LBN 96
@@ -1704,6 +769,8 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_MD_GC_WIDTH 1
#define FCN_MD_RIC_LBN 2
#define FCN_MD_RIC_WIDTH 1
+#define FCN_MD_RDC_LBN 1
+#define FCN_MD_RDC_WIDTH 1
#define FCN_MD_WRC_LBN 0
#define FCN_MD_WRC_WIDTH 1
@@ -1721,6 +788,14 @@ static struct efab_mac_operations ef1002_mac_operations = {
/* PHY management status & mask register */
#define FCN_MD_STAT_REG_KER 0xc50
+#define FCN_MD_PINT_LBN 4
+#define FCN_MD_PINT_WIDTH 1
+#define FCN_MD_DONE_LBN 3
+#define FCN_MD_DONE_WIDTH 1
+#define FCN_MD_BSERR_LBN 2
+#define FCN_MD_BSERR_WIDTH 1
+#define FCN_MD_LNFL_LBN 1
+#define FCN_MD_LNFL_WIDTH 1
#define FCN_MD_BSY_LBN 0
#define FCN_MD_BSY_WIDTH 1
@@ -1738,6 +813,11 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_MAC_SPEED_LBN 0
#define FCN_MAC_SPEED_WIDTH 2
+/* 10Gig Xaui XGXS Default Values */
+#define XX_TXDRV_DEQ_DEFAULT 0xe /* deq=.6 */
+#define XX_TXDRV_DTX_DEFAULT 0x5 /* 1.25 */
+#define XX_SD_CTL_DRV_DEFAULT 0 /* 20mA */
+
/* GMAC registers */
#define FALCON_GMAC_REGBANK 0xe00
#define FALCON_GMAC_REGBANK_SIZE 0x200
@@ -1801,18 +881,45 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_XM_RXEN_LBN 1
#define FCN_XM_RXEN_WIDTH 1
+/* XGMAC management interrupt mask register */
+#define FCN_XM_MGT_INT_MSK_REG_MAC_B0 0x5
+#define FCN_XM_MSK_PRMBLE_ERR_LBN 2
+#define FCN_XM_MSK_PRMBLE_ERR_WIDTH 1
+#define FCN_XM_MSK_RMTFLT_LBN 1
+#define FCN_XM_MSK_RMTFLT_WIDTH 1
+#define FCN_XM_MSK_LCLFLT_LBN 0
+#define FCN_XM_MSK_LCLFLT_WIDTH 1
+
+/* XGMAC flow control register */
+#define FCN_XM_FC_REG_MAC 0x7
+#define FCN_XM_PAUSE_TIME_LBN 16
+#define FCN_XM_PAUSE_TIME_WIDTH 16
+#define FCN_XM_DIS_FCNTL_LBN 0
+#define FCN_XM_DIS_FCNTL_WIDTH 1
+
/* XGMAC transmit parameter register */
#define FCN_XM_TX_PARAM_REG_MAC 0x0d
#define FCN_XM_TX_JUMBO_MODE_LBN 31
#define FCN_XM_TX_JUMBO_MODE_WIDTH 1
#define FCN_XM_MAX_TX_FRM_SIZE_LBN 16
#define FCN_XM_MAX_TX_FRM_SIZE_WIDTH 14
+#define FCN_XM_ACPT_ALL_MCAST_LBN 11
+#define FCN_XM_ACPT_ALL_MCAST_WIDTH 1
/* XGMAC receive parameter register */
#define FCN_XM_RX_PARAM_REG_MAC 0x0e
#define FCN_XM_MAX_RX_FRM_SIZE_LBN 0
#define FCN_XM_MAX_RX_FRM_SIZE_WIDTH 14
+/* XGMAC management interrupt status register */
+#define FCN_XM_MGT_INT_REG_MAC_B0 0x0f
+#define FCN_XM_PRMBLE_ERR 2
+#define FCN_XM_PRMBLE_WIDTH 1
+#define FCN_XM_RMTFLT_LBN 1
+#define FCN_XM_RMTFLT_WIDTH 1
+#define FCN_XM_LCLFLT_LBN 0
+#define FCN_XM_LCLFLT_WIDTH 1
+
/* XAUI XGXS core status register */
#define FCN_XX_ALIGN_DONE_LBN 20
#define FCN_XX_ALIGN_DONE_WIDTH 1
@@ -1823,10 +930,35 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_XX_COMMA_DET_LBN 12
#define FCN_XX_COMMA_DET_WIDTH 4
#define FCN_XX_COMMA_DET_RESET 0xf
-
+#define FCN_XX_CHARERR_LBN 4
+#define FCN_XX_CHARERR_WIDTH 4
+#define FCN_XX_CHARERR_RESET 0xf
+#define FCN_XX_DISPERR_LBN 0
+#define FCN_XX_DISPERR_WIDTH 4
+#define FCN_XX_DISPERR_RESET 0xf
/* XGXS/XAUI powerdown/reset register */
#define FCN_XX_PWR_RST_REG_MAC 0x10
+#define FCN_XX_PWRDND_EN_LBN 15
+#define FCN_XX_PWRDND_EN_WIDTH 1
+#define FCN_XX_PWRDNC_EN_LBN 14
+#define FCN_XX_PWRDNC_EN_WIDTH 1
+#define FCN_XX_PWRDNB_EN_LBN 13
+#define FCN_XX_PWRDNB_EN_WIDTH 1
+#define FCN_XX_PWRDNA_EN_LBN 12
+#define FCN_XX_PWRDNA_EN_WIDTH 1
+#define FCN_XX_RSTPLLCD_EN_LBN 9
+#define FCN_XX_RSTPLLCD_EN_WIDTH 1
+#define FCN_XX_RSTPLLAB_EN_LBN 8
+#define FCN_XX_RSTPLLAB_EN_WIDTH 1
+#define FCN_XX_RESETD_EN_LBN 7
+#define FCN_XX_RESETD_EN_WIDTH 1
+#define FCN_XX_RESETC_EN_LBN 6
+#define FCN_XX_RESETC_EN_WIDTH 1
+#define FCN_XX_RESETB_EN_LBN 5
+#define FCN_XX_RESETB_EN_WIDTH 1
+#define FCN_XX_RESETA_EN_LBN 4
+#define FCN_XX_RESETA_EN_WIDTH 1
#define FCN_XX_RSTXGXSRX_EN_LBN 2
#define FCN_XX_RSTXGXSRX_EN_WIDTH 1
#define FCN_XX_RSTXGXSTX_EN_LBN 1
@@ -1834,8 +966,66 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_XX_RST_XX_EN_LBN 0
#define FCN_XX_RST_XX_EN_WIDTH 1
+
+/* XGXS/XAUI powerdown/reset control register */
+#define FCN_XX_SD_CTL_REG_MAC 0x11
+#define FCN_XX_TERMADJ1_LBN 17
+#define FCN_XX_TERMADJ1_WIDTH 1
+#define FCN_XX_TERMADJ0_LBN 16
+#define FCN_XX_TERMADJ0_WIDTH 1
+#define FCN_XX_HIDRVD_LBN 15
+#define FCN_XX_HIDRVD_WIDTH 1
+#define FCN_XX_LODRVD_LBN 14
+#define FCN_XX_LODRVD_WIDTH 1
+#define FCN_XX_HIDRVC_LBN 13
+#define FCN_XX_HIDRVC_WIDTH 1
+#define FCN_XX_LODRVC_LBN 12
+#define FCN_XX_LODRVC_WIDTH 1
+#define FCN_XX_HIDRVB_LBN 11
+#define FCN_XX_HIDRVB_WIDTH 1
+#define FCN_XX_LODRVB_LBN 10
+#define FCN_XX_LODRVB_WIDTH 1
+#define FCN_XX_HIDRVA_LBN 9
+#define FCN_XX_HIDRVA_WIDTH 1
+#define FCN_XX_LODRVA_LBN 8
+#define FCN_XX_LODRVA_WIDTH 1
+#define FCN_XX_LPBKD_LBN 3
+#define FCN_XX_LPBKD_WIDTH 1
+#define FCN_XX_LPBKC_LBN 2
+#define FCN_XX_LPBKC_WIDTH 1
+#define FCN_XX_LPBKB_LBN 1
+#define FCN_XX_LPBKB_WIDTH 1
+#define FCN_XX_LPBKA_LBN 0
+#define FCN_XX_LPBKA_WIDTH 1
+
+#define FCN_XX_TXDRV_CTL_REG_MAC 0x12
+#define FCN_XX_DEQD_LBN 28
+#define FCN_XX_DEQD_WIDTH 4
+#define FCN_XX_DEQC_LBN 24
+#define FCN_XX_DEQC_WIDTH 4
+#define FCN_XX_DEQB_LBN 20
+#define FCN_XX_DEQB_WIDTH 4
+#define FCN_XX_DEQA_LBN 16
+#define FCN_XX_DEQA_WIDTH 4
+#define FCN_XX_DTXD_LBN 12
+#define FCN_XX_DTXD_WIDTH 4
+#define FCN_XX_DTXC_LBN 8
+#define FCN_XX_DTXC_WIDTH 4
+#define FCN_XX_DTXB_LBN 4
+#define FCN_XX_DTXB_WIDTH 4
+#define FCN_XX_DTXA_LBN 0
+#define FCN_XX_DTXA_WIDTH 4
+
+/* Receive filter table */
+#define FCN_RX_FILTER_TBL0 0xF00000
+
/* Receive descriptor pointer table */
-#define FCN_RX_DESC_PTR_TBL_KER 0x11800
+#define FCN_RX_DESC_PTR_TBL_KER_A1 0x11800
+#define FCN_RX_DESC_PTR_TBL_KER_B0 0xF40000
+#define FCN_RX_ISCSI_DDIG_EN_LBN 88
+#define FCN_RX_ISCSI_DDIG_EN_WIDTH 1
+#define FCN_RX_ISCSI_HDIG_EN_LBN 87
+#define FCN_RX_ISCSI_HDIG_EN_WIDTH 1
#define FCN_RX_DESCQ_BUF_BASE_ID_LBN 36
#define FCN_RX_DESCQ_BUF_BASE_ID_WIDTH 20
#define FCN_RX_DESCQ_EVQ_ID_LBN 24
@@ -1856,9 +1046,16 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_RX_DESCQ_EN_WIDTH 1
/* Transmit descriptor pointer table */
-#define FCN_TX_DESC_PTR_TBL_KER 0x11900
+#define FCN_TX_DESC_PTR_TBL_KER_A1 0x11900
+#define FCN_TX_DESC_PTR_TBL_KER_B0 0xF50000
+#define FCN_TX_NON_IP_DROP_DIS_B0_LBN 91
+#define FCN_TX_NON_IP_DROP_DIS_B0_WIDTH 1
#define FCN_TX_DESCQ_EN_LBN 88
#define FCN_TX_DESCQ_EN_WIDTH 1
+#define FCN_TX_ISCSI_DDIG_EN_LBN 87
+#define FCN_TX_ISCSI_DDIG_EN_WIDTH 1
+#define FCN_TX_ISCSI_HDIG_EN_LBN 86
+#define FCN_TX_ISCSI_HDIG_EN_WIDTH 1
#define FCN_TX_DESCQ_BUF_BASE_ID_LBN 36
#define FCN_TX_DESCQ_BUF_BASE_ID_WIDTH 20
#define FCN_TX_DESCQ_EVQ_ID_LBN 24
@@ -1877,7 +1074,8 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_TX_DESCQ_FLUSH_WIDTH 1
/* Event queue pointer */
-#define FCN_EVQ_PTR_TBL_KER 0x11a00
+#define FCN_EVQ_PTR_TBL_KER_A1 0x11a00
+#define FCN_EVQ_PTR_TBL_KER_B0 0xf60000
#define FCN_EVQ_EN_LBN 23
#define FCN_EVQ_EN_WIDTH 1
#define FCN_EVQ_SIZE_LBN 20
@@ -1892,16 +1090,22 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_EVQ_BUF_BASE_ID_LBN 0
#define FCN_EVQ_BUF_BASE_ID_WIDTH 20
+/* RSS indirection table */
+#define FCN_RX_RSS_INDIR_TBL_B0 0xFB0000
+
/* Event queue read pointer */
-#define FCN_EVQ_RPTR_REG_KER 0x11b00
+#define FCN_EVQ_RPTR_REG_KER_A1 0x11b00
+#define FCN_EVQ_RPTR_REG_KER_B0 0xfa0000
#define FCN_EVQ_RPTR_LBN 0
#define FCN_EVQ_RPTR_WIDTH 14
-#define FCN_EVQ_RPTR_REG_KER_DWORD ( FCN_EVQ_RPTR_REG_KER + 0 )
+#define FCN_EVQ_RPTR_REG_KER_DWORD_A1 ( FCN_EVQ_RPTR_REG_KER_A1 + 0 )
+#define FCN_EVQ_RPTR_REG_KER_DWORD_B0 ( FCN_EVQ_RPTR_REG_KER_B0 + 0 )
#define FCN_EVQ_RPTR_DWORD_LBN 0
#define FCN_EVQ_RPTR_DWORD_WIDTH 14
/* Special buffer descriptors */
-#define FCN_BUF_FULL_TBL_KER 0x18000
+#define FCN_BUF_FULL_TBL_KER_A1 0x18000
+#define FCN_BUF_FULL_TBL_KER_B0 0x800000
#define FCN_IP_DAT_BUF_SIZE_LBN 50
#define FCN_IP_DAT_BUF_SIZE_WIDTH 1
#define FCN_IP_DAT_BUF_SIZE_8K 1
@@ -1914,13 +1118,11 @@ static struct efab_mac_operations ef1002_mac_operations = {
/** Offset of a GMAC register within Falcon */
#define FALCON_GMAC_REG( efab, mac_reg ) \
( FALCON_GMAC_REGBANK + \
- ( (efab)->port * FALCON_GMAC_REGBANK_SIZE ) + \
( (mac_reg) * FALCON_GMAC_REG_SIZE ) )
/** Offset of an XMAC register within Falcon */
#define FALCON_XMAC_REG( efab_port, mac_reg ) \
( FALCON_XMAC_REGBANK + \
- ( (efab_port)->port * FALCON_XMAC_REGBANK_SIZE ) + \
( (mac_reg) * FALCON_XMAC_REG_SIZE ) )
#define FCN_MAC_DATA_LBN 0
@@ -1962,10 +1164,22 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_TX_EV_DESC_PTR_LBN 0
#define FCN_TX_EV_DESC_PTR_WIDTH 12
-/* Fixed special buffer numbers to use */
-#define FALCON_EVQ_ID 0
-#define FALCON_TXD_ID 1
-#define FALCON_RXD_ID 2
+/*******************************************************************************
+ *
+ *
+ * Low-level hardware access
+ *
+ *
+ *******************************************************************************/
+
+#define FCN_REVISION_REG(efab, reg) \
+ ( ( efab->pci_revision == FALCON_REV_B0 ) ? reg ## _B0 : reg ## _A1 )
+
+#define EFAB_SET_OWORD_FIELD_VER(efab, reg, field, val) \
+ if ( efab->pci_revision == FALCON_REV_B0 ) \
+ EFAB_SET_OWORD_FIELD ( reg, field ## _B0, val ); \
+ else \
+ EFAB_SET_OWORD_FIELD ( reg, field ## _A1, val );
#if FALCON_USE_IO_BAR
@@ -1995,8 +1209,9 @@ static inline uint32_t _falcon_readl ( struct efab_nic *efab,
* Write to a Falcon register
*
*/
-static inline void falcon_write ( struct efab_nic *efab, efab_oword_t *value,
- unsigned int reg ) {
+static inline void
+falcon_write ( struct efab_nic *efab, efab_oword_t *value, unsigned int reg )
+{
EFAB_REGDUMP ( "Writing register %x with " EFAB_OWORD_FMT "\n",
reg, EFAB_OWORD_VAL ( *value ) );
@@ -2004,6 +1219,7 @@ static inline void falcon_write ( struct efab_nic *efab, efab_oword_t *value,
_falcon_writel ( efab, value->u32[0], reg + 0 );
_falcon_writel ( efab, value->u32[1], reg + 4 );
_falcon_writel ( efab, value->u32[2], reg + 8 );
+ wmb();
_falcon_writel ( efab, value->u32[3], reg + 12 );
wmb();
}
@@ -2012,10 +1228,11 @@ static inline void falcon_write ( struct efab_nic *efab, efab_oword_t *value,
* Write to Falcon SRAM
*
*/
-static inline void falcon_write_sram ( struct efab_nic *efab,
- efab_qword_t *value,
- unsigned int index ) {
- unsigned int reg = ( FCN_BUF_FULL_TBL_KER +
+static inline void
+falcon_write_sram ( struct efab_nic *efab, efab_qword_t *value,
+ unsigned int index )
+{
+ unsigned int reg = ( FCN_REVISION_REG ( efab, FCN_BUF_FULL_TBL_KER ) +
( index * sizeof ( *value ) ) );
EFAB_REGDUMP ( "Writing SRAM register %x with " EFAB_QWORD_FMT "\n",
@@ -2030,8 +1247,9 @@ static inline void falcon_write_sram ( struct efab_nic *efab,
* Write dword to Falcon register that allows partial writes
*
*/
-static inline void falcon_writel ( struct efab_nic *efab, efab_dword_t *value,
- unsigned int reg ) {
+static inline void
+falcon_writel ( struct efab_nic *efab, efab_dword_t *value, unsigned int reg )
+{
EFAB_REGDUMP ( "Writing partial register %x with " EFAB_DWORD_FMT "\n",
reg, EFAB_DWORD_VAL ( *value ) );
_falcon_writel ( efab, value->u32[0], reg );
@@ -2041,9 +1259,11 @@ static inline void falcon_writel ( struct efab_nic *efab, efab_dword_t *value,
* Read from a Falcon register
*
*/
-static inline void falcon_read ( struct efab_nic *efab, efab_oword_t *value,
- unsigned int reg ) {
+static inline void
+falcon_read ( struct efab_nic *efab, efab_oword_t *value, unsigned int reg )
+{
value->u32[0] = _falcon_readl ( efab, reg + 0 );
+ wmb();
value->u32[1] = _falcon_readl ( efab, reg + 4 );
value->u32[2] = _falcon_readl ( efab, reg + 8 );
value->u32[3] = _falcon_readl ( efab, reg + 12 );
@@ -2056,10 +1276,11 @@ static inline void falcon_read ( struct efab_nic *efab, efab_oword_t *value,
* Read from Falcon SRAM
*
*/
-static inline void falcon_read_sram ( struct efab_nic *efab,
- efab_qword_t *value,
- unsigned int index ) {
- unsigned int reg = ( FCN_BUF_FULL_TBL_KER +
+static inline void
+falcon_read_sram ( struct efab_nic *efab, efab_qword_t *value,
+ unsigned int index )
+{
+ unsigned int reg = ( FCN_REVISION_REG ( efab, FCN_BUF_FULL_TBL_KER ) +
( index * sizeof ( *value ) ) );
value->u32[0] = _falcon_readl ( efab, reg + 0 );
@@ -2072,44 +1293,14 @@ static inline void falcon_read_sram ( struct efab_nic *efab,
* Read dword from a portion of a Falcon register
*
*/
-static inline void falcon_readl ( struct efab_nic *efab, efab_dword_t *value,
- unsigned int reg ) {
+static inline void
+falcon_readl ( struct efab_nic *efab, efab_dword_t *value, unsigned int reg )
+{
value->u32[0] = _falcon_readl ( efab, reg );
EFAB_REGDUMP ( "Read from register %x, got " EFAB_DWORD_FMT "\n",
reg, EFAB_DWORD_VAL ( *value ) );
}
-/**
- * Verified write to Falcon SRAM
- *
- */
-static inline void falcon_write_sram_verify ( struct efab_nic *efab,
- efab_qword_t *value,
- unsigned int index ) {
- efab_qword_t verify;
-
- falcon_write_sram ( efab, value, index );
- udelay ( 1000 );
- falcon_read_sram ( efab, &verify, index );
- if ( memcmp ( &verify, value, sizeof ( verify ) ) != 0 ) {
- EFAB_ERR ( "SRAM index %x failure: wrote " EFAB_QWORD_FMT
- " got " EFAB_QWORD_FMT "\n", index,
- EFAB_QWORD_VAL ( *value ),
- EFAB_QWORD_VAL ( verify ) );
- }
-}
-
-/**
- * Get memory base
- *
- */
-static void falcon_get_membase ( struct efab_nic *efab ) {
- unsigned long membase_phys;
-
- membase_phys = pci_bar_start ( efab->pci, PCI_BASE_ADDRESS_2 );
- efab->membase = ioremap ( membase_phys, 0x20000 );
-}
-
#define FCN_DUMP_REG( efab, _reg ) do { \
efab_oword_t reg; \
falcon_read ( efab, &reg, _reg ); \
@@ -2125,12 +1316,47 @@ static void falcon_get_membase ( struct efab_nic *efab ) {
} while ( 0 );
/**
+ * See if an event is present
+ *
+ * @v event Falcon event structure
+ * @ret True An event is pending
+ * @ret False No event is pending
+ *
+ * We check both the high and low dword of the event for all ones. We
+ * wrote all ones when we cleared the event, and no valid event can
+ * have all ones in either its high or low dwords. This approach is
+ * robust against reordering.
+ *
+ * Note that using a single 64-bit comparison is incorrect; even
+ * though the CPU read will be atomic, the DMA write may not be.
+ */
+static inline int
+falcon_event_present ( falcon_event_t* event )
+{
+ return ( ! ( EFAB_DWORD_IS_ALL_ONES ( event->dword[0] ) |
+ EFAB_DWORD_IS_ALL_ONES ( event->dword[1] ) ) );
+}
+
+static void
+falcon_eventq_read_ack ( struct efab_nic *efab, struct efab_ev_queue *ev_queue )
+{
+ efab_dword_t reg;
+
+ EFAB_POPULATE_DWORD_1 ( reg, FCN_EVQ_RPTR_DWORD, ev_queue->read_ptr );
+ falcon_writel ( efab, &reg,
+ FCN_REVISION_REG ( efab, FCN_EVQ_RPTR_REG_KER_DWORD ) );
+}
+
+#if 0
+/**
* Dump register contents (for debugging)
*
* Marked as static inline so that it will not be compiled in if not
* used.
*/
-static inline void falcon_dump_regs ( struct efab_nic *efab ) {
+static inline void
+falcon_dump_regs ( struct efab_nic *efab )
+{
FCN_DUMP_REG ( efab, FCN_INT_EN_REG_KER );
FCN_DUMP_REG ( efab, FCN_INT_ADR_REG_KER );
FCN_DUMP_REG ( efab, FCN_GLB_CTL_REG_KER );
@@ -2142,9 +1368,9 @@ static inline void falcon_dump_regs ( struct efab_nic *efab ) {
FCN_DUMP_REG ( efab, FCN_TX_DC_CFG_REG_KER );
FCN_DUMP_REG ( efab, FCN_MAC0_CTRL_REG_KER );
FCN_DUMP_REG ( efab, FCN_MAC1_CTRL_REG_KER );
- FCN_DUMP_REG ( efab, FCN_RX_DESC_PTR_TBL_KER );
- FCN_DUMP_REG ( efab, FCN_TX_DESC_PTR_TBL_KER );
- FCN_DUMP_REG ( efab, FCN_EVQ_PTR_TBL_KER );
+ FCN_DUMP_REG ( efab, FCN_REVISION_REG ( efab, FCN_RX_DESC_PTR_TBL_KER ) );
+ FCN_DUMP_REG ( efab, FCN_REVISION_REG ( efab, FCN_TX_DESC_PTR_TBL_KER ) );
+ FCN_DUMP_REG ( efab, FCN_REVISION_REG ( efab, FCN_EVQ_PTR_TBL_KER ) );
FCN_DUMP_MAC_REG ( efab, GM_CFG1_REG_MAC );
FCN_DUMP_MAC_REG ( efab, GM_CFG2_REG_MAC );
FCN_DUMP_MAC_REG ( efab, GM_MAX_FLEN_REG_MAC );
@@ -2158,391 +1384,356 @@ static inline void falcon_dump_regs ( struct efab_nic *efab ) {
FCN_DUMP_MAC_REG ( efab, GMF_CFG4_REG_MAC );
FCN_DUMP_MAC_REG ( efab, GMF_CFG5_REG_MAC );
}
+#endif
-/**
- * Create special buffer
- *
- */
-static void falcon_create_special_buffer ( struct efab_nic *efab,
- void *addr, unsigned int index ) {
- efab_qword_t buf_desc;
- unsigned long dma_addr;
+static void
+falcon_interrupts ( struct efab_nic *efab, int enabled, int force )
+{
+ efab_oword_t int_en_reg_ker;
- memset ( addr, 0, 4096 );
- dma_addr = virt_to_bus ( addr );
- EFAB_ASSERT ( ( dma_addr & ( EFAB_BUF_ALIGN - 1 ) ) == 0 );
- EFAB_POPULATE_QWORD_3 ( buf_desc,
- FCN_IP_DAT_BUF_SIZE, FCN_IP_DAT_BUF_SIZE_4K,
- FCN_BUF_ADR_FBUF, ( dma_addr >> 12 ),
- FCN_BUF_OWNER_ID_FBUF, 0 );
- falcon_write_sram_verify ( efab, &buf_desc, index );
+ EFAB_POPULATE_OWORD_2 ( int_en_reg_ker,
+ FCN_KER_INT_KER, force,
+ FCN_DRV_INT_EN_KER, enabled );
+ falcon_write ( efab, &int_en_reg_ker, FCN_INT_EN_REG_KER );
}
-/**
- * Update event queue read pointer
+/*******************************************************************************
*
- */
-static void falcon_eventq_read_ack ( struct efab_nic *efab ) {
- efab_dword_t reg;
-
- EFAB_ASSERT ( efab->eventq_read_ptr < EFAB_EVQ_SIZE );
-
- EFAB_POPULATE_DWORD_1 ( reg, FCN_EVQ_RPTR_DWORD,
- efab->eventq_read_ptr );
- falcon_writel ( efab, &reg, FCN_EVQ_RPTR_REG_KER_DWORD );
-}
-
-/**
- * Reset device
*
- */
-static int falcon_reset ( struct efab_nic *efab ) {
- efab_oword_t glb_ctl_reg_ker;
-
- /* Initiate software reset */
- EFAB_POPULATE_OWORD_7 ( glb_ctl_reg_ker,
- PCIE_CORE_RST_CTL, EXCLUDE_FROM_RESET,
- PCIE_NSTCK_RST_CTL, EXCLUDE_FROM_RESET,
- PCIE_SD_RST_CTL, EXCLUDE_FROM_RESET,
- EE_RST_CTL, EXCLUDE_FROM_RESET,
- PCIX_RST_CTL, EXCLUDE_FROM_RESET,
- EXT_PHY_RST_DUR, 0x7 /* datasheet recommended */,
- SWRST, 1 );
-
- falcon_write ( efab, &glb_ctl_reg_ker, FCN_GLB_CTL_REG_KER );
-
- /* Allow 20ms for reset */
- mdelay ( 20 );
+ * SPI access
+ *
+ *
+ *******************************************************************************/
- /* Check for device reset complete */
- falcon_read ( efab, &glb_ctl_reg_ker, FCN_GLB_CTL_REG_KER );
- if ( EFAB_OWORD_FIELD ( glb_ctl_reg_ker, SWRST ) != 0 ) {
- EFAB_ERR ( "Reset failed\n" );
- return 0;
- }
- return 1;
-}
+/** Maximum length for a single SPI transaction */
+#define FALCON_SPI_MAX_LEN 16
-/**
- * Wait for SPI command completion
- *
- */
-static int falcon_spi_wait ( struct efab_nic *efab ) {
+static int
+falcon_spi_wait ( struct efab_nic *efab )
+{
efab_oword_t reg;
int count;
count = 0;
do {
udelay ( 100 );
- falcon_read ( efab, &reg, FCN_EE_SPI_HCMD_REG_KER );
+ falcon_read ( efab, &reg, FCN_EE_SPI_HCMD_REG );
if ( EFAB_OWORD_FIELD ( reg, FCN_EE_SPI_HCMD_CMD_EN ) == 0 )
- return 1;
+ return 0;
} while ( ++count < 1000 );
- printf ( "Timed out waiting for SPI\n" );
- return 0;
+
+ EFAB_ERR ( "Timed out waiting for SPI\n" );
+ return -ETIMEDOUT;
}
-/**
- * Perform SPI read/write
- *
- */
-static int falcon_spi_rw ( struct spi_bus *bus, struct spi_device *device,
- unsigned int command, int address,
- const void *data_out, void *data_in, size_t len ) {
- struct efab_nic *efab = container_of ( bus, struct efab_nic, spi );
+static int
+falcon_spi_rw ( struct spi_bus* bus, struct spi_device *device,
+ unsigned int command, int address,
+ const void* data_out, void *data_in, size_t len )
+{
+ struct efab_nic *efab = container_of ( bus, struct efab_nic, spi_bus );
+ int address_len, rc, device_id, read_cmd;
efab_oword_t reg;
- /* Program address register */
- EFAB_POPULATE_OWORD_1 ( reg, FCN_EE_SPI_HADR_ADR, address );
- falcon_write ( efab, &reg, FCN_EE_SPI_HADR_REG_KER );
-
- /* Program data register, if applicable */
+ /* falcon_init_spi_device() should have reduced the block size
+ * down so this constraint holds */
+ assert ( len <= FALCON_SPI_MAX_LEN );
+
+ /* Is this the FLASH or EEPROM device? */
+ if ( device == &efab->spi_flash )
+ device_id = FCN_EE_SPI_FLASH;
+ else if ( device == &efab->spi_eeprom )
+ device_id = FCN_EE_SPI_EEPROM;
+ else {
+ EFAB_ERR ( "Unknown device %p\n", device );
+ return -EINVAL;
+ }
+
+ EFAB_TRACE ( "Executing spi command %d on device %d at %d for %zd bytes\n",
+ command, device_id, address, len );
+
+ /* The bus must be idle */
+ rc = falcon_spi_wait ( efab );
+ if ( rc )
+ goto fail1;
+
+ /* Copy data out */
if ( data_out ) {
memcpy ( &reg, data_out, len );
- falcon_write ( efab, &reg, FCN_EE_SPI_HDATA_REG_KER );
+ falcon_write ( efab, &reg, FCN_EE_SPI_HDATA_REG );
+ }
+
+ /* Program address register */
+ if ( address >= 0 ) {
+ EFAB_POPULATE_OWORD_1 ( reg, FCN_EE_SPI_HADR_ADR, address );
+ falcon_write ( efab, &reg, FCN_EE_SPI_HADR_REG );
}
/* Issue command */
+ address_len = ( address >= 0 ) ? device->address_len / 8 : 0;
+ read_cmd = ( data_in ? FCN_EE_SPI_READ : FCN_EE_SPI_WRITE );
EFAB_POPULATE_OWORD_7 ( reg,
- FCN_EE_SPI_HCMD_CMD_EN, 1,
- FCN_EE_SPI_HCMD_SF_SEL, device->slave,
+ FCN_EE_SPI_HCMD_CMD_EN, 1,
+ FCN_EE_SPI_HCMD_SF_SEL, device_id,
FCN_EE_SPI_HCMD_DABCNT, len,
- FCN_EE_SPI_HCMD_READ, ( data_out ?
- FCN_EE_SPI_WRITE : FCN_EE_SPI_READ ),
+ FCN_EE_SPI_HCMD_READ, read_cmd,
FCN_EE_SPI_HCMD_DUBCNT, 0,
- FCN_EE_SPI_HCMD_ADBCNT,
- ( device->address_len / 8 ),
+ FCN_EE_SPI_HCMD_ADBCNT, address_len,
FCN_EE_SPI_HCMD_ENC, command );
- falcon_write ( efab, &reg, FCN_EE_SPI_HCMD_REG_KER );
-
- /* Wait for operation to complete */
- if ( ! falcon_spi_wait ( efab ) )
- return 0;
+ falcon_write ( efab, &reg, FCN_EE_SPI_HCMD_REG );
- /* Read data, if applicable */
+ /* Wait for the command to complete */
+ rc = falcon_spi_wait ( efab );
+ if ( rc )
+ goto fail2;
+
+ /* Copy data in */
if ( data_in ) {
- falcon_read ( efab, &reg, FCN_EE_SPI_HDATA_REG_KER );
+ falcon_read ( efab, &reg, FCN_EE_SPI_HDATA_REG );
memcpy ( data_in, &reg, len );
}
-
+
return 0;
-}
-/**
- * Initialise SPI bus and devices
- *
- */
-static void falcon_init_spi ( struct efab_nic *efab ) {
- efab_oword_t reg;
- int eeprom_9bit;
-
- /* Initialise SPI bus */
- efab->spi.rw = falcon_spi_rw;
- efab->falcon_eeprom.bus = &efab->spi;
- efab->falcon_eeprom.slave = FCN_EE_SPI_EEPROM;
- efab->falcon_flash.bus = &efab->spi;
- efab->falcon_flash.slave = FCN_EE_SPI_FLASH;
-
- /* Initialise flash if present */
- if ( efab->has_flash ) {
- DBG ( "Flash is present\n" );
- init_at25f1024 ( &efab->falcon_flash );
- }
-
- /* Initialise EEPROM if present */
- if ( efab->has_eeprom ) {
- if ( efab->is_asic ) {
- falcon_read ( efab, &reg, FCN_VPD_CONFIG_REG_KER );
- eeprom_9bit = EFAB_OWORD_FIELD ( reg, FCN_VPD_9BIT );
- } else {
- eeprom_9bit = 1;
- }
- if ( eeprom_9bit ) {
- DBG ( "Small EEPROM is present\n" );
- init_at25040 ( &efab->falcon_eeprom );
- } else {
- DBG ( "Large EEPROM is present\n" );
- init_mc25xx640 ( &efab->falcon_eeprom );
- /* Falcon's SPI interface cannot support a block
- size larger than 16, so forcibly reduce it
- */
- efab->falcon_eeprom.nvs.block_size = 16;
- }
- }
-}
+fail2:
+fail1:
+ EFAB_ERR ( "Failed SPI command %d to device %d address 0x%x len 0x%zx\n",
+ command, device_id, address, len );
-/** Offset of MAC address within EEPROM or Flash */
-#define FALCON_MAC_ADDRESS_OFFSET(port) ( 0x310 + 0x08 * (port) )
+ return rc;
+}
-static struct nvo_fragment falcon_eeprom_fragments[] = {
- { 0x100, 0x100 },
+/** Portion of EEPROM available for non-volatile options */
+static struct nvo_fragment falcon_nvo_fragments[] = {
+ { 0x100, 0xf0 },
{ 0, 0 }
};
-/**
- * Read MAC address from EEPROM
+/*******************************************************************************
*
- */
-static int falcon_read_eeprom ( struct efab_nic *efab ) {
- struct nvs_device *nvs;
-
- /* Determine the NVS device containing the MAC address */
- nvs = ( efab->has_flash ?
- &efab->falcon_flash.nvs : &efab->falcon_eeprom.nvs );
-
- return ( nvs_read ( nvs, FALCON_MAC_ADDRESS_OFFSET ( efab->port ),
- efab->mac_addr, sizeof ( efab->mac_addr ) ) == 0 );
-}
-
-/** RX descriptor */
-typedef efab_qword_t falcon_rx_desc_t;
-
-/**
- * Build RX descriptor
*
- */
-static void falcon_build_rx_desc ( struct efab_nic *efab,
- struct efab_rx_buf *rx_buf ) {
- falcon_rx_desc_t *rxd;
-
- rxd = ( ( falcon_rx_desc_t * ) efab->rxd ) + rx_buf->id;
- EFAB_POPULATE_QWORD_2 ( *rxd,
- FCN_RX_KER_BUF_SIZE, EFAB_DATA_BUF_SIZE,
- FCN_RX_KER_BUF_ADR,
- virt_to_bus ( rx_buf->addr ) );
-}
-
-/**
- * Update RX descriptor write pointer
+ * Falcon bit-bashed I2C interface
*
- */
-static void falcon_notify_rx_desc ( struct efab_nic *efab ) {
- efab_dword_t reg;
-
- EFAB_POPULATE_DWORD_1 ( reg, FCN_RX_DESC_WPTR_DWORD,
- efab->rx_write_ptr );
- falcon_writel ( efab, &reg, FCN_RX_DESC_UPD_REG_KER_DWORD );
-}
+ *
+ *******************************************************************************/
-/** TX descriptor */
-typedef efab_qword_t falcon_tx_desc_t;
+static void
+falcon_i2c_bit_write ( struct bit_basher *basher, unsigned int bit_id,
+ unsigned long data )
+{
+ struct efab_nic *efab = container_of ( basher, struct efab_nic,
+ i2c_bb.basher );
+ efab_oword_t reg;
-/**
- * Build TX descriptor
- *
- */
-static void falcon_build_tx_desc ( struct efab_nic *efab,
- struct efab_tx_buf *tx_buf ) {
- falcon_rx_desc_t *txd;
+ falcon_read ( efab, &reg, FCN_GPIO_CTL_REG_KER );
+ switch ( bit_id ) {
+ case I2C_BIT_SCL:
+ EFAB_SET_OWORD_FIELD ( reg, FCN_GPIO0_OEN, ( data ? 0 : 1 ) );
+ break;
+ case I2C_BIT_SDA:
+ EFAB_SET_OWORD_FIELD ( reg, FCN_GPIO3_OEN, ( data ? 0 : 1 ) );
+ break;
+ default:
+ EFAB_ERR ( "%s bit=%d\n", __func__, bit_id );
+ break;
+ }
- txd = ( ( falcon_rx_desc_t * ) efab->txd ) + tx_buf->id;
- EFAB_POPULATE_QWORD_3 ( *txd,
- FCN_TX_KER_PORT, efab->port,
- FCN_TX_KER_BYTE_CNT, tx_buf->len,
- FCN_TX_KER_BUF_ADR,
- virt_to_bus ( tx_buf->addr ) );
+ falcon_write ( efab, &reg, FCN_GPIO_CTL_REG_KER );
}
-/**
- * Update TX descriptor write pointer
- *
- */
-static void falcon_notify_tx_desc ( struct efab_nic *efab ) {
- efab_dword_t reg;
+static int
+falcon_i2c_bit_read ( struct bit_basher *basher, unsigned int bit_id )
+{
+ struct efab_nic *efab = container_of ( basher, struct efab_nic,
+ i2c_bb.basher );
+ efab_oword_t reg;
+
+ falcon_read ( efab, &reg, FCN_GPIO_CTL_REG_KER );
+ switch ( bit_id ) {
+ case I2C_BIT_SCL:
+ return EFAB_OWORD_FIELD ( reg, FCN_GPIO0_IN );
+ break;
+ case I2C_BIT_SDA:
+ return EFAB_OWORD_FIELD ( reg, FCN_GPIO3_IN );
+ break;
+ default:
+ EFAB_ERR ( "%s bit=%d\n", __func__, bit_id );
+ break;
+ }
- EFAB_POPULATE_DWORD_1 ( reg, FCN_TX_DESC_WPTR_DWORD,
- efab->tx_write_ptr );
- falcon_writel ( efab, &reg, FCN_TX_DESC_UPD_REG_KER_DWORD );
+ return -1;
}
-/** An event */
-typedef efab_qword_t falcon_event_t;
+static struct bit_basher_operations falcon_i2c_bit_ops = {
+ .read = falcon_i2c_bit_read,
+ .write = falcon_i2c_bit_write,
+};
-/**
- * See if an event is present
+
+/*******************************************************************************
*
- * @v event Falcon event structure
- * @ret True An event is pending
- * @ret False No event is pending
*
- * We check both the high and low dword of the event for all ones. We
- * wrote all ones when we cleared the event, and no valid event can
- * have all ones in either its high or low dwords. This approach is
- * robust against reordering.
+ * MDIO access
*
- * Note that using a single 64-bit comparison is incorrect; even
- * though the CPU read will be atomic, the DMA write may not be.
- */
-static inline int falcon_event_present ( falcon_event_t* event ) {
- return ( ! ( EFAB_DWORD_IS_ALL_ONES ( event->dword[0] ) |
- EFAB_DWORD_IS_ALL_ONES ( event->dword[1] ) ) );
-}
-
-/**
- * Retrieve event from event queue
*
- */
-static int falcon_fetch_event ( struct efab_nic *efab,
- struct efab_event *event ) {
- falcon_event_t *evt;
- int ev_code;
- int rx_port;
+ *******************************************************************************/
- /* Check for event */
- evt = ( ( falcon_event_t * ) efab->eventq ) + efab->eventq_read_ptr;
- if ( !falcon_event_present ( evt ) ) {
- /* No event */
- return 0;
- }
-
- DBG ( "Event is " EFAB_QWORD_FMT "\n", EFAB_QWORD_VAL ( *evt ) );
+static int
+falcon_gmii_wait ( struct efab_nic *efab )
+{
+ efab_dword_t md_stat;
+ int count;
- /* Decode event */
- ev_code = EFAB_QWORD_FIELD ( *evt, FCN_EV_CODE );
- event->drop = 0;
- switch ( ev_code ) {
- case FCN_TX_IP_EV_DECODE:
- event->type = EFAB_EV_TX;
- break;
- case FCN_RX_IP_EV_DECODE:
- event->type = EFAB_EV_RX;
- event->rx_id = EFAB_QWORD_FIELD ( *evt, FCN_RX_EV_DESC_PTR );
- event->rx_len = EFAB_QWORD_FIELD ( *evt, FCN_RX_EV_BYTE_CNT );
- event->drop = !EFAB_QWORD_FIELD ( *evt, FCN_RX_EV_PKT_OK );
- rx_port = EFAB_QWORD_FIELD ( *evt, FCN_RX_PORT );
- if ( rx_port != efab->port ) {
- /* Ignore packets on the wrong port. We can't
- * just set event->type = EFAB_EV_NONE,
- * because then the descriptor ring won't get
- * refilled.
- */
- event->rx_len = 0;
+ /* wait upto 10ms */
+ for (count = 0; count < 1000; count++) {
+ falcon_readl ( efab, &md_stat, FCN_MD_STAT_REG_KER );
+ if ( EFAB_DWORD_FIELD ( md_stat, FCN_MD_BSY ) == 0 ) {
+ if ( EFAB_DWORD_FIELD ( md_stat, FCN_MD_LNFL ) != 0 ||
+ EFAB_DWORD_FIELD ( md_stat, FCN_MD_BSERR ) != 0 ) {
+ EFAB_ERR ( "Error from GMII access "
+ EFAB_DWORD_FMT"\n",
+ EFAB_DWORD_VAL ( md_stat ));
+ return -EIO;
+ }
+ return 0;
}
- break;
- case FCN_DRIVER_EV_DECODE:
- /* Ignore start-of-day events */
- event->type = EFAB_EV_NONE;
- break;
- default:
- EFAB_ERR ( "Unknown event type %d data %08lx\n", ev_code,
- EFAB_DWORD_FIELD ( *evt, EFAB_DWORD_0 ) );
- event->type = EFAB_EV_NONE;
+ udelay(10);
}
- /* Clear event and any pending interrupts */
- EFAB_SET_QWORD ( *evt );
- falcon_writel ( efab, 0, FCN_INT_ACK_KER_REG );
- udelay ( 10 );
+ EFAB_ERR ( "Timed out waiting for GMII\n" );
+ return -ETIMEDOUT;
+}
- /* Increment and update event queue read pointer */
- efab->eventq_read_ptr = ( ( efab->eventq_read_ptr + 1 )
- % EFAB_EVQ_SIZE );
- falcon_eventq_read_ack ( efab );
+static void
+falcon_mdio_write ( struct efab_nic *efab, int device,
+ int location, int value )
+{
+ efab_oword_t reg;
- return 1;
-}
+ EFAB_TRACE ( "Writing GMII %d register %02x with %04x\n",
+ device, location, value );
-/**
- * Enable/disable/generate interrupt
- *
- */
-static inline void falcon_interrupts ( struct efab_nic *efab, int enabled,
- int force ) {
- efab_oword_t int_en_reg_ker;
+ /* Check MII not currently being accessed */
+ if ( falcon_gmii_wait ( efab ) )
+ return;
- EFAB_POPULATE_OWORD_2 ( int_en_reg_ker,
- FCN_KER_INT_KER, force,
- FCN_DRV_INT_EN_KER, enabled );
- falcon_write ( efab, &int_en_reg_ker, FCN_INT_EN_REG_KER );
-}
+ /* Write the address/ID register */
+ EFAB_POPULATE_OWORD_1 ( reg, FCN_MD_PHY_ADR, location );
+ falcon_write ( efab, &reg, FCN_MD_PHY_ADR_REG_KER );
-/**
- * Enable/disable interrupts
- *
- */
-static void falcon_mask_irq ( struct efab_nic *efab, int enabled ) {
- falcon_interrupts ( efab, enabled, 0 );
- if ( enabled ) {
- /* Events won't trigger interrupts until we do this */
- falcon_eventq_read_ack ( efab );
+ if ( efab->phy_10g ) {
+ /* clause45 */
+ EFAB_POPULATE_OWORD_2 ( reg,
+ FCN_MD_PRT_ADR, efab->phy_addr,
+ FCN_MD_DEV_ADR, device );
}
-}
+ else {
+ /* clause22 */
+ assert ( device == 0 );
-/**
- * Generate interrupt
- *
- */
-static void falcon_generate_irq ( struct efab_nic *efab ) {
- falcon_interrupts ( efab, 1, 1 );
+ EFAB_POPULATE_OWORD_2 ( reg,
+ FCN_MD_PRT_ADR, efab->phy_addr,
+ FCN_MD_DEV_ADR, location );
+ }
+ falcon_write ( efab, &reg, FCN_MD_ID_REG_KER );
+
+
+ /* Write data */
+ EFAB_POPULATE_OWORD_1 ( reg, FCN_MD_TXD, value );
+ falcon_write ( efab, &reg, FCN_MD_TXD_REG_KER );
+
+ EFAB_POPULATE_OWORD_2 ( reg,
+ FCN_MD_WRC, 1,
+ FCN_MD_GC, ( efab->phy_10g ? 0 : 1 ) );
+ falcon_write ( efab, &reg, FCN_MD_CS_REG_KER );
+
+ /* Wait for data to be written */
+ if ( falcon_gmii_wait ( efab ) ) {
+ /* Abort the write operation */
+ EFAB_POPULATE_OWORD_2 ( reg,
+ FCN_MD_WRC, 0,
+ FCN_MD_GC, 1);
+ falcon_write ( efab, &reg, FCN_MD_CS_REG_KER );
+ udelay(10);
+ }
}
+static int
+falcon_mdio_read ( struct efab_nic *efab, int device, int location )
+{
+ efab_oword_t reg;
+ int value;
-/**
- * Reconfigure MAC wrapper
+ /* Check MII not currently being accessed */
+ if ( falcon_gmii_wait ( efab ) )
+ return -1;
+
+ if ( efab->phy_10g ) {
+ /* clause45 */
+ EFAB_POPULATE_OWORD_1 ( reg, FCN_MD_PHY_ADR, location );
+ falcon_write ( efab, &reg, FCN_MD_PHY_ADR_REG_KER );
+
+ EFAB_POPULATE_OWORD_2 ( reg,
+ FCN_MD_PRT_ADR, efab->phy_addr,
+ FCN_MD_DEV_ADR, device );
+ falcon_write ( efab, &reg, FCN_MD_ID_REG_KER);
+
+ /* request data to be read */
+ EFAB_POPULATE_OWORD_2 ( reg,
+ FCN_MD_RDC, 1,
+ FCN_MD_GC, 0 );
+ }
+ else {
+ /* clause22 */
+ assert ( device == 0 );
+
+ EFAB_POPULATE_OWORD_2 ( reg,
+ FCN_MD_PRT_ADR, efab->phy_addr,
+ FCN_MD_DEV_ADR, location );
+ falcon_write ( efab, &reg, FCN_MD_ID_REG_KER );
+
+ /* Request data to be read */
+ EFAB_POPULATE_OWORD_2 ( reg,
+ FCN_MD_RIC, 1,
+ FCN_MD_GC, 1 );
+ }
+
+ falcon_write ( efab, &reg, FCN_MD_CS_REG_KER );
+
+ /* Wait for data to become available */
+ if ( falcon_gmii_wait ( efab ) ) {
+ /* Abort the read operation */
+ EFAB_POPULATE_OWORD_2 ( reg,
+ FCN_MD_RIC, 0,
+ FCN_MD_GC, 1 );
+ falcon_write ( efab, &reg, FCN_MD_CS_REG_KER );
+ udelay ( 10 );
+ value = -1;
+ }
+ else {
+ /* Read the data */
+ falcon_read ( efab, &reg, FCN_MD_RXD_REG_KER );
+ value = EFAB_OWORD_FIELD ( reg, FCN_MD_RXD );
+ }
+
+ EFAB_TRACE ( "Read from GMII %d register %02x, got %04x\n",
+ device, location, value );
+
+ return value;
+}
+
+/*******************************************************************************
*
- */
-static void falcon_reconfigure_mac_wrapper ( struct efab_nic *efab ) {
+ *
+ * MAC wrapper
+ *
+ *
+ *******************************************************************************/
+
+static void
+falcon_reconfigure_mac_wrapper ( struct efab_nic *efab )
+{
efab_oword_t reg;
int link_speed;
@@ -2561,22 +1752,153 @@ static void falcon_reconfigure_mac_wrapper ( struct efab_nic *efab ) {
FCN_MAC_UC_PROM, 0,
FCN_MAC_LINK_STATUS, 1,
FCN_MAC_SPEED, link_speed );
- falcon_write ( efab, &reg,
- ( efab->port == 0 ?
- FCN_MAC0_CTRL_REG_KER : FCN_MAC1_CTRL_REG_KER ) );
- /* Disable flow-control (i.e. never generate pause frames) */
- falcon_read ( efab, &reg, FCN_RX_CFG_REG_KER );
- EFAB_SET_OWORD_FIELD ( reg, FCN_RX_XOFF_EN, 0 );
- falcon_write ( efab, &reg, FCN_RX_CFG_REG_KER );
+ falcon_write ( efab, &reg, FCN_MAC0_CTRL_REG_KER );
}
-/**
- * Write dword to a Falcon MAC register
+/*******************************************************************************
*
- */
-static void falcon_gmac_writel ( struct efab_nic *efab,
- efab_dword_t *value, unsigned int mac_reg ) {
+ *
+ * GMAC handling
+ *
+ *
+ *******************************************************************************/
+
+/* GMAC configuration register 1 */
+#define GM_CFG1_REG_MAC 0x00
+#define GM_SW_RST_LBN 31
+#define GM_SW_RST_WIDTH 1
+#define GM_RX_FC_EN_LBN 5
+#define GM_RX_FC_EN_WIDTH 1
+#define GM_TX_FC_EN_LBN 4
+#define GM_TX_FC_EN_WIDTH 1
+#define GM_RX_EN_LBN 2
+#define GM_RX_EN_WIDTH 1
+#define GM_TX_EN_LBN 0
+#define GM_TX_EN_WIDTH 1
+
+/* GMAC configuration register 2 */
+#define GM_CFG2_REG_MAC 0x01
+#define GM_PAMBL_LEN_LBN 12
+#define GM_PAMBL_LEN_WIDTH 4
+#define GM_IF_MODE_LBN 8
+#define GM_IF_MODE_WIDTH 2
+#define GM_PAD_CRC_EN_LBN 2
+#define GM_PAD_CRC_EN_WIDTH 1
+#define GM_FD_LBN 0
+#define GM_FD_WIDTH 1
+
+/* GMAC maximum frame length register */
+#define GM_MAX_FLEN_REG_MAC 0x04
+#define GM_MAX_FLEN_LBN 0
+#define GM_MAX_FLEN_WIDTH 16
+
+/* GMAC MII management configuration register */
+#define GM_MII_MGMT_CFG_REG_MAC 0x08
+#define GM_MGMT_CLK_SEL_LBN 0
+#define GM_MGMT_CLK_SEL_WIDTH 3
+
+/* GMAC MII management command register */
+#define GM_MII_MGMT_CMD_REG_MAC 0x09
+#define GM_MGMT_SCAN_CYC_LBN 1
+#define GM_MGMT_SCAN_CYC_WIDTH 1
+#define GM_MGMT_RD_CYC_LBN 0
+#define GM_MGMT_RD_CYC_WIDTH 1
+
+/* GMAC MII management address register */
+#define GM_MII_MGMT_ADR_REG_MAC 0x0a
+#define GM_MGMT_PHY_ADDR_LBN 8
+#define GM_MGMT_PHY_ADDR_WIDTH 5
+#define GM_MGMT_REG_ADDR_LBN 0
+#define GM_MGMT_REG_ADDR_WIDTH 5
+
+/* GMAC MII management control register */
+#define GM_MII_MGMT_CTL_REG_MAC 0x0b
+#define GM_MGMT_CTL_LBN 0
+#define GM_MGMT_CTL_WIDTH 16
+
+/* GMAC MII management status register */
+#define GM_MII_MGMT_STAT_REG_MAC 0x0c
+#define GM_MGMT_STAT_LBN 0
+#define GM_MGMT_STAT_WIDTH 16
+
+/* GMAC MII management indicators register */
+#define GM_MII_MGMT_IND_REG_MAC 0x0d
+#define GM_MGMT_BUSY_LBN 0
+#define GM_MGMT_BUSY_WIDTH 1
+
+/* GMAC station address register 1 */
+#define GM_ADR1_REG_MAC 0x10
+#define GM_HWADDR_5_LBN 24
+#define GM_HWADDR_5_WIDTH 8
+#define GM_HWADDR_4_LBN 16
+#define GM_HWADDR_4_WIDTH 8
+#define GM_HWADDR_3_LBN 8
+#define GM_HWADDR_3_WIDTH 8
+#define GM_HWADDR_2_LBN 0
+#define GM_HWADDR_2_WIDTH 8
+
+/* GMAC station address register 2 */
+#define GM_ADR2_REG_MAC 0x11
+#define GM_HWADDR_1_LBN 24
+#define GM_HWADDR_1_WIDTH 8
+#define GM_HWADDR_0_LBN 16
+#define GM_HWADDR_0_WIDTH 8
+
+/* GMAC FIFO configuration register 0 */
+#define GMF_CFG0_REG_MAC 0x12
+#define GMF_FTFENREQ_LBN 12
+#define GMF_FTFENREQ_WIDTH 1
+#define GMF_STFENREQ_LBN 11
+#define GMF_STFENREQ_WIDTH 1
+#define GMF_FRFENREQ_LBN 10
+#define GMF_FRFENREQ_WIDTH 1
+#define GMF_SRFENREQ_LBN 9
+#define GMF_SRFENREQ_WIDTH 1
+#define GMF_WTMENREQ_LBN 8
+#define GMF_WTMENREQ_WIDTH 1
+
+/* GMAC FIFO configuration register 1 */
+#define GMF_CFG1_REG_MAC 0x13
+#define GMF_CFGFRTH_LBN 16
+#define GMF_CFGFRTH_WIDTH 5
+#define GMF_CFGXOFFRTX_LBN 0
+#define GMF_CFGXOFFRTX_WIDTH 16
+
+/* GMAC FIFO configuration register 2 */
+#define GMF_CFG2_REG_MAC 0x14
+#define GMF_CFGHWM_LBN 16
+#define GMF_CFGHWM_WIDTH 6
+#define GMF_CFGLWM_LBN 0
+#define GMF_CFGLWM_WIDTH 6
+
+/* GMAC FIFO configuration register 3 */
+#define GMF_CFG3_REG_MAC 0x15
+#define GMF_CFGHWMFT_LBN 16
+#define GMF_CFGHWMFT_WIDTH 6
+#define GMF_CFGFTTH_LBN 0
+#define GMF_CFGFTTH_WIDTH 6
+
+/* GMAC FIFO configuration register 4 */
+#define GMF_CFG4_REG_MAC 0x16
+#define GMF_HSTFLTRFRM_PAUSE_LBN 12
+#define GMF_HSTFLTRFRM_PAUSE_WIDTH 12
+
+/* GMAC FIFO configuration register 5 */
+#define GMF_CFG5_REG_MAC 0x17
+#define GMF_CFGHDPLX_LBN 22
+#define GMF_CFGHDPLX_WIDTH 1
+#define GMF_CFGBYTMODE_LBN 19
+#define GMF_CFGBYTMODE_WIDTH 1
+#define GMF_HSTDRPLT64_LBN 18
+#define GMF_HSTDRPLT64_WIDTH 1
+#define GMF_HSTFLTRFRMDC_PAUSE_LBN 12
+#define GMF_HSTFLTRFRMDC_PAUSE_WIDTH 1
+
+static void
+falcon_gmac_writel ( struct efab_nic *efab, efab_dword_t *value,
+ unsigned int mac_reg )
+{
efab_oword_t temp;
EFAB_POPULATE_OWORD_1 ( temp, FCN_MAC_DATA,
@@ -2584,12 +1906,10 @@ static void falcon_gmac_writel ( struct efab_nic *efab,
falcon_write ( efab, &temp, FALCON_GMAC_REG ( efab, mac_reg ) );
}
-/**
- * Read dword from a Falcon GMAC register
- *
- */
-static void falcon_gmac_readl ( struct efab_nic *efab, efab_dword_t *value,
- unsigned int mac_reg ) {
+static void
+falcon_gmac_readl ( struct efab_nic *efab, efab_dword_t *value,
+ unsigned int mac_reg )
+{
efab_oword_t temp;
falcon_read ( efab, &temp, FALCON_GMAC_REG ( efab, mac_reg ) );
@@ -2597,12 +1917,172 @@ static void falcon_gmac_readl ( struct efab_nic *efab, efab_dword_t *value,
EFAB_OWORD_FIELD ( temp, FCN_MAC_DATA ) );
}
+static void
+mentormac_reset ( struct efab_nic *efab )
+{
+ efab_dword_t reg;
+
+ /* Take into reset */
+ EFAB_POPULATE_DWORD_1 ( reg, GM_SW_RST, 1 );
+ falcon_gmac_writel ( efab, &reg, GM_CFG1_REG_MAC );
+ udelay ( 1000 );
+
+ /* Take out of reset */
+ EFAB_POPULATE_DWORD_1 ( reg, GM_SW_RST, 0 );
+ falcon_gmac_writel ( efab, &reg, GM_CFG1_REG_MAC );
+ udelay ( 1000 );
+
+ /* Configure GMII interface so PHY is accessible. Note that
+ * GMII interface is connected only to port 0, and that on
+ * Falcon this is a no-op.
+ */
+ EFAB_POPULATE_DWORD_1 ( reg, GM_MGMT_CLK_SEL, 0x4 );
+ falcon_gmac_writel ( efab, &reg, GM_MII_MGMT_CFG_REG_MAC );
+ udelay ( 10 );
+}
+
+static void
+mentormac_init ( struct efab_nic *efab )
+{
+ int pause, if_mode, full_duplex, bytemode, half_duplex;
+ efab_dword_t reg;
+
+ /* Configuration register 1 */
+ pause = ( efab->link_options & LPA_PAUSE ) ? 1 : 0;
+ if ( ! ( efab->link_options & LPA_DUPLEX ) ) {
+ /* Half-duplex operation requires TX flow control */
+ pause = 1;
+ }
+ EFAB_POPULATE_DWORD_4 ( reg,
+ GM_TX_EN, 1,
+ GM_TX_FC_EN, pause,
+ GM_RX_EN, 1,
+ GM_RX_FC_EN, 1 );
+ falcon_gmac_writel ( efab, &reg, GM_CFG1_REG_MAC );
+ udelay ( 10 );
+
+ /* Configuration register 2 */
+ if_mode = ( efab->link_options & LPA_1000 ) ? 2 : 1;
+ full_duplex = ( efab->link_options & LPA_DUPLEX ) ? 1 : 0;
+ EFAB_POPULATE_DWORD_4 ( reg,
+ GM_IF_MODE, if_mode,
+ GM_PAD_CRC_EN, 1,
+ GM_FD, full_duplex,
+ GM_PAMBL_LEN, 0x7 /* ? */ );
+ falcon_gmac_writel ( efab, &reg, GM_CFG2_REG_MAC );
+ udelay ( 10 );
+
+ /* Max frame len register */
+ EFAB_POPULATE_DWORD_1 ( reg, GM_MAX_FLEN,
+ EFAB_MAX_FRAME_LEN ( ETH_FRAME_LEN ) );
+ falcon_gmac_writel ( efab, &reg, GM_MAX_FLEN_REG_MAC );
+ udelay ( 10 );
+
+ /* FIFO configuration register 0 */
+ EFAB_POPULATE_DWORD_5 ( reg,
+ GMF_FTFENREQ, 1,
+ GMF_STFENREQ, 1,
+ GMF_FRFENREQ, 1,
+ GMF_SRFENREQ, 1,
+ GMF_WTMENREQ, 1 );
+ falcon_gmac_writel ( efab, &reg, GMF_CFG0_REG_MAC );
+ udelay ( 10 );
+
+ /* FIFO configuration register 1 */
+ EFAB_POPULATE_DWORD_2 ( reg,
+ GMF_CFGFRTH, 0x12,
+ GMF_CFGXOFFRTX, 0xffff );
+ falcon_gmac_writel ( efab, &reg, GMF_CFG1_REG_MAC );
+ udelay ( 10 );
+
+ /* FIFO configuration register 2 */
+ EFAB_POPULATE_DWORD_2 ( reg,
+ GMF_CFGHWM, 0x3f,
+ GMF_CFGLWM, 0xa );
+ falcon_gmac_writel ( efab, &reg, GMF_CFG2_REG_MAC );
+ udelay ( 10 );
+
+ /* FIFO configuration register 3 */
+ EFAB_POPULATE_DWORD_2 ( reg,
+ GMF_CFGHWMFT, 0x1c,
+ GMF_CFGFTTH, 0x08 );
+ falcon_gmac_writel ( efab, &reg, GMF_CFG3_REG_MAC );
+ udelay ( 10 );
+
+ /* FIFO configuration register 4 */
+ EFAB_POPULATE_DWORD_1 ( reg, GMF_HSTFLTRFRM_PAUSE, 1 );
+ falcon_gmac_writel ( efab, &reg, GMF_CFG4_REG_MAC );
+ udelay ( 10 );
+
+ /* FIFO configuration register 5 */
+ bytemode = ( efab->link_options & LPA_1000 ) ? 1 : 0;
+ half_duplex = ( efab->link_options & LPA_DUPLEX ) ? 0 : 1;
+ falcon_gmac_readl ( efab, &reg, GMF_CFG5_REG_MAC );
+ EFAB_SET_DWORD_FIELD ( reg, GMF_CFGBYTMODE, bytemode );
+ EFAB_SET_DWORD_FIELD ( reg, GMF_CFGHDPLX, half_duplex );
+ EFAB_SET_DWORD_FIELD ( reg, GMF_HSTDRPLT64, half_duplex );
+ EFAB_SET_DWORD_FIELD ( reg, GMF_HSTFLTRFRMDC_PAUSE, 0 );
+ falcon_gmac_writel ( efab, &reg, GMF_CFG5_REG_MAC );
+ udelay ( 10 );
+
+ /* MAC address */
+ EFAB_POPULATE_DWORD_4 ( reg,
+ GM_HWADDR_5, efab->mac_addr[5],
+ GM_HWADDR_4, efab->mac_addr[4],
+ GM_HWADDR_3, efab->mac_addr[3],
+ GM_HWADDR_2, efab->mac_addr[2] );
+ falcon_gmac_writel ( efab, &reg, GM_ADR1_REG_MAC );
+ udelay ( 10 );
+ EFAB_POPULATE_DWORD_2 ( reg,
+ GM_HWADDR_1, efab->mac_addr[1],
+ GM_HWADDR_0, efab->mac_addr[0] );
+ falcon_gmac_writel ( efab, &reg, GM_ADR2_REG_MAC );
+ udelay ( 10 );
+}
+
+static int
+falcon_init_gmac ( struct efab_nic *efab )
+{
+ /* Reset the MAC */
+ mentormac_reset ( efab );
+
+ /* Initialise PHY */
+ efab->phy_op->init ( efab );
+
+ /* check the link is up */
+ if ( !efab->link_up )
+ return -EAGAIN;
+
+ /* Initialise MAC */
+ mentormac_init ( efab );
+
+ /* reconfigure the MAC wrapper */
+ falcon_reconfigure_mac_wrapper ( efab );
+
+ return 0;
+}
+
+static struct efab_mac_operations falcon_gmac_operations = {
+ .init = falcon_init_gmac,
+};
+
+
+/*******************************************************************************
+ *
+ *
+ * XMAC handling
+ *
+ *
+ *******************************************************************************/
+
/**
* Write dword to a Falcon XMAC register
*
*/
-static void falcon_xmac_writel ( struct efab_nic *efab,
- efab_dword_t *value, unsigned int mac_reg ) {
+static void
+falcon_xmac_writel ( struct efab_nic *efab, efab_dword_t *value,
+ unsigned int mac_reg )
+{
efab_oword_t temp;
EFAB_POPULATE_OWORD_1 ( temp, FCN_MAC_DATA,
@@ -2615,9 +2095,10 @@ static void falcon_xmac_writel ( struct efab_nic *efab,
* Read dword from a Falcon XMAC register
*
*/
-static void falcon_xmac_readl ( struct efab_nic *efab,
- efab_dword_t *value,
- unsigned int mac_reg ) {
+static void
+falcon_xmac_readl ( struct efab_nic *efab, efab_dword_t *value,
+ unsigned int mac_reg )
+{
efab_oword_t temp;
falcon_read ( efab, &temp,
@@ -2627,109 +2108,159 @@ static void falcon_xmac_readl ( struct efab_nic *efab,
}
/**
- * Initialise GMAC
- *
+ * Configure Falcon XAUI output
*/
-static int falcon_init_gmac ( struct efab_nic *efab ) {
- static struct efab_mentormac_parameters falcon_mentormac_params = {
- .gmf_cfgfrth = 0x12,
- .gmf_cfgftth = 0x08,
- .gmf_cfghwmft = 0x1c,
- .gmf_cfghwm = 0x3f,
- .gmf_cfglwm = 0xa,
- };
+static void
+falcon_setup_xaui ( struct efab_nic *efab )
+{
+ efab_dword_t sdctl, txdrv;
+
+ falcon_xmac_readl ( efab, &sdctl, FCN_XX_SD_CTL_REG_MAC );
+ EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_HIDRVD, XX_SD_CTL_DRV_DEFAULT );
+ EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_LODRVD, XX_SD_CTL_DRV_DEFAULT );
+ EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_HIDRVC, XX_SD_CTL_DRV_DEFAULT );
+ EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_LODRVC, XX_SD_CTL_DRV_DEFAULT );
+ EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_HIDRVB, XX_SD_CTL_DRV_DEFAULT );
+ EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_LODRVB, XX_SD_CTL_DRV_DEFAULT );
+ EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_HIDRVA, XX_SD_CTL_DRV_DEFAULT );
+ EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_LODRVA, XX_SD_CTL_DRV_DEFAULT );
+ falcon_xmac_writel ( efab, &sdctl, FCN_XX_SD_CTL_REG_MAC );
+
+ EFAB_POPULATE_DWORD_8 ( txdrv,
+ FCN_XX_DEQD, XX_TXDRV_DEQ_DEFAULT,
+ FCN_XX_DEQC, XX_TXDRV_DEQ_DEFAULT,
+ FCN_XX_DEQB, XX_TXDRV_DEQ_DEFAULT,
+ FCN_XX_DEQA, XX_TXDRV_DEQ_DEFAULT,
+ FCN_XX_DTXD, XX_TXDRV_DTX_DEFAULT,
+ FCN_XX_DTXC, XX_TXDRV_DTX_DEFAULT,
+ FCN_XX_DTXB, XX_TXDRV_DTX_DEFAULT,
+ FCN_XX_DTXA, XX_TXDRV_DTX_DEFAULT);
+ falcon_xmac_writel ( efab, &txdrv, FCN_XX_TXDRV_CTL_REG_MAC);
+}
- /* Initialise PHY */
- alaska_init ( efab );
+static int
+falcon_xgmii_status ( struct efab_nic *efab )
+{
+ efab_dword_t reg;
- /* check the link is up */
- if ( !efab->link_up )
+ if ( efab->pci_revision < FALCON_REV_B0 )
+ return 1;
+ /* The ISR latches, so clear it and re-read */
+ falcon_xmac_readl ( efab, &reg, FCN_XM_MGT_INT_REG_MAC_B0 );
+ falcon_xmac_readl ( efab, &reg, FCN_XM_MGT_INT_REG_MAC_B0 );
+
+ if ( EFAB_DWORD_FIELD ( reg, FCN_XM_LCLFLT ) ||
+ EFAB_DWORD_FIELD ( reg, FCN_XM_RMTFLT ) ) {
+ EFAB_TRACE ( "MGT_INT: "EFAB_DWORD_FMT"\n",
+ EFAB_DWORD_VAL ( reg ) );
return 0;
-
- /* Initialise MAC */
- mentormac_init ( efab, &falcon_mentormac_params );
-
- /* reconfigure the MAC wrapper */
- falcon_reconfigure_mac_wrapper ( efab );
+ }
return 1;
}
-/**
- * Reset GMAC
- *
- */
-static int falcon_reset_gmac ( struct efab_nic *efab ) {
- mentormac_reset ( efab );
- return 1;
+static void
+falcon_mask_status_intr ( struct efab_nic *efab, int enable )
+{
+ efab_dword_t reg;
+
+ if ( efab->pci_revision < FALCON_REV_B0 )
+ return;
+
+ /* Flush the ISR */
+ if ( enable )
+ falcon_xmac_readl ( efab, &reg, FCN_XM_MGT_INT_REG_MAC_B0 );
+
+ EFAB_POPULATE_DWORD_2 ( reg,
+ FCN_XM_MSK_RMTFLT, !enable,
+ FCN_XM_MSK_LCLFLT, !enable);
+ falcon_xmac_readl ( efab, &reg, FCN_XM_MGT_INT_MSK_REG_MAC_B0 );
}
/**
- * Reset XAUI/XGXS block
+ * Reset 10G MAC connected to port
*
*/
-static int falcon_reset_xaui ( struct efab_nic *efab )
+static int
+falcon_reset_xmac ( struct efab_nic *efab )
{
efab_dword_t reg;
int count;
-
- EFAB_POPULATE_DWORD_1 ( reg, FCN_XX_RST_XX_EN, 1 );
- efab->mac_op->mac_writel ( efab, &reg, FCN_XX_PWR_RST_REG_MAC );
+
+ EFAB_POPULATE_DWORD_1 ( reg, FCN_XM_CORE_RST, 1 );
+ falcon_xmac_writel ( efab, &reg, FCN_XM_GLB_CFG_REG_MAC );
for ( count = 0 ; count < 1000 ; count++ ) {
udelay ( 10 );
- efab->mac_op->mac_readl ( efab, &reg,
- FCN_XX_PWR_RST_REG_MAC );
- if ( EFAB_DWORD_FIELD ( reg, FCN_XX_RST_XX_EN ) == 0 )
- return 1;
+ falcon_xmac_readl ( efab, &reg,
+ FCN_XM_GLB_CFG_REG_MAC );
+ if ( EFAB_DWORD_FIELD ( reg, FCN_XM_CORE_RST ) == 0 )
+ return 0;
}
-
- /* an error of some kind */
- return 0;
+ return -ETIMEDOUT;
}
-/**
- * Reset 10G MAC connected to port
- *
- */
-static int falcon_reset_xmac ( struct efab_nic *efab ) {
+
+static int
+falcon_reset_xaui ( struct efab_nic *efab )
+{
efab_dword_t reg;
int count;
- EFAB_POPULATE_DWORD_1 ( reg, FCN_XM_CORE_RST, 1 );
- efab->mac_op->mac_writel ( efab, &reg, FCN_XM_GLB_CFG_REG_MAC );
+ if (!efab->is_asic)
+ return 0;
- for ( count = 0 ; count < 1000 ; count++ ) {
- udelay ( 10 );
- efab->mac_op->mac_readl ( efab, &reg,
- FCN_XM_GLB_CFG_REG_MAC );
- if ( EFAB_DWORD_FIELD ( reg, FCN_XM_CORE_RST ) == 0 )
- return 1;
+ EFAB_POPULATE_DWORD_1 ( reg, FCN_XX_RST_XX_EN, 1 );
+ falcon_xmac_writel ( efab, &reg, FCN_XX_PWR_RST_REG_MAC );
+
+ /* Give some time for the link to establish */
+ for (count = 0; count < 1000; count++) { /* wait upto 10ms */
+ falcon_xmac_readl ( efab, &reg, FCN_XX_PWR_RST_REG_MAC );
+ if ( EFAB_DWORD_FIELD ( reg, FCN_XX_RST_XX_EN ) == 0 ) {
+ falcon_setup_xaui ( efab );
+ return 0;
+ }
+ udelay(10);
}
- return 0;
+ EFAB_ERR ( "timed out waiting for XAUI/XGXS reset\n" );
+ return -ETIMEDOUT;
}
-/**
- * Get status of 10G link
- *
- */
-static int falcon_xaui_link_ok ( struct efab_nic *efab ) {
+static int
+falcon_xaui_link_ok ( struct efab_nic *efab )
+{
efab_dword_t reg;
- int align_done;
- int sync_status;
- int link_ok = 0;
+ int align_done, lane_status, sync;
+ int has_phyxs;
+ int link_ok = 1;
+
+ /* Read Falcon XAUI side */
+ if ( efab->is_asic ) {
+ /* Read link status */
+ falcon_xmac_readl ( efab, &reg, FCN_XX_CORE_STAT_REG_MAC );
+ align_done = EFAB_DWORD_FIELD ( reg, FCN_XX_ALIGN_DONE );
- /* Read link status */
- efab->mac_op->mac_readl ( efab, &reg, FCN_XX_CORE_STAT_REG_MAC );
- align_done = EFAB_DWORD_FIELD ( reg, FCN_XX_ALIGN_DONE );
- sync_status = EFAB_DWORD_FIELD ( reg, FCN_XX_SYNC_STAT );
- if ( align_done && ( sync_status == FCN_XX_SYNC_STAT_DECODE_SYNCED ) ) {
- link_ok = 1;
+ sync = EFAB_DWORD_FIELD ( reg, FCN_XX_SYNC_STAT );
+ sync = ( sync == FCN_XX_SYNC_STAT_DECODE_SYNCED );
+
+ link_ok = align_done && sync;
}
/* Clear link status ready for next read */
EFAB_SET_DWORD_FIELD ( reg, FCN_XX_COMMA_DET, FCN_XX_COMMA_DET_RESET );
- efab->mac_op->mac_writel ( efab, &reg, FCN_XX_CORE_STAT_REG_MAC );
+ EFAB_SET_DWORD_FIELD ( reg, FCN_XX_CHARERR, FCN_XX_CHARERR_RESET);
+ EFAB_SET_DWORD_FIELD ( reg, FCN_XX_DISPERR, FCN_XX_DISPERR_RESET);
+ falcon_xmac_writel ( efab, &reg, FCN_XX_CORE_STAT_REG_MAC );
+
+ has_phyxs = ( efab->phy_op->mmds & ( 1 << MDIO_MMD_PHYXS ) );
+ if ( link_ok && has_phyxs ) {
+ lane_status = falcon_mdio_read ( efab, MDIO_MMD_PHYXS,
+ MDIO_PHYXS_LANE_STATE );
+ link_ok = ( lane_status & ( 1 << MDIO_PHYXS_LANE_ALIGNED_LBN ) );
+
+ if (!link_ok )
+ EFAB_LOG ( "XGXS lane status: %x\n", lane_status );
+ }
return link_ok;
}
@@ -2738,28 +2269,18 @@ static int falcon_xaui_link_ok ( struct efab_nic *efab ) {
* Initialise XMAC
*
*/
-static int falcon_init_xmac ( struct efab_nic *efab ) {
+static void
+falcon_reconfigure_xmac ( struct efab_nic *efab )
+{
efab_dword_t reg;
- int count;
+ int max_frame_len;
- if ( !falcon_reset_xmac ( efab ) ) {
- EFAB_ERR ( "failed resetting XMAC\n" );
- return 0;
- }
- if ( !falcon_reset_xaui ( efab ) ) {
- EFAB_ERR ( "failed resetting XAUI\n");
- return 0;
- }
-
- /* CX4 is always 10000FD only */
- efab->link_options = LPA_10000FULL;
-
- /* Configure MAC */
+ /* Configure MAC - cut-thru mode is hard wired on */
EFAB_POPULATE_DWORD_3 ( reg,
FCN_XM_RX_JUMBO_MODE, 1,
FCN_XM_TX_STAT_EN, 1,
FCN_XM_RX_STAT_EN, 1);
- efab->mac_op->mac_writel ( efab, &reg, FCN_XM_GLB_CFG_REG_MAC );
+ falcon_xmac_writel ( efab, &reg, FCN_XM_GLB_CFG_REG_MAC );
/* Configure TX */
EFAB_POPULATE_DWORD_6 ( reg,
@@ -2769,23 +2290,31 @@ static int falcon_init_xmac ( struct efab_nic *efab ) {
FCN_XM_TXCRC, 1,
FCN_XM_FCNTL, 1,
FCN_XM_IPG, 0x3 );
- efab->mac_op->mac_writel ( efab, &reg, FCN_XM_TX_CFG_REG_MAC );
+ falcon_xmac_writel ( efab, &reg, FCN_XM_TX_CFG_REG_MAC );
/* Configure RX */
- EFAB_POPULATE_DWORD_3 ( reg,
+ EFAB_POPULATE_DWORD_4 ( reg,
FCN_XM_RXEN, 1,
- FCN_XM_AUTO_DEPAD, 1,
+ FCN_XM_AUTO_DEPAD, 0,
+ FCN_XM_ACPT_ALL_MCAST, 1,
FCN_XM_PASS_CRC_ERR, 1 );
- efab->mac_op->mac_writel ( efab, &reg, FCN_XM_RX_CFG_REG_MAC );
+ falcon_xmac_writel ( efab, &reg, FCN_XM_RX_CFG_REG_MAC );
/* Set frame length */
+ max_frame_len = EFAB_MAX_FRAME_LEN ( ETH_FRAME_LEN );
EFAB_POPULATE_DWORD_1 ( reg,
- FCN_XM_MAX_RX_FRM_SIZE, ETH_FRAME_LEN );
- efab->mac_op->mac_writel ( efab, &reg, FCN_XM_RX_PARAM_REG_MAC );
+ FCN_XM_MAX_RX_FRM_SIZE, max_frame_len );
+ falcon_xmac_writel ( efab, &reg, FCN_XM_RX_PARAM_REG_MAC );
EFAB_POPULATE_DWORD_2 ( reg,
- FCN_XM_MAX_TX_FRM_SIZE, ETH_FRAME_LEN,
+ FCN_XM_MAX_TX_FRM_SIZE, max_frame_len,
FCN_XM_TX_JUMBO_MODE, 1 );
- efab->mac_op->mac_writel ( efab, &reg, FCN_XM_TX_PARAM_REG_MAC );
+ falcon_xmac_writel ( efab, &reg, FCN_XM_TX_PARAM_REG_MAC );
+
+ /* Enable flow control receipt */
+ EFAB_POPULATE_DWORD_2 ( reg,
+ FCN_XM_PAUSE_TIME, 0xfffe,
+ FCN_XM_DIS_FCNTL, 0 );
+ falcon_xmac_writel ( efab, &reg, FCN_XM_FC_REG_MAC );
/* Set MAC address */
EFAB_POPULATE_DWORD_4 ( reg,
@@ -2793,639 +2322,1922 @@ static int falcon_init_xmac ( struct efab_nic *efab ) {
FCN_XM_ADR_1, efab->mac_addr[1],
FCN_XM_ADR_2, efab->mac_addr[2],
FCN_XM_ADR_3, efab->mac_addr[3] );
- efab->mac_op->mac_writel ( efab, &reg, FCN_XM_ADR_LO_REG_MAC );
+ falcon_xmac_writel ( efab, &reg, FCN_XM_ADR_LO_REG_MAC );
EFAB_POPULATE_DWORD_2 ( reg,
FCN_XM_ADR_4, efab->mac_addr[4],
FCN_XM_ADR_5, efab->mac_addr[5] );
- efab->mac_op->mac_writel ( efab, &reg, FCN_XM_ADR_HI_REG_MAC );
+ falcon_xmac_writel ( efab, &reg, FCN_XM_ADR_HI_REG_MAC );
+}
- /* Reconfigure MAC wrapper */
- falcon_reconfigure_mac_wrapper ( efab );
+static int
+falcon_init_xmac ( struct efab_nic *efab )
+{
+ int count, rc;
+
+ /* Mask the PHY management interrupt */
+ falcon_mask_status_intr ( efab, 0 );
+ /* Initialise the PHY to instantiate the clock. */
+ rc = efab->phy_op->init ( efab );
+ if ( rc ) {
+ EFAB_ERR ( "unable to initialise PHY\n" );
+ goto fail1;
+ }
+
+ falcon_reset_xaui ( efab );
+
+ /* Give the PHY and MAC time to faff */
+ mdelay ( 100 );
+
+ /* Reset and reconfigure the XMAC */
+ rc = falcon_reset_xmac ( efab );
+ if ( rc )
+ goto fail2;
+ falcon_reconfigure_xmac ( efab );
+ falcon_reconfigure_mac_wrapper ( efab );
/**
- * Try resetting XAUI on its own waiting for the link
- * to come up
+ * Now wait for the link to come up. This may take a while
+ * for some slower PHY's.
*/
- for(count=0; count<5; count++) {
- /* Check link status */
- efab->link_up = falcon_xaui_link_ok ( efab );
- if ( efab->link_up ) {
- /**
- * Print out a speed message since we don't have a PHY
- */
- EFAB_LOG ( "%dMbps %s-duplex\n",
- ( efab->link_options & LPA_10000 ? 1000 :
- ( efab->link_options & LPA_1000 ? 1000 :
- ( efab->link_options & LPA_100 ? 100 : 10 ) ) ),
- ( efab->link_options & LPA_DUPLEX ? "full" : "half" ) );
- break;
+ for (count=0; count<50; count++) {
+ int link_ok = 1;
+
+ /* Wait a while for the link to come up. */
+ mdelay ( 100 );
+ if ((count % 5) == 0)
+ putchar ( '.' );
+
+ /* Does the PHY think the wire-side link is up? */
+ link_ok = mdio_clause45_links_ok ( efab );
+ /* Ensure the XAUI link to the PHY is good */
+ if ( link_ok ) {
+ link_ok = falcon_xaui_link_ok ( efab );
+ if ( !link_ok )
+ falcon_reset_xaui ( efab );
}
- if ( !falcon_reset_xaui ( efab ) ) {
- EFAB_ERR ( "failed resetting xaui\n" );
+ /* Check fault indication */
+ if ( link_ok )
+ link_ok = falcon_xgmii_status ( efab );
+
+ efab->link_up = link_ok;
+ if ( link_ok ) {
+ /* unmask the status interrupt */
+ falcon_mask_status_intr ( efab, 1 );
return 0;
}
- udelay(100);
}
- return 1;
+ /* Link failed to come up, but initialisation was fine. */
+ rc = -ETIMEDOUT;
+
+fail2:
+fail1:
+ return rc;
+}
+
+static struct efab_mac_operations falcon_xmac_operations = {
+ .init = falcon_init_xmac,
+};
+
+/*******************************************************************************
+ *
+ *
+ * Null PHY handling
+ *
+ *
+ *******************************************************************************/
+
+static int
+falcon_xaui_phy_init ( struct efab_nic *efab )
+{
+ /* CX4 is always 10000FD only */
+ efab->link_options = LPA_10000FULL;
+
+ /* There is no PHY! */
+ return 0;
}
+static struct efab_phy_operations falcon_xaui_phy_ops = {
+ .init = falcon_xaui_phy_init,
+ .mmds = 0,
+};
+
+
+/*******************************************************************************
+ *
+ *
+ * Alaska PHY
+ *
+ *
+ *******************************************************************************/
+
/**
- * Wait for GMII access to complete
+ * Initialise Alaska PHY
*
*/
-static int falcon_gmii_wait ( struct efab_nic *efab ) {
- efab_oword_t md_stat;
+static int
+alaska_init ( struct efab_nic *efab )
+{
+ unsigned int advertised, lpa;
+
+ /* Read link up status */
+ efab->link_up = gmii_link_ok ( efab );
+
+ if ( ! efab->link_up )
+ return -EIO;
+
+ /* Determine link options from PHY. */
+ advertised = gmii_autoneg_advertised ( efab );
+ lpa = gmii_autoneg_lpa ( efab );
+ efab->link_options = gmii_nway_result ( advertised & lpa );
+
+ return 0;
+}
+
+static struct efab_phy_operations falcon_alaska_phy_ops = {
+ .init = alaska_init,
+};
+
+/*******************************************************************************
+ *
+ *
+ * xfp
+ *
+ *
+ *******************************************************************************/
+
+#define XFP_REQUIRED_DEVS ( MDIO_MMDREG_DEVS0_PCS | \
+ MDIO_MMDREG_DEVS0_PMAPMD | \
+ MDIO_MMDREG_DEVS0_PHYXS )
+
+static int
+falcon_xfp_phy_init ( struct efab_nic *efab )
+{
+ int rc;
+
+ /* Optical link is always 10000FD only */
+ efab->link_options = LPA_10000FULL;
+
+ /* Reset the PHY */
+ rc = mdio_clause45_reset_mmd ( efab, MDIO_MMD_PHYXS );
+ if ( rc )
+ return rc;
+
+ return 0;
+}
+
+static struct efab_phy_operations falcon_xfp_phy_ops = {
+ .init = falcon_xfp_phy_init,
+ .mmds = XFP_REQUIRED_DEVS,
+};
+
+/*******************************************************************************
+ *
+ *
+ * txc43128
+ *
+ *
+ *******************************************************************************/
+
+/* Command register */
+#define TXC_GLRGS_GLCMD (0xc004)
+#define TXC_GLCMD_LMTSWRST_LBN (14)
+
+/* Amplitude on lanes 0+1, 2+3 */
+#define TXC_ALRGS_ATXAMP0 (0xc041)
+#define TXC_ALRGS_ATXAMP1 (0xc042)
+/* Bit position of value for lane 0+2, 1+3 */
+#define TXC_ATXAMP_LANE02_LBN (3)
+#define TXC_ATXAMP_LANE13_LBN (11)
+
+#define TXC_ATXAMP_1280_mV (0)
+#define TXC_ATXAMP_1200_mV (8)
+#define TXC_ATXAMP_1120_mV (12)
+#define TXC_ATXAMP_1060_mV (14)
+#define TXC_ATXAMP_0820_mV (25)
+#define TXC_ATXAMP_0720_mV (26)
+#define TXC_ATXAMP_0580_mV (27)
+#define TXC_ATXAMP_0440_mV (28)
+
+#define TXC_ATXAMP_0820_BOTH ( (TXC_ATXAMP_0820_mV << TXC_ATXAMP_LANE02_LBN) | \
+ (TXC_ATXAMP_0820_mV << TXC_ATXAMP_LANE13_LBN) )
+
+#define TXC_ATXAMP_DEFAULT (0x6060) /* From databook */
+
+/* Preemphasis on lanes 0+1, 2+3 */
+#define TXC_ALRGS_ATXPRE0 (0xc043)
+#define TXC_ALRGS_ATXPRE1 (0xc044)
+
+#define TXC_ATXPRE_NONE (0)
+#define TXC_ATXPRE_DEFAULT (0x1010) /* From databook */
+
+#define TXC_REQUIRED_DEVS ( MDIO_MMDREG_DEVS0_PCS | \
+ MDIO_MMDREG_DEVS0_PMAPMD | \
+ MDIO_MMDREG_DEVS0_PHYXS )
+
+static int
+falcon_txc_logic_reset ( struct efab_nic *efab )
+{
+ int val;
+ int tries = 50;
+
+ val = falcon_mdio_read ( efab, MDIO_MMD_PCS, TXC_GLRGS_GLCMD );
+ val |= (1 << TXC_GLCMD_LMTSWRST_LBN);
+ falcon_mdio_write ( efab, MDIO_MMD_PCS, TXC_GLRGS_GLCMD, val );
+
+ while ( tries--) {
+ val = falcon_mdio_read ( efab, MDIO_MMD_PCS, TXC_GLRGS_GLCMD );
+ if ( ~val & ( 1 << TXC_GLCMD_LMTSWRST_LBN ) )
+ return 0;
+ udelay(1);
+ }
+
+ EFAB_ERR ( "logic reset failed\n" );
+
+ return -ETIMEDOUT;
+}
+
+static int
+falcon_txc_phy_init ( struct efab_nic *efab )
+{
+ int rc;
+
+ /* CX4 is always 10000FD only */
+ efab->link_options = LPA_10000FULL;
+
+ /* reset the phy */
+ rc = mdio_clause45_reset_mmd ( efab, MDIO_MMD_PMAPMD );
+ if ( rc )
+ goto fail1;
+
+ rc = mdio_clause45_check_mmds ( efab );
+ if ( rc )
+ goto fail2;
+
+ /* Turn amplitude down and preemphasis off on the host side
+ * (PHY<->MAC) as this is believed less likely to upset falcon
+ * and no adverse effects have been noted. It probably also
+ * saves a picowatt or two */
+
+ /* Turn off preemphasis */
+ falcon_mdio_write ( efab, MDIO_MMD_PHYXS, TXC_ALRGS_ATXPRE0,
+ TXC_ATXPRE_NONE );
+ falcon_mdio_write ( efab, MDIO_MMD_PHYXS, TXC_ALRGS_ATXPRE1,
+ TXC_ATXPRE_NONE );
+
+ /* Turn down the amplitude */
+ falcon_mdio_write ( efab, MDIO_MMD_PHYXS, TXC_ALRGS_ATXAMP0,
+ TXC_ATXAMP_0820_BOTH );
+ falcon_mdio_write ( efab, MDIO_MMD_PHYXS, TXC_ALRGS_ATXAMP1,
+ TXC_ATXAMP_0820_BOTH );
+
+ /* Set the line side amplitude and preemphasis to the databook
+ * defaults as an erratum causes them to be 0 on at least some
+ * PHY rev.s */
+ falcon_mdio_write ( efab, MDIO_MMD_PMAPMD, TXC_ALRGS_ATXPRE0,
+ TXC_ATXPRE_DEFAULT );
+ falcon_mdio_write ( efab, MDIO_MMD_PMAPMD, TXC_ALRGS_ATXPRE1,
+ TXC_ATXPRE_DEFAULT );
+ falcon_mdio_write ( efab, MDIO_MMD_PMAPMD, TXC_ALRGS_ATXAMP0,
+ TXC_ATXAMP_DEFAULT );
+ falcon_mdio_write ( efab, MDIO_MMD_PMAPMD, TXC_ALRGS_ATXAMP1,
+ TXC_ATXAMP_DEFAULT );
+
+ rc = falcon_txc_logic_reset ( efab );
+ if ( rc )
+ goto fail3;
+
+ return 0;
+
+fail3:
+fail2:
+fail1:
+ return rc;
+}
+
+static struct efab_phy_operations falcon_txc_phy_ops = {
+ .init = falcon_txc_phy_init,
+ .mmds = TXC_REQUIRED_DEVS,
+};
+
+/*******************************************************************************
+ *
+ *
+ * tenxpress
+ *
+ *
+ *******************************************************************************/
+
+
+#define TENXPRESS_REQUIRED_DEVS ( MDIO_MMDREG_DEVS0_PMAPMD | \
+ MDIO_MMDREG_DEVS0_PCS | \
+ MDIO_MMDREG_DEVS0_PHYXS )
+
+#define PCS_TEST_SELECT_REG 0xd807 /* PRM 10.5.8 */
+#define CLK312_EN_LBN 3
+#define CLK312_EN_WIDTH 1
+
+#define PCS_CLOCK_CTRL_REG 0xd801
+#define PLL312_RST_N_LBN 2
+
+/* Special Software reset register */
+#define PMA_PMD_EXT_CTRL_REG 49152
+#define PMA_PMD_EXT_SSR_LBN 15
+
+/* Boot status register */
+#define PCS_BOOT_STATUS_REG 0xd000
+#define PCS_BOOT_FATAL_ERR_LBN 0
+#define PCS_BOOT_PROGRESS_LBN 1
+#define PCS_BOOT_PROGRESS_WIDTH 2
+#define PCS_BOOT_COMPLETE_LBN 3
+
+#define PCS_SOFT_RST2_REG 0xd806
+#define SERDES_RST_N_LBN 13
+#define XGXS_RST_N_LBN 12
+
+static int
+falcon_tenxpress_check_c11 ( struct efab_nic *efab )
+{
int count;
+ uint32_t boot_stat;
- for ( count = 0 ; count < 1000 ; count++ ) {
- udelay ( 10 );
- falcon_read ( efab, &md_stat, FCN_MD_STAT_REG_KER );
- if ( EFAB_OWORD_FIELD ( md_stat, FCN_MD_BSY ) == 0 )
- return 1;
+ /* Check that the C11 CPU has booted */
+ for (count=0; count<10; count++) {
+ boot_stat = falcon_mdio_read ( efab, MDIO_MMD_PCS,
+ PCS_BOOT_STATUS_REG );
+ if ( boot_stat & ( 1 << PCS_BOOT_COMPLETE_LBN ) )
+ return 0;
+
+ udelay(10);
}
- EFAB_ERR ( "Timed out waiting for GMII\n" );
+
+ EFAB_ERR ( "C11 failed to boot\n" );
+ return -ETIMEDOUT;
+}
+
+static int
+falcon_tenxpress_phy_init ( struct efab_nic *efab )
+{
+ int rc, reg;
+
+ /* 10XPRESS is always 10000FD (at the moment) */
+ efab->link_options = LPA_10000FULL;
+
+ /* Wait for the blocks to come out of reset */
+ rc = mdio_clause45_wait_reset_mmds ( efab );
+ if ( rc )
+ goto fail1;
+
+ rc = mdio_clause45_check_mmds ( efab );
+ if ( rc )
+ goto fail2;
+
+ /* Turn on the clock */
+ reg = (1 << CLK312_EN_LBN);
+ falcon_mdio_write ( efab, MDIO_MMD_PCS, PCS_TEST_SELECT_REG, reg);
+
+ /* Wait 200ms for the PHY to boot */
+ mdelay(200);
+
+ rc = falcon_tenxpress_check_c11 ( efab );
+ if ( rc )
+ goto fail3;
+
return 0;
+
+fail3:
+fail2:
+fail1:
+ return rc;
}
+static struct efab_phy_operations falcon_tenxpress_phy_ops = {
+ .init = falcon_tenxpress_phy_init,
+ .mmds = TENXPRESS_REQUIRED_DEVS,
+};
-static struct efab_mac_operations falcon_xmac_operations = {
- .mac_readl = falcon_xmac_readl,
- .mac_writel = falcon_xmac_writel,
- .init = falcon_init_xmac,
- .reset = falcon_reset_xmac,
+/*******************************************************************************
+ *
+ *
+ * PM8358
+ *
+ *
+ *******************************************************************************/
+
+/* The PM8358 just presents a DTE XS */
+#define PM8358_REQUIRED_DEVS (MDIO_MMDREG_DEVS0_DTEXS)
+
+/* PHY-specific definitions */
+/* Master ID and Global Performance Monitor Update */
+#define PMC_MASTER_REG (0xd000)
+/* Analog Tx Rx settings under software control */
+#define PMC_MASTER_ANLG_CTRL (1<< 11)
+
+/* Master Configuration register 2 */
+#define PMC_MCONF2_REG (0xd002)
+/* Drive Tx off centre of data eye (1) vs. clock edge (0) */
+#define PMC_MCONF2_TEDGE (1 << 2)
+/* Drive Rx off centre of data eye (1) vs. clock edge (0) */
+#define PMC_MCONF2_REDGE (1 << 3)
+
+/* Analog Rx settings */
+#define PMC_ANALOG_RX_CFG0 (0xd025)
+#define PMC_ANALOG_RX_CFG1 (0xd02d)
+#define PMC_ANALOG_RX_CFG2 (0xd035)
+#define PMC_ANALOG_RX_CFG3 (0xd03d)
+
+
+#define PMC_ANALOG_RX_TERM (1 << 15) /* Bit 15 of RX CFG: 0 for 100 ohms float,
+ 1 for 50 to 1.2V */
+#define PMC_ANALOG_RX_EQ_MASK (3 << 8)
+#define PMC_ANALOG_RX_EQ_NONE (0 << 8)
+#define PMC_ANALOG_RX_EQ_HALF (1 << 8)
+#define PMC_ANALOG_RX_EQ_FULL (2 << 8)
+#define PMC_ANALOG_RX_EQ_RSVD (3 << 8)
+
+static int
+falcon_pm8358_phy_init ( struct efab_nic *efab )
+{
+ int rc, reg, i;
+
+ /* This is a XAUI retimer part */
+ efab->link_options = LPA_10000FULL;
+
+ rc = mdio_clause45_reset_mmd ( efab, MDIO_MMDREG_DEVS0_DTEXS );
+ if ( rc )
+ return rc;
+
+ /* Enable software control of analogue settings */
+ reg = falcon_mdio_read ( efab, MDIO_MMD_DTEXS, PMC_MASTER_REG );
+ reg |= PMC_MASTER_ANLG_CTRL;
+ falcon_mdio_write ( efab, MDIO_MMD_DTEXS, PMC_MASTER_REG, reg );
+
+ /* Turn rx eq on for all channels */
+ for (i=0; i< 3; i++) {
+ /* The analog CFG registers are evenly spaced 8 apart */
+ uint16_t addr = PMC_ANALOG_RX_CFG0 + 8*i;
+ reg = falcon_mdio_read ( efab, MDIO_MMD_DTEXS, addr );
+ reg = ( reg & ~PMC_ANALOG_RX_EQ_MASK ) | PMC_ANALOG_RX_EQ_FULL;
+ falcon_mdio_write ( efab, MDIO_MMD_DTEXS, addr, reg );
+ }
+
+ /* Set TEDGE, clear REDGE */
+ reg = falcon_mdio_read ( efab, MDIO_MMD_DTEXS, PMC_MCONF2_REG );
+ reg = ( reg & ~PMC_MCONF2_REDGE) | PMC_MCONF2_TEDGE;
+ falcon_mdio_write ( efab, MDIO_MMD_DTEXS, PMC_MCONF2_REG, reg );
+
+ return 0;
+}
+
+static struct efab_phy_operations falcon_pm8358_phy_ops = {
+ .init = falcon_pm8358_phy_init,
+ .mmds = PM8358_REQUIRED_DEVS,
};
-static struct efab_mac_operations falcon_gmac_operations = {
- .mac_readl = falcon_gmac_readl,
- .mac_writel = falcon_gmac_writel,
- .init = falcon_init_gmac,
- .reset = falcon_reset_gmac,
+/*******************************************************************************
+ *
+ *
+ * SFE4001 support
+ *
+ *
+ *******************************************************************************/
+
+#define MAX_TEMP_THRESH 90
+
+/* I2C Expander */
+#define PCA9539 0x74
+
+#define P0_IN 0x00
+#define P0_OUT 0x02
+#define P0_CONFIG 0x06
+
+#define P0_EN_1V0X_LBN 0
+#define P0_EN_1V0X_WIDTH 1
+#define P0_EN_1V2_LBN 1
+#define P0_EN_1V2_WIDTH 1
+#define P0_EN_2V5_LBN 2
+#define P0_EN_2V5_WIDTH 1
+#define P0_EN_3V3X_LBN 3
+#define P0_EN_3V3X_WIDTH 1
+#define P0_EN_5V_LBN 4
+#define P0_EN_5V_WIDTH 1
+#define P0_X_TRST_LBN 6
+#define P0_X_TRST_WIDTH 1
+
+#define P1_IN 0x01
+#define P1_CONFIG 0x07
+
+#define P1_AFE_PWD_LBN 0
+#define P1_AFE_PWD_WIDTH 1
+#define P1_DSP_PWD25_LBN 1
+#define P1_DSP_PWD25_WIDTH 1
+#define P1_SPARE_LBN 4
+#define P1_SPARE_WIDTH 4
+
+/* Temperature Sensor */
+#define MAX6647 0x4e
+
+#define RSL 0x02
+#define RLHN 0x05
+#define WLHO 0x0b
+
+static struct i2c_device i2c_pca9539 = {
+ .dev_addr = PCA9539,
+ .dev_addr_len = 1,
+ .word_addr_len = 1,
};
-/**
- * Initialise NIC
+static struct i2c_device i2c_max6647 = {
+ .dev_addr = MAX6647,
+ .dev_addr_len = 1,
+ .word_addr_len = 1,
+};
+
+static int
+sfe4001_init ( struct efab_nic *efab )
+{
+ struct i2c_interface *i2c = &efab->i2c_bb.i2c;
+ efab_dword_t reg;
+ uint8_t in, cfg, out;
+ int count, rc;
+
+ EFAB_LOG ( "Initialise SFE4001 board\n" );
+
+ /* Ensure XGXS and XAUI SerDes are held in reset */
+ EFAB_POPULATE_DWORD_7 ( reg,
+ FCN_XX_PWRDNA_EN, 1,
+ FCN_XX_PWRDNB_EN, 1,
+ FCN_XX_RSTPLLAB_EN, 1,
+ FCN_XX_RESETA_EN, 1,
+ FCN_XX_RESETB_EN, 1,
+ FCN_XX_RSTXGXSRX_EN, 1,
+ FCN_XX_RSTXGXSTX_EN, 1 );
+ falcon_xmac_writel ( efab, &reg, FCN_XX_PWR_RST_REG_MAC);
+ udelay(10);
+
+ /* Set DSP over-temperature alert threshold */
+ cfg = MAX_TEMP_THRESH;
+ rc = i2c->write ( i2c, &i2c_max6647, WLHO, &cfg, EFAB_BYTE );
+ if ( rc )
+ goto fail1;
+
+ /* Read it back and verify */
+ rc = i2c->read ( i2c, &i2c_max6647, RLHN, &in, EFAB_BYTE );
+ if ( rc )
+ goto fail2;
+
+ if ( in != MAX_TEMP_THRESH ) {
+ EFAB_ERR ( "Unable to verify MAX6647 limit (requested=%d "
+ "confirmed=%d)\n", cfg, in );
+ rc = -EIO;
+ goto fail3;
+ }
+
+ /* Clear any previous over-temperature alert */
+ rc = i2c->read ( i2c, &i2c_max6647, RSL, &in, EFAB_BYTE );
+ if ( rc )
+ goto fail4;
+
+ /* Enable port 0 and 1 outputs on IO expander */
+ cfg = 0x00;
+ rc = i2c->write ( i2c, &i2c_pca9539, P0_CONFIG, &cfg, EFAB_BYTE );
+ if ( rc )
+ goto fail5;
+ cfg = 0xff & ~(1 << P1_SPARE_LBN);
+ rc = i2c->write ( i2c, &i2c_pca9539, P1_CONFIG, &cfg, EFAB_BYTE );
+ if ( rc )
+ goto fail6;
+
+ /* Turn all power off then wait 1 sec. This ensures PHY is reset */
+ out = 0xff & ~((0 << P0_EN_1V2_LBN) | (0 << P0_EN_2V5_LBN) |
+ (0 << P0_EN_3V3X_LBN) | (0 << P0_EN_5V_LBN) |
+ (0 << P0_EN_1V0X_LBN));
+
+ rc = i2c->write ( i2c, &i2c_pca9539, P0_OUT, &out, EFAB_BYTE );
+ if ( rc )
+ goto fail7;
+
+ mdelay(1000);
+
+ for (count=0; count<20; count++) {
+ /* Turn on 1.2V, 2.5V, 3.3V and 5V power rails */
+ out = 0xff & ~( (1 << P0_EN_1V2_LBN) | (1 << P0_EN_2V5_LBN) |
+ (1 << P0_EN_3V3X_LBN) | (1 << P0_EN_5V_LBN) |
+ (1 << P0_X_TRST_LBN) );
+
+ rc = i2c->write ( i2c, &i2c_pca9539, P0_OUT, &out, EFAB_BYTE );
+ if ( rc )
+ goto fail8;
+
+ mdelay ( 10 );
+
+ /* Turn on the 1V power rail */
+ out &= ~( 1 << P0_EN_1V0X_LBN );
+ rc = i2c->write ( i2c, &i2c_pca9539, P0_OUT, &out, EFAB_BYTE );
+ if ( rc )
+ goto fail9;
+
+ EFAB_LOG ( "Waiting for power...(attempt %d)\n", count);
+ mdelay ( 1000 );
+
+ /* Check DSP is powered */
+ rc = i2c->read ( i2c, &i2c_pca9539, P1_IN, &in, EFAB_BYTE );
+ if ( rc )
+ goto fail10;
+
+ if ( in & ( 1 << P1_AFE_PWD_LBN ) )
+ return 0;
+ }
+
+ rc = -ETIMEDOUT;
+
+fail10:
+fail9:
+fail8:
+fail7:
+ /* Turn off power rails */
+ out = 0xff;
+ (void) i2c->write ( i2c, &i2c_pca9539, P0_OUT, &out, EFAB_BYTE );
+ /* Disable port 1 outputs on IO expander */
+ out = 0xff;
+ (void) i2c->write ( i2c, &i2c_pca9539, P1_CONFIG, &out, EFAB_BYTE );
+fail6:
+ /* Disable port 0 outputs */
+ out = 0xff;
+ (void) i2c->write ( i2c, &i2c_pca9539, P1_CONFIG, &out, EFAB_BYTE );
+fail5:
+fail4:
+fail3:
+fail2:
+fail1:
+ EFAB_ERR ( "Failed initialising SFE4001 board\n" );
+ return rc;
+}
+
+static void
+sfe4001_fini ( struct efab_nic *efab )
+{
+ struct i2c_interface *i2c = &efab->i2c_bb.i2c;
+ uint8_t in, cfg, out;
+
+ EFAB_ERR ( "Turning off SFE4001\n" );
+
+ /* Turn off all power rails */
+ out = 0xff;
+ (void) i2c->write ( i2c, &i2c_pca9539, P0_OUT, &out, EFAB_BYTE );
+
+ /* Disable port 1 outputs on IO expander */
+ cfg = 0xff;
+ (void) i2c->write ( i2c, &i2c_pca9539, P1_CONFIG, &cfg, EFAB_BYTE );
+
+ /* Disable port 0 outputs on IO expander */
+ cfg = 0xff;
+ (void) i2c->write ( i2c, &i2c_pca9539, P0_CONFIG, &cfg, EFAB_BYTE );
+
+ /* Clear any over-temperature alert */
+ (void) i2c->read ( i2c, &i2c_max6647, RSL, &in, EFAB_BYTE );
+}
+
+struct efab_board_operations sfe4001_ops = {
+ .init = sfe4001_init,
+ .fini = sfe4001_fini,
+};
+
+static int sfe4002_init ( struct efab_nic *efab __attribute__((unused)) )
+{
+ return 0;
+}
+static void sfe4002_fini ( struct efab_nic *efab __attribute__((unused)) )
+{
+}
+
+struct efab_board_operations sfe4002_ops = {
+ .init = sfe4002_init,
+ .fini = sfe4002_fini,
+};
+
+static int sfe4003_init ( struct efab_nic *efab __attribute__((unused)) )
+{
+ return 0;
+}
+static void sfe4003_fini ( struct efab_nic *efab __attribute__((unused)) )
+{
+}
+
+struct efab_board_operations sfe4003_ops = {
+ .init = sfe4003_init,
+ .fini = sfe4003_fini,
+};
+
+/*******************************************************************************
*
- */
-static int falcon_init_nic ( struct efab_nic *efab ) {
- efab_oword_t reg;
- efab_dword_t timer_cmd;
- int version, minor;
+ *
+ * Hardware initialisation
+ *
+ *
+ *******************************************************************************/
- /* use card in internal SRAM mode */
- falcon_read ( efab, &reg, FCN_NIC_STAT_REG );
- EFAB_SET_OWORD_FIELD ( reg, ONCHIP_SRAM, 1 );
- falcon_write ( efab, &reg, FCN_NIC_STAT_REG );
- wmb();
+static void
+falcon_free_special_buffer ( void *p )
+{
+ /* We don't bother cleaning up the buffer table entries -
+ * we're hardly limited */
+ free_dma ( p, EFAB_BUF_ALIGN );
+}
+
+static void*
+falcon_alloc_special_buffer ( struct efab_nic *efab, int bytes,
+ struct efab_special_buffer *entry )
+{
+ void* buffer;
+ int remaining;
+ efab_qword_t buf_desc;
+ unsigned long dma_addr;
+
+ /* Allocate the buffer, aligned on a buffer address boundary */
+ buffer = malloc_dma ( bytes, EFAB_BUF_ALIGN );
+ if ( ! buffer )
+ return NULL;
+
+ /* Push buffer table entries to back the buffer */
+ entry->id = efab->buffer_head;
+ entry->dma_addr = dma_addr = virt_to_bus ( buffer );
+ assert ( ( dma_addr & ( EFAB_BUF_ALIGN - 1 ) ) == 0 );
+
+ remaining = bytes;
+ while ( remaining > 0 ) {
+ EFAB_POPULATE_QWORD_3 ( buf_desc,
+ FCN_IP_DAT_BUF_SIZE, FCN_IP_DAT_BUF_SIZE_4K,
+ FCN_BUF_ADR_FBUF, ( dma_addr >> 12 ),
+ FCN_BUF_OWNER_ID_FBUF, 0 );
+
+ falcon_write_sram ( efab, &buf_desc, efab->buffer_head );
+
+ ++efab->buffer_head;
+ dma_addr += EFAB_BUF_ALIGN;
+ remaining -= EFAB_BUF_ALIGN;
+ }
+
+ EFAB_TRACE ( "Allocated 0x%x bytes at %p backed by buffer table "
+ "entries 0x%x..0x%x\n", bytes, buffer, entry->id,
+ efab->buffer_head - 1 );
+
+ return buffer;
+}
- /* identify FPGA/ASIC, and strapping mode */
- falcon_read ( efab, &reg, ALTERA_BUILD_REG_KER );
- version = EFAB_OWORD_FIELD ( reg, VER_ALL );
- efab->is_asic = version ? 0 : 1;
+static void
+clear_b0_fpga_memories ( struct efab_nic *efab)
+{
+ efab_oword_t blanko, temp;
+ efab_dword_t blankd;
+ int offset;
+
+ EFAB_ZERO_OWORD ( blanko );
+ EFAB_ZERO_DWORD ( blankd );
+
+ /* Clear the address region register */
+ EFAB_POPULATE_OWORD_4 ( temp,
+ FCN_ADR_REGION0, 0,
+ FCN_ADR_REGION1, ( 1 << 16 ),
+ FCN_ADR_REGION2, ( 2 << 16 ),
+ FCN_ADR_REGION3, ( 3 << 16 ) );
+ falcon_write ( efab, &temp, FCN_ADR_REGION_REG_KER );
- if ( efab->is_asic ) {
- falcon_read ( efab, &reg, FCN_NIC_STAT_REG );
- if ( EFAB_OWORD_FIELD ( reg, STRAP_10G ) ) {
- efab->is_10g = 1;
- }
- if ( EFAB_OWORD_FIELD ( reg, STRAP_DUAL_PORT ) ) {
- efab->is_dual = 1;
- }
+ EFAB_TRACE ( "Clearing filter and RSS tables\n" );
+
+ for ( offset = FCN_RX_FILTER_TBL0 ;
+ offset < FCN_RX_RSS_INDIR_TBL_B0+0x800 ;
+ offset += 0x10 ) {
+ falcon_write ( efab, &blanko, offset );
+ }
+
+ EFAB_TRACE ( "Wiping buffer tables\n" );
+
+ /* Notice the 8 byte access mode */
+ for ( offset = 0x2800000 ;
+ offset < 0x3000000 ;
+ offset += 0x8) {
+ _falcon_writel ( efab, 0, offset );
+ _falcon_writel ( efab, 0, offset + 4 );
+ wmb();
+ }
+}
+
+static int
+falcon_reset ( struct efab_nic *efab )
+{
+ efab_oword_t glb_ctl_reg_ker;
+
+ /* Initiate software reset */
+ EFAB_POPULATE_OWORD_6 ( glb_ctl_reg_ker,
+ FCN_PCIE_CORE_RST_CTL, EXCLUDE_FROM_RESET,
+ FCN_PCIE_NSTCK_RST_CTL, EXCLUDE_FROM_RESET,
+ FCN_PCIE_SD_RST_CTL, EXCLUDE_FROM_RESET,
+ FCN_EE_RST_CTL, EXCLUDE_FROM_RESET,
+ FCN_EXT_PHY_RST_DUR, 0x7, /* 10ms */
+ FCN_SWRST, 1 );
+
+ falcon_write ( efab, &glb_ctl_reg_ker, FCN_GLB_CTL_REG_KER );
+
+ /* Allow 50ms for reset */
+ mdelay ( 50 );
+
+ /* Check for device reset complete */
+ falcon_read ( efab, &glb_ctl_reg_ker, FCN_GLB_CTL_REG_KER );
+ if ( EFAB_OWORD_FIELD ( glb_ctl_reg_ker, FCN_SWRST ) != 0 ) {
+ EFAB_ERR ( "Reset failed\n" );
+ return -ETIMEDOUT;
+ }
+
+ if ( ( efab->pci_revision == FALCON_REV_B0 ) && !efab->is_asic ) {
+ clear_b0_fpga_memories ( efab );
+ }
+
+ return 0;
+}
+
+/** Offset of MAC address within EEPROM or Flash */
+#define FALCON_MAC_ADDRESS_OFFSET 0x310
+
+/*
+ * Falcon EEPROM structure
+ */
+#define SF_NV_CONFIG_BASE 0x300
+#define SF_NV_CONFIG_EXTRA 0xA0
+
+struct falcon_nv_config_ver2 {
+ uint16_t nports;
+ uint8_t port0_phy_addr;
+ uint8_t port0_phy_type;
+ uint8_t port1_phy_addr;
+ uint8_t port1_phy_type;
+ uint16_t asic_sub_revision;
+ uint16_t board_revision;
+ uint8_t mac_location;
+};
+
+struct falcon_nv_extra {
+ uint16_t magicnumber;
+ uint16_t structure_version;
+ uint16_t checksum;
+ union {
+ struct falcon_nv_config_ver2 ver2;
+ } ver_specific;
+};
+
+#define BOARD_TYPE(_rev) (_rev >> 8)
+
+static void
+falcon_probe_nic_variant ( struct efab_nic *efab, struct pci_device *pci )
+{
+ efab_oword_t altera_build, nic_stat;
+ int is_pcie, fpga_version;
+ uint8_t revision;
+
+ /* PCI revision */
+ pci_read_config_byte ( pci, PCI_CLASS_REVISION, &revision );
+ efab->pci_revision = revision;
+
+ /* Asic vs FPGA */
+ falcon_read ( efab, &altera_build, FCN_ALTERA_BUILD_REG_KER );
+ fpga_version = EFAB_OWORD_FIELD ( altera_build, FCN_VER_ALL );
+ efab->is_asic = (fpga_version == 0);
+
+ /* MAC and PCI type */
+ falcon_read ( efab, &nic_stat, FCN_NIC_STAT_REG );
+ if ( efab->pci_revision == FALCON_REV_B0 ) {
+ is_pcie = 1;
+ efab->phy_10g = EFAB_OWORD_FIELD ( nic_stat, FCN_STRAP_10G );
+ }
+ else if ( efab->is_asic ) {
+ is_pcie = EFAB_OWORD_FIELD ( nic_stat, FCN_STRAP_PCIE );
+ efab->phy_10g = EFAB_OWORD_FIELD ( nic_stat, FCN_STRAP_10G );
}
else {
- falcon_read ( efab, &reg, ALTERA_BUILD_REG_KER );
- minor = EFAB_OWORD_FIELD ( reg, VER_MINOR );
+ int minor = EFAB_OWORD_FIELD ( altera_build, FCN_VER_MINOR );
+ is_pcie = 0;
+ efab->phy_10g = ( minor == 0x14 );
+ }
+}
+
+static void
+falcon_init_spi_device ( struct efab_nic *efab, struct spi_device *spi )
+{
+ /* Falcon's SPI interface only supports reads/writes of up to 16 bytes.
+ * Reduce the nvs block size down to satisfy this - which means callers
+ * should use the nvs_* functions rather than spi_*. */
+ if ( spi->nvs.block_size > FALCON_SPI_MAX_LEN )
+ spi->nvs.block_size = FALCON_SPI_MAX_LEN;
+
+ spi->bus = &efab->spi_bus;
+ efab->spi = spi;
+}
+
+static int
+falcon_probe_spi ( struct efab_nic *efab )
+{
+ efab_oword_t nic_stat, gpio_ctl, ee_vpd_cfg;
+ int has_flash, has_eeprom, ad9bit;
+
+ falcon_read ( efab, &nic_stat, FCN_NIC_STAT_REG );
+ falcon_read ( efab, &gpio_ctl, FCN_GPIO_CTL_REG_KER );
+ falcon_read ( efab, &ee_vpd_cfg, FCN_EE_VPD_CFG_REG );
+
+ /* determine if FLASH / EEPROM is present */
+ if ( ( efab->pci_revision >= FALCON_REV_B0 ) || efab->is_asic ) {
+ has_flash = EFAB_OWORD_FIELD ( nic_stat, FCN_SF_PRST );
+ has_eeprom = EFAB_OWORD_FIELD ( nic_stat, FCN_EE_PRST );
+ } else {
+ has_flash = EFAB_OWORD_FIELD ( gpio_ctl, FCN_FLASH_PRESENT );
+ has_eeprom = EFAB_OWORD_FIELD ( gpio_ctl, FCN_EEPROM_PRESENT );
+ }
+ ad9bit = EFAB_OWORD_FIELD ( ee_vpd_cfg, FCN_EE_VPD_EN_AD9_MODE );
+
+ /* Configure the SPI and I2C bus */
+ efab->spi_bus.rw = falcon_spi_rw;
+ init_i2c_bit_basher ( &efab->i2c_bb, &falcon_i2c_bit_ops );
+
+ /* Configure the EEPROM SPI device. Generally, an Atmel 25040
+ * (or similar) is used, but this is only possible if there is also
+ * a flash device present to store the boot-time chip configuration.
+ */
+ if ( has_eeprom ) {
+ if ( has_flash && ad9bit )
+ init_at25040 ( &efab->spi_eeprom );
+ else
+ init_mc25xx640 ( &efab->spi_eeprom );
+ falcon_init_spi_device ( efab, &efab->spi_eeprom );
+ }
+
+ /* Configure the FLASH SPI device */
+ if ( has_flash ) {
+ init_at25f1024 ( &efab->spi_flash );
+ falcon_init_spi_device ( efab, &efab->spi_flash );
+ }
+
+ EFAB_LOG ( "flash is %s, EEPROM is %s%s\n",
+ ( has_flash ? "present" : "absent" ),
+ ( has_eeprom ? "present " : "absent" ),
+ ( has_eeprom ? (ad9bit ? "(9bit)" : "(16bit)") : "") );
+
+ /* The device MUST have flash or eeprom */
+ if ( ! efab->spi ) {
+ EFAB_ERR ( "Device appears to have no flash or eeprom\n" );
+ return -EIO;
+ }
+
+ /* If the device has EEPROM attached, then advertise NVO space */
+ if ( has_eeprom )
+ nvo_init ( &efab->nvo, &efab->spi_eeprom.nvs, falcon_nvo_fragments,
+ &efab->netdev->refcnt );
+
+ return 0;
+}
+
+static int
+falcon_probe_nvram ( struct efab_nic *efab )
+{
+ struct nvs_device *nvs = &efab->spi->nvs;
+ struct falcon_nv_extra nv;
+ int rc, board_revision;
+
+ /* Read the MAC address */
+ rc = nvs_read ( nvs, FALCON_MAC_ADDRESS_OFFSET,
+ efab->mac_addr, ETH_ALEN );
+ if ( rc )
+ return rc;
+
+ /* Poke through the NVRAM structure for the PHY type. */
+ rc = nvs_read ( nvs, SF_NV_CONFIG_BASE + SF_NV_CONFIG_EXTRA,
+ &nv, sizeof ( nv ) );
+ if ( rc )
+ return rc;
+
+ /* Handle each supported NVRAM version */
+ if ( ( le16_to_cpu ( nv.magicnumber ) == FCN_NV_MAGIC_NUMBER ) &&
+ ( le16_to_cpu ( nv.structure_version ) >= 2 ) ) {
+ struct falcon_nv_config_ver2* ver2 = &nv.ver_specific.ver2;
- if ( minor == 0x14 ) {
- efab->is_10g = 1;
- } else if ( minor == 0x13 ) {
- efab->is_dual = 1;
- }
+ /* Get the PHY type */
+ efab->phy_addr = le16_to_cpu ( ver2->port0_phy_addr );
+ efab->phy_type = le16_to_cpu ( ver2->port0_phy_type );
+ board_revision = le16_to_cpu ( ver2->board_revision );
+ }
+ else {
+ EFAB_ERR ( "NVram is not recognised\n" );
+ return -EINVAL;
}
- DBG ( "NIC type: %s %dx%s\n",
- efab->is_asic ? "ASIC" : "FPGA",
- efab->is_dual ? 2 : 1,
- efab->is_10g ? "10G" : "1G" );
+ efab->board_type = BOARD_TYPE ( board_revision );
+
+ EFAB_TRACE ( "Falcon board %d phy %d @ addr %d\n",
+ efab->board_type, efab->phy_type, efab->phy_addr );
- /* patch in MAC operations */
- if ( efab->is_10g )
+ /* Patch in the board operations */
+ switch ( efab->board_type ) {
+ case EFAB_BOARD_SFE4001:
+ efab->board_op = &sfe4001_ops;
+ break;
+ case EFAB_BOARD_SFE4002:
+ efab->board_op = &sfe4002_ops;
+ break;
+ case EFAB_BOARD_SFE4003:
+ efab->board_op = &sfe4003_ops;
+ break;
+ default:
+ EFAB_ERR ( "Unrecognised board type\n" );
+ return -EINVAL;
+ }
+
+ /* Patch in MAC operations */
+ if ( efab->phy_10g )
efab->mac_op = &falcon_xmac_operations;
else
efab->mac_op = &falcon_gmac_operations;
-
- if ( !efab->is_dual && ( efab->port == 1 ) ) {
- /* device doesn't exist */
- return 0;
- }
- /* determine EEPROM / FLASH */
- if ( efab->is_asic ) {
- falcon_read ( efab, &reg, FCN_NIC_STAT_REG );
- efab->has_flash = EFAB_OWORD_FIELD ( reg, SF_PRST );
- efab->has_eeprom = EFAB_OWORD_FIELD ( reg, EE_PRST );
- } else {
- falcon_read ( efab, &reg, FCN_GPIO_CTL_REG_KER );
- efab->has_flash = EFAB_OWORD_FIELD ( reg, FCN_FLASH_PRESENT );
- efab->has_eeprom = EFAB_OWORD_FIELD ( reg, FCN_EEPROM_PRESENT);
+ /* Hook in the PHY ops */
+ switch ( efab->phy_type ) {
+ case PHY_TYPE_10XPRESS:
+ efab->phy_op = &falcon_tenxpress_phy_ops;
+ break;
+ case PHY_TYPE_CX4:
+ efab->phy_op = &falcon_xaui_phy_ops;
+ break;
+ case PHY_TYPE_XFP:
+ efab->phy_op = &falcon_xfp_phy_ops;
+ break;
+ case PHY_TYPE_CX4_RTMR:
+ efab->phy_op = &falcon_txc_phy_ops;
+ break;
+ case PHY_TYPE_PM8358:
+ efab->phy_op = &falcon_pm8358_phy_ops;
+ break;
+ case PHY_TYPE_1GIG_ALASKA:
+ efab->phy_op = &falcon_alaska_phy_ops;
+ break;
+ default:
+ EFAB_ERR ( "Unknown PHY type: %d\n", efab->phy_type );
+ return -EINVAL;
}
- DBG ( "flash is %s, EEPROM is %s\n",
- ( efab->has_flash ? "present" : "absent" ),
- ( efab->has_eeprom ? "present" : "absent" ) );
- falcon_init_spi ( efab );
+ return 0;
+}
+
+static int
+falcon_init_sram ( struct efab_nic *efab )
+{
+ efab_oword_t reg;
+ int count;
+
+ /* use card in internal SRAM mode */
+ falcon_read ( efab, &reg, FCN_NIC_STAT_REG );
+ EFAB_SET_OWORD_FIELD ( reg, FCN_ONCHIP_SRAM, 1 );
+ falcon_write ( efab, &reg, FCN_NIC_STAT_REG );
+
+ /* Deactivate any external SRAM that might be present */
+ EFAB_POPULATE_OWORD_2 ( reg,
+ FCN_GPIO1_OEN, 1,
+ FCN_GPIO1_OUT, 1 );
+ falcon_write ( efab, &reg, FCN_GPIO_CTL_REG_KER );
+
+ /* Initiate SRAM reset */
+ EFAB_POPULATE_OWORD_2 ( reg,
+ FCN_SRAM_OOB_BT_INIT_EN, 1,
+ FCN_SRM_NUM_BANKS_AND_BANK_SIZE, 0 );
+ falcon_write ( efab, &reg, FCN_SRM_CFG_REG_KER );
+
+ /* Wait for SRAM reset to complete */
+ count = 0;
+ do {
+ /* SRAM reset is slow; expect around 16ms */
+ mdelay ( 20 );
+
+ /* Check for reset complete */
+ falcon_read ( efab, &reg, FCN_SRM_CFG_REG_KER );
+ if ( !EFAB_OWORD_FIELD ( reg, FCN_SRAM_OOB_BT_INIT_EN ) )
+ return 0;
+ } while (++count < 20); /* wait upto 0.4 sec */
+
+ EFAB_ERR ( "timed out waiting for SRAM reset\n");
+ return -ETIMEDOUT;
+}
+
+static void
+falcon_setup_nic ( struct efab_nic *efab )
+{
+ efab_dword_t timer_cmd;
+ efab_oword_t reg;
+ int tx_fc, xoff_thresh, xon_thresh;
+
+ /* bug5129: Clear the parity enables on the TX data fifos as
+ * they produce false parity errors because of timing issues
+ */
+ falcon_read ( efab, &reg, FCN_SPARE_REG_KER );
+ EFAB_SET_OWORD_FIELD ( reg, FCN_MEM_PERR_EN_TX_DATA, 0 );
+ falcon_write ( efab, &reg, FCN_SPARE_REG_KER );
+
/* Set up TX and RX descriptor caches in SRAM */
- EFAB_POPULATE_OWORD_1 ( reg, FCN_SRM_TX_DC_BASE_ADR,
- 0x130000 /* recommended in datasheet */ );
+ EFAB_POPULATE_OWORD_1 ( reg, FCN_SRM_TX_DC_BASE_ADR, 0x130000 );
falcon_write ( efab, &reg, FCN_SRM_TX_DC_CFG_REG_KER );
- EFAB_POPULATE_OWORD_1 ( reg, FCN_TX_DC_SIZE, 2 /* 32 descriptors */ );
+ EFAB_POPULATE_OWORD_1 ( reg, FCN_TX_DC_SIZE, 1 /* 16 descriptors */ );
falcon_write ( efab, &reg, FCN_TX_DC_CFG_REG_KER );
- EFAB_POPULATE_OWORD_1 ( reg, FCN_SRM_RX_DC_BASE_ADR,
- 0x100000 /* recommended in datasheet */ );
+ EFAB_POPULATE_OWORD_1 ( reg, FCN_SRM_RX_DC_BASE_ADR, 0x100000 );
falcon_write ( efab, &reg, FCN_SRM_RX_DC_CFG_REG_KER );
EFAB_POPULATE_OWORD_1 ( reg, FCN_RX_DC_SIZE, 2 /* 32 descriptors */ );
falcon_write ( efab, &reg, FCN_RX_DC_CFG_REG_KER );
- /* Set number of RSS CPUs */
- EFAB_POPULATE_OWORD_1 ( reg, FCN_NUM_KER, 0 );
+ /* Set number of RSS CPUs
+ * bug7244: Increase filter depth to reduce RX_RESET likelyhood
+ */
+ EFAB_POPULATE_OWORD_5 ( reg,
+ FCN_NUM_KER, 0,
+ FCN_UDP_FULL_SRCH_LIMIT, 8,
+ FCN_UDP_WILD_SRCH_LIMIT, 8,
+ FCN_TCP_WILD_SRCH_LIMIT, 8,
+ FCN_TCP_FULL_SRCH_LIMIT, 8);
falcon_write ( efab, &reg, FCN_RX_FILTER_CTL_REG_KER );
udelay ( 1000 );
+
+ /* Setup RX. Wait for descriptor is broken and must
+ * be disabled. RXDP recovery shouldn't be needed, but is.
+ * disable ISCSI parsing because we don't need it
+ */
+ falcon_read ( efab, &reg, FCN_RX_SELF_RST_REG_KER );
+ EFAB_SET_OWORD_FIELD ( reg, FCN_RX_NODESC_WAIT_DIS, 1 );
+ EFAB_SET_OWORD_FIELD ( reg, FCN_RX_RECOVERY_EN, 1 );
+ EFAB_SET_OWORD_FIELD ( reg, FCN_RX_ISCSI_DIS, 1 );
+ falcon_write ( efab, &reg, FCN_RX_SELF_RST_REG_KER );
- /* Reset the MAC */
- mentormac_reset ( efab );
+ /* Determine recommended flow control settings. *
+ * Flow control is qualified on B0 and A1/1G, not on A1/10G */
+ if ( efab->pci_revision == FALCON_REV_B0 ) {
+ tx_fc = 1;
+ xoff_thresh = 54272; /* ~80Kb - 3*max MTU */
+ xon_thresh = 27648; /* ~3*max MTU */
+ }
+ else if ( !efab->phy_10g ) {
+ tx_fc = 1;
+ xoff_thresh = 2048;
+ xon_thresh = 512;
+ }
+ else {
+ tx_fc = xoff_thresh = xon_thresh = 0;
+ }
- /* Set up event queue */
- falcon_create_special_buffer ( efab, efab->eventq, FALCON_EVQ_ID );
- /* Fill eventq with all ones ( empty events ) */
- memset(efab->eventq, 0xff, 4096);
- /* push eventq to card */
- EFAB_POPULATE_OWORD_3 ( reg,
- FCN_EVQ_EN, 1,
- FCN_EVQ_SIZE, FCN_EVQ_SIZE_512,
- FCN_EVQ_BUF_BASE_ID, FALCON_EVQ_ID );
- falcon_write ( efab, &reg, FCN_EVQ_PTR_TBL_KER );
- udelay ( 1000 );
+ /* Setup TX and RX */
+ falcon_read ( efab, &reg, FCN_TX_CFG2_REG_KER );
+ EFAB_SET_OWORD_FIELD ( reg, FCN_TX_DIS_NON_IP_EV, 1 );
+ falcon_write ( efab, &reg, FCN_TX_CFG2_REG_KER );
+
+ falcon_read ( efab, &reg, FCN_RX_CFG_REG_KER );
+ EFAB_SET_OWORD_FIELD_VER ( efab, reg, FCN_RX_USR_BUF_SIZE,
+ (3*4096) / 32 );
+ if ( efab->pci_revision == FALCON_REV_B0)
+ EFAB_SET_OWORD_FIELD ( reg, FCN_RX_INGR_EN_B0, 1 );
+ EFAB_SET_OWORD_FIELD_VER ( efab, reg, FCN_RX_XON_MAC_TH,
+ xon_thresh / 256);
+ EFAB_SET_OWORD_FIELD_VER ( efab, reg, FCN_RX_XOFF_MAC_TH,
+ xoff_thresh / 256);
+ EFAB_SET_OWORD_FIELD_VER ( efab, reg, FCN_RX_XOFF_MAC_EN, tx_fc);
+ falcon_write ( efab, &reg, FCN_RX_CFG_REG_KER );
/* Set timer register */
EFAB_POPULATE_DWORD_2 ( timer_cmd,
FCN_TIMER_MODE, FCN_TIMER_MODE_DIS,
FCN_TIMER_VAL, 0 );
falcon_writel ( efab, &timer_cmd, FCN_TIMER_CMD_REG_KER );
- udelay ( 1000 );
+}
+
+static void
+falcon_init_resources ( struct efab_nic *efab )
+{
+ struct efab_ev_queue *ev_queue = &efab->ev_queue;
+ struct efab_rx_queue *rx_queue = &efab->rx_queue;
+ struct efab_tx_queue *tx_queue = &efab->tx_queue;
- /* Initialise event queue read pointer */
- falcon_eventq_read_ack ( efab );
+ efab_oword_t reg;
+ int jumbo;
+
+ /* Initialise the ptrs */
+ tx_queue->read_ptr = tx_queue->write_ptr = 0;
+ rx_queue->read_ptr = rx_queue->write_ptr = 0;
+ ev_queue->read_ptr = 0;
+
+ /* Push the event queue to the hardware */
+ EFAB_POPULATE_OWORD_3 ( reg,
+ FCN_EVQ_EN, 1,
+ FCN_EVQ_SIZE, FQS(FCN_EVQ, EFAB_EVQ_SIZE),
+ FCN_EVQ_BUF_BASE_ID, ev_queue->entry.id );
+ falcon_write ( efab, &reg,
+ FCN_REVISION_REG ( efab, FCN_EVQ_PTR_TBL_KER ) );
- /* Set up TX descriptor ring */
- falcon_create_special_buffer ( efab, efab->txd, FALCON_TXD_ID );
- EFAB_POPULATE_OWORD_5 ( reg,
+ /* Push the tx queue to the hardware */
+ EFAB_POPULATE_OWORD_8 ( reg,
FCN_TX_DESCQ_EN, 1,
- FCN_TX_DESCQ_BUF_BASE_ID, FALCON_TXD_ID,
+ FCN_TX_ISCSI_DDIG_EN, 0,
+ FCN_TX_ISCSI_DDIG_EN, 0,
+ FCN_TX_DESCQ_BUF_BASE_ID, tx_queue->entry.id,
FCN_TX_DESCQ_EVQ_ID, 0,
- FCN_TX_DESCQ_SIZE, FCN_TX_DESCQ_SIZE_512,
- FCN_TX_DESCQ_TYPE, 0 /* kernel queue */ );
- falcon_write ( efab, &reg, FCN_TX_DESC_PTR_TBL_KER );
-
- /* Set up RX descriptor ring */
- falcon_create_special_buffer ( efab, efab->rxd, FALCON_RXD_ID );
- EFAB_POPULATE_OWORD_6 ( reg,
- FCN_RX_DESCQ_BUF_BASE_ID, FALCON_RXD_ID,
+ FCN_TX_DESCQ_SIZE, FQS(FCN_TX_DESCQ, EFAB_TXD_SIZE),
+ FCN_TX_DESCQ_TYPE, 0 /* kernel queue */,
+ FCN_TX_NON_IP_DROP_DIS_B0, 1 );
+ falcon_write ( efab, &reg,
+ FCN_REVISION_REG ( efab, FCN_TX_DESC_PTR_TBL_KER ) );
+
+ /* Push the rx queue to the hardware */
+ jumbo = ( efab->pci_revision == FALCON_REV_B0 ) ? 0 : 1;
+ EFAB_POPULATE_OWORD_8 ( reg,
+ FCN_RX_ISCSI_DDIG_EN, 0,
+ FCN_RX_ISCSI_HDIG_EN, 0,
+ FCN_RX_DESCQ_BUF_BASE_ID, rx_queue->entry.id,
FCN_RX_DESCQ_EVQ_ID, 0,
- FCN_RX_DESCQ_SIZE, FCN_RX_DESCQ_SIZE_512,
+ FCN_RX_DESCQ_SIZE, FQS(FCN_RX_DESCQ, EFAB_RXD_SIZE),
FCN_RX_DESCQ_TYPE, 0 /* kernel queue */,
- FCN_RX_DESCQ_JUMBO, 1,
+ FCN_RX_DESCQ_JUMBO, jumbo,
FCN_RX_DESCQ_EN, 1 );
- falcon_write ( efab, &reg, FCN_RX_DESC_PTR_TBL_KER );
+ falcon_write ( efab, &reg,
+ FCN_REVISION_REG ( efab, FCN_RX_DESC_PTR_TBL_KER ) );
/* Program INT_ADR_REG_KER */
EFAB_POPULATE_OWORD_1 ( reg,
- FCN_INT_ADR_KER,
- virt_to_bus ( &efab->int_ker ) );
+ FCN_INT_ADR_KER, virt_to_bus ( &efab->int_ker ) );
falcon_write ( efab, &reg, FCN_INT_ADR_REG_KER );
- udelay ( 1000 );
- /* Register non-volatile storage */
- if ( efab->has_eeprom ) {
- nvo_init ( &efab->nvo, &efab->falcon_eeprom.nvs,
- falcon_eeprom_fragments, NULL /* hack */ );
- if ( register_nvo ( &efab->nvo, NULL /* hack */ ) != 0 )
- return 0;
- }
+ /* Ack the event queue */
+ falcon_eventq_read_ack ( efab, ev_queue );
+}
- return 1;
+static void
+falcon_fini_resources ( struct efab_nic *efab )
+{
+ efab_oword_t cmd;
+
+ /* Disable interrupts */
+ falcon_interrupts ( efab, 0, 0 );
+
+ /* Flush the dma queues */
+ EFAB_POPULATE_OWORD_2 ( cmd,
+ FCN_TX_FLUSH_DESCQ_CMD, 1,
+ FCN_TX_FLUSH_DESCQ, 0 );
+ falcon_write ( efab, &cmd,
+ FCN_REVISION_REG ( efab, FCN_TX_DESC_PTR_TBL_KER ) );
+
+ EFAB_POPULATE_OWORD_2 ( cmd,
+ FCN_RX_FLUSH_DESCQ_CMD, 1,
+ FCN_RX_FLUSH_DESCQ, 0 );
+ falcon_write ( efab, &cmd,
+ FCN_REVISION_REG ( efab, FCN_RX_DESC_PTR_TBL_KER ) );
+
+ mdelay ( 100 );
+
+ /* Remove descriptor rings from card */
+ EFAB_ZERO_OWORD ( cmd );
+ falcon_write ( efab, &cmd,
+ FCN_REVISION_REG ( efab, FCN_TX_DESC_PTR_TBL_KER ) );
+ falcon_write ( efab, &cmd,
+ FCN_REVISION_REG ( efab, FCN_RX_DESC_PTR_TBL_KER ) );
+ falcon_write ( efab, &cmd,
+ FCN_REVISION_REG ( efab, FCN_EVQ_PTR_TBL_KER ) );
}
-/** MDIO write */
-static void falcon_mdio_write ( struct efab_nic *efab, int location,
- int value ) {
- int phy_id = efab->port + 2;
- efab_oword_t reg;
+/*******************************************************************************
+ *
+ *
+ * Hardware rx path
+ *
+ *
+ *******************************************************************************/
- EFAB_TRACE ( "Writing GMII %d register %02x with %04x\n",
- phy_id, location, value );
+static void
+falcon_build_rx_desc ( falcon_rx_desc_t *rxd, struct io_buffer *iob )
+{
+ EFAB_POPULATE_QWORD_2 ( *rxd,
+ FCN_RX_KER_BUF_SIZE, EFAB_RX_BUF_SIZE,
+ FCN_RX_KER_BUF_ADR, virt_to_bus ( iob->data ) );
+}
- /* Check MII not currently being accessed */
- if ( ! falcon_gmii_wait ( efab ) )
- return;
+static void
+falcon_notify_rx_desc ( struct efab_nic *efab, struct efab_rx_queue *rx_queue )
+{
+ efab_dword_t reg;
+ int ptr = rx_queue->write_ptr % EFAB_RXD_SIZE;
- /* Write the address registers */
- EFAB_POPULATE_OWORD_1 ( reg, FCN_MD_PHY_ADR, 0 /* phy_id ? */ );
- falcon_write ( efab, &reg, FCN_MD_PHY_ADR_REG_KER );
- udelay ( 10 );
- EFAB_POPULATE_OWORD_2 ( reg,
- FCN_MD_PRT_ADR, phy_id,
- FCN_MD_DEV_ADR, location );
- falcon_write ( efab, &reg, FCN_MD_ID_REG_KER );
- udelay ( 10 );
+ EFAB_POPULATE_DWORD_1 ( reg, FCN_RX_DESC_WPTR_DWORD, ptr );
+ falcon_writel ( efab, &reg, FCN_RX_DESC_UPD_REG_KER_DWORD );
+}
- /* Write data */
- EFAB_POPULATE_OWORD_1 ( reg, FCN_MD_TXD, value );
- falcon_write ( efab, &reg, FCN_MD_TXD_REG_KER );
- udelay ( 10 );
- EFAB_POPULATE_OWORD_2 ( reg,
- FCN_MD_WRC, 1,
- FCN_MD_GC, 1 );
- falcon_write ( efab, &reg, FCN_MD_CS_REG_KER );
- udelay ( 10 );
-
- /* Wait for data to be written */
- falcon_gmii_wait ( efab );
+
+/*******************************************************************************
+ *
+ *
+ * Hardware tx path
+ *
+ *
+ *******************************************************************************/
+
+static void
+falcon_build_tx_desc ( falcon_tx_desc_t *txd, struct io_buffer *iob )
+{
+ EFAB_POPULATE_QWORD_2 ( *txd,
+ FCN_TX_KER_BYTE_CNT, iob_len ( iob ),
+ FCN_TX_KER_BUF_ADR, virt_to_bus ( iob->data ) );
}
-/** MDIO read */
-static int falcon_mdio_read ( struct efab_nic *efab, int location ) {
- int phy_id = efab->port + 2;
- efab_oword_t reg;
- int value;
+static void
+falcon_notify_tx_desc ( struct efab_nic *efab,
+ struct efab_tx_queue *tx_queue )
+{
+ efab_dword_t reg;
+ int ptr = tx_queue->write_ptr % EFAB_TXD_SIZE;
- /* Check MII not currently being accessed */
- if ( ! falcon_gmii_wait ( efab ) )
- return 0xffff;
+ EFAB_POPULATE_DWORD_1 ( reg, FCN_TX_DESC_WPTR_DWORD, ptr );
+ falcon_writel ( efab, &reg, FCN_TX_DESC_UPD_REG_KER_DWORD );
+}
- /* Write the address registers */
- EFAB_POPULATE_OWORD_1 ( reg, FCN_MD_PHY_ADR, 0 /* phy_id ? */ );
- falcon_write ( efab, &reg, FCN_MD_PHY_ADR_REG_KER );
- udelay ( 10 );
- EFAB_POPULATE_OWORD_2 ( reg,
- FCN_MD_PRT_ADR, phy_id,
- FCN_MD_DEV_ADR, location );
- falcon_write ( efab, &reg, FCN_MD_ID_REG_KER );
- udelay ( 10 );
- /* Request data to be read */
- EFAB_POPULATE_OWORD_2 ( reg,
- FCN_MD_RIC, 1,
- FCN_MD_GC, 1 );
- falcon_write ( efab, &reg, FCN_MD_CS_REG_KER );
- udelay ( 10 );
-
- /* Wait for data to become available */
- falcon_gmii_wait ( efab );
+/*******************************************************************************
+ *
+ *
+ * Software receive interface
+ *
+ *
+ *******************************************************************************/
- /* Read the data */
- falcon_read ( efab, &reg, FCN_MD_RXD_REG_KER );
- value = EFAB_OWORD_FIELD ( reg, FCN_MD_RXD );
+static int
+efab_fill_rx_queue ( struct efab_nic *efab,
+ struct efab_rx_queue *rx_queue )
+{
+ int fill_level = rx_queue->write_ptr - rx_queue->read_ptr;
+ int space = EFAB_NUM_RX_DESC - fill_level - 1;
+ int pushed = 0;
+
+ while ( space ) {
+ int buf_id = rx_queue->write_ptr % EFAB_NUM_RX_DESC;
+ int desc_id = rx_queue->write_ptr % EFAB_RXD_SIZE;
+ struct io_buffer *iob;
+ falcon_rx_desc_t *rxd;
+
+ assert ( rx_queue->buf[buf_id] == NULL );
+ iob = alloc_iob ( EFAB_RX_BUF_SIZE );
+ if ( !iob )
+ break;
- EFAB_TRACE ( "Read from GMII %d register %02x, got %04x\n",
- phy_id, location, value );
+ EFAB_TRACE ( "pushing rx_buf[%d] iob %p data %p\n",
+ buf_id, iob, iob->data );
- return value;
+ rx_queue->buf[buf_id] = iob;
+ rxd = rx_queue->ring + desc_id;
+ falcon_build_rx_desc ( rxd, iob );
+ ++rx_queue->write_ptr;
+ ++pushed;
+ --space;
+ }
+
+ if ( pushed ) {
+ /* Push the ptr to hardware */
+ falcon_notify_rx_desc ( efab, rx_queue );
+
+ fill_level = rx_queue->write_ptr - rx_queue->read_ptr;
+ EFAB_TRACE ( "pushed %d rx buffers to fill level %d\n",
+ pushed, fill_level );
+ }
+
+ if ( fill_level == 0 )
+ return -ENOMEM;
+ return 0;
}
+
+static void
+efab_receive ( struct efab_nic *efab, unsigned int id, int len, int drop )
+{
+ struct efab_rx_queue *rx_queue = &efab->rx_queue;
+ struct io_buffer *iob;
+ unsigned int read_ptr = rx_queue->read_ptr % EFAB_RXD_SIZE;
+ unsigned int buf_ptr = rx_queue->read_ptr % EFAB_NUM_RX_DESC;
-static struct efab_operations falcon_operations = {
- .get_membase = falcon_get_membase,
- .reset = falcon_reset,
- .init_nic = falcon_init_nic,
- .read_eeprom = falcon_read_eeprom,
- .build_rx_desc = falcon_build_rx_desc,
- .notify_rx_desc = falcon_notify_rx_desc,
- .build_tx_desc = falcon_build_tx_desc,
- .notify_tx_desc = falcon_notify_tx_desc,
- .fetch_event = falcon_fetch_event,
- .mask_irq = falcon_mask_irq,
- .generate_irq = falcon_generate_irq,
- .mdio_write = falcon_mdio_write,
- .mdio_read = falcon_mdio_read,
-};
+ assert ( id == read_ptr );
+
+ /* Pop this rx buffer out of the software ring */
+ iob = rx_queue->buf[buf_ptr];
+ rx_queue->buf[buf_ptr] = NULL;
-/**************************************************************************
+ EFAB_TRACE ( "popping rx_buf[%d] iob %p data %p with %d bytes %s\n",
+ id, iob, iob->data, len, drop ? "bad" : "ok" );
+
+ /* Pass the packet up if required */
+ if ( drop )
+ free_iob ( iob );
+ else {
+ iob_put ( iob, len );
+ netdev_rx ( efab->netdev, iob );
+ }
+
+ ++rx_queue->read_ptr;
+}
+
+/*******************************************************************************
*
- * Etherfabric abstraction layer
*
- **************************************************************************
- */
-
-/**
- * Push RX buffer to RXD ring
+ * Software transmit interface
*
- */
-static inline void efab_push_rx_buffer ( struct efab_nic *efab,
- struct efab_rx_buf *rx_buf ) {
- /* Create RX descriptor */
- rx_buf->id = efab->rx_write_ptr;
- efab->op->build_rx_desc ( efab, rx_buf );
+ *
+ *******************************************************************************/
- /* Update RX write pointer */
- efab->rx_write_ptr = ( efab->rx_write_ptr + 1 ) % EFAB_RXD_SIZE;
- efab->op->notify_rx_desc ( efab );
+static int
+efab_transmit ( struct net_device *netdev, struct io_buffer *iob )
+{
+ struct efab_nic *efab = netdev_priv ( netdev );
+ struct efab_tx_queue *tx_queue = &efab->tx_queue;
+ int fill_level, space;
+ falcon_tx_desc_t *txd;
+ int buf_id;
+
+ fill_level = tx_queue->write_ptr - tx_queue->read_ptr;
+ space = EFAB_TXD_SIZE - fill_level - 1;
+ if ( space < 1 )
+ return -ENOBUFS;
+
+ /* Save the iobuffer for later completion */
+ buf_id = tx_queue->write_ptr % EFAB_TXD_SIZE;
+ assert ( tx_queue->buf[buf_id] == NULL );
+ tx_queue->buf[buf_id] = iob;
+
+ EFAB_TRACE ( "tx_buf[%d] for iob %p data %p len %zd\n",
+ buf_id, iob, iob->data, iob_len ( iob ) );
+
+ /* Form the descriptor, and push it to hardware */
+ txd = tx_queue->ring + buf_id;
+ falcon_build_tx_desc ( txd, iob );
+ ++tx_queue->write_ptr;
+ falcon_notify_tx_desc ( efab, tx_queue );
- DBG ( "Added RX id %x\n", rx_buf->id );
+ return 0;
}
-/**
- * Push TX buffer to TXD ring
- *
- */
-static inline void efab_push_tx_buffer ( struct efab_nic *efab,
- struct efab_tx_buf *tx_buf ) {
- /* Create TX descriptor */
- tx_buf->id = efab->tx_write_ptr;
- efab->op->build_tx_desc ( efab, tx_buf );
+static int
+efab_transmit_done ( struct efab_nic *efab, int id )
+{
+ struct efab_tx_queue *tx_queue = &efab->tx_queue;
+ unsigned int read_ptr, stop;
+
+ /* Complete all buffers from read_ptr up to and including id */
+ read_ptr = tx_queue->read_ptr % EFAB_TXD_SIZE;
+ stop = ( id + 1 ) % EFAB_TXD_SIZE;
- /* Update TX write pointer */
- efab->tx_write_ptr = ( efab->tx_write_ptr + 1 ) % EFAB_TXD_SIZE;
- efab->op->notify_tx_desc ( efab );
+ while ( read_ptr != stop ) {
+ struct io_buffer *iob = tx_queue->buf[read_ptr];
+ assert ( iob );
- DBG ( "Added TX id %x\n", tx_buf->id );
+ /* Complete the tx buffer */
+ if ( iob )
+ netdev_tx_complete ( efab->netdev, iob );
+ tx_queue->buf[read_ptr] = NULL;
+
+ ++tx_queue->read_ptr;
+ read_ptr = tx_queue->read_ptr % EFAB_TXD_SIZE;
+ }
+
+ return 0;
}
-/**
- * Initialise MAC and wait for link up
+/*******************************************************************************
*
- */
-static int efab_init_mac ( struct efab_nic *efab ) {
- int count;
+ *
+ * Hardware event path
+ *
+ *
+ *******************************************************************************/
- /* This can take several seconds */
- EFAB_LOG ( "Waiting for link.." );
- for ( count=0; count<5; count++ ) {
- putchar ( '.' );
+static void
+falcon_clear_interrupts ( struct efab_nic *efab )
+{
+ efab_dword_t reg;
- if ( ! efab->mac_op->init ( efab ) ) {
- EFAB_ERR ( "Failed reinitialising MAC\n" );
- return 0;
- }
- if ( efab->link_up ) {
- /* PHY init printed the message for us */
- return 1;
- }
- EFAB_ERR( "link is down" );
- sleep ( 1 );
+ if ( efab->pci_revision == FALCON_REV_B0 ) {
+ /* read the ISR */
+ falcon_readl( efab, &reg, INT_ISR0_B0 );
+ }
+ else {
+ /* write to the INT_ACK register */
+ falcon_writel ( efab, 0, FCN_INT_ACK_KER_REG_A1 );
+ mb();
+ falcon_readl ( efab, &reg,
+ WORK_AROUND_BROKEN_PCI_READS_REG_KER_A1 );
}
- EFAB_ERR ( " timed initialising MAC\n " );
+}
- return 0;
+static void
+falcon_handle_event ( struct efab_nic *efab, falcon_event_t *evt )
+{
+ int ev_code, desc_ptr, len, drop;
+
+ /* Decode event */
+ ev_code = EFAB_QWORD_FIELD ( *evt, FCN_EV_CODE );
+ switch ( ev_code ) {
+ case FCN_TX_IP_EV_DECODE:
+ desc_ptr = EFAB_QWORD_FIELD ( *evt, FCN_TX_EV_DESC_PTR );
+ efab_transmit_done ( efab, desc_ptr );
+ break;
+
+ case FCN_RX_IP_EV_DECODE:
+ desc_ptr = EFAB_QWORD_FIELD ( *evt, FCN_RX_EV_DESC_PTR );
+ len = EFAB_QWORD_FIELD ( *evt, FCN_RX_EV_BYTE_CNT );
+ drop = !EFAB_QWORD_FIELD ( *evt, FCN_RX_EV_PKT_OK );
+
+ efab_receive ( efab, desc_ptr, len, drop );
+ break;
+
+ default:
+ EFAB_TRACE ( "Unknown event type %d\n", ev_code );
+ break;
+ }
}
-/**
- * Initialise NIC
+/*******************************************************************************
*
- */
-static int efab_init_nic ( struct efab_nic *efab ) {
- int i;
+ *
+ * Software (polling) interrupt handler
+ *
+ *
+ *******************************************************************************/
- /* Initialise NIC */
- if ( ! efab->op->init_nic ( efab ) )
- return 0;
+static void
+efab_poll ( struct net_device *netdev )
+{
+ struct efab_nic *efab = netdev_priv ( netdev );
+ struct efab_ev_queue *ev_queue = &efab->ev_queue;
+ struct efab_rx_queue *rx_queue = &efab->rx_queue;
+ falcon_event_t *evt;
- /* Push RX descriptors */
- for ( i = 0 ; i < EFAB_RX_BUFS ; i++ ) {
- efab_push_rx_buffer ( efab, &efab->rx_bufs[i] );
+ /* Read the event queue by directly looking for events
+ * (we don't even bother to read the eventq write ptr) */
+ evt = ev_queue->ring + ev_queue->read_ptr;
+ while ( falcon_event_present ( evt ) ) {
+
+ EFAB_TRACE ( "Event at index 0x%x address %p is "
+ EFAB_QWORD_FMT "\n", ev_queue->read_ptr,
+ evt, EFAB_QWORD_VAL ( *evt ) );
+
+ falcon_handle_event ( efab, evt );
+
+ /* Clear the event */
+ EFAB_SET_QWORD ( *evt );
+
+ /* Move to the next event. We don't ack the event
+ * queue until the end */
+ ev_queue->read_ptr = ( ( ev_queue->read_ptr + 1 ) %
+ EFAB_EVQ_SIZE );
+ evt = ev_queue->ring + ev_queue->read_ptr;
}
- /* Read MAC address from EEPROM */
- if ( ! efab->op->read_eeprom ( efab ) )
- return 0;
+ /* Push more buffers if needed */
+ (void) efab_fill_rx_queue ( efab, rx_queue );
- /* Initialise MAC and wait for link up */
- if ( ! efab_init_mac ( efab ) )
- return 0;
+ /* Clear any pending interrupts */
+ falcon_clear_interrupts ( efab );
- return 1;
+ /* Ack the event queue */
+ falcon_eventq_read_ack ( efab, ev_queue );
}
-/**************************************************************************
+static void
+efab_irq ( struct net_device *netdev, int enable )
+{
+ struct efab_nic *efab = netdev_priv ( netdev );
+ struct efab_ev_queue *ev_queue = &efab->ev_queue;
+
+ switch ( enable ) {
+ case 0:
+ falcon_interrupts ( efab, 0, 0 );
+ break;
+ case 1:
+ falcon_interrupts ( efab, 1, 0 );
+ falcon_eventq_read_ack ( efab, ev_queue );
+ break;
+ case 2:
+ falcon_interrupts ( efab, 1, 1 );
+ break;
+ }
+}
+
+/*******************************************************************************
*
- * Etherboot interface
*
- **************************************************************************
- */
+ * Software open/close
+ *
+ *
+ *******************************************************************************/
-/**************************************************************************
-POLL - Wait for a frame
-***************************************************************************/
-static int etherfabric_poll ( struct nic *nic, int retrieve ) {
- struct efab_nic *efab = nic->priv_data;
- struct efab_event event;
- static struct efab_rx_buf *rx_buf = NULL;
- int i, drop = 0;
-
- /* Process the event queue until we hit either a packet
- * received event or an empty event slot.
- */
- while ( ( rx_buf == NULL ) &&
- efab->op->fetch_event ( efab, &event ) ) {
- drop = event.drop;
- if ( event.type == EFAB_EV_TX ) {
- /* TX completed - mark as done */
- DBG ( "TX id %x complete\n",
- efab->tx_buf.id );
- } else if ( event.type == EFAB_EV_RX ) {
- /* RX - find corresponding buffer */
- for ( i = 0 ; i < EFAB_RX_BUFS ; i++ ) {
- if ( efab->rx_bufs[i].id == event.rx_id ) {
- rx_buf = &efab->rx_bufs[i];
- rx_buf->len = event.rx_len;
- DBG ( "RX id %x (len %x) received\n",
- rx_buf->id, rx_buf->len );
- break;
- }
- }
- if ( ! rx_buf ) {
- EFAB_ERR ( "Invalid RX ID %x\n", event.rx_id );
- }
- } else if ( event.type == EFAB_EV_NONE ) {
- DBG ( "Ignorable event\n" );
- } else {
- DBG ( "Unknown event\n" );
- }
- }
+static void
+efab_free_resources ( struct efab_nic *efab )
+{
+ struct efab_ev_queue *ev_queue = &efab->ev_queue;
+ struct efab_rx_queue *rx_queue = &efab->rx_queue;
+ struct efab_tx_queue *tx_queue = &efab->tx_queue;
+ int i;
- /* If there is no packet, return 0 */
- if ( ! rx_buf )
- return 0;
+ for ( i = 0; i < EFAB_NUM_RX_DESC; i++ ) {
+ if ( rx_queue->buf[i] )
+ free_iob ( rx_queue->buf[i] );
+ }
- /* drop this event if necessary */
- if ( drop ) {
- DBG( "discarding RX event\n" );
- return 0;
+ for ( i = 0; i < EFAB_TXD_SIZE; i++ ) {
+ if ( tx_queue->buf[i] )
+ netdev_tx_complete ( efab->netdev, tx_queue->buf[i] );
}
- /* If we don't want to retrieve it just yet, return 1 */
- if ( ! retrieve )
- return 1;
+ if ( rx_queue->ring )
+ falcon_free_special_buffer ( rx_queue->ring );
- /* There seems to be a hardware race. The event can show up
- * on the event FIFO before the DMA has completed, so we
- * insert a tiny delay. If this proves unreliable, we should
- * switch to using event DMA rather than the event FIFO, since
- * event DMA ordering is guaranteed.
- */
- udelay ( 2 );
+ if ( tx_queue->ring )
+ falcon_free_special_buffer ( tx_queue->ring );
- /* Copy packet contents */
- nic->packetlen = rx_buf->len;
- memcpy ( nic->packet, rx_buf->addr, nic->packetlen );
+ if ( ev_queue->ring )
+ falcon_free_special_buffer ( ev_queue->ring );
- /* Give this buffer back to the NIC */
- efab_push_rx_buffer ( efab, rx_buf );
+ memset ( rx_queue, 0, sizeof ( *rx_queue ) );
+ memset ( tx_queue, 0, sizeof ( *tx_queue ) );
+ memset ( ev_queue, 0, sizeof ( *ev_queue ) );
- /* Prepare to receive next packet */
- rx_buf = NULL;
+ /* Ensure subsequent buffer allocations start at id 0 */
+ efab->buffer_head = 0;
+}
- return 1;
+static int
+efab_alloc_resources ( struct efab_nic *efab )
+{
+ struct efab_ev_queue *ev_queue = &efab->ev_queue;
+ struct efab_rx_queue *rx_queue = &efab->rx_queue;
+ struct efab_tx_queue *tx_queue = &efab->tx_queue;
+ size_t bytes;
+
+ /* Allocate the hardware event queue */
+ bytes = sizeof ( falcon_event_t ) * EFAB_TXD_SIZE;
+ ev_queue->ring = falcon_alloc_special_buffer ( efab, bytes,
+ &ev_queue->entry );
+ if ( !ev_queue->ring )
+ goto fail1;
+
+ /* Initialise the hardware event queue */
+ memset ( ev_queue->ring, 0xff, bytes );
+
+ /* Allocate the hardware tx queue */
+ bytes = sizeof ( falcon_tx_desc_t ) * EFAB_TXD_SIZE;
+ tx_queue->ring = falcon_alloc_special_buffer ( efab, bytes,
+ &tx_queue->entry );
+ if ( ! tx_queue->ring )
+ goto fail2;
+
+ /* Allocate the hardware rx queue */
+ bytes = sizeof ( falcon_rx_desc_t ) * EFAB_RXD_SIZE;
+ rx_queue->ring = falcon_alloc_special_buffer ( efab, bytes,
+ &rx_queue->entry );
+ if ( ! rx_queue->ring )
+ goto fail3;
+
+ return 0;
+
+fail3:
+ falcon_free_special_buffer ( tx_queue->ring );
+ tx_queue->ring = NULL;
+fail2:
+ falcon_free_special_buffer ( ev_queue->ring );
+ ev_queue->ring = NULL;
+fail1:
+ return -ENOMEM;
}
-/**************************************************************************
-TRANSMIT - Transmit a frame
-***************************************************************************/
-static void etherfabric_transmit ( struct nic *nic, const char *dest,
- unsigned int type, unsigned int size,
- const char *data ) {
- struct efab_nic *efab = nic->priv_data;
- unsigned int nstype = htons ( type );
-
- /* Fill TX buffer, pad to ETH_ZLEN */
- memcpy ( efab->tx_buf.addr, dest, ETH_ALEN );
- memcpy ( efab->tx_buf.addr + ETH_ALEN, nic->node_addr, ETH_ALEN );
- memcpy ( efab->tx_buf.addr + 2 * ETH_ALEN, &nstype, 2 );
- memcpy ( efab->tx_buf.addr + ETH_HLEN, data, size );
- size += ETH_HLEN;
- while ( size < ETH_ZLEN ) {
- efab->tx_buf.addr[size++] = '\0';
- }
- efab->tx_buf.len = size;
-
- /* Push TX descriptor */
- efab_push_tx_buffer ( efab, &efab->tx_buf );
-
- /* Allow enough time for the packet to be transmitted. This
- * is a temporary hack until we update to the new driver API.
- */
- udelay ( 20 );
+static int
+efab_init_mac ( struct efab_nic *efab )
+{
+ int count, rc;
+
+ /* This can take several seconds */
+ EFAB_LOG ( "Waiting for link..\n" );
+ for ( count=0; count<5; count++ ) {
+ rc = efab->mac_op->init ( efab );
+ if ( rc ) {
+ EFAB_ERR ( "Failed reinitialising MAC, error %s\n",
+ strerror ( rc ));
+ return rc;
+ }
- return;
+ /* Sleep for 2s to wait for the link to settle, either
+ * because we want to use it, or because we're about
+ * to reset the mac anyway
+ */
+ sleep ( 2 );
+
+ if ( ! efab->link_up ) {
+ EFAB_ERR ( "!\n" );
+ continue;
+ }
+
+ EFAB_LOG ( "\n%dMbps %s-duplex\n",
+ ( efab->link_options & LPA_10000 ? 10000 :
+ ( efab->link_options & LPA_1000 ? 1000 :
+ ( efab->link_options & LPA_100 ? 100 : 10 ) ) ),
+ ( efab->link_options & LPA_DUPLEX ?
+ "full" : "half" ) );
+
+ /* TODO: Move link state handling to the poll() routine */
+ netdev_link_up ( efab->netdev );
+ return 0;
+ }
+
+ EFAB_ERR ( "timed initialising MAC\n" );
+ return -ETIMEDOUT;
}
-/**************************************************************************
-DISABLE - Turn off ethernet interface
-***************************************************************************/
-static void etherfabric_disable ( struct nic *nic ) {
- struct efab_nic *efab = nic->priv_data;
+static void
+efab_close ( struct net_device *netdev )
+{
+ struct efab_nic *efab = netdev_priv ( netdev );
- efab->op->reset ( efab );
- if ( efab->membase )
- iounmap ( efab->membase );
+ falcon_fini_resources ( efab );
+ efab_free_resources ( efab );
+ efab->board_op->fini ( efab );
+ falcon_reset ( efab );
}
-/**************************************************************************
-IRQ - handle interrupts
-***************************************************************************/
-static void etherfabric_irq ( struct nic *nic, irq_action_t action ) {
- struct efab_nic *efab = nic->priv_data;
-
- switch ( action ) {
- case DISABLE :
- efab->op->mask_irq ( efab, 1 );
- break;
- case ENABLE :
- efab->op->mask_irq ( efab, 0 );
- break;
- case FORCE :
- /* Force NIC to generate a receive interrupt */
- efab->op->generate_irq ( efab );
- break;
- }
+static int
+efab_open ( struct net_device *netdev )
+{
+ struct efab_nic *efab = netdev_priv ( netdev );
+ struct efab_rx_queue *rx_queue = &efab->rx_queue;
+ int rc;
+
+ rc = falcon_reset ( efab );
+ if ( rc )
+ goto fail1;
+
+ rc = efab->board_op->init ( efab );
+ if ( rc )
+ goto fail2;
- return;
+ rc = falcon_init_sram ( efab );
+ if ( rc )
+ goto fail3;
+
+ /* Configure descriptor caches before pushing hardware queues */
+ falcon_setup_nic ( efab );
+
+ rc = efab_alloc_resources ( efab );
+ if ( rc )
+ goto fail4;
+
+ falcon_init_resources ( efab );
+
+ /* Push rx buffers */
+ rc = efab_fill_rx_queue ( efab, rx_queue );
+ if ( rc )
+ goto fail5;
+
+ /* Try and bring the interface up */
+ rc = efab_init_mac ( efab );
+ if ( rc )
+ goto fail6;
+
+ return 0;
+
+fail6:
+fail5:
+ efab_free_resources ( efab );
+fail4:
+fail3:
+ efab->board_op->fini ( efab );
+fail2:
+ falcon_reset ( efab );
+fail1:
+ return rc;
}
-static struct nic_operations etherfabric_operations = {
- .connect = dummy_connect,
- .poll = etherfabric_poll,
- .transmit = etherfabric_transmit,
- .irq = etherfabric_irq,
+static struct net_device_operations efab_operations = {
+ .open = efab_open,
+ .close = efab_close,
+ .transmit = efab_transmit,
+ .poll = efab_poll,
+ .irq = efab_irq,
};
-/**************************************************************************
-PROBE - Look for an adapter, this routine's visible to the outside
-***************************************************************************/
-static int etherfabric_probe ( struct nic *nic, struct pci_device *pci ) {
- static struct efab_nic efab;
- static int nic_port = 1;
- struct efab_buffers *buffers;
- int i;
+static void
+efab_remove ( struct pci_device *pci )
+{
+ struct net_device *netdev = pci_get_drvdata ( pci );
+ struct efab_nic *efab = netdev_priv ( netdev );
- /* Set up our private data structure */
- nic->priv_data = &efab;
- memset ( &efab, 0, sizeof ( efab ) );
- memset ( &efab_buffers, 0, sizeof ( efab_buffers ) );
+ if ( efab->membase ) {
+ falcon_reset ( efab );
- /* Hook in appropriate operations table. Do this early. */
- if ( pci->device == EF1002_DEVID ) {
- efab.op = &ef1002_operations;
- } else {
- efab.op = &falcon_operations;
+ iounmap ( efab->membase );
+ efab->membase = NULL;
}
- /* Initialise efab data structure */
- efab.pci = pci;
- buffers = ( ( struct efab_buffers * )
- ( ( ( void * ) &efab_buffers ) +
- ( - virt_to_bus ( &efab_buffers ) ) % EFAB_BUF_ALIGN ) );
- efab.eventq = buffers->eventq;
- efab.txd = buffers->txd;
- efab.rxd = buffers->rxd;
- efab.tx_buf.addr = buffers->tx_buf;
- for ( i = 0 ; i < EFAB_RX_BUFS ; i++ ) {
- efab.rx_bufs[i].addr = buffers->rx_buf[i];
+ if ( efab->nvo.nvs ) {
+ unregister_nvo ( &efab->nvo );
+ efab->nvo.nvs = NULL;
}
- /* Enable the PCI device */
- adjust_pci_device ( pci );
- nic->ioaddr = pci->ioaddr & ~3;
- nic->irqno = pci->irq;
+ unregister_netdev ( netdev );
+ netdev_nullify ( netdev );
+ netdev_put ( netdev );
+}
+
+static int
+efab_probe ( struct pci_device *pci,
+ const struct pci_device_id *id )
+{
+ struct net_device *netdev;
+ struct efab_nic *efab;
+ unsigned long mmio_start, mmio_len;
+ int rc;
+
+ /* Create the network adapter */
+ netdev = alloc_etherdev ( sizeof ( struct efab_nic ) );
+ if ( ! netdev ) {
+ rc = -ENOMEM;
+ goto fail1;
+ }
+
+ /* Initialise the network adapter, and initialise private storage */
+ netdev_init ( netdev, &efab_operations );
+ pci_set_drvdata ( pci, netdev );
+ netdev->dev = &pci->dev;
+
+ efab = netdev_priv ( netdev );
+ memset ( efab, 0, sizeof ( *efab ) );
+ efab->netdev = netdev;
/* Get iobase/membase */
- efab.iobase = nic->ioaddr;
- efab.op->get_membase ( &efab );
+ mmio_start = pci_bar_start ( pci, PCI_BASE_ADDRESS_2 );
+ mmio_len = pci_bar_size ( pci, PCI_BASE_ADDRESS_2 );
+ efab->membase = ioremap ( mmio_start, mmio_len );
+ EFAB_TRACE ( "BAR of %lx bytes at phys %lx mapped at %p\n",
+ mmio_len, mmio_start, efab->membase );
- /* Switch NIC ports (i.e. try different ports on each probe) */
- nic_port = 1 - nic_port;
- efab.port = nic_port;
+ /* Enable the PCI device */
+ adjust_pci_device ( pci );
+ efab->iobase = pci->ioaddr & ~3;
+
+ /* Determine the NIC variant */
+ falcon_probe_nic_variant ( efab, pci );
+
+ /* Read the SPI interface and determine the MAC address,
+ * and the board and phy variant. Hook in the op tables */
+ rc = falcon_probe_spi ( efab );
+ if ( rc )
+ goto fail2;
+ rc = falcon_probe_nvram ( efab );
+ if ( rc )
+ goto fail3;
+
+ memcpy ( netdev->ll_addr, efab->mac_addr, ETH_ALEN );
+
+ netdev_link_up ( netdev );
+ rc = register_netdev ( netdev );
+ if ( rc )
+ goto fail4;
+
+ /* Advertise non-volatile storage */
+ if ( efab->nvo.nvs ) {
+ rc = register_nvo ( &efab->nvo, netdev_settings ( netdev ) );
+ if ( rc )
+ goto fail5;
+ }
- /* Initialise hardware */
- if ( ! efab_init_nic ( &efab ) )
- return 0;
- memcpy ( nic->node_addr, efab.mac_addr, ETH_ALEN );
+ EFAB_LOG ( "Found %s EtherFabric %s %s revision %d\n", id->name,
+ efab->is_asic ? "ASIC" : "FPGA",
+ efab->phy_10g ? "10G" : "1G",
+ efab->pci_revision );
- /* point to NIC specific routines */
- nic->nic_op = &etherfabric_operations;
+ return 0;
- return 1;
+fail5:
+ unregister_netdev ( netdev );
+fail4:
+fail3:
+fail2:
+ iounmap ( efab->membase );
+ efab->membase = NULL;
+ netdev_put ( netdev );
+fail1:
+ return rc;
}
-static struct pci_device_id etherfabric_nics[] = {
-PCI_ROM(0x1924, 0xC101, "ef1002", "EtherFabric EF1002"),
-PCI_ROM(0x1924, 0x0703, "falcon", "EtherFabric Falcon"),
-};
-PCI_DRIVER ( etherfabric_driver, etherfabric_nics, PCI_NO_CLASS );
+static struct pci_device_id efab_nics[] = {
+ PCI_ROM(0x1924, 0x0703, "falcon", "EtherFabric Falcon"),
+ PCI_ROM(0x1924, 0x0710, "falconb0", "EtherFabric FalconB0"),
+};
-DRIVER ( "EFAB", nic_driver, pci_driver, etherfabric_driver,
- etherfabric_probe, etherfabric_disable );
+struct pci_driver etherfabric_driver __pci_driver = {
+ .ids = efab_nics,
+ .id_count = sizeof ( efab_nics ) / sizeof ( efab_nics[0] ),
+ .probe = efab_probe,
+ .remove = efab_remove,
+};
/*
* Local variables:
diff --git a/gpxe/src/drivers/net/etherfabric_nic.h b/gpxe/src/drivers/net/etherfabric_nic.h
new file mode 100644
index 00000000..4be50fbb
--- /dev/null
+++ b/gpxe/src/drivers/net/etherfabric_nic.h
@@ -0,0 +1,201 @@
+/**************************************************************************
+ *
+ * Etherboot driver for Level 5 Etherfabric network cards
+ *
+ * Written by Michael Brown <mbrown@fensystems.co.uk>
+ *
+ * Copyright Fen Systems Ltd. 2005
+ * Copyright Level 5 Networks Inc. 2005
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License (GPL), incorporated herein by
+ * reference. Drivers based on or derived from this code fall under
+ * the GPL and must retain the authorship, copyright and license
+ * notice.
+ *
+ **************************************************************************
+ */
+#ifndef EFAB_NIC_H
+#define EFAB_NIC_H
+#include <gpxe/bitbash.h>
+#include <gpxe/i2c.h>
+#include <gpxe/spi.h>
+#include <gpxe/nvo.h>
+#include <gpxe/if_ether.h>
+/**************************************************************************
+ *
+ * Constants and macros
+ *
+ **************************************************************************
+ */
+/* Board IDs. Early boards have no board_type, (e.g. EF1002 and 401/403)
+ * But newer boards are getting bigger...
+ */
+typedef enum {
+ EFAB_BOARD_INVALID = 0, /* Early boards do not have board rev. info. */
+ EFAB_BOARD_SFE4001 = 1,
+ EFAB_BOARD_SFE4002 = 2,
+ EFAB_BOARD_SFE4003 = 3,
+ /* Insert new types before here */
+ EFAB_BOARD_MAX
+} efab_board_type;
+
+/* PHY types. */
+typedef enum {
+ PHY_TYPE_AUTO = 0, /* on development board detect between CX4 & alaska */
+ PHY_TYPE_CX4_RTMR = 1,
+ PHY_TYPE_1GIG_ALASKA = 2,
+ PHY_TYPE_10XPRESS = 3,
+ PHY_TYPE_XFP = 4,
+ PHY_TYPE_CX4 = 5,
+ PHY_TYPE_PM8358 = 6,
+} phy_type_t;
+
+/**************************************************************************
+ *
+ * Hardware data structures and sizing
+ *
+ **************************************************************************
+ */
+
+#define dma_addr_t unsigned long
+typedef efab_qword_t falcon_rx_desc_t;
+typedef efab_qword_t falcon_tx_desc_t;
+typedef efab_qword_t falcon_event_t;
+
+#define EFAB_BUF_ALIGN 4096
+#define EFAB_RXD_SIZE 512
+#define EFAB_TXD_SIZE 512
+#define EFAB_EVQ_SIZE 512
+
+#define EFAB_NUM_RX_DESC 16
+#define EFAB_RX_BUF_SIZE 1600
+
+/**************************************************************************
+ *
+ * Data structures
+ *
+ **************************************************************************
+ */
+
+struct efab_nic;
+
+/* A buffer table allocation backing a tx dma, rx dma or eventq */
+struct efab_special_buffer {
+ dma_addr_t dma_addr;
+ int id;
+};
+
+/* A TX queue */
+struct efab_tx_queue {
+ /* The hardware ring */
+ falcon_tx_desc_t *ring;
+
+ /* The software ring storing io_buffers. */
+ struct io_buffer *buf[EFAB_TXD_SIZE];
+
+ /* The buffer table reservation pushed to hardware */
+ struct efab_special_buffer entry;
+
+ /* Software descriptor write ptr */
+ unsigned int write_ptr;
+
+ /* Hardware descriptor read ptr */
+ unsigned int read_ptr;
+};
+
+/* An RX queue */
+struct efab_rx_queue {
+ /* The hardware ring */
+ falcon_rx_desc_t *ring;
+
+ /* The software ring storing io_buffers */
+ struct io_buffer *buf[EFAB_NUM_RX_DESC];
+
+ /* The buffer table reservation pushed to hardware */
+ struct efab_special_buffer entry;
+
+ /* Descriptor write ptr, into both the hardware and software rings */
+ unsigned int write_ptr;
+
+ /* Hardware completion ptr */
+ unsigned int read_ptr;
+};
+
+/* An event queue */
+struct efab_ev_queue {
+ /* The hardware ring to push to hardware.
+ * Must be the first entry in the structure */
+ falcon_event_t *ring;
+
+ /* The buffer table reservation pushed to hardware */
+ struct efab_special_buffer entry;
+
+ /* Pointers into the ring */
+ unsigned int read_ptr;
+};
+
+struct efab_mac_operations {
+ int ( * init ) ( struct efab_nic *efab );
+};
+
+struct efab_phy_operations {
+ int ( * init ) ( struct efab_nic *efab );
+ unsigned int mmds;
+};
+
+struct efab_board_operations {
+ int ( * init ) ( struct efab_nic *efab );
+ void ( * fini ) ( struct efab_nic *efab );
+};
+
+struct efab_nic {
+ struct net_device *netdev;
+ int pci_revision;
+ int is_asic;
+
+ /* I2C bit-bashed interface */
+ struct i2c_bit_basher i2c_bb;
+
+ /** SPI bus and devices, and the user visible NVO area */
+ struct spi_bus spi_bus;
+ struct spi_device spi_flash;
+ struct spi_device spi_eeprom;
+ struct spi_device *spi;
+ struct nvo_block nvo;
+
+ /** Board, MAC, and PHY operations tables */
+ struct efab_board_operations *board_op;
+ struct efab_mac_operations *mac_op;
+ struct efab_phy_operations *phy_op;
+
+ /* PHY and board types */
+ int phy_addr;
+ int phy_type;
+ int phy_10g;
+ int board_type;
+
+ /** Memory and IO base */
+ void *membase;
+ unsigned int iobase;
+
+ /* Buffer table allocation head */
+ int buffer_head;
+
+ /* Queues */
+ struct efab_rx_queue rx_queue;
+ struct efab_tx_queue tx_queue;
+ struct efab_ev_queue ev_queue;
+
+ /** MAC address */
+ uint8_t mac_addr[ETH_ALEN];
+ /** GMII link options */
+ unsigned int link_options;
+ /** Link status */
+ int link_up;
+
+ /** INT_REG_KER */
+ efab_oword_t int_ker __attribute__ (( aligned ( 16 ) ));
+};
+#endif /* EFAB_NIC_H */
+
diff --git a/gpxe/src/drivers/net/forcedeth.c b/gpxe/src/drivers/net/forcedeth.c
index 54fadbd7..a30f1378 100644
--- a/gpxe/src/drivers/net/forcedeth.c
+++ b/gpxe/src/drivers/net/forcedeth.c
@@ -452,7 +452,7 @@ static int reg_delay(int offset, u32 mask,
delaymax -= delay;
if (delaymax < 0) {
if (msg)
- printf(msg);
+ printf("%s", msg);
return 1;
}
} while ((readl(base + offset) & mask) != target);
diff --git a/gpxe/src/drivers/net/ipoib.c b/gpxe/src/drivers/net/ipoib.c
index 16b2a0c8..8ad2c29f 100644
--- a/gpxe/src/drivers/net/ipoib.c
+++ b/gpxe/src/drivers/net/ipoib.c
@@ -33,9 +33,6 @@
* IP over Infiniband
*/
-/** IPoIB MTU */
-#define IPOIB_MTU 2048
-
/** Number of IPoIB data send work queue entries */
#define IPOIB_DATA_NUM_SEND_WQES 2
@@ -60,8 +57,6 @@ struct ipoib_queue_set {
struct ib_completion_queue *cq;
/** Queue pair */
struct ib_queue_pair *qp;
- /** Receive work queue fill level */
- unsigned int recv_fill;
/** Receive work queue maximum fill level */
unsigned int recv_max_fill;
};
@@ -90,49 +85,146 @@ struct ipoib_device {
int broadcast_attached;
};
+/** TID half used to identify get path record replies */
+#define IPOIB_TID_GET_PATH_REC 0x11111111UL
+
+/** TID half used to identify multicast member record replies */
+#define IPOIB_TID_MC_MEMBER_REC 0x22222222UL
+
+/** IPoIB metadata TID */
+static uint32_t ipoib_meta_tid = 0;
+
+/** Broadcast QPN used in IPoIB MAC addresses
+ *
+ * This is a guaranteed invalid real QPN
+ */
+#define IPOIB_BROADCAST_QPN 0xffffffffUL
+
+/** Broadcast IPoIB address */
+static struct ipoib_mac ipoib_broadcast = {
+ .qpn = ntohl ( IPOIB_BROADCAST_QPN ),
+ .gid.u.bytes = { 0xff, 0x12, 0x40, 0x1b, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff },
+};
+
+/****************************************************************************
+ *
+ * IPoIB peer cache
+ *
+ ****************************************************************************
+ */
+
/**
- * IPoIB path cache entry
+ * IPoIB peer address
*
* This serves a similar role to the ARP cache for Ethernet. (ARP
* *is* used on IPoIB; we have two caches to maintain.)
*/
-struct ipoib_cached_path {
- /** Destination GID */
- struct ib_gid gid;
- /** Destination LID */
- unsigned int dlid;
+struct ipoib_peer {
+ /** Key */
+ uint8_t key;
+ /** MAC address */
+ struct ipoib_mac mac;
+ /** LID */
+ unsigned int lid;
/** Service level */
unsigned int sl;
/** Rate */
unsigned int rate;
};
-/** Number of IPoIB path cache entries */
-#define IPOIB_NUM_CACHED_PATHS 2
+/** Number of IPoIB peer cache entries
+ *
+ * Must be a power of two.
+ */
+#define IPOIB_NUM_CACHED_PEERS 4
-/** IPoIB path cache */
-static struct ipoib_cached_path ipoib_path_cache[IPOIB_NUM_CACHED_PATHS];
+/** IPoIB peer address cache */
+static struct ipoib_peer ipoib_peer_cache[IPOIB_NUM_CACHED_PEERS];
-/** Oldest IPoIB path cache entry index */
-static unsigned int ipoib_path_cache_idx = 0;
+/** Oldest IPoIB peer cache entry index */
+static unsigned int ipoib_peer_cache_idx = 1;
-/** TID half used to identify get path record replies */
-#define IPOIB_TID_GET_PATH_REC 0x11111111UL
+/**
+ * Look up cached peer by key
+ *
+ * @v key Peer cache key
+ * @ret peer Peer cache entry, or NULL
+ */
+static struct ipoib_peer * ipoib_lookup_peer_by_key ( unsigned int key ) {
+ struct ipoib_peer *peer;
+ unsigned int i;
-/** TID half used to identify multicast member record replies */
-#define IPOIB_TID_MC_MEMBER_REC 0x22222222UL
+ for ( i = 0 ; i < IPOIB_NUM_CACHED_PEERS ; i++ ) {
+ peer = &ipoib_peer_cache[i];
+ if ( peer->key == key )
+ return peer;
+ }
-/** IPoIB metadata TID */
-static uint32_t ipoib_meta_tid = 0;
+ if ( key != 0 ) {
+ DBG ( "IPoIB warning: peer cache lost track of key %x while "
+ "still in use\n", key );
+ }
+ return NULL;
+}
-/** IPv4 broadcast GID */
-static const struct ib_gid ipv4_broadcast_gid = {
- { { 0xff, 0x12, 0x40, 0x1b, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff } }
-};
+/**
+ * Look up cached peer by GID
+ *
+ * @v gid Peer GID
+ * @ret peer Peer cache entry, or NULL
+ */
+static struct ipoib_peer *
+ipoib_lookup_peer_by_gid ( const struct ib_gid *gid ) {
+ struct ipoib_peer *peer;
+ unsigned int i;
+
+ for ( i = 0 ; i < IPOIB_NUM_CACHED_PEERS ; i++ ) {
+ peer = &ipoib_peer_cache[i];
+ if ( memcmp ( &peer->mac.gid, gid,
+ sizeof ( peer->mac.gid) ) == 0 ) {
+ return peer;
+ }
+ }
-/** Maximum time we will wait for the broadcast join to succeed */
-#define IPOIB_JOIN_MAX_DELAY_MS 1000
+ return NULL;
+}
+
+/**
+ * Store GID and QPN in peer cache
+ *
+ * @v gid Peer GID
+ * @v qpn Peer QPN
+ * @ret peer Peer cache entry
+ */
+static struct ipoib_peer *
+ipoib_cache_peer ( const struct ib_gid *gid, unsigned long qpn ) {
+ struct ipoib_peer *peer;
+ unsigned int key;
+
+ /* Look for existing cache entry */
+ peer = ipoib_lookup_peer_by_gid ( gid );
+ if ( peer ) {
+ assert ( peer->mac.qpn = ntohl ( qpn ) );
+ return peer;
+ }
+
+ /* No entry found: create a new one */
+ key = ipoib_peer_cache_idx++;
+ peer = &ipoib_peer_cache[ key % IPOIB_NUM_CACHED_PEERS ];
+ if ( peer->key )
+ DBG ( "IPoIB peer %x evicted from cache\n", peer->key );
+
+ memset ( peer, 0, sizeof ( *peer ) );
+ peer->key = key;
+ peer->mac.qpn = htonl ( qpn );
+ memcpy ( &peer->mac.gid, gid, sizeof ( peer->mac.gid ) );
+ DBG ( "IPoIB peer %x has GID %08x:%08x:%08x:%08x and QPN %lx\n",
+ peer->key, htonl ( gid->u.dwords[0] ),
+ htonl ( gid->u.dwords[1] ), htonl ( gid->u.dwords[2] ),
+ htonl ( gid->u.dwords[3] ), qpn );
+ return peer;
+}
/****************************************************************************
*
@@ -141,37 +233,32 @@ static const struct ib_gid ipv4_broadcast_gid = {
****************************************************************************
*/
-/** Broadcast QPN used in IPoIB MAC addresses
- *
- * This is a guaranteed invalid real QPN
- */
-#define IPOIB_BROADCAST_QPN 0xffffffffUL
-
-/** Broadcast IPoIB address */
-static struct ipoib_mac ipoib_broadcast = {
- .qpn = ntohl ( IPOIB_BROADCAST_QPN ),
-};
-
/**
* Add IPoIB link-layer header
*
* @v iobuf I/O buffer
- * @v netdev Network device
- * @v net_protocol Network-layer protocol
* @v ll_dest Link-layer destination address
+ * @v ll_source Source link-layer address
+ * @v net_proto Network-layer protocol, in network-byte order
+ * @ret rc Return status code
*/
-static int ipoib_push ( struct io_buffer *iobuf,
- struct net_device *netdev __unused,
- struct net_protocol *net_protocol,
- const void *ll_dest ) {
+static int ipoib_push ( struct io_buffer *iobuf, const void *ll_dest,
+ const void *ll_source __unused, uint16_t net_proto ) {
struct ipoib_hdr *ipoib_hdr =
iob_push ( iobuf, sizeof ( *ipoib_hdr ) );
+ const struct ipoib_mac *dest_mac = ll_dest;
+ const struct ipoib_mac *src_mac = ll_source;
+ struct ipoib_peer *dest;
+ struct ipoib_peer *src;
+
+ /* Add link-layer addresses to cache */
+ dest = ipoib_cache_peer ( &dest_mac->gid, ntohl ( dest_mac->qpn ) );
+ src = ipoib_cache_peer ( &src_mac->gid, ntohl ( src_mac->qpn ) );
/* Build IPoIB header */
- memcpy ( &ipoib_hdr->pseudo.peer, ll_dest,
- sizeof ( ipoib_hdr->pseudo.peer ) );
- ipoib_hdr->real.proto = net_protocol->net_proto;
- ipoib_hdr->real.reserved = 0;
+ ipoib_hdr->proto = net_proto;
+ ipoib_hdr->u.peer.dest = dest->key;
+ ipoib_hdr->u.peer.src = src->key;
return 0;
}
@@ -180,15 +267,16 @@ static int ipoib_push ( struct io_buffer *iobuf,
* Remove IPoIB link-layer header
*
* @v iobuf I/O buffer
- * @v netdev Network device
- * @v net_proto Network-layer protocol, in network-byte order
- * @v ll_source Source link-layer address
+ * @ret ll_dest Link-layer destination address
+ * @ret ll_source Source link-layer address
+ * @ret net_proto Network-layer protocol, in network-byte order
* @ret rc Return status code
*/
-static int ipoib_pull ( struct io_buffer *iobuf,
- struct net_device *netdev __unused,
- uint16_t *net_proto, const void **ll_source ) {
+static int ipoib_pull ( struct io_buffer *iobuf, const void **ll_dest,
+ const void **ll_source, uint16_t *net_proto ) {
struct ipoib_hdr *ipoib_hdr = iobuf->data;
+ struct ipoib_peer *dest;
+ struct ipoib_peer *source;
/* Sanity check */
if ( iob_len ( iobuf ) < sizeof ( *ipoib_hdr ) ) {
@@ -200,9 +288,17 @@ static int ipoib_pull ( struct io_buffer *iobuf,
/* Strip off IPoIB header */
iob_pull ( iobuf, sizeof ( *ipoib_hdr ) );
+ /* Identify source and destination addresses, and clear
+ * reserved word in IPoIB header
+ */
+ dest = ipoib_lookup_peer_by_key ( ipoib_hdr->u.peer.dest );
+ source = ipoib_lookup_peer_by_key ( ipoib_hdr->u.peer.src );
+ ipoib_hdr->u.reserved = 0;
+
/* Fill in required fields */
- *net_proto = ipoib_hdr->real.proto;
- *ll_source = &ipoib_hdr->pseudo.peer;
+ *ll_dest = ( dest ? &dest->mac : &ipoib_broadcast );
+ *ll_source = ( source ? &source->mac : &ipoib_broadcast );
+ *net_proto = ipoib_hdr->proto;
return 0;
}
@@ -217,7 +313,7 @@ const char * ipoib_ntoa ( const void *ll_addr ) {
static char buf[45];
const struct ipoib_mac *mac = ll_addr;
- snprintf ( buf, sizeof ( buf ), "%08lx:%08lx:%08lx:%08lx:%08lx",
+ snprintf ( buf, sizeof ( buf ), "%08x:%08x:%08x:%08x:%08x",
htonl ( mac->qpn ), htonl ( mac->gid.u.dwords[0] ),
htonl ( mac->gid.u.dwords[1] ),
htonl ( mac->gid.u.dwords[2] ),
@@ -225,6 +321,21 @@ const char * ipoib_ntoa ( const void *ll_addr ) {
return buf;
}
+/**
+ * Hash multicast address
+ *
+ * @v af Address family
+ * @v net_addr Network-layer address
+ * @v ll_addr Link-layer address to fill in
+ * @ret rc Return status code
+ */
+static int ipoib_mc_hash ( unsigned int af __unused,
+ const void *net_addr __unused,
+ void *ll_addr __unused ) {
+
+ return -ENOTSUP;
+}
+
/** IPoIB protocol */
struct ll_protocol ipoib_protocol __ll_protocol = {
.name = "IPoIB",
@@ -235,6 +346,7 @@ struct ll_protocol ipoib_protocol __ll_protocol = {
.push = ipoib_push,
.pull = ipoib_pull,
.ntoa = ipoib_ntoa,
+ .mc_hash = ipoib_mc_hash,
};
/****************************************************************************
@@ -266,11 +378,17 @@ static void ipoib_destroy_qset ( struct ipoib_device *ipoib,
*
* @v ipoib IPoIB device
* @v qset Queue set
+ * @v num_cqes Number of completion queue entries
+ * @v cq_op Completion queue operations
+ * @v num_send_wqes Number of send work queue entries
+ * @v num_recv_wqes Number of receive work queue entries
+ * @v qkey Queue key
* @ret rc Return status code
*/
static int ipoib_create_qset ( struct ipoib_device *ipoib,
struct ipoib_queue_set *qset,
unsigned int num_cqes,
+ struct ib_completion_queue_operations *cq_op,
unsigned int num_send_wqes,
unsigned int num_recv_wqes,
unsigned long qkey ) {
@@ -285,7 +403,7 @@ static int ipoib_create_qset ( struct ipoib_device *ipoib,
qset->recv_max_fill = num_recv_wqes;
/* Allocate completion queue */
- qset->cq = ib_create_cq ( ibdev, num_cqes );
+ qset->cq = ib_create_cq ( ibdev, num_cqes, cq_op );
if ( ! qset->cq ) {
DBGC ( ipoib, "IPoIB %p could not allocate completion queue\n",
ipoib );
@@ -312,28 +430,6 @@ static int ipoib_create_qset ( struct ipoib_device *ipoib,
}
/**
- * Find path cache entry by GID
- *
- * @v gid GID
- * @ret entry Path cache entry, or NULL
- */
-static struct ipoib_cached_path *
-ipoib_find_cached_path ( struct ib_gid *gid ) {
- struct ipoib_cached_path *path;
- unsigned int i;
-
- for ( i = 0 ; i < IPOIB_NUM_CACHED_PATHS ; i++ ) {
- path = &ipoib_path_cache[i];
- if ( memcmp ( &path->gid, gid, sizeof ( *gid ) ) == 0 )
- return path;
- }
- DBG ( "IPoIB %08lx:%08lx:%08lx:%08lx cache miss\n",
- htonl ( gid->u.dwords[0] ), htonl ( gid->u.dwords[1] ),
- htonl ( gid->u.dwords[2] ), htonl ( gid->u.dwords[3] ) );
- return NULL;
-}
-
-/**
* Transmit path record request
*
* @v ipoib IPoIB device
@@ -344,36 +440,38 @@ static int ipoib_get_path_record ( struct ipoib_device *ipoib,
struct ib_gid *gid ) {
struct ib_device *ibdev = ipoib->ibdev;
struct io_buffer *iobuf;
- struct ib_mad_path_record *path_record;
+ struct ib_mad_sa *sa;
struct ib_address_vector av;
int rc;
/* Allocate I/O buffer */
- iobuf = alloc_iob ( sizeof ( *path_record ) );
+ iobuf = alloc_iob ( sizeof ( *sa ) );
if ( ! iobuf )
return -ENOMEM;
- iob_put ( iobuf, sizeof ( *path_record ) );
- path_record = iobuf->data;
- memset ( path_record, 0, sizeof ( *path_record ) );
+ iob_put ( iobuf, sizeof ( *sa ) );
+ sa = iobuf->data;
+ memset ( sa, 0, sizeof ( *sa ) );
/* Construct path record request */
- path_record->mad_hdr.base_version = IB_MGMT_BASE_VERSION;
- path_record->mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_ADM;
- path_record->mad_hdr.class_version = 2;
- path_record->mad_hdr.method = IB_MGMT_METHOD_GET;
- path_record->mad_hdr.attr_id = htons ( IB_SA_ATTR_PATH_REC );
- path_record->mad_hdr.tid[0] = IPOIB_TID_GET_PATH_REC;
- path_record->mad_hdr.tid[1] = ipoib_meta_tid++;
- path_record->sa_hdr.comp_mask[1] =
+ sa->mad_hdr.base_version = IB_MGMT_BASE_VERSION;
+ sa->mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_ADM;
+ sa->mad_hdr.class_version = 2;
+ sa->mad_hdr.method = IB_MGMT_METHOD_GET;
+ sa->mad_hdr.attr_id = htons ( IB_SA_ATTR_PATH_REC );
+ sa->mad_hdr.tid[0] = IPOIB_TID_GET_PATH_REC;
+ sa->mad_hdr.tid[1] = ipoib_meta_tid++;
+ sa->sa_hdr.comp_mask[1] =
htonl ( IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID );
- memcpy ( &path_record->dgid, gid, sizeof ( path_record->dgid ) );
- memcpy ( &path_record->sgid, &ibdev->port_gid,
- sizeof ( path_record->sgid ) );
+ memcpy ( &sa->sa_data.path_record.dgid, gid,
+ sizeof ( sa->sa_data.path_record.dgid ) );
+ memcpy ( &sa->sa_data.path_record.sgid, &ibdev->gid,
+ sizeof ( sa->sa_data.path_record.sgid ) );
/* Construct address vector */
memset ( &av, 0, sizeof ( av ) );
- av.dlid = ibdev->sm_lid;
- av.dest_qp = IB_SA_QPN;
+ av.lid = ibdev->sm_lid;
+ av.sl = ibdev->sm_sl;
+ av.qpn = IB_SA_QPN;
av.qkey = IB_GLOBAL_QKEY;
/* Post send request */
@@ -400,40 +498,41 @@ static int ipoib_mc_member_record ( struct ipoib_device *ipoib,
struct ib_gid *gid, int join ) {
struct ib_device *ibdev = ipoib->ibdev;
struct io_buffer *iobuf;
- struct ib_mad_mc_member_record *mc_member_record;
+ struct ib_mad_sa *sa;
struct ib_address_vector av;
int rc;
/* Allocate I/O buffer */
- iobuf = alloc_iob ( sizeof ( *mc_member_record ) );
+ iobuf = alloc_iob ( sizeof ( *sa ) );
if ( ! iobuf )
return -ENOMEM;
- iob_put ( iobuf, sizeof ( *mc_member_record ) );
- mc_member_record = iobuf->data;
- memset ( mc_member_record, 0, sizeof ( *mc_member_record ) );
+ iob_put ( iobuf, sizeof ( *sa ) );
+ sa = iobuf->data;
+ memset ( sa, 0, sizeof ( *sa ) );
/* Construct path record request */
- mc_member_record->mad_hdr.base_version = IB_MGMT_BASE_VERSION;
- mc_member_record->mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_ADM;
- mc_member_record->mad_hdr.class_version = 2;
- mc_member_record->mad_hdr.method =
+ sa->mad_hdr.base_version = IB_MGMT_BASE_VERSION;
+ sa->mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_ADM;
+ sa->mad_hdr.class_version = 2;
+ sa->mad_hdr.method =
( join ? IB_MGMT_METHOD_SET : IB_MGMT_METHOD_DELETE );
- mc_member_record->mad_hdr.attr_id = htons ( IB_SA_ATTR_MC_MEMBER_REC );
- mc_member_record->mad_hdr.tid[0] = IPOIB_TID_MC_MEMBER_REC;
- mc_member_record->mad_hdr.tid[1] = ipoib_meta_tid++;
- mc_member_record->sa_hdr.comp_mask[1] =
+ sa->mad_hdr.attr_id = htons ( IB_SA_ATTR_MC_MEMBER_REC );
+ sa->mad_hdr.tid[0] = IPOIB_TID_MC_MEMBER_REC;
+ sa->mad_hdr.tid[1] = ipoib_meta_tid++;
+ sa->sa_hdr.comp_mask[1] =
htonl ( IB_SA_MCMEMBER_REC_MGID | IB_SA_MCMEMBER_REC_PORT_GID |
IB_SA_MCMEMBER_REC_JOIN_STATE );
- mc_member_record->scope__join_state = 1;
- memcpy ( &mc_member_record->mgid, gid,
- sizeof ( mc_member_record->mgid ) );
- memcpy ( &mc_member_record->port_gid, &ibdev->port_gid,
- sizeof ( mc_member_record->port_gid ) );
+ sa->sa_data.mc_member_record.scope__join_state = 1;
+ memcpy ( &sa->sa_data.mc_member_record.mgid, gid,
+ sizeof ( sa->sa_data.mc_member_record.mgid ) );
+ memcpy ( &sa->sa_data.mc_member_record.port_gid, &ibdev->gid,
+ sizeof ( sa->sa_data.mc_member_record.port_gid ) );
/* Construct address vector */
memset ( &av, 0, sizeof ( av ) );
- av.dlid = ibdev->sm_lid;
- av.dest_qp = IB_SA_QPN;
+ av.lid = ibdev->sm_lid;
+ av.sl = ibdev->sm_sl;
+ av.qpn = IB_SA_QPN;
av.qkey = IB_GLOBAL_QKEY;
/* Post send request */
@@ -459,49 +558,51 @@ static int ipoib_transmit ( struct net_device *netdev,
struct io_buffer *iobuf ) {
struct ipoib_device *ipoib = netdev->priv;
struct ib_device *ibdev = ipoib->ibdev;
- struct ipoib_pseudo_hdr *ipoib_pshdr = iobuf->data;
+ struct ipoib_hdr *ipoib_hdr;
+ struct ipoib_peer *dest;
struct ib_address_vector av;
struct ib_gid *gid;
- struct ipoib_cached_path *path;
- int rc;
/* Sanity check */
- if ( iob_len ( iobuf ) < sizeof ( *ipoib_pshdr ) ) {
+ if ( iob_len ( iobuf ) < sizeof ( *ipoib_hdr ) ) {
DBGC ( ipoib, "IPoIB %p buffer too short\n", ipoib );
return -EINVAL;
}
- iob_pull ( iobuf, ( sizeof ( *ipoib_pshdr ) ) );
+ ipoib_hdr = iobuf->data;
/* Attempting transmission while link is down will put the
* queue pair into an error state, so don't try it.
*/
- if ( ! ibdev->link_up )
+ if ( ! ib_link_ok ( ibdev ) )
return -ENETUNREACH;
+ /* Identify destination address */
+ dest = ipoib_lookup_peer_by_key ( ipoib_hdr->u.peer.dest );
+ if ( ! dest )
+ return -ENXIO;
+ ipoib_hdr->u.reserved = 0;
+
/* Construct address vector */
memset ( &av, 0, sizeof ( av ) );
- av.qkey = IB_GLOBAL_QKEY;
+ av.qkey = ipoib->data_qkey;
av.gid_present = 1;
- if ( ipoib_pshdr->peer.qpn == htonl ( IPOIB_BROADCAST_QPN ) ) {
- /* Broadcast address */
- av.dest_qp = IB_BROADCAST_QPN;
- av.dlid = ipoib->broadcast_lid;
+ if ( dest->mac.qpn == htonl ( IPOIB_BROADCAST_QPN ) ) {
+ /* Broadcast */
+ av.qpn = IB_BROADCAST_QPN;
+ av.lid = ipoib->broadcast_lid;
gid = &ipoib->broadcast_gid;
} else {
- /* Unicast - look in path cache */
- path = ipoib_find_cached_path ( &ipoib_pshdr->peer.gid );
- if ( ! path ) {
- /* No path entry - get path record */
- rc = ipoib_get_path_record ( ipoib,
- &ipoib_pshdr->peer.gid );
- netdev_tx_complete ( netdev, iobuf );
- return rc;
+ /* Unicast */
+ if ( ! dest->lid ) {
+ /* No LID yet - get path record to fetch LID */
+ ipoib_get_path_record ( ipoib, &dest->mac.gid );
+ return -ENOENT;
}
- av.dest_qp = ntohl ( ipoib_pshdr->peer.qpn );
- av.dlid = path->dlid;
- av.rate = path->rate;
- av.sl = path->sl;
- gid = &ipoib_pshdr->peer.gid;
+ av.qpn = ntohl ( dest->mac.qpn );
+ av.lid = dest->lid;
+ av.rate = dest->rate;
+ av.sl = dest->sl;
+ gid = &dest->mac.gid;
}
memcpy ( &av.gid, gid, sizeof ( av.gid ) );
@@ -513,17 +614,15 @@ static int ipoib_transmit ( struct net_device *netdev,
*
* @v ibdev Infiniband device
* @v qp Queue pair
- * @v completion Completion
* @v iobuf I/O buffer
+ * @v rc Completion status code
*/
static void ipoib_data_complete_send ( struct ib_device *ibdev __unused,
struct ib_queue_pair *qp,
- struct ib_completion *completion,
- struct io_buffer *iobuf ) {
+ struct io_buffer *iobuf, int rc ) {
struct net_device *netdev = ib_qp_get_ownerdata ( qp );
- netdev_tx_complete_err ( netdev, iobuf,
- ( completion->syndrome ? -EIO : 0 ) );
+ netdev_tx_complete_err ( netdev, iobuf, rc );
}
/**
@@ -531,67 +630,67 @@ static void ipoib_data_complete_send ( struct ib_device *ibdev __unused,
*
* @v ibdev Infiniband device
* @v qp Queue pair
- * @v completion Completion
+ * @v av Address vector, or NULL
* @v iobuf I/O buffer
+ * @v rc Completion status code
*/
static void ipoib_data_complete_recv ( struct ib_device *ibdev __unused,
struct ib_queue_pair *qp,
- struct ib_completion *completion,
- struct io_buffer *iobuf ) {
+ struct ib_address_vector *av,
+ struct io_buffer *iobuf, int rc ) {
struct net_device *netdev = ib_qp_get_ownerdata ( qp );
struct ipoib_device *ipoib = netdev->priv;
- struct ipoib_pseudo_hdr *ipoib_pshdr;
+ struct ipoib_hdr *ipoib_hdr;
+ struct ipoib_peer *src;
- if ( completion->syndrome ) {
- netdev_rx_err ( netdev, iobuf, -EIO );
- goto done;
- }
-
- iob_put ( iobuf, completion->len );
- if ( iob_len ( iobuf ) < sizeof ( struct ib_global_route_header ) ) {
- DBGC ( ipoib, "IPoIB %p received data packet too short to "
- "contain GRH\n", ipoib );
- DBGC_HD ( ipoib, iobuf->data, iob_len ( iobuf ) );
- netdev_rx_err ( netdev, iobuf, -EIO );
- goto done;
+ if ( rc != 0 ) {
+ netdev_rx_err ( netdev, iobuf, rc );
+ return;
}
- iob_pull ( iobuf, sizeof ( struct ib_global_route_header ) );
- if ( iob_len ( iobuf ) < sizeof ( struct ipoib_real_hdr ) ) {
+ /* Sanity check */
+ if ( iob_len ( iobuf ) < sizeof ( struct ipoib_hdr ) ) {
DBGC ( ipoib, "IPoIB %p received data packet too short to "
"contain IPoIB header\n", ipoib );
DBGC_HD ( ipoib, iobuf->data, iob_len ( iobuf ) );
netdev_rx_err ( netdev, iobuf, -EIO );
- goto done;
+ return;
}
+ ipoib_hdr = iobuf->data;
- ipoib_pshdr = iob_push ( iobuf, sizeof ( *ipoib_pshdr ) );
- /* FIXME: fill in a MAC address for the sake of AoE! */
+ /* Parse source address */
+ if ( av->gid_present ) {
+ src = ipoib_cache_peer ( &av->gid, av->qpn );
+ ipoib_hdr->u.peer.src = src->key;
+ }
+ /* Hand off to network layer */
netdev_rx ( netdev, iobuf );
-
- done:
- ipoib->data.recv_fill--;
}
+/** IPoIB data completion operations */
+static struct ib_completion_queue_operations ipoib_data_cq_op = {
+ .complete_send = ipoib_data_complete_send,
+ .complete_recv = ipoib_data_complete_recv,
+};
+
/**
* Handle IPoIB metadata send completion
*
* @v ibdev Infiniband device
* @v qp Queue pair
- * @v completion Completion
* @v iobuf I/O buffer
+ * @v rc Completion status code
*/
static void ipoib_meta_complete_send ( struct ib_device *ibdev __unused,
struct ib_queue_pair *qp,
- struct ib_completion *completion,
- struct io_buffer *iobuf ) {
+ struct io_buffer *iobuf, int rc ) {
struct net_device *netdev = ib_qp_get_ownerdata ( qp );
struct ipoib_device *ipoib = netdev->priv;
- if ( completion->syndrome ) {
- DBGC ( ipoib, "IPoIB %p metadata TX completion error %x\n",
- ipoib, completion->syndrome );
+ if ( rc != 0 ) {
+ DBGC ( ipoib, "IPoIB %p metadata TX completion error: %s\n",
+ ipoib, strerror ( rc ) );
}
free_iob ( iobuf );
}
@@ -602,26 +701,25 @@ static void ipoib_meta_complete_send ( struct ib_device *ibdev __unused,
* @v ipoib IPoIB device
* @v path_record Path record
*/
-static void ipoib_recv_path_record ( struct ipoib_device *ipoib __unused,
- struct ib_mad_path_record *path_record ) {
- struct ipoib_cached_path *path;
+static void ipoib_recv_path_record ( struct ipoib_device *ipoib,
+ struct ib_path_record *path_record ) {
+ struct ipoib_peer *peer;
+
+ /* Locate peer cache entry */
+ peer = ipoib_lookup_peer_by_gid ( &path_record->dgid );
+ if ( ! peer ) {
+ DBGC ( ipoib, "IPoIB %p received unsolicited path record\n",
+ ipoib );
+ return;
+ }
/* Update path cache entry */
- path = &ipoib_path_cache[ipoib_path_cache_idx];
- memcpy ( &path->gid, &path_record->dgid, sizeof ( path->gid ) );
- path->dlid = ntohs ( path_record->dlid );
- path->sl = ( path_record->reserved__sl & 0x0f );
- path->rate = ( path_record->rate_selector__rate & 0x3f );
-
- DBG ( "IPoIB %08lx:%08lx:%08lx:%08lx dlid %x sl %x rate %x\n",
- htonl ( path->gid.u.dwords[0] ), htonl ( path->gid.u.dwords[1] ),
- htonl ( path->gid.u.dwords[2] ), htonl ( path->gid.u.dwords[3] ),
- path->dlid, path->sl, path->rate );
-
- /* Update path cache index */
- ipoib_path_cache_idx++;
- if ( ipoib_path_cache_idx == IPOIB_NUM_CACHED_PATHS )
- ipoib_path_cache_idx = 0;
+ peer->lid = ntohs ( path_record->dlid );
+ peer->sl = ( path_record->reserved__sl & 0x0f );
+ peer->rate = ( path_record->rate_selector__rate & 0x3f );
+
+ DBG ( "IPoIB peer %x has dlid %x sl %x rate %x\n",
+ peer->key, peer->lid, peer->sl, peer->rate );
}
/**
@@ -631,7 +729,7 @@ static void ipoib_recv_path_record ( struct ipoib_device *ipoib __unused,
* @v mc_member_record Multicast membership record
*/
static void ipoib_recv_mc_member_record ( struct ipoib_device *ipoib,
- struct ib_mad_mc_member_record *mc_member_record ) {
+ struct ib_mc_member_record *mc_member_record ) {
int joined;
int rc;
@@ -657,64 +755,64 @@ static void ipoib_recv_mc_member_record ( struct ipoib_device *ipoib,
*
* @v ibdev Infiniband device
* @v qp Queue pair
- * @v completion Completion
+ * @v av Address vector, or NULL
* @v iobuf I/O buffer
+ * @v rc Completion status code
*/
-static void ipoib_meta_complete_recv ( struct ib_device *ibdev __unused,
- struct ib_queue_pair *qp,
- struct ib_completion *completion,
- struct io_buffer *iobuf ) {
+static void
+ipoib_meta_complete_recv ( struct ib_device *ibdev __unused,
+ struct ib_queue_pair *qp,
+ struct ib_address_vector *av __unused,
+ struct io_buffer *iobuf, int rc ) {
struct net_device *netdev = ib_qp_get_ownerdata ( qp );
struct ipoib_device *ipoib = netdev->priv;
- union ib_mad *mad;
+ struct ib_mad_sa *sa;
- if ( completion->syndrome ) {
- DBGC ( ipoib, "IPoIB %p metadata RX completion error %x\n",
- ipoib, completion->syndrome );
+ if ( rc != 0 ) {
+ DBGC ( ipoib, "IPoIB %p metadata RX completion error: %s\n",
+ ipoib, strerror ( rc ) );
goto done;
}
- iob_put ( iobuf, completion->len );
- if ( iob_len ( iobuf ) < sizeof ( struct ib_global_route_header ) ) {
- DBGC ( ipoib, "IPoIB %p received metadata packet too short "
- "to contain GRH\n", ipoib );
- DBGC_HD ( ipoib, iobuf->data, iob_len ( iobuf ) );
- goto done;
- }
- iob_pull ( iobuf, sizeof ( struct ib_global_route_header ) );
- if ( iob_len ( iobuf ) < sizeof ( *mad ) ) {
+ if ( iob_len ( iobuf ) < sizeof ( *sa ) ) {
DBGC ( ipoib, "IPoIB %p received metadata packet too short "
"to contain reply\n", ipoib );
DBGC_HD ( ipoib, iobuf->data, iob_len ( iobuf ) );
goto done;
}
- mad = iobuf->data;
+ sa = iobuf->data;
- if ( mad->mad_hdr.status != 0 ) {
+ if ( sa->mad_hdr.status != 0 ) {
DBGC ( ipoib, "IPoIB %p metadata RX err status %04x\n",
- ipoib, ntohs ( mad->mad_hdr.status ) );
+ ipoib, ntohs ( sa->mad_hdr.status ) );
goto done;
}
- switch ( mad->mad_hdr.tid[0] ) {
+ switch ( sa->mad_hdr.tid[0] ) {
case IPOIB_TID_GET_PATH_REC:
- ipoib_recv_path_record ( ipoib, &mad->path_record );
+ ipoib_recv_path_record ( ipoib, &sa->sa_data.path_record );
break;
case IPOIB_TID_MC_MEMBER_REC:
- ipoib_recv_mc_member_record ( ipoib, &mad->mc_member_record );
+ ipoib_recv_mc_member_record ( ipoib,
+ &sa->sa_data.mc_member_record );
break;
default:
DBGC ( ipoib, "IPoIB %p unwanted response:\n",
ipoib );
- DBGC_HD ( ipoib, mad, sizeof ( *mad ) );
+ DBGC_HD ( ipoib, sa, sizeof ( *sa ) );
break;
}
done:
- ipoib->meta.recv_fill--;
free_iob ( iobuf );
}
+/** IPoIB metadata completion operations */
+static struct ib_completion_queue_operations ipoib_meta_cq_op = {
+ .complete_send = ipoib_meta_complete_send,
+ .complete_recv = ipoib_meta_complete_recv,
+};
+
/**
* Refill IPoIB receive ring
*
@@ -726,15 +824,14 @@ static void ipoib_refill_recv ( struct ipoib_device *ipoib,
struct io_buffer *iobuf;
int rc;
- while ( qset->recv_fill < qset->recv_max_fill ) {
- iobuf = alloc_iob ( IPOIB_MTU );
+ while ( qset->qp->recv.fill < qset->recv_max_fill ) {
+ iobuf = alloc_iob ( IPOIB_PKT_LEN );
if ( ! iobuf )
break;
if ( ( rc = ib_post_recv ( ibdev, qset->qp, iobuf ) ) != 0 ) {
free_iob ( iobuf );
break;
}
- qset->recv_fill++;
}
}
@@ -747,10 +844,8 @@ static void ipoib_poll ( struct net_device *netdev ) {
struct ipoib_device *ipoib = netdev->priv;
struct ib_device *ibdev = ipoib->ibdev;
- ib_poll_cq ( ibdev, ipoib->meta.cq, ipoib_meta_complete_send,
- ipoib_meta_complete_recv );
- ib_poll_cq ( ibdev, ipoib->data.cq, ipoib_data_complete_send,
- ipoib_data_complete_recv );
+ ib_poll_cq ( ibdev, ipoib->meta.cq );
+ ib_poll_cq ( ibdev, ipoib->data.cq );
ipoib_refill_recv ( ipoib, &ipoib->meta );
ipoib_refill_recv ( ipoib, &ipoib->data );
}
@@ -831,9 +926,17 @@ static int ipoib_open ( struct net_device *netdev ) {
struct ipoib_mac *mac = ( ( struct ipoib_mac * ) netdev->ll_addr );
int rc;
+ /* Open IB device */
+ if ( ( rc = ib_open ( ipoib->ibdev ) ) != 0 ) {
+ DBGC ( ipoib, "IPoIB %p could not open device: %s\n",
+ ipoib, strerror ( rc ) );
+ goto err_ib_open;
+ }
+
/* Allocate metadata queue set */
if ( ( rc = ipoib_create_qset ( ipoib, &ipoib->meta,
IPOIB_META_NUM_CQES,
+ &ipoib_meta_cq_op,
IPOIB_META_NUM_SEND_WQES,
IPOIB_META_NUM_RECV_WQES,
IB_GLOBAL_QKEY ) ) != 0 ) {
@@ -845,6 +948,7 @@ static int ipoib_open ( struct net_device *netdev ) {
/* Allocate data queue set */
if ( ( rc = ipoib_create_qset ( ipoib, &ipoib->data,
IPOIB_DATA_NUM_CQES,
+ &ipoib_data_cq_op,
IPOIB_DATA_NUM_SEND_WQES,
IPOIB_DATA_NUM_RECV_WQES,
IB_GLOBAL_QKEY ) ) != 0 ) {
@@ -874,6 +978,8 @@ static int ipoib_open ( struct net_device *netdev ) {
err_create_data_qset:
ipoib_destroy_qset ( ipoib, &ipoib->meta );
err_create_meta_qset:
+ ib_close ( ipoib->ibdev );
+ err_ib_open:
return rc;
}
@@ -895,6 +1001,9 @@ static void ipoib_close ( struct net_device *netdev ) {
/* Tear down the queues */
ipoib_destroy_qset ( ipoib, &ipoib->data );
ipoib_destroy_qset ( ipoib, &ipoib->meta );
+
+ /* Close IB device */
+ ib_close ( ipoib->ibdev );
}
/** IPoIB network device operations */
@@ -923,15 +1032,15 @@ static void ipoib_set_ib_params ( struct ipoib_device *ipoib ) {
/* Calculate GID portion of MAC address based on port GID */
mac = ( ( struct ipoib_mac * ) netdev->ll_addr );
- memcpy ( &mac->gid, &ibdev->port_gid, sizeof ( mac->gid ) );
+ memcpy ( &mac->gid, &ibdev->gid, sizeof ( mac->gid ) );
/* Calculate broadcast GID based on partition key */
- memcpy ( &ipoib->broadcast_gid, &ipv4_broadcast_gid,
+ memcpy ( &ipoib->broadcast_gid, &ipoib_broadcast.gid,
sizeof ( ipoib->broadcast_gid ) );
ipoib->broadcast_gid.u.words[2] = htons ( ibdev->pkey );
/* Set net device link state to reflect Infiniband link state */
- if ( ibdev->link_up ) {
+ if ( ib_link_ok ( ibdev ) ) {
netdev_link_up ( netdev );
} else {
netdev_link_down ( netdev );
diff --git a/gpxe/src/drivers/net/mtnic.c b/gpxe/src/drivers/net/mtnic.c
index dd577f4a..0d84a44c 100755..100644
--- a/gpxe/src/drivers/net/mtnic.c
+++ b/gpxe/src/drivers/net/mtnic.c
@@ -30,13 +30,13 @@
* SOFTWARE.
*
*/
-#include <stdio.h>
#include <strings.h>
#include <errno.h>
#include <gpxe/malloc.h>
#include <gpxe/umalloc.h>
#include <byteswap.h>
#include <unistd.h>
+#include <gpxe/io.h>
#include <gpxe/pci.h>
#include <gpxe/ethernet.h>
#include <gpxe/netdevice.h>
@@ -47,28 +47,12 @@
/*
- mtnic.c - gPXE driver for Mellanox 10Gig ConnectX EN
+ mtnic.c - gPXE driver for Mellanox 10Gig ConnectX EN
*/
-/* (mcb30) - The Mellanox driver used "1" as a universal error code;
- * this at least makes it a valid error number.
- */
-#define MTNIC_ERROR -EIO
-
-
-/** Set port number to use
- *
- * 0 - port 1
- * 1 - port 2
- */
-#define MTNIC_PORT_NUM 0
-/* Note: for verbose printing do Make ... DEBUG=mtnic */
-
-
-
/********************************************************************
*
@@ -87,11 +71,11 @@
* and it's physical aligned address in 'pa'
*/
static int
-mtnic_alloc_aligned(unsigned int size, void **va, u32 *pa, unsigned int alignment)
+mtnic_alloc_aligned(unsigned int size, void **va, unsigned long *pa, unsigned int alignment)
{
*va = alloc_memblock(size, alignment);
if (!*va) {
- return MTNIC_ERROR;
+ return -EADDRINUSE;
}
*pa = (u32)virt_to_bus(*va);
return 0;
@@ -105,21 +89,21 @@ mtnic_alloc_aligned(unsigned int size, void **va, u32 *pa, unsigned int alignmen
*
*/
static int
-mtnic_alloc_cmdif(struct mtnic_priv *priv)
+mtnic_alloc_cmdif(struct mtnic *mtnic)
{
- u32 bar = mtnic_pci_dev.dev.bar[0];
+ u32 bar = mtnic_pci_dev.dev.bar[0];
- priv->hcr = ioremap(bar + MTNIC_HCR_BASE, MTNIC_HCR_SIZE);
- if (!priv->hcr) {
- DBG("Couldn't map command register.");
- return MTNIC_ERROR;
+ mtnic->hcr = ioremap(bar + MTNIC_HCR_BASE, MTNIC_HCR_SIZE);
+ if ( !mtnic->hcr ) {
+ DBG("Couldn't map command register\n");
+ return -EADDRINUSE;
}
- mtnic_alloc_aligned(PAGE_SIZE, (void *)&priv->cmd.buf, &priv->cmd.mapping, PAGE_SIZE);
- if (!priv->cmd.buf) {
+ mtnic_alloc_aligned(PAGE_SIZE, (void *)&mtnic->cmd.buf, &mtnic->cmd.mapping, PAGE_SIZE);
+ if ( !mtnic->cmd.buf ) {
DBG("Error in allocating buffer for command interface\n");
- return MTNIC_ERROR;
+ return -EADDRINUSE;
}
- return 0;
+ return 0;
}
/**
@@ -128,12 +112,13 @@ mtnic_alloc_cmdif(struct mtnic_priv *priv)
static void
mtnic_free_io_buffers(struct mtnic_ring *ring)
{
- int index;
+ int index;
for (; ring->cons <= ring->prod; ++ring->cons) {
index = ring->cons & ring->size_mask;
- if (ring->iobuf[index])
+ if ( ring->iobuf[index] ) {
free_iob(ring->iobuf[index]);
+ }
}
}
@@ -145,7 +130,7 @@ mtnic_free_io_buffers(struct mtnic_ring *ring)
*
*/
static int
-mtnic_alloc_iobuf(struct mtnic_priv *priv, struct mtnic_ring *ring,
+mtnic_alloc_iobuf(struct mtnic_port *priv, struct mtnic_ring *ring,
unsigned int size)
{
struct mtnic_rx_desc *rx_desc_ptr = ring->buf;
@@ -154,25 +139,20 @@ mtnic_alloc_iobuf(struct mtnic_priv *priv, struct mtnic_ring *ring,
while ((u32)(ring->prod - ring->cons) < UNITS_BUFFER_SIZE) {
index = ring->prod & ring->size_mask;
ring->iobuf[index] = alloc_iob(size);
- if (!&ring->iobuf[index]) {
+ if (!ring->iobuf[index]) {
if (ring->prod <= (ring->cons + 1)) {
- DBG("Error allocating Rx io "
- "buffer number %lx", index);
- /* In case of error freeing io buffer */
- mtnic_free_io_buffers(ring);
- return MTNIC_ERROR;
+ DBG ( "Dropping packet, buffer is full\n" );
}
-
break;
}
/* Attach io_buffer to descriptor */
rx_desc_ptr = ring->buf +
- (sizeof(struct mtnic_rx_desc) * index);
+ (sizeof(struct mtnic_rx_desc) * index);
rx_desc_ptr->data.count = cpu_to_be32(size);
- rx_desc_ptr->data.mem_type = priv->fw.mem_type_snoop_be;
+ rx_desc_ptr->data.mem_type = priv->mtnic->fw.mem_type_snoop_be;
rx_desc_ptr->data.addr_l = cpu_to_be32(
- virt_to_bus(ring->iobuf[index]->data));
+ virt_to_bus(ring->iobuf[index]->data));
++ ring->prod;
}
@@ -190,8 +170,8 @@ mtnic_alloc_iobuf(struct mtnic_priv *priv, struct mtnic_ring *ring,
*
*/
static int
-mtnic_alloc_ring(struct mtnic_priv *priv, struct mtnic_ring *ring,
- u32 size, u16 stride, u16 cq, u8 is_rx)
+mtnic_alloc_ring(struct mtnic_port *priv, struct mtnic_ring *ring,
+ u32 size, u16 stride, u16 cq, u8 is_rx)
{
unsigned int i;
int err;
@@ -207,18 +187,18 @@ mtnic_alloc_ring(struct mtnic_priv *priv, struct mtnic_ring *ring,
/* Alloc descriptors buffer */
ring->buf_size = ring->size * ((is_rx) ? sizeof(struct mtnic_rx_desc) :
- sizeof(struct mtnic_tx_desc));
+ sizeof(struct mtnic_tx_desc));
err = mtnic_alloc_aligned(ring->buf_size, (void *)&ring->buf,
- &ring->dma, PAGE_SIZE);
- if (err) {
- DBG("Failed allocating descriptor ring sizeof %lx\n",
+ &ring->dma, PAGE_SIZE);
+ if (err) {
+ DBG("Failed allocating descriptor ring sizeof %x\n",
ring->buf_size);
- return MTNIC_ERROR;
+ return -EADDRINUSE;
}
- memset(ring->buf, 0, ring->buf_size);
+ memset(ring->buf, 0, ring->buf_size);
- DBG("Allocated %s ring (addr:%p) - buf:%p size:%lx"
- "buf_size:%lx dma:%lx\n",
+ DBG("Allocated %s ring (addr:%p) - buf:%p size:%x"
+ "buf_size:%x dma:%lx\n",
is_rx ? "Rx" : "Tx", ring, ring->buf, ring->size,
ring->buf_size, ring->dma);
@@ -226,11 +206,11 @@ mtnic_alloc_ring(struct mtnic_priv *priv, struct mtnic_ring *ring,
if (is_rx) { /* RX ring */
/* Alloc doorbell */
err = mtnic_alloc_aligned(sizeof(struct mtnic_cq_db_record),
- (void *)&ring->db, &ring->db_dma, 32);
+ (void *)&ring->db, &ring->db_dma, 32);
if (err) {
DBG("Failed allocating Rx ring doorbell record\n");
- free(ring->buf);
- return MTNIC_ERROR;
+ free_memblock(ring->buf, ring->buf_size);
+ return -EADDRINUSE;
}
/* ==- Configure Descriptor -== */
@@ -244,14 +224,14 @@ mtnic_alloc_ring(struct mtnic_priv *priv, struct mtnic_ring *ring,
/*The last ctrl descriptor is '0' and points to the first one*/
/* Alloc IO_BUFFERS */
- err = mtnic_alloc_iobuf(priv, ring, DEF_IOBUF_SIZE);
+ err = mtnic_alloc_iobuf ( priv, ring, DEF_IOBUF_SIZE );
if (err) {
- DBG("ERROR Allocating io buffer");
- free(ring->buf);
- return MTNIC_ERROR;
+ DBG("ERROR Allocating io buffer\n");
+ free_memblock(ring->buf, ring->buf_size);
+ return -EADDRINUSE;
}
- } else { /* TX ring */
+ } else { /* TX ring */
/* Set initial ownership of all Tx Desc' to SW (1) */
for (i = 0; i < ring->size; i++) {
tx_desc = ring->buf + ring->stride * i;
@@ -259,17 +239,17 @@ mtnic_alloc_ring(struct mtnic_priv *priv, struct mtnic_ring *ring,
}
/* DB */
ring->db_offset = cpu_to_be32(
- ((u32) priv->fw.tx_offset[priv->port]) << 8);
+ ((u32) priv->mtnic->fw.tx_offset[priv->port]) << 8);
/* Map Tx+CQ doorbells */
- DBG("Mapping TxCQ doorbell at offset:0x%lx\n",
- priv->fw.txcq_db_offset);
+ DBG("Mapping TxCQ doorbell at offset:0x%x\n",
+ priv->mtnic->fw.txcq_db_offset);
ring->txcq_db = ioremap(mtnic_pci_dev.dev.bar[2] +
- priv->fw.txcq_db_offset, PAGE_SIZE);
+ priv->mtnic->fw.txcq_db_offset, PAGE_SIZE);
if (!ring->txcq_db) {
DBG("Couldn't map txcq doorbell, aborting...\n");
- free(ring->buf);
- return MTNIC_ERROR;
+ free_memblock(ring->buf, ring->buf_size);
+ return -EADDRINUSE;
}
}
@@ -286,7 +266,7 @@ mtnic_alloc_ring(struct mtnic_priv *priv, struct mtnic_ring *ring,
*/
static int
mtnic_alloc_cq(struct net_device *dev, int num, struct mtnic_cq *cq,
- u8 is_rx, u32 size, u32 offset_ind)
+ u8 is_rx, u32 size, u32 offset_ind)
{
int err ;
unsigned int i;
@@ -300,26 +280,26 @@ mtnic_alloc_cq(struct net_device *dev, int num, struct mtnic_cq *cq,
/* Alloc doorbell */
err = mtnic_alloc_aligned(sizeof(struct mtnic_cq_db_record),
- (void *)&cq->db, &cq->db_dma, 32);
+ (void *)&cq->db, &cq->db_dma, 32);
if (err) {
DBG("Failed allocating CQ doorbell record\n");
- return MTNIC_ERROR;
+ return -EADDRINUSE;
}
memset(cq->db, 0, sizeof(struct mtnic_cq_db_record));
/* Alloc CQEs buffer */
cq->buf_size = size * sizeof(struct mtnic_cqe);
err = mtnic_alloc_aligned(cq->buf_size,
- (void *)&cq->buf, &cq->dma, PAGE_SIZE);
+ (void *)&cq->buf, &cq->dma, PAGE_SIZE);
if (err) {
DBG("Failed allocating CQ buffer\n");
- free(cq->db);
- return MTNIC_ERROR;
+ free_memblock(cq->db, sizeof(struct mtnic_cq_db_record));
+ return -EADDRINUSE;
}
- memset(cq->buf, 0, cq->buf_size);
- DBG("Allocated CQ (addr:%p) - size:%lx buf:%p buf_size:%lx "
+ memset(cq->buf, 0, cq->buf_size);
+ DBG("Allocated CQ (addr:%p) - size:%x buf:%p buf_size:%x "
"dma:%lx db:%p db_dma:%lx\n"
- "cqn offset:%lx \n", cq, cq->size, cq->buf,
+ "cqn offset:%x \n", cq, cq->size, cq->buf,
cq->buf_size, cq->dma, cq->db,
cq->db_dma, offset_ind);
@@ -343,19 +323,20 @@ mtnic_alloc_cq(struct net_device *dev, int num, struct mtnic_cq *cq,
unsigned int
mtnic_alloc_resources(struct net_device *dev)
{
- struct mtnic_priv *priv = netdev_priv(dev);
- int err;
+ struct mtnic_port *priv = netdev_priv(dev);
+ int err;
int cq_ind = 0;
- int cq_offset = priv->fw.cq_offset;
+ int cq_offset = priv->mtnic->fw.cq_offset;
/* Alloc 1st CQ */
- err = mtnic_alloc_cq(dev, cq_ind, &priv->cq[cq_ind], 1 /* RX */,
+ err = mtnic_alloc_cq(dev, cq_ind, &priv->cq[cq_ind], 1 /* RX */,
UNITS_BUFFER_SIZE, cq_offset + cq_ind);
if (err) {
DBG("Failed allocating Rx CQ\n");
- return MTNIC_ERROR;
+ return -EADDRINUSE;
}
+
/* Alloc RX */
err = mtnic_alloc_ring(priv, &priv->rx_ring, UNITS_BUFFER_SIZE,
sizeof(struct mtnic_rx_desc), cq_ind, /* RX */1);
@@ -364,7 +345,8 @@ mtnic_alloc_resources(struct net_device *dev)
goto cq0_error;
}
- ++cq_ind;
+
+ ++cq_ind;
/* alloc 2nd CQ */
err = mtnic_alloc_cq(dev, cq_ind, &priv->cq[cq_ind], 0 /* TX */,
@@ -385,17 +367,18 @@ mtnic_alloc_resources(struct net_device *dev)
return 0;
cq1_error:
- free(priv->cq[1].buf);
- free(priv->cq[1].db);
+ free_memblock(priv->cq[1].buf, priv->cq[1].buf_size);
+ free_memblock(priv->cq[1].db, sizeof(struct mtnic_cq_db_record));
+
rx_error:
- free(priv->rx_ring.buf);
- free(priv->rx_ring.db);
+ free_memblock(priv->rx_ring.buf, priv->rx_ring.buf_size);
+ free_memblock(priv->rx_ring.db, sizeof(struct mtnic_cq_db_record));
mtnic_free_io_buffers(&priv->rx_ring);
cq0_error:
- free(priv->cq[0].buf);
- free(priv->cq[0].db);
+ free_memblock(priv->cq[0].buf, priv->cq[0].buf_size);
+ free_memblock(priv->cq[0].db, sizeof(struct mtnic_cq_db_record));
- return MTNIC_ERROR;
+ return -EADDRINUSE;
}
@@ -405,35 +388,35 @@ cq0_error:
* Note: EQ is not used by the driver but must be allocated
*/
static int
-mtnic_alloc_eq(struct mtnic_priv *priv)
+mtnic_alloc_eq(struct mtnic *mtnic)
{
int err;
unsigned int i;
struct mtnic_eqe *eqe_desc = NULL;
/* Allocating doorbell */
- priv->eq_db = ioremap(mtnic_pci_dev.dev.bar[2] +
- priv->fw.eq_db_offset, sizeof(u32));
- if (!priv->eq_db) {
+ mtnic->eq_db = ioremap(mtnic_pci_dev.dev.bar[2] +
+ mtnic->fw.eq_db_offset, sizeof(u32));
+ if (!mtnic->eq_db) {
DBG("Couldn't map EQ doorbell, aborting...\n");
- return MTNIC_ERROR;
+ return -EADDRINUSE;
}
/* Allocating buffer */
- priv->eq.size = NUM_EQES;
- priv->eq.buf_size = priv->eq.size * sizeof(struct mtnic_eqe);
- err = mtnic_alloc_aligned(priv->eq.buf_size, (void *)&priv->eq.buf,
- &priv->eq.dma, PAGE_SIZE);
+ mtnic->eq.size = NUM_EQES;
+ mtnic->eq.buf_size = mtnic->eq.size * sizeof(struct mtnic_eqe);
+ err = mtnic_alloc_aligned(mtnic->eq.buf_size, (void *)&mtnic->eq.buf,
+ &mtnic->eq.dma, PAGE_SIZE);
if (err) {
DBG("Failed allocating EQ buffer\n");
- iounmap(priv->eq_db);
- return MTNIC_ERROR;
+ iounmap(mtnic->eq_db);
+ return -EADDRINUSE;
}
- memset(priv->eq.buf, 0, priv->eq.buf_size);
+ memset(mtnic->eq.buf, 0, mtnic->eq.buf_size);
- for (i = 0; i < priv->eq.size; i++)
- eqe_desc = priv->eq.buf + (sizeof(struct mtnic_eqe) * i);
- eqe_desc->own |= MTNIC_BIT_EQE_OWN;
+ for (i = 0; i < mtnic->eq.size; i++)
+ eqe_desc = mtnic->eq.buf + (sizeof(struct mtnic_eqe) * i);
+ eqe_desc->own |= MTNIC_BIT_EQE_OWN;
mdelay(20);
return 0;
@@ -458,32 +441,32 @@ mtnic_alloc_eq(struct mtnic_priv *priv)
*
*********************************************************************/
static inline int
-cmdif_go_bit(struct mtnic_priv *priv)
+cmdif_go_bit(struct mtnic *mtnic)
{
- struct mtnic_if_cmd_reg *hcr = priv->hcr;
+ struct mtnic_if_cmd_reg *hcr = mtnic->hcr;
u32 status;
int i;
for (i = 0; i < TBIT_RETRIES; i++) {
status = be32_to_cpu(readl(&hcr->status_go_opcode));
if ((status & MTNIC_BC_MASK(MTNIC_MASK_CMD_REG_T_BIT)) ==
- (priv->cmd.tbit << MTNIC_BC_OFF(MTNIC_MASK_CMD_REG_T_BIT))) {
+ (mtnic->cmd.tbit << MTNIC_BC_OFF(MTNIC_MASK_CMD_REG_T_BIT))) {
/* Read expected t-bit - now return go-bit value */
return status & MTNIC_BC_MASK(MTNIC_MASK_CMD_REG_GO_BIT);
}
}
DBG("Invalid tbit after %d retries!\n", TBIT_RETRIES);
- return 1; /* Return busy... */
+ return -EBUSY; /* Return busy... */
}
/* Base Command interface */
static int
-mtnic_cmd(struct mtnic_priv *priv, void *in_imm,
+mtnic_cmd(struct mtnic *mtnic, void *in_imm,
void *out_imm, u32 in_modifier, u16 op)
{
- struct mtnic_if_cmd_reg *hcr = priv->hcr;
+ struct mtnic_if_cmd_reg *hcr = mtnic->hcr;
int err = 0;
u32 out_param_h = 0;
u32 out_param_l = 0;
@@ -497,43 +480,43 @@ mtnic_cmd(struct mtnic_priv *priv, void *in_imm,
token++;
- if (cmdif_go_bit(priv)) {
+ if ( cmdif_go_bit ( mtnic ) ) {
DBG("GO BIT BUSY:%p.\n", hcr + 6);
- err = MTNIC_ERROR;
+ err = -EBUSY;
goto out;
}
if (in_imm) {
in_param_h = *((u32*)in_imm);
in_param_l = *((u32*)in_imm + 1);
} else {
- in_param_l = cpu_to_be32(priv->cmd.mapping);
+ in_param_l = cpu_to_be32(mtnic->cmd.mapping);
}
- out_param_l = cpu_to_be32(priv->cmd.mapping);
+ out_param_l = cpu_to_be32(mtnic->cmd.mapping);
/* writing to MCR */
- writel(in_param_h, &hcr->in_param_h);
- writel(in_param_l, &hcr->in_param_l);
- writel((u32) cpu_to_be32(in_modifier), &hcr->input_modifier);
- writel(out_param_h, &hcr->out_param_h);
- writel(out_param_l, &hcr->out_param_l);
- writel((u32)cpu_to_be32(token << 16), &hcr->token);
+ writel(in_param_h, &hcr->in_param_h);
+ writel(in_param_l, &hcr->in_param_l);
+ writel((u32) cpu_to_be32(in_modifier), &hcr->input_modifier);
+ writel(out_param_h, &hcr->out_param_h);
+ writel(out_param_l, &hcr->out_param_l);
+ writel((u32)cpu_to_be32(token << 16), &hcr->token);
wmb();
/* flip toggle bit before each write to the HCR */
- priv->cmd.tbit = !priv->cmd.tbit;
- writel((u32)
+ mtnic->cmd.tbit = !mtnic->cmd.tbit;
+ writel( ( u32 )
cpu_to_be32(MTNIC_BC_MASK(MTNIC_MASK_CMD_REG_GO_BIT) |
- (priv->cmd.tbit << MTNIC_BC_OFF(MTNIC_MASK_CMD_REG_T_BIT)) | op),
+ ( mtnic->cmd.tbit << MTNIC_BC_OFF ( MTNIC_MASK_CMD_REG_T_BIT ) ) | op ),
&hcr->status_go_opcode);
- while (cmdif_go_bit(priv) && (timeout <= GO_BIT_TIMEOUT)) {
- mdelay(1);
+ while ( cmdif_go_bit ( mtnic ) && ( timeout <= GO_BIT_TIMEOUT ) ) {
+ mdelay ( 1 );
++timeout;
}
- if (cmdif_go_bit(priv)) {
+ if ( cmdif_go_bit ( mtnic ) ) {
DBG("Command opcode:0x%x token:0x%x TIMEOUT.\n", op, token);
- err = MTNIC_ERROR;
+ err = -EBUSY;
goto out;
}
@@ -543,10 +526,10 @@ mtnic_cmd(struct mtnic_priv *priv, void *in_imm,
}
status = be32_to_cpu((u32)readl(&hcr->status_go_opcode)) >> 24;
- /*DBG("Command opcode:0x%x token:0x%x returned:0x%lx\n",
- op, token, status);*/
if (status) {
+ DBG("Command opcode:0x%x token:0x%x returned:0x%x\n",
+ op, token, status);
return status;
}
@@ -556,12 +539,12 @@ out:
/* MAP PAGES wrapper */
static int
-mtnic_map_cmd(struct mtnic_priv *priv, u16 op, struct mtnic_pages pages)
+mtnic_map_cmd(struct mtnic *mtnic, u16 op, struct mtnic_pages pages)
{
- unsigned int j;
+ unsigned int j;
u32 addr;
unsigned int len;
- u32 *page_arr = priv->cmd.buf;
+ u32 *page_arr = mtnic->cmd.buf;
int nent = 0;
int err = 0;
@@ -570,28 +553,28 @@ mtnic_map_cmd(struct mtnic_priv *priv, u16 op, struct mtnic_pages pages)
len = PAGE_SIZE * pages.num;
pages.buf = (u32 *)umalloc(PAGE_SIZE * (pages.num + 1));
addr = PAGE_SIZE + ((virt_to_bus(pages.buf) & 0xfffff000) + PAGE_SIZE);
- DBG("Mapping pages: size: %lx address: %p\n", pages.num, pages.buf);
+ DBG("Mapping pages: size: %x address: %p\n", pages.num, pages.buf);
if (addr & (PAGE_MASK)) {
DBG("Got FW area not aligned to %d (%llx/%x)\n",
PAGE_SIZE, (u64) addr, len);
- return MTNIC_ERROR;
+ return -EADDRINUSE;
}
/* Function maps each PAGE seperately */
for (j = 0; j < len; j+= PAGE_SIZE) {
page_arr[nent * 4 + 3] = cpu_to_be32(addr + j);
if (++nent == MTNIC_MAILBOX_SIZE / 16) {
- err = mtnic_cmd(priv, NULL, NULL, nent, op);
+ err = mtnic_cmd(mtnic, NULL, NULL, nent, op);
if (err)
- return MTNIC_ERROR;
- nent = 0;
+ return -EIO;
+ nent = 0;
}
}
- if (nent)
- err = mtnic_cmd(priv, NULL, NULL, nent, op);
-
+ if (nent) {
+ err = mtnic_cmd(mtnic, NULL, NULL, nent, op);
+ }
return err;
}
@@ -601,45 +584,44 @@ mtnic_map_cmd(struct mtnic_priv *priv, u16 op, struct mtnic_pages pages)
* Query FW
*/
static int
-mtnic_QUERY_FW(struct mtnic_priv *priv)
+mtnic_QUERY_FW ( struct mtnic *mtnic )
{
int err;
- struct mtnic_if_query_fw_out_mbox *cmd = priv->cmd.buf;
+ struct mtnic_if_query_fw_out_mbox *cmd = mtnic->cmd.buf;
- err = mtnic_cmd(priv, NULL, NULL, 0, MTNIC_IF_CMD_QUERY_FW);
+ err = mtnic_cmd(mtnic, NULL, NULL, 0, MTNIC_IF_CMD_QUERY_FW);
if (err)
- return MTNIC_ERROR;
+ return -EIO;
/* Get FW and interface versions */
- priv->fw_ver = ((u64) be16_to_cpu(cmd->rev_maj) << 32) |
- ((u64) be16_to_cpu(cmd->rev_min) << 16) |
- (u64) be16_to_cpu(cmd->rev_smin);
- priv->fw.ifc_rev = be16_to_cpu(cmd->ifc_rev);
+ mtnic->fw_ver = ((u64) be16_to_cpu(cmd->rev_maj) << 32) |
+ ((u64) be16_to_cpu(cmd->rev_min) << 16) |
+ (u64) be16_to_cpu(cmd->rev_smin);
+ mtnic->fw.ifc_rev = be16_to_cpu(cmd->ifc_rev);
/* Get offset for internal error reports (debug) */
- priv->fw.err_buf.offset = be64_to_cpu(cmd->err_buf_start);
- priv->fw.err_buf.size = be32_to_cpu(cmd->err_buf_size);
+ mtnic->fw.err_buf.offset = be64_to_cpu(cmd->err_buf_start);
+ mtnic->fw.err_buf.size = be32_to_cpu(cmd->err_buf_size);
- DBG("Error buf offset is %llx\n", priv->fw.err_buf.offset);
+ DBG("Error buf offset is %llx\n", mtnic->fw.err_buf.offset);
/* Get number of required FW (4k) pages */
- priv->fw.fw_pages.num = be16_to_cpu(cmd->fw_pages);
+ mtnic->fw.fw_pages.num = be16_to_cpu(cmd->fw_pages);
return 0;
}
static int
-mtnic_OPEN_NIC(struct mtnic_priv *priv)
+mtnic_OPEN_NIC(struct mtnic *mtnic)
{
-
- struct mtnic_if_open_nic_in_mbox *open_nic = priv->cmd.buf;
+ struct mtnic_if_open_nic_in_mbox *open_nic = mtnic->cmd.buf;
u32 extra_pages[2] = {0};
int err;
memset(open_nic, 0, sizeof *open_nic);
- /* port 1 */
+ /* port 1 */
open_nic->log_rx_p1 = 0;
open_nic->log_cq_p1 = 1;
@@ -655,46 +637,47 @@ mtnic_OPEN_NIC(struct mtnic_priv *priv)
open_nic->steer_p2 = MTNIC_IF_STEER_RSS;
/* MAC + VLAN - leave reserved */
- err = mtnic_cmd(priv, NULL, extra_pages, 0, MTNIC_IF_CMD_OPEN_NIC);
- priv->fw.extra_pages.num = be32_to_cpu(*(extra_pages+1));
- DBG("Extra pages num is %lx\n", priv->fw.extra_pages.num);
+ err = mtnic_cmd(mtnic, NULL, extra_pages, 0, MTNIC_IF_CMD_OPEN_NIC);
+
+ mtnic->fw.extra_pages.num = be32_to_cpu(*(extra_pages+1));
+ DBG("Extra pages num is %x\n", mtnic->fw.extra_pages.num);
return err;
}
static int
-mtnic_CONFIG_RX(struct mtnic_priv *priv)
+mtnic_CONFIG_RX(struct mtnic *mtnic)
{
struct mtnic_if_config_rx_in_imm config_rx;
memset(&config_rx, 0, sizeof config_rx);
- return mtnic_cmd(priv, &config_rx, NULL, 0, MTNIC_IF_CMD_CONFIG_RX);
+ return mtnic_cmd(mtnic, &config_rx, NULL, 0, MTNIC_IF_CMD_CONFIG_RX);
}
static int
-mtnic_CONFIG_TX(struct mtnic_priv *priv)
+mtnic_CONFIG_TX(struct mtnic *mtnic)
{
struct mtnic_if_config_send_in_imm config_tx;
config_tx.enph_gpf = 0;
- return mtnic_cmd(priv, &config_tx, NULL, 0, MTNIC_IF_CMD_CONFIG_TX);
+ return mtnic_cmd(mtnic, &config_tx, NULL, 0, MTNIC_IF_CMD_CONFIG_TX);
}
static int
-mtnic_HEART_BEAT(struct mtnic_priv *priv, u32 *link_state)
+mtnic_HEART_BEAT(struct mtnic_port *priv, u32 *link_state)
{
struct mtnic_if_heart_beat_out_imm heart_beat;
int err;
u32 flags;
- err = mtnic_cmd(priv, NULL, &heart_beat, 0, MTNIC_IF_CMD_HEART_BEAT);
+ err = mtnic_cmd(priv->mtnic, NULL, &heart_beat, 0, MTNIC_IF_CMD_HEART_BEAT);
if (!err) {
flags = be32_to_cpu(heart_beat.flags);
if (flags & MTNIC_BC_MASK(MTNIC_MASK_HEAR_BEAT_INT_ERROR)) {
DBG("Internal error detected\n");
- return MTNIC_ERROR;
+ return -EIO;
}
*link_state = flags &
- ~((u32) MTNIC_BC_MASK(MTNIC_MASK_HEAR_BEAT_INT_ERROR));
+ ~((u32) MTNIC_BC_MASK(MTNIC_MASK_HEAR_BEAT_INT_ERROR));
}
return err;
}
@@ -705,31 +688,31 @@ mtnic_HEART_BEAT(struct mtnic_priv *priv, u32 *link_state)
*/
static int
-mtnic_SET_PORT_DEFAULT_RING(struct mtnic_priv *priv, u8 port, u16 ring)
+mtnic_SET_PORT_DEFAULT_RING(struct mtnic_port *priv, u8 port, u16 ring)
{
struct mtnic_if_set_port_default_ring_in_imm def_ring;
memset(&def_ring, 0, sizeof(def_ring));
def_ring.ring = ring;
- return mtnic_cmd(priv, &def_ring, NULL, port + 1,
+ return mtnic_cmd(priv->mtnic, &def_ring, NULL, port + 1,
MTNIC_IF_CMD_SET_PORT_DEFAULT_RING);
}
static int
-mtnic_CONFIG_PORT_RSS_STEER(struct mtnic_priv *priv, int port)
+mtnic_CONFIG_PORT_RSS_STEER(struct mtnic_port *priv, int port)
{
- memset(priv->cmd.buf, 0, PAGE_SIZE);
- return mtnic_cmd(priv, NULL, NULL, port + 1,
- MTNIC_IF_CMD_CONFIG_PORT_RSS_STEER);
+ memset(priv->mtnic->cmd.buf, 0, PAGE_SIZE);
+ return mtnic_cmd(priv->mtnic, NULL, NULL, port + 1,
+ MTNIC_IF_CMD_CONFIG_PORT_RSS_STEER);
}
static int
-mtnic_SET_PORT_RSS_INDIRECTION(struct mtnic_priv *priv, int port)
+mtnic_SET_PORT_RSS_INDIRECTION(struct mtnic_port *priv, int port)
{
- memset(priv->cmd.buf, 0, PAGE_SIZE);
- return mtnic_cmd(priv, NULL, NULL, port + 1,
- MTNIC_IF_CMD_SET_PORT_RSS_INDIRECTION);
+ memset(priv->mtnic->cmd.buf, 0, PAGE_SIZE);
+ return mtnic_cmd(priv->mtnic, NULL, NULL, port + 1,
+ MTNIC_IF_CMD_SET_PORT_RSS_INDIRECTION);
}
@@ -737,89 +720,89 @@ mtnic_SET_PORT_RSS_INDIRECTION(struct mtnic_priv *priv, int port)
* Config commands
*/
static int
-mtnic_CONFIG_CQ(struct mtnic_priv *priv, int port,
- u16 cq_ind, struct mtnic_cq *cq)
+mtnic_CONFIG_CQ(struct mtnic_port *priv, int port,
+ u16 cq_ind, struct mtnic_cq *cq)
{
- struct mtnic_if_config_cq_in_mbox *config_cq = priv->cmd.buf;
+ struct mtnic_if_config_cq_in_mbox *config_cq = priv->mtnic->cmd.buf;
memset(config_cq, 0, sizeof *config_cq);
config_cq->cq = cq_ind;
config_cq->size = fls(UNITS_BUFFER_SIZE - 1);
config_cq->offset = ((cq->dma) & (PAGE_MASK)) >> 6;
config_cq->db_record_addr_l = cpu_to_be32(cq->db_dma);
- config_cq->page_address[1] = cpu_to_be32(cq->dma);
- DBG("config cq address: %lx dma_address: %lx"
- "offset: %d size %d index: %d "
+ config_cq->page_address[1] = cpu_to_be32(cq->dma);
+ DBG("config cq address: %x dma_address: %lx"
+ "offset: %d size %d index: %d\n"
, config_cq->page_address[1],cq->dma,
config_cq->offset, config_cq->size, config_cq->cq );
- return mtnic_cmd(priv, NULL, NULL, port + 1,
- MTNIC_IF_CMD_CONFIG_CQ);
+ return mtnic_cmd(priv->mtnic, NULL, NULL, port + 1,
+ MTNIC_IF_CMD_CONFIG_CQ);
}
static int
-mtnic_CONFIG_TX_RING(struct mtnic_priv *priv, u8 port,
- u16 ring_ind, struct mtnic_ring *ring)
+mtnic_CONFIG_TX_RING(struct mtnic_port *priv, u8 port,
+ u16 ring_ind, struct mtnic_ring *ring)
{
- struct mtnic_if_config_send_ring_in_mbox *config_tx_ring = priv->cmd.buf;
+ struct mtnic_if_config_send_ring_in_mbox *config_tx_ring = priv->mtnic->cmd.buf;
memset(config_tx_ring, 0, sizeof *config_tx_ring);
config_tx_ring->ring = cpu_to_be16(ring_ind);
config_tx_ring->size = fls(UNITS_BUFFER_SIZE - 1);
config_tx_ring->cq = cpu_to_be16(ring->cq);
config_tx_ring->page_address[1] = cpu_to_be32(ring->dma);
- return mtnic_cmd(priv, NULL, NULL, port + 1,
+ return mtnic_cmd(priv->mtnic, NULL, NULL, port + 1,
MTNIC_IF_CMD_CONFIG_TX_RING);
}
static int
-mtnic_CONFIG_RX_RING(struct mtnic_priv *priv, u8 port,
- u16 ring_ind, struct mtnic_ring *ring)
+mtnic_CONFIG_RX_RING(struct mtnic_port *priv, u8 port,
+ u16 ring_ind, struct mtnic_ring *ring)
{
- struct mtnic_if_config_rx_ring_in_mbox *config_rx_ring = priv->cmd.buf;
+ struct mtnic_if_config_rx_ring_in_mbox *config_rx_ring = priv->mtnic->cmd.buf;
memset(config_rx_ring, 0, sizeof *config_rx_ring);
config_rx_ring->ring = ring_ind;
- MTNIC_BC_PUT(config_rx_ring->stride_size, fls(UNITS_BUFFER_SIZE - 1),
- MTNIC_MASK_CONFIG_RX_RING_SIZE);
- MTNIC_BC_PUT(config_rx_ring->stride_size, 1,
- MTNIC_MASK_CONFIG_RX_RING_STRIDE);
+ MTNIC_BC_PUT(config_rx_ring->stride_size, fls(UNITS_BUFFER_SIZE - 1),
+ MTNIC_MASK_CONFIG_RX_RING_SIZE);
+ MTNIC_BC_PUT(config_rx_ring->stride_size, 1,
+ MTNIC_MASK_CONFIG_RX_RING_STRIDE);
config_rx_ring->cq = cpu_to_be16(ring->cq);
config_rx_ring->db_record_addr_l = cpu_to_be32(ring->db_dma);
- DBG("Config RX ring starting at address:%lx\n", ring->dma);
+ DBG("Config RX ring starting at address:%lx\n", ring->dma);
config_rx_ring->page_address[1] = cpu_to_be32(ring->dma);
- return mtnic_cmd(priv, NULL, NULL, port + 1,
- MTNIC_IF_CMD_CONFIG_RX_RING);
+ return mtnic_cmd(priv->mtnic, NULL, NULL, port + 1,
+ MTNIC_IF_CMD_CONFIG_RX_RING);
}
static int
-mtnic_CONFIG_EQ(struct mtnic_priv *priv)
+mtnic_CONFIG_EQ(struct mtnic *mtnic)
{
- struct mtnic_if_config_eq_in_mbox *eq = priv->cmd.buf;
+ struct mtnic_if_config_eq_in_mbox *eq = mtnic->cmd.buf;
- if (priv->eq.dma & (PAGE_MASK)) {
+ if (mtnic->eq.dma & (PAGE_MASK)) {
DBG("misalligned eq buffer:%lx\n",
- priv->eq.dma);
- return MTNIC_ERROR;
- }
+ mtnic->eq.dma);
+ return -EADDRINUSE;
+ }
- memset(eq, 0, sizeof *eq);
- MTNIC_BC_PUT(eq->offset, priv->eq.dma >> 6, MTNIC_MASK_CONFIG_EQ_OFFSET);
- MTNIC_BC_PUT(eq->size, fls(priv->eq.size - 1) - 1, MTNIC_MASK_CONFIG_EQ_SIZE);
+ memset(eq, 0, sizeof *eq);
+ MTNIC_BC_PUT(eq->offset, mtnic->eq.dma >> 6, MTNIC_MASK_CONFIG_EQ_OFFSET);
+ MTNIC_BC_PUT(eq->size, fls(mtnic->eq.size - 1) - 1, MTNIC_MASK_CONFIG_EQ_SIZE);
MTNIC_BC_PUT(eq->int_vector, 0, MTNIC_MASK_CONFIG_EQ_INT_VEC);
- eq->page_address[1] = cpu_to_be32(priv->eq.dma);
+ eq->page_address[1] = cpu_to_be32(mtnic->eq.dma);
- return mtnic_cmd(priv, NULL, NULL, 0, MTNIC_IF_CMD_CONFIG_EQ);
+ return mtnic_cmd(mtnic, NULL, NULL, 0, MTNIC_IF_CMD_CONFIG_EQ);
}
static int
-mtnic_SET_RX_RING_ADDR(struct mtnic_priv *priv, u8 port, u64* mac)
+mtnic_SET_RX_RING_ADDR(struct mtnic_port *priv, u8 port, u64* mac)
{
struct mtnic_if_set_rx_ring_addr_in_imm ring_addr;
u32 modifier = ((u32) port + 1) << 16;
@@ -829,63 +812,64 @@ mtnic_SET_RX_RING_ADDR(struct mtnic_priv *priv, u8 port, u64* mac)
ring_addr.mac_31_0 = cpu_to_be32(*mac & 0xffffffff);
ring_addr.mac_47_32 = cpu_to_be16((*mac >> 32) & 0xffff);
ring_addr.flags_vlan_id |= cpu_to_be16(
- MTNIC_BC_MASK(MTNIC_MASK_SET_RX_RING_ADDR_BY_MAC));
+ MTNIC_BC_MASK(MTNIC_MASK_SET_RX_RING_ADDR_BY_MAC));
- return mtnic_cmd(priv, &ring_addr, NULL, modifier, MTNIC_IF_CMD_SET_RX_RING_ADDR);
+ return mtnic_cmd(priv->mtnic, &ring_addr, NULL, modifier, MTNIC_IF_CMD_SET_RX_RING_ADDR);
}
static int
-mtnic_SET_PORT_STATE(struct mtnic_priv *priv, u8 port, u8 state)
+mtnic_SET_PORT_STATE(struct mtnic_port *priv, u8 port, u8 state)
{
struct mtnic_if_set_port_state_in_imm port_state;
port_state.state = state ? cpu_to_be32(
- MTNIC_BC_MASK(MTNIC_MASK_CONFIG_PORT_STATE)) : 0;
+ MTNIC_BC_MASK(MTNIC_MASK_CONFIG_PORT_STATE)) : 0;
port_state.reserved = 0;
- return mtnic_cmd(priv, &port_state, NULL, port + 1,
+ return mtnic_cmd(priv->mtnic, &port_state, NULL, port + 1,
MTNIC_IF_CMD_SET_PORT_STATE);
}
static int
-mtnic_SET_PORT_MTU(struct mtnic_priv *priv, u8 port, u16 mtu)
+mtnic_SET_PORT_MTU(struct mtnic_port *priv, u8 port, u16 mtu)
{
struct mtnic_if_set_port_mtu_in_imm set_mtu;
memset(&set_mtu, 0, sizeof(set_mtu));
set_mtu.mtu = cpu_to_be16(mtu);
- return mtnic_cmd(priv, &set_mtu, NULL, port + 1,
- MTNIC_IF_CMD_SET_PORT_MTU);
+ return mtnic_cmd(priv->mtnic, &set_mtu, NULL, port + 1,
+ MTNIC_IF_CMD_SET_PORT_MTU);
}
-
+/*
static int
-mtnic_CONFIG_PORT_VLAN_FILTER(struct mtnic_priv *priv, int port)
+mtnic_CONFIG_PORT_VLAN_FILTER(struct mtnic_port *priv, int port)
{
- struct mtnic_if_config_port_vlan_filter_in_mbox *vlan_filter = priv->cmd.buf;
+ struct mtnic_if_config_port_vlan_filter_in_mbox *vlan_filter = priv->mtnic->cmd.buf;
- /* When no vlans are configured we disable the filter
- * (i.e., pass all vlans) because we ignore them anyhow */
+ // When no vlans are configured we disable the filter
+ // (i.e., pass all vlans) because we ignore them anyhow
memset(vlan_filter, 0xff, sizeof(*vlan_filter));
- return mtnic_cmd(priv, NULL, NULL, port + 1,
- MTNIC_IF_CMD_CONFIG_PORT_VLAN_FILTER);
+ return mtnic_cmd(priv->mtnic, NULL, NULL, port + 1,
+ MTNIC_IF_CMD_CONFIG_PORT_VLAN_FILTER);
}
+*/
static int
-mtnic_RELEASE_RESOURCE(struct mtnic_priv *priv, u8 port, u8 type, u8 index)
+mtnic_RELEASE_RESOURCE(struct mtnic_port *priv, u8 port, u8 type, u8 index)
{
struct mtnic_if_release_resource_in_imm rel;
memset(&rel, 0, sizeof rel);
rel.index = index;
rel.type = type;
- return mtnic_cmd(priv,
- &rel, NULL, (type == MTNIC_IF_RESOURCE_TYPE_EQ) ?
- 0 : port + 1, MTNIC_IF_CMD_RELEASE_RESOURCE);
+ return mtnic_cmd ( priv->mtnic,
+ &rel, NULL, ( type == MTNIC_IF_RESOURCE_TYPE_EQ ) ?
+ 0 : port + 1, MTNIC_IF_CMD_RELEASE_RESOURCE );
}
static int
-mtnic_QUERY_CAP(struct mtnic_priv *priv, u8 index, u8 mod, u64 *result)
+mtnic_QUERY_CAP(struct mtnic *mtnic, u8 index, u8 mod, u64 *result)
{
struct mtnic_if_query_cap_in_imm cap;
u32 out_imm[2];
@@ -894,7 +878,7 @@ mtnic_QUERY_CAP(struct mtnic_priv *priv, u8 index, u8 mod, u64 *result)
memset(&cap, 0, sizeof cap);
cap.cap_index = index;
cap.cap_modifier = mod;
- err = mtnic_cmd(priv, &cap, &out_imm, 0, MTNIC_IF_CMD_QUERY_CAP);
+ err = mtnic_cmd(mtnic, &cap, &out_imm, 0, MTNIC_IF_CMD_QUERY_CAP);
*((u32*)result) = be32_to_cpu(*(out_imm+1));
*((u32*)result + 1) = be32_to_cpu(*out_imm);
@@ -906,28 +890,38 @@ mtnic_QUERY_CAP(struct mtnic_priv *priv, u8 index, u8 mod, u64 *result)
#define DO_QUERY_CAP(cap, mod, var) \
- err = mtnic_QUERY_CAP(priv, cap, mod, &result); \
+ err = mtnic_QUERY_CAP(mtnic, cap, mod, &result);\
if (err) \
return err; \
(var) = result
static int
-mtnic_query_cap(struct mtnic_priv *priv)
+mtnic_query_num_ports(struct mtnic *mtnic)
+{
+ int err = 0;
+ u64 result;
+
+ DO_QUERY_CAP(MTNIC_IF_CAP_NUM_PORTS, 0, mtnic->fw.num_ports);
+
+ return 0;
+}
+
+static int
+mtnic_query_mac(struct mtnic *mtnic)
{
int err = 0;
int i;
- u64 result;
+ u64 result;
- DO_QUERY_CAP(MTNIC_IF_CAP_NUM_PORTS, 0, priv->fw.num_ports);
- for (i = 0; i < priv->fw.num_ports; i++) {
- DO_QUERY_CAP(MTNIC_IF_CAP_DEFAULT_MAC, i + 1, priv->fw.mac[i]);
+ for (i = 0; i < mtnic->fw.num_ports; i++) {
+ DO_QUERY_CAP(MTNIC_IF_CAP_DEFAULT_MAC, i + 1, mtnic->fw.mac[i]);
}
return 0;
}
static int
-mtnic_query_offsets(struct mtnic_priv *priv)
+mtnic_query_offsets(struct mtnic *mtnic)
{
int err;
int i;
@@ -935,18 +929,18 @@ mtnic_query_offsets(struct mtnic_priv *priv)
DO_QUERY_CAP(MTNIC_IF_CAP_MEM_KEY,
MTNIC_IF_MEM_TYPE_SNOOP,
- priv->fw.mem_type_snoop_be);
- priv->fw.mem_type_snoop_be = cpu_to_be32(priv->fw.mem_type_snoop_be);
- DO_QUERY_CAP(MTNIC_IF_CAP_TX_CQ_DB_OFFSET, 0, priv->fw.txcq_db_offset);
- DO_QUERY_CAP(MTNIC_IF_CAP_EQ_DB_OFFSET, 0, priv->fw.eq_db_offset);
+ mtnic->fw.mem_type_snoop_be);
+ mtnic->fw.mem_type_snoop_be = cpu_to_be32(mtnic->fw.mem_type_snoop_be);
+ DO_QUERY_CAP(MTNIC_IF_CAP_TX_CQ_DB_OFFSET, 0, mtnic->fw.txcq_db_offset);
+ DO_QUERY_CAP(MTNIC_IF_CAP_EQ_DB_OFFSET, 0, mtnic->fw.eq_db_offset);
- for (i = 0; i < priv->fw.num_ports; i++) {
- DO_QUERY_CAP(MTNIC_IF_CAP_CQ_OFFSET, i + 1, priv->fw.cq_offset);
- DO_QUERY_CAP(MTNIC_IF_CAP_TX_OFFSET, i + 1, priv->fw.tx_offset[i]);
- DO_QUERY_CAP(MTNIC_IF_CAP_RX_OFFSET, i + 1, priv->fw.rx_offset[i]);
- DBG("--> Port %d CQ offset:0x%x\n", i, priv->fw.cq_offset);
- DBG("--> Port %d Tx offset:0x%x\n", i, priv->fw.tx_offset[i]);
- DBG("--> Port %d Rx offset:0x%x\n", i, priv->fw.rx_offset[i]);
+ for (i = 0; i < mtnic->fw.num_ports; i++) {
+ DO_QUERY_CAP(MTNIC_IF_CAP_CQ_OFFSET, i + 1, mtnic->fw.cq_offset);
+ DO_QUERY_CAP(MTNIC_IF_CAP_TX_OFFSET, i + 1, mtnic->fw.tx_offset[i]);
+ DO_QUERY_CAP(MTNIC_IF_CAP_RX_OFFSET, i + 1, mtnic->fw.rx_offset[i]);
+ DBG("--> Port %d CQ offset:0x%x\n", i, mtnic->fw.cq_offset);
+ DBG("--> Port %d Tx offset:0x%x\n", i, mtnic->fw.tx_offset[i]);
+ DBG("--> Port %d Rx offset:0x%x\n", i, mtnic->fw.rx_offset[i]);
}
mdelay(20);
@@ -976,11 +970,12 @@ mtnic_query_offsets(struct mtnic_priv *priv)
* Reset device
*/
void
-mtnic_reset(void)
+mtnic_reset ( void )
{
- void *reset = ioremap(mtnic_pci_dev.dev.bar[0] + MTNIC_RESET_OFFSET, 4);
- writel(cpu_to_be32(1), reset);
- iounmap(reset);
+ void *reset = ioremap ( mtnic_pci_dev.dev.bar[0] + MTNIC_RESET_OFFSET,
+ 4 );
+ writel ( cpu_to_be32 ( 1 ), reset );
+ iounmap ( reset );
}
@@ -1018,18 +1013,18 @@ mtnic_init_pci(struct pci_device *dev)
int err;
/* save bars */
- DBG("bus=%d devfn=0x%x", dev->bus, dev->devfn);
+ DBG("bus=%d devfn=0x%x\n", dev->bus, dev->devfn);
for (i = 0; i < 6; ++i) {
mtnic_pci_dev.dev.bar[i] =
- pci_bar_start(dev, PCI_BASE_ADDRESS_0 + (i << 2));
+ pci_bar_start(dev, PCI_BASE_ADDRESS_0 + (i << 2));
DBG("bar[%d]= 0x%08lx \n", i, mtnic_pci_dev.dev.bar[i]);
}
/* save config space */
for (i = 0; i < 64; ++i) {
err = pci_read_config_dword(dev, i << 2,
- &mtnic_pci_dev.dev.
- dev_config_space[i]);
+ &mtnic_pci_dev.dev.
+ dev_config_space[i]);
if (err) {
DBG("Can not save configuration space");
return err;
@@ -1038,144 +1033,140 @@ mtnic_init_pci(struct pci_device *dev)
mtnic_pci_dev.dev.dev = dev;
- return 0;
+ return 0;
}
/**
* Initial hardware
*/
static inline
-int mtnic_init_card(struct net_device *dev)
+int mtnic_init_card(struct mtnic *mtnic)
{
- struct mtnic_priv *priv = netdev_priv(dev);
int err = 0;
- /* Set state */
- priv->state = CARD_DOWN;
- /* Set port */
- priv->port = MTNIC_PORT_NUM;
-
- /* Alloc command interface */
- err = mtnic_alloc_cmdif(priv);
+ /* Alloc command interface */
+ err = mtnic_alloc_cmdif ( mtnic );
if (err) {
- DBG("Failed to init command interface, aborting.\n");
- return MTNIC_ERROR;
+ DBG("Failed to init command interface, aborting\n");
+ return -EADDRINUSE;
}
-
- /**
- * Bring up HW
- */
- err = mtnic_QUERY_FW(priv);
+ /**
+ * Bring up HW
+ */
+ err = mtnic_QUERY_FW ( mtnic );
if (err) {
- DBG("QUERY_FW command failed, aborting.\n");
+ DBG("QUERY_FW command failed, aborting\n");
goto cmd_error;
}
-
- DBG("Command interface revision:%d\n", priv->fw.ifc_rev);
+ DBG("Command interface revision:%d\n", mtnic->fw.ifc_rev);
/* Allocate memory for FW and start it */
- err = mtnic_map_cmd(priv, MTNIC_IF_CMD_MAP_FW, priv->fw.fw_pages);
+ err = mtnic_map_cmd(mtnic, MTNIC_IF_CMD_MAP_FW, mtnic->fw.fw_pages);
if (err) {
DBG("Eror In MAP_FW\n");
- if (priv->fw.fw_pages.buf)
- free(priv->fw.fw_pages.buf);
+ if (mtnic->fw.fw_pages.buf)
+ ufree((intptr_t)mtnic->fw.fw_pages.buf);
goto cmd_error;
}
/* Run firmware */
- err = mtnic_cmd(priv, NULL, NULL, 0, MTNIC_IF_CMD_RUN_FW);
+ err = mtnic_cmd(mtnic, NULL, NULL, 0, MTNIC_IF_CMD_RUN_FW);
if (err) {
DBG("Eror In RUN FW\n");
goto map_fw_error;
}
- DBG("FW version:%d.%d.%d\n",
- (u16) (priv->fw_ver >> 32),
- (u16) ((priv->fw_ver >> 16) & 0xffff),
- (u16) (priv->fw_ver & 0xffff));
+ DBG("FW version:%d.%d.%d\n",
+ (u16) (mtnic->fw_ver >> 32),
+ (u16) ((mtnic->fw_ver >> 16) & 0xffff),
+ (u16) (mtnic->fw_ver & 0xffff));
- /* Get device information */
- err = mtnic_query_cap(priv);
+ /* Query num ports */
+ err = mtnic_query_num_ports(mtnic);
if (err) {
- DBG("Insufficient resources, aborting.\n");
+ DBG("Insufficient resources, aborting\n");
goto map_fw_error;
}
/* Open NIC */
- err = mtnic_OPEN_NIC(priv);
+ err = mtnic_OPEN_NIC(mtnic);
if (err) {
- DBG("Failed opening NIC, aborting.\n");
+ DBG("Failed opening NIC, aborting\n");
goto map_fw_error;
}
/* Allocate and map pages worksace */
- err = mtnic_map_cmd(priv, MTNIC_IF_CMD_MAP_PAGES, priv->fw.extra_pages);
+ err = mtnic_map_cmd(mtnic, MTNIC_IF_CMD_MAP_PAGES, mtnic->fw.extra_pages);
+ if (err) {
+ DBG("Couldn't allocate %x FW extra pages, aborting\n",
+ mtnic->fw.extra_pages.num);
+ if (mtnic->fw.extra_pages.buf)
+ ufree((intptr_t)mtnic->fw.extra_pages.buf);
+ goto map_fw_error;
+ }
+
+
+ /* Get device information */
+ err = mtnic_query_mac(mtnic);
if (err) {
- DBG("Couldn't allocate %lx FW extra pages, aborting.\n",
- priv->fw.extra_pages.num);
- if (priv->fw.extra_pages.buf)
- free(priv->fw.extra_pages.buf);
+ DBG("Insufficient resources in quesry mac, aborting\n");
goto map_fw_error;
}
/* Get device offsets */
- err = mtnic_query_offsets(priv);
+ err = mtnic_query_offsets(mtnic);
if (err) {
- DBG("Failed retrieving resource offests, aborting.\n");
- free(priv->fw.extra_pages.buf);
+ DBG("Failed retrieving resource offests, aborting\n");
+ ufree((intptr_t)mtnic->fw.extra_pages.buf);
goto map_extra_error;
}
- /* Alloc EQ */
- err = mtnic_alloc_eq(priv);
+ /* Alloc EQ */
+ err = mtnic_alloc_eq(mtnic);
if (err) {
DBG("Failed init shared resources. error: %d\n", err);
goto map_extra_error;
- }
+ }
/* Configure HW */
- err = mtnic_CONFIG_EQ(priv);
+ err = mtnic_CONFIG_EQ(mtnic);
if (err) {
DBG("Failed configuring EQ\n");
goto eq_error;
}
- err = mtnic_CONFIG_RX(priv);
+ err = mtnic_CONFIG_RX(mtnic);
if (err) {
DBG("Failed Rx configuration\n");
goto eq_error;
}
- err = mtnic_CONFIG_TX(priv);
+ err = mtnic_CONFIG_TX(mtnic);
if (err) {
DBG("Failed Tx configuration\n");
goto eq_error;
}
- DBG("Activating port:%d\n", MTNIC_PORT_NUM + 1);
-
- priv->state = CARD_INITIALIZED;
return 0;
eq_error:
- iounmap(priv->eq_db);
- free(priv->eq.buf);
+ iounmap(mtnic->eq_db);
+ free_memblock(mtnic->eq.buf, mtnic->eq.buf_size);
map_extra_error:
- free(priv->fw.extra_pages.buf);
+ ufree((intptr_t)mtnic->fw.extra_pages.buf);
map_fw_error:
- free(priv->fw.fw_pages.buf);
+ ufree((intptr_t)mtnic->fw.fw_pages.buf);
cmd_error:
- iounmap(priv->hcr);
- free(priv->cmd.buf);
- free(priv);
+ iounmap(mtnic->hcr);
+ free_memblock(mtnic->cmd.buf, PAGE_SIZE);
- return MTNIC_ERROR;
+ return -EADDRINUSE;
}
@@ -1195,7 +1186,7 @@ cmd_error:
*
*
********************************************************************/
-void mtnic_process_tx_cq(struct mtnic_priv *priv, struct net_device *dev,
+void mtnic_process_tx_cq(struct mtnic_port *priv, struct net_device *dev,
struct mtnic_cq *cq)
{
struct mtnic_cqe *cqe = cq->buf;
@@ -1209,10 +1200,10 @@ void mtnic_process_tx_cq(struct mtnic_priv *priv, struct net_device *dev,
/* Owner bit changes every round */
while (XNOR(cqe->op_tr_own & MTNIC_BIT_CQ_OWN, cq->last & cq->size)) {
netdev_tx_complete (dev, ring->iobuf[index]);
- ++cq->last;
- index = cq->last & (cq->size-1);
+ ++cq->last;
+ index = cq->last & (cq->size-1);
cqe = &cq->buf[index];
- }
+ }
/* Update consumer index */
cq->db->update_ci = cpu_to_be32(cq->last & 0xffffff);
@@ -1221,13 +1212,16 @@ void mtnic_process_tx_cq(struct mtnic_priv *priv, struct net_device *dev,
}
-int mtnic_process_rx_cq(struct mtnic_priv *priv, struct net_device *dev, struct mtnic_cq *cq)
+int mtnic_process_rx_cq(struct mtnic_port *priv,
+ struct net_device *dev,
+ struct mtnic_cq *cq)
{
struct mtnic_cqe *cqe;
struct mtnic_ring *ring = &priv->rx_ring;
int index;
int err;
struct io_buffer *rx_iob;
+ unsigned int length;
/* We assume a 1:1 mapping between CQEs and Rx descriptors, so Rx
@@ -1253,16 +1247,21 @@ int mtnic_process_rx_cq(struct mtnic_priv *priv, struct net_device *dev, struct
/*
* Packet is OK - process it.
*/
- rx_iob = ring->iobuf[index];
- iob_put(rx_iob, DEF_IOBUF_SIZE);
+ length = be32_to_cpu(cqe->byte_cnt);
+ rx_iob = ring->iobuf[index];
+ iob_put(rx_iob, length);
+
/* Add this packet to the receive queue. */
netdev_rx(dev, rx_iob);
- ring->iobuf[index] = NULL;
+ ring->iobuf[index] = NULL;
next:
++cq->last;
index = cq->last & (cq->size-1);
cqe = &cq->buf[index];
+
+
+
}
/* Update consumer index */
@@ -1274,7 +1273,7 @@ next:
err = mtnic_alloc_iobuf(priv, &priv->rx_ring, DEF_IOBUF_SIZE);
if (err) {
DBG("ERROR Allocating io buffer");
- return MTNIC_ERROR;
+ return -EADDRINUSE;
}
}
@@ -1307,24 +1306,27 @@ next:
static int
mtnic_open(struct net_device *dev)
{
- struct mtnic_priv *priv = netdev_priv(dev);
+ struct mtnic_port *priv = netdev_priv(dev);
+
int err = 0;
struct mtnic_ring *ring;
struct mtnic_cq *cq;
int cq_ind = 0;
u32 dev_link_state;
+ int link_check;
- DBG("starting port:%d", priv->port);
+ DBG("starting port:%d, MAC Address: 0x%12llx\n",
+ priv->port, priv->mtnic->fw.mac[priv->port]);
/* Alloc and configure CQs, TX, RX */
- err = mtnic_alloc_resources(dev);
+ err = mtnic_alloc_resources ( dev );
if (err) {
DBG("Error allocating resources\n");
- return MTNIC_ERROR;
+ return -EADDRINUSE;
}
/* Pass CQs configuration to HW */
- for (cq_ind = 0; cq_ind < NUM_CQS; ++cq_ind) {
+ for (cq_ind = 0; cq_ind < NUM_CQS; ++cq_ind) {
cq = &priv->cq[cq_ind];
err = mtnic_CONFIG_CQ(priv, priv->port, cq_ind, cq);
if (err) {
@@ -1333,24 +1335,25 @@ mtnic_open(struct net_device *dev)
if (cq_ind)
goto cq_error;
else
- return MTNIC_ERROR;
- }
+ goto allocation_error;
+ }
/* Update consumer index */
cq->db->update_ci = cpu_to_be32(cq->last & 0xffffff);
}
+
/* Pass Tx configuration to HW */
ring = &priv->tx_ring;
- err = mtnic_CONFIG_TX_RING(priv, priv->port, 0, ring);
+ err = mtnic_CONFIG_TX_RING(priv, priv->port, 0, ring);
if (err) {
DBG("Failed configuring Tx ring:0\n");
- goto cq_error;
+ goto cq_error;
}
/* Pass RX configuration to HW */
- ring = &priv->rx_ring;
- err = mtnic_CONFIG_RX_RING(priv, priv->port, 0, ring);
+ ring = &priv->rx_ring;
+ err = mtnic_CONFIG_RX_RING(priv, priv->port, 0, ring);
if (err) {
DBG("Failed configuring Rx ring:0\n");
goto tx_error;
@@ -1365,6 +1368,7 @@ mtnic_open(struct net_device *dev)
goto rx_error;
}
+
/* Set the port default ring to ring 0 */
err = mtnic_SET_PORT_DEFAULT_RING(priv, priv->port, 0);
if (err) {
@@ -1373,7 +1377,7 @@ mtnic_open(struct net_device *dev)
}
/* Set Mac address */
- err = mtnic_SET_RX_RING_ADDR(priv, priv->port, &priv->fw.mac[priv->port]);
+ err = mtnic_SET_RX_RING_ADDR(priv, priv->port, &priv->mtnic->fw.mac[priv->port]);
if (err) {
DBG("Failed setting default MAC address\n");
goto rx_error;
@@ -1387,11 +1391,14 @@ mtnic_open(struct net_device *dev)
}
/* Configure VLAN filter */
+ /* By adding this function, The second port won't accept packets
err = mtnic_CONFIG_PORT_VLAN_FILTER(priv, priv->port);
- if (err) {
+ if (err) {
DBG("Failed configuring VLAN filter\n");
goto rx_error;
}
+ */
+
/* Bring up physical link */
err = mtnic_SET_PORT_STATE(priv, priv->port, 1);
@@ -1399,29 +1406,52 @@ mtnic_open(struct net_device *dev)
DBG("Failed bringing up port\n");
goto rx_error;
}
- mdelay(300); /* Let link state stabilize if cable was connected */
+ /* PORT IS UP */
priv->state = CARD_UP;
- err = mtnic_HEART_BEAT(priv, &dev_link_state);
- if (err) {
- DBG("Failed getting device link state\n");
- return MTNIC_ERROR;
+
+ /* Checking Link is up */
+ DBG ( "Checking if link is up\n" );
+
+
+ for ( link_check = 0; link_check < CHECK_LINK_TIMES; link_check ++ ) {
+ /* Let link state stabilize if cable was connected */
+ mdelay ( DELAY_LINK_CHECK );
+
+ err = mtnic_HEART_BEAT(priv, &dev_link_state);
+ if (err) {
+ DBG("Failed getting device link state\n");
+ return -ENETDOWN;
+ }
+
+ if ( dev_link_state & priv->port ) {
+ /* Link is up */
+ break;
+ }
}
- if (!(dev_link_state & 0x3)) {
+
+
+ if ( ! ( dev_link_state & 0x3 ) ) {
DBG("Link down, check cables and restart\n");
- return MTNIC_ERROR;
+ netdev_link_down ( dev );
+ return -ENETDOWN;
}
- return 0;
+ DBG ( "Link is up!\n" );
+ /* Mark as link up */
+ netdev_link_up ( dev );
+
+ return 0;
rx_error:
err = mtnic_RELEASE_RESOURCE(priv, priv->port,
- MTNIC_IF_RESOURCE_TYPE_RX_RING, 0);
+ MTNIC_IF_RESOURCE_TYPE_RX_RING, 0);
tx_error:
err |= mtnic_RELEASE_RESOURCE(priv, priv->port,
MTNIC_IF_RESOURCE_TYPE_TX_RING, 0);
+
cq_error:
while (cq_ind) {
err |= mtnic_RELEASE_RESOURCE(priv, priv->port,
@@ -1430,66 +1460,81 @@ cq_error:
if (err)
DBG("Eror Releasing resources\n");
- return MTNIC_ERROR;
+allocation_error:
+
+ free_memblock(priv->tx_ring.buf, priv->tx_ring.buf_size);
+ iounmap(priv->tx_ring.txcq_db);
+ free_memblock(priv->cq[1].buf, priv->cq[1].buf_size);
+ free_memblock(priv->cq[1].db, sizeof(struct mtnic_cq_db_record));
+ free_memblock(priv->rx_ring.buf, priv->rx_ring.buf_size);
+ free_memblock(priv->rx_ring.db, sizeof(struct mtnic_cq_db_record));
+ free_memblock(priv->cq[0].buf, priv->cq[0].buf_size);
+ free_memblock(priv->cq[0].db, sizeof(struct mtnic_cq_db_record));
+
+ mtnic_free_io_buffers(&priv->rx_ring);
+
+ return -ENETDOWN;
}
+
/** Check if we got completion for receive and transmit and
* check the line with heart_bit command */
static void
-mtnic_poll(struct net_device *dev)
+mtnic_poll ( struct net_device *dev )
{
- struct mtnic_priv *priv = netdev_priv(dev);
+ struct mtnic_port *priv = netdev_priv(dev);
struct mtnic_cq *cq;
u32 dev_link_state;
int err;
unsigned int i;
- /* In case of an old error then return */
+ /* In case of an old error then return */
if (priv->state != CARD_UP)
return;
/* We do not check the device every call _poll call,
- since it will slow it down */
+ since it will slow it down */
if ((priv->poll_counter % ROUND_TO_CHECK) == 0) {
/* Check device */
err = mtnic_HEART_BEAT(priv, &dev_link_state);
if (err) {
DBG("Device has internal error\n");
- priv->state = CARD_DOWN;
+ priv->state = CARD_LINK_DOWN;
return;
}
if (!(dev_link_state & 0x3)) {
DBG("Link down, check cables and restart\n");
- priv->state = CARD_DOWN;
+ priv->state = CARD_LINK_DOWN;
return;
}
}
-
/* Polling CQ */
for (i = 0; i < NUM_CQS; i++) {
cq = &priv->cq[i]; //Passing on the 2 cqs.
if (cq->is_rx) {
- err = mtnic_process_rx_cq(priv, cq->dev, cq);
+ err = mtnic_process_rx_cq(priv, cq->dev, cq);
if (err) {
- priv->state = CARD_DOWN;
+ priv->state = CARD_LINK_DOWN;
DBG(" Error allocating RX buffers\n");
return;
}
- } else {
- mtnic_process_tx_cq(priv, cq->dev, cq);
+ } else {
+ mtnic_process_tx_cq(priv, cq->dev, cq);
}
}
++ priv->poll_counter;
}
+
+
static int
mtnic_transmit( struct net_device *dev, struct io_buffer *iobuf )
{
- struct mtnic_priv *priv = netdev_priv(dev);
+ struct mtnic_port *priv = netdev_priv(dev);
struct mtnic_ring *ring;
struct mtnic_tx_desc *tx_desc;
struct mtnic_data_seg *data;
@@ -1497,34 +1542,34 @@ mtnic_transmit( struct net_device *dev, struct io_buffer *iobuf )
/* In case of an error then return */
if (priv->state != CARD_UP)
- return MTNIC_ERROR;
+ return -ENETDOWN;
ring = &priv->tx_ring;
- index = ring->prod & ring->size_mask;
+ index = ring->prod & ring->size_mask;
if ((ring->prod - ring->cons) >= ring->size) {
- DBG("No space left for descriptors!!! cons: %lx prod: %lx\n",
+ DBG("No space left for descriptors!!! cons: %x prod: %x\n",
ring->cons, ring->prod);
mdelay(5);
- return MTNIC_ERROR;/* no space left */
+ return -EAGAIN;/* no space left */
}
- /* get current descriptor */
+ /* get current descriptor */
tx_desc = ring->buf + (index * sizeof(struct mtnic_tx_desc));
- /* Prepare ctrl segement */
- tx_desc->ctrl.size_vlan = cpu_to_be32(2);
- tx_desc->ctrl.flags = cpu_to_be32(MTNIC_BIT_TX_COMP |
- MTNIC_BIT_NO_ICRC);
- tx_desc->ctrl.op_own = cpu_to_be32(MTNIC_OPCODE_SEND) |
- ((ring->prod & ring->size) ?
- cpu_to_be32(MTNIC_BIT_DESC_OWN) : 0);
-
/* Prepare Data Seg */
data = &tx_desc->data;
data->addr_l = cpu_to_be32((u32)virt_to_bus(iobuf->data));
data->count = cpu_to_be32(iob_len(iobuf));
- data->mem_type = priv->fw.mem_type_snoop_be;
+ data->mem_type = priv->mtnic->fw.mem_type_snoop_be;
+
+ /* Prepare ctrl segement */
+ tx_desc->ctrl.size_vlan = cpu_to_be32(2);
+ tx_desc->ctrl.flags = cpu_to_be32(MTNIC_BIT_TX_COMP |
+ MTNIC_BIT_NO_ICRC);
+ tx_desc->ctrl.op_own = cpu_to_be32(MTNIC_OPCODE_SEND) |
+ ((ring->prod & ring->size) ?
+ cpu_to_be32(MTNIC_BIT_DESC_OWN) : 0);
/* Attach io_buffer */
ring->iobuf[index] = iobuf;
@@ -1543,11 +1588,13 @@ mtnic_transmit( struct net_device *dev, struct io_buffer *iobuf )
static void
mtnic_close(struct net_device *dev)
{
- struct mtnic_priv *priv = netdev_priv(dev);
+ struct mtnic_port *priv = netdev_priv(dev);
int err = 0;
DBG("Close called for port:%d\n", priv->port);
- if (priv->state == CARD_UP) {
+ if ( ( priv->state == CARD_UP ) ||
+ ( priv->state == CARD_LINK_DOWN ) ) {
+
/* Disable port */
err |= mtnic_SET_PORT_STATE(priv, priv->port, 0);
/*
@@ -1565,31 +1612,33 @@ mtnic_close(struct net_device *dev)
/* Stop CQs */
err |= mtnic_RELEASE_RESOURCE(priv, priv->port,
- MTNIC_IF_RESOURCE_TYPE_CQ, 0);
+ MTNIC_IF_RESOURCE_TYPE_CQ, 0);
err |= mtnic_RELEASE_RESOURCE(priv, priv->port,
- MTNIC_IF_RESOURCE_TYPE_CQ, 1);
+ MTNIC_IF_RESOURCE_TYPE_CQ, 1);
if (err) {
- DBG("Close reported error %d", err);
+ DBG("Close reported error %d\n", err);
}
- /* Free memory */
- free(priv->tx_ring.buf);
+ mdelay ( 10 );
+
+ /* free memory */
+ free_memblock(priv->tx_ring.buf, priv->tx_ring.buf_size);
iounmap(priv->tx_ring.txcq_db);
- free(priv->cq[1].buf);
- free(priv->cq[1].db);
+ free_memblock(priv->cq[1].buf, priv->cq[1].buf_size);
+ free_memblock(priv->cq[1].db, sizeof(struct mtnic_cq_db_record));
+ free_memblock(priv->rx_ring.buf, priv->rx_ring.buf_size);
+ free_memblock(priv->rx_ring.db, sizeof(struct mtnic_cq_db_record));
+ free_memblock(priv->cq[0].buf, priv->cq[0].buf_size);
+ free_memblock(priv->cq[0].db, sizeof(struct mtnic_cq_db_record));
/* Free RX buffers */
mtnic_free_io_buffers(&priv->rx_ring);
- free(priv->rx_ring.buf);
- free(priv->rx_ring.db);
- free(priv->cq[0].buf);
- free(priv->cq[0].db);
- priv->state = CARD_INITIALIZED;
}
+ priv->state = CARD_INITIALIZED;
}
@@ -1599,35 +1648,61 @@ mtnic_disable(struct pci_device *pci)
{
int err;
- struct net_device *dev = pci_get_drvdata(pci);
- struct mtnic_priv *priv = netdev_priv(dev);
-
- /* Should NOT happen! but just in case */
- if (priv->state == CARD_UP)
- mtnic_close(dev);
-
- if (priv->state == CARD_INITIALIZED) {
- err = mtnic_RELEASE_RESOURCE(priv, 0,
- MTNIC_IF_RESOURCE_TYPE_EQ, 0);
- DBG("Calling MTNIC_CLOSE command\n");
- err |= mtnic_cmd(priv, NULL, NULL, 0,
- MTNIC_IF_CMD_CLOSE_NIC);
- if (err) {
- DBG("Error Releasing resources %d\n", err);
- }
+ int i;
+ struct mtnic *mtnic = pci_get_drvdata(pci);
+
+
+ struct net_device *dev;
+ struct mtnic_port *priv;
- free(priv->cmd.buf);
- iounmap(priv->hcr);
- ufree((u32)priv->fw.fw_pages.buf);
- ufree((u32)priv->fw.extra_pages.buf);
- free(priv->eq.buf);
- iounmap(priv->eq_db);
- priv->state = CARD_DOWN;
+ for ( i = ( mtnic->fw.num_ports - 1 ); i >= 0; i-- ) {
+
+ dev = mtnic->netdev[i];
+
+ priv = netdev_priv(dev);
+
+ /* Just in case */
+ if ( ( priv->state == CARD_UP ) ||
+ ( priv->state == CARD_LINK_DOWN ) )
+ mtnic_close ( dev );
+ }
+
+ /* Releasing EQ */
+ priv = netdev_priv ( mtnic->netdev[0] );
+ err = mtnic_RELEASE_RESOURCE(priv, 1,
+ MTNIC_IF_RESOURCE_TYPE_EQ, 0);
+
+ DBG("Calling MTNIC_CLOSE command\n");
+ err |= mtnic_cmd(mtnic, NULL, NULL, 0,
+ MTNIC_IF_CMD_CLOSE_NIC);
+ if (err) {
+ DBG("Error Releasing resources %d\n", err);
+ }
+
+ free_memblock(mtnic->cmd.buf, PAGE_SIZE);
+ iounmap(mtnic->hcr);
+ ufree((intptr_t)mtnic->fw.fw_pages.buf);
+ ufree((intptr_t)mtnic->fw.extra_pages.buf);
+ free_memblock(mtnic->eq.buf, mtnic->eq.buf_size);
+ iounmap(mtnic->eq_db);
+
+
+ for ( i = ( mtnic->fw.num_ports - 1 ); i >= 0; i-- ) {
+ dev = mtnic->netdev[i];
+ unregister_netdev ( dev );
+ netdev_nullify ( dev );
+ netdev_put ( dev );
}
- unregister_netdev(dev);
- netdev_nullify(dev);
- netdev_put(dev);
+ free ( mtnic );
+
+
+ mtnic_reset ();
+ mdelay ( 1000 );
+ /* Restore config, if we would like to retry booting */
+ restore_config ();
+
+
}
@@ -1642,11 +1717,11 @@ mtnic_irq(struct net_device *netdev __unused, int enable __unused)
/** mtnic net device operations */
static struct net_device_operations mtnic_operations = {
- .open = mtnic_open,
- .close = mtnic_close,
- .transmit = mtnic_transmit,
- .poll = mtnic_poll,
- .irq = mtnic_irq,
+ .open = mtnic_open,
+ .close = mtnic_close,
+ .transmit = mtnic_transmit,
+ .poll = mtnic_poll,
+ .irq = mtnic_irq,
};
@@ -1657,102 +1732,119 @@ static struct net_device_operations mtnic_operations = {
static int
mtnic_probe(struct pci_device *pci,
- const struct pci_device_id *id __unused)
+ const struct pci_device_id *id __unused)
{
- struct net_device *dev;
- struct mtnic_priv *priv;
+ struct mtnic_port *priv;
+ struct mtnic *mtnic;
int err;
u64 mac;
- u32 result = 0;
- void *dev_id;
- int i;
+ int port_index;
+
- adjust_pci_device(pci);
+ adjust_pci_device(pci);
- err = mtnic_init_pci(pci);
+ err = mtnic_init_pci(pci);
if (err) {
DBG("Error in pci_init\n");
- return MTNIC_ERROR;
+ return -EIO;
}
mtnic_reset();
- mdelay(1000);
+ mdelay(1000);
- err = restore_config();
+ err = restore_config();
if (err) {
- DBG("Error restoring config\n");
+ DBG("Error in restoring config\n");
return err;
}
- /* Checking MTNIC device ID */
- dev_id = ioremap(mtnic_pci_dev.dev.bar[0] +
- MTNIC_DEVICE_ID_OFFSET, 4);
- result = ntohl(readl(dev_id));
- iounmap(dev_id);
- if (result != MTNIC_DEVICE_ID) {
- DBG("Wrong Devie ID (0x%lx) !!!", result);
- return MTNIC_ERROR;
+ mtnic = zalloc ( sizeof ( *mtnic ) );
+ if ( ! mtnic ) {
+ DBG ( "Error Allocating mtnic buffer\n" );
+ return -EADDRINUSE;
}
- /* Initializing net device */
- dev = alloc_etherdev(sizeof(struct mtnic_priv));
- if (dev == NULL) {
- DBG("Net device allocation failed\n");
- return MTNIC_ERROR;
- }
- /*
- * Initialize driver private data
- */
- priv = netdev_priv(dev);
- memset(priv, 0, sizeof(struct mtnic_priv));
- priv->dev = dev;
- priv->pdev = pci;
- priv->dev->dev = &pci->dev;
- /* Attach pci device */
- pci_set_drvdata(pci, priv->dev);
- netdev_init(dev, &mtnic_operations);
+ pci_set_drvdata(pci, mtnic);
+
+ mtnic->pdev = pci;
/* Initialize hardware */
- err = mtnic_init_card(dev);
+ err = mtnic_init_card ( mtnic );
if (err) {
DBG("Error in init_card\n");
- return MTNIC_ERROR;
+ goto err_init_card;
}
- /* Program the MAC address */
- mac = priv->fw.mac[priv->port];
- printf("Port %d Mac address: 0x%12llx\n", MTNIC_PORT_NUM + 1, mac);
- for (i = 0;i < MAC_ADDRESS_SIZE; ++i) {
- dev->ll_addr[MAC_ADDRESS_SIZE - i - 1] = mac & 0xFF;
- mac = mac >> 8;
+ for ( port_index = 0; port_index < mtnic->fw.num_ports; port_index ++ ) {
+ /* Initializing net device */
+ mtnic->netdev[port_index] = alloc_etherdev( sizeof ( struct mtnic_port ) );
+ if ( mtnic->netdev[port_index] == NULL ) {
+ DBG("Net device allocation failed\n");
+ goto err_alloc_mtnic;
+ }
+
+ /*
+ * Initialize driver private data
+ */
+
+ mtnic->netdev[port_index]->dev = &pci->dev;
+ priv = netdev_priv ( mtnic->netdev[port_index] );
+ memset ( priv, 0, sizeof ( struct mtnic_port ) );
+ priv->mtnic = mtnic;
+ priv->netdev = mtnic->netdev[port_index];
+
+ /* Attach pci device */
+ netdev_init(mtnic->netdev[port_index], &mtnic_operations);
+
+ /* Set port number */
+ priv->port = port_index;
+
+ /* Set state */
+ priv->state = CARD_DOWN;
}
- /* Mark as link up; we don't yet handle link state */
- netdev_link_up ( dev );
- if (register_netdev(dev)) {
- DBG("Netdev registration failed\n");
- return MTNIC_ERROR;
+ int mac_idx;
+ for ( port_index = 0; port_index < mtnic->fw.num_ports; port_index ++ ) {
+ priv = netdev_priv ( mtnic->netdev[port_index] );
+ /* Program the MAC address */
+ mac = priv->mtnic->fw.mac[port_index];
+ for (mac_idx = 0; mac_idx < MAC_ADDRESS_SIZE; ++mac_idx) {
+ mtnic->netdev[port_index]->ll_addr[MAC_ADDRESS_SIZE - mac_idx - 1] = mac & 0xFF;
+ mac = mac >> 8;
+ }
+
+ if ( register_netdev ( mtnic->netdev[port_index] ) ) {
+ DBG("Netdev registration failed\n");
+ priv->state = CARD_INITIALIZED;
+ goto err_alloc_mtnic;
+ }
}
return 0;
-}
-
+err_alloc_mtnic:
+ free ( mtnic );
+err_init_card:
+ return -EIO;
+}
static struct pci_device_id mtnic_nics[] = {
- PCI_ROM(0x15b3, 0x6368, "mtnic", "Mellanox MTNIC driver"),
+ PCI_ROM ( 0x15b3, 0x6368, "mt25448", "Mellanox ConnectX EN driver" ),
+ PCI_ROM ( 0x15b3, 0x6372, "mt25458", "Mellanox ConnectX ENt driver" ),
+ PCI_ROM ( 0x15b3, 0x6750, "mt26448", "Mellanox ConnectX EN GEN2 driver" ),
+ PCI_ROM ( 0x15b3, 0x675a, "mt26458", "Mellanox ConnectX ENt GEN2 driver" ),
};
struct pci_driver mtnic_driver __pci_driver = {
.ids = mtnic_nics,
.id_count = sizeof(mtnic_nics) / sizeof(mtnic_nics[0]),
- .probe = mtnic_probe,
+ .probe = mtnic_probe,
.remove = mtnic_disable,
};
diff --git a/gpxe/src/drivers/net/mtnic.h b/gpxe/src/drivers/net/mtnic.h
index 70a238e5..57a7b98c 100755..100644
--- a/gpxe/src/drivers/net/mtnic.h
+++ b/gpxe/src/drivers/net/mtnic.h
@@ -38,24 +38,28 @@
/*
* Device setup
*/
-
-/*
- Note port number can be changed under mtnic.c !
-*/
#define MTNIC_MAX_PORTS 2
+#define MTNIC_PORT1 0
+#define MTNIC_PORT2 1
#define NUM_TX_RINGS 1
#define NUM_RX_RINGS 1
#define NUM_CQS (NUM_RX_RINGS + NUM_TX_RINGS)
#define GO_BIT_TIMEOUT 6000
#define TBIT_RETRIES 100
#define UNITS_BUFFER_SIZE 8 /* can be configured to 4/8/16 */
-#define MAX_GAP_PROD_CONS (UNITS_BUFFER_SIZE/4)
-#define DEF_MTU 1600
-#define DEF_IOBUF_SIZE 1600
+#define MAX_GAP_PROD_CONS ( UNITS_BUFFER_SIZE / 4 )
+#define ETH_DEF_LEN 1540 /* 40 bytes used by the card */
+#define ETH_FCS_LEN 14
+#define DEF_MTU ETH_DEF_LEN + ETH_FCS_LEN
+#define DEF_IOBUF_SIZE ETH_DEF_LEN
+
#define MAC_ADDRESS_SIZE 6
#define NUM_EQES 16
#define ROUND_TO_CHECK 0x400
+#define DELAY_LINK_CHECK 300
+#define CHECK_LINK_TIMES 7
+
#define XNOR(x,y) (!(x) == !(y))
#define dma_addr_t unsigned long
@@ -108,7 +112,7 @@ typedef enum mtnic_if_cmd {
MTNIC_IF_CMD_CONFIG_RX = 0x005, /* general receive configuration */
MTNIC_IF_CMD_CONFIG_TX = 0x006, /* general transmit configuration */
MTNIC_IF_CMD_CONFIG_INT_FREQ = 0x007, /* interrupt timers freq limits */
- MTNIC_IF_CMD_HEART_BEAT = 0x008, /* NOP command testing liveliness */
+ MTNIC_IF_CMD_HEART_BEAT = 0x008, /* NOP command testing liveliness */
MTNIC_IF_CMD_CLOSE_NIC = 0x009, /* release memory and stop the NIC */
/* Port commands: */
@@ -119,22 +123,22 @@ typedef enum mtnic_if_cmd {
MTNIC_IF_CMD_CONFIG_PORT_VLAN_FILTER = 0x14, /* configure VLAN filter */
MTNIC_IF_CMD_CONFIG_PORT_MCAST_FILTER = 0x15, /* configure mcast filter */
MTNIC_IF_CMD_ENABLE_PORT_MCAST_FILTER = 0x16, /* enable/disable */
- MTNIC_IF_CMD_SET_PORT_MTU = 0x17, /* set port MTU */
+ MTNIC_IF_CMD_SET_PORT_MTU = 0x17, /* set port MTU */
MTNIC_IF_CMD_SET_PORT_PROMISCUOUS_MODE = 0x18, /* enable/disable promisc */
MTNIC_IF_CMD_SET_PORT_DEFAULT_RING = 0x19, /* set the default ring */
- MTNIC_IF_CMD_SET_PORT_STATE = 0x1a, /* set link up/down */
- MTNIC_IF_CMD_DUMP_STAT = 0x1b, /* dump statistics */
+ MTNIC_IF_CMD_SET_PORT_STATE = 0x1a, /* set link up/down */
+ MTNIC_IF_CMD_DUMP_STAT = 0x1b, /* dump statistics */
MTNIC_IF_CMD_ARM_PORT_STATE_EVENT = 0x1c, /* arm the port state event */
/* Ring / Completion queue commands: */
- MTNIC_IF_CMD_CONFIG_CQ = 0x20, /* set up completion queue */
- MTNIC_IF_CMD_CONFIG_RX_RING = 0x21, /* setup Rx ring */
- MTNIC_IF_CMD_SET_RX_RING_ADDR = 0x22, /* set Rx ring filter by address */
+ MTNIC_IF_CMD_CONFIG_CQ = 0x20, /* set up completion queue */
+ MTNIC_IF_CMD_CONFIG_RX_RING = 0x21, /* setup Rx ring */
+ MTNIC_IF_CMD_SET_RX_RING_ADDR = 0x22, /* set Rx ring filter by address */
MTNIC_IF_CMD_SET_RX_RING_MCAST = 0x23, /* set Rx ring mcast filter */
- MTNIC_IF_CMD_ARM_RX_RING_WM = 0x24, /* one-time low-watermark INT */
- MTNIC_IF_CMD_CONFIG_TX_RING = 0x25, /* set up Tx ring */
+ MTNIC_IF_CMD_ARM_RX_RING_WM = 0x24, /* one-time low-watermark INT */
+ MTNIC_IF_CMD_CONFIG_TX_RING = 0x25, /* set up Tx ring */
MTNIC_IF_CMD_ENFORCE_TX_RING_ADDR = 0x26, /* setup anti spoofing */
- MTNIC_IF_CMD_CONFIG_EQ = 0x27, /* config EQ ring */
+ MTNIC_IF_CMD_CONFIG_EQ = 0x27, /* config EQ ring */
MTNIC_IF_CMD_RELEASE_RESOURCE = 0x28, /* release internal ref to resource */
}
mtnic_if_cmd_t;
@@ -144,15 +148,15 @@ mtnic_if_cmd_t;
typedef enum mtnic_if_caps {
MTNIC_IF_CAP_MAX_TX_RING_PER_PORT = 0x0,
MTNIC_IF_CAP_MAX_RX_RING_PER_PORT = 0x1,
- MTNIC_IF_CAP_MAX_CQ_PER_PORT = 0x2,
- MTNIC_IF_CAP_NUM_PORTS = 0x3,
- MTNIC_IF_CAP_MAX_TX_DESC = 0x4,
- MTNIC_IF_CAP_MAX_RX_DESC = 0x5,
- MTNIC_IF_CAP_MAX_CQES = 0x6,
- MTNIC_IF_CAP_MAX_TX_SG_ENTRIES = 0x7,
- MTNIC_IF_CAP_MAX_RX_SG_ENTRIES = 0x8,
- MTNIC_IF_CAP_MEM_KEY = 0x9, /* key to mem (after map_pages) */
- MTNIC_IF_CAP_RSS_HASH_TYPE = 0xa, /* one of mtnic_if_rss_types_t */
+ MTNIC_IF_CAP_MAX_CQ_PER_PORT = 0x2,
+ MTNIC_IF_CAP_NUM_PORTS = 0x3,
+ MTNIC_IF_CAP_MAX_TX_DESC = 0x4,
+ MTNIC_IF_CAP_MAX_RX_DESC = 0x5,
+ MTNIC_IF_CAP_MAX_CQES = 0x6,
+ MTNIC_IF_CAP_MAX_TX_SG_ENTRIES = 0x7,
+ MTNIC_IF_CAP_MAX_RX_SG_ENTRIES = 0x8,
+ MTNIC_IF_CAP_MEM_KEY = 0x9, /* key to mem (after map_pages) */
+ MTNIC_IF_CAP_RSS_HASH_TYPE = 0xa, /* one of mtnic_if_rss_types_t */
MTNIC_IF_CAP_MAX_PORT_UCAST_ADDR = 0xc,
MTNIC_IF_CAP_MAX_RING_UCAST_ADDR = 0xd, /* only for ADDR steer */
MTNIC_IF_CAP_MAX_PORT_MCAST_ADDR = 0xe,
@@ -164,20 +168,20 @@ typedef enum mtnic_if_caps {
MTNIC_IF_CAP_EQ_DB_OFFSET = 0x14, /* offset in bytes for EQ doorbell record */
/* These are per port - using port number from cap modifier field */
- MTNIC_IF_CAP_SPEED = 0x20,
- MTNIC_IF_CAP_DEFAULT_MAC = 0x21,
- MTNIC_IF_CAP_EQ_OFFSET = 0x22,
- MTNIC_IF_CAP_CQ_OFFSET = 0x23,
+ MTNIC_IF_CAP_SPEED = 0x20,
+ MTNIC_IF_CAP_DEFAULT_MAC = 0x21,
+ MTNIC_IF_CAP_EQ_OFFSET = 0x22,
+ MTNIC_IF_CAP_CQ_OFFSET = 0x23,
MTNIC_IF_CAP_TX_OFFSET = 0x24,
MTNIC_IF_CAP_RX_OFFSET = 0x25,
} mtnic_if_caps_t;
typedef enum mtnic_if_steer_types {
- MTNIC_IF_STEER_NONE = 0,
- MTNIC_IF_STEER_PRIORITY = 1,
- MTNIC_IF_STEER_RSS = 2,
- MTNIC_IF_STEER_ADDRESS = 3,
+ MTNIC_IF_STEER_NONE = 0,
+ MTNIC_IF_STEER_PRIORITY = 1,
+ MTNIC_IF_STEER_RSS = 2,
+ MTNIC_IF_STEER_ADDRESS = 3,
} mtnic_if_steer_types_t;
/** types of memory access modes */
@@ -188,19 +192,12 @@ typedef enum mtnic_if_memory_types {
enum {
- MTNIC_HCR_BASE = 0x1f000,
- MTNIC_HCR_SIZE = 0x0001c,
- MTNIC_CLR_INT_SIZE = 0x00008,
+ MTNIC_HCR_BASE = 0x1f000,
+ MTNIC_HCR_SIZE = 0x0001c,
+ MTNIC_CLR_INT_SIZE = 0x00008,
};
-#define MELLANOX_VENDOR_ID 0x15b3
-#define MTNIC_DEVICE_ID 0x00a00190
#define MTNIC_RESET_OFFSET 0xF0010
-#define MTNIC_DEVICE_ID_OFFSET 0xF0014
-
-
-
-
@@ -265,7 +262,7 @@ struct mtnic_ring {
/* Buffers */
u32 buf_size; /* ring buffer size in bytes */
- dma_addr_t dma;
+ dma_addr_t dma;
void *buf;
struct io_buffer *iobuf[UNITS_BUFFER_SIZE];
@@ -274,7 +271,7 @@ struct mtnic_ring {
u32 db_offset;
/* Rx ring only */
- dma_addr_t iobuf_dma;
+ dma_addr_t iobuf_dma;
struct mtnic_rx_db_record *db;
dma_addr_t db_dma;
};
@@ -351,15 +348,16 @@ struct mtnic_eqe {
struct mtnic_eq {
u32 size; /* number of EQEs in ring */
- u32 buf_size; /* EQ size in bytes */
+ u32 buf_size; /* EQ size in bytes */
void *buf;
dma_addr_t dma;
};
enum mtnic_state {
CARD_DOWN,
- CARD_INITIALIZED,
- CARD_UP
+ CARD_INITIALIZED,
+ CARD_UP,
+ CARD_LINK_DOWN,
};
/* FW */
@@ -375,9 +373,9 @@ struct mtnic_err_buf {
struct mtnic_cmd {
- void *buf;
- u32 mapping;
- u32 tbit;
+ void *buf;
+ unsigned long mapping;
+ u32 tbit;
};
@@ -395,40 +393,52 @@ struct mtnic_txcq_db {
* Device private data
*
*/
-struct mtnic_priv {
- struct net_device *dev;
- struct pci_device *pdev;
- u8 port;
+struct mtnic {
+ struct net_device *netdev[MTNIC_MAX_PORTS];
+ struct mtnic_if_cmd_reg *hcr;
+ struct mtnic_cmd cmd;
+ struct pci_device *pdev;
- enum mtnic_state state;
- /* Firmware and board info */
- u64 fw_ver;
+ struct mtnic_eq eq;
+ u32 *eq_db;
+
+ /* Firmware and board info */
+ u64 fw_ver;
struct {
- struct mtnic_pages fw_pages;
- struct mtnic_pages extra_pages;
- struct mtnic_err_buf err_buf;
- u16 ifc_rev;
- u8 num_ports;
- u64 mac[MTNIC_MAX_PORTS];
- u16 cq_offset;
- u16 tx_offset[MTNIC_MAX_PORTS];
- u16 rx_offset[MTNIC_MAX_PORTS];
- u32 mem_type_snoop_be;
- u32 txcq_db_offset;
- u32 eq_db_offset;
- } fw;
-
-
- struct mtnic_if_cmd_reg *hcr;
- struct mtnic_cmd cmd;
+ struct mtnic_pages fw_pages;
+ struct mtnic_pages extra_pages;
+ struct mtnic_err_buf err_buf;
+ u16 ifc_rev;
+ u8 num_ports;
+ u64 mac[MTNIC_MAX_PORTS];
+ u16 cq_offset;
+ u16 tx_offset[MTNIC_MAX_PORTS];
+ u16 rx_offset[MTNIC_MAX_PORTS];
+ u32 mem_type_snoop_be;
+ u32 txcq_db_offset;
+ u32 eq_db_offset;
+ } fw;
+};
+
+
+
+
+
+struct mtnic_port {
+
+ struct mtnic *mtnic;
+ u8 port;
+
+ enum mtnic_state state;
/* TX, RX, CQs, EQ */
- struct mtnic_ring tx_ring;
- struct mtnic_ring rx_ring;
- struct mtnic_cq cq[NUM_CQS];
- struct mtnic_eq eq;
- u32 *eq_db;
- u32 poll_counter;
+ struct mtnic_ring tx_ring;
+ struct mtnic_ring rx_ring;
+ struct mtnic_cq cq[NUM_CQS];
+ u32 poll_counter;
+ struct net_device *netdev;
+
+
};
@@ -492,33 +502,34 @@ struct mtnic_if_query_fw_out_mbox {
/* CMD MTNIC_IF_CMD_QUERY_CAP */
struct mtnic_if_query_cap_in_imm {
u16 reserved1;
- u8 cap_modifier; /* a modifier for the particular capability */
- u8 cap_index; /* the index of the capability queried */
+ u8 cap_modifier; /* a modifier for the particular capability */
+ u8 cap_index; /* the index of the capability queried */
u32 reserved2;
};
/* CMD OPEN_NIC */
struct mtnic_if_open_nic_in_mbox {
- u16 reserved1;
- u16 mkey; /* number of mem keys for all chip*/
- u32 mkey_entry; /* mem key entries for each key*/
- u8 log_rx_p1; /* log2 rx rings for port1 */
- u8 log_cq_p1; /* log2 cq for port1 */
- u8 log_tx_p1; /* log2 tx rings for port1 */
- u8 steer_p1; /* port 1 steering mode */
- u16 reserved2;
- u8 log_vlan_p1; /* log2 vlan per rx port1 */
- u8 log_mac_p1; /* log2 mac per rx port1 */
-
- u8 log_rx_p2; /* log2 rx rings for port1 */
- u8 log_cq_p2; /* log2 cq for port1 */
- u8 log_tx_p2; /* log2 tx rings for port1 */
- u8 steer_p2; /* port 1 steering mode */
- u16 reserved3;
- u8 log_vlan_p2; /* log2 vlan per rx port1 */
- u8 log_mac_p2; /* log2 mac per rx port1 */
+ u16 reserved1;
+ u16 mkey; /* number of mem keys for all chip*/
+ u32 mkey_entry; /* mem key entries for each key*/
+ u8 log_rx_p1; /* log2 rx rings for port1 */
+ u8 log_cq_p1; /* log2 cq for port1 */
+ u8 log_tx_p1; /* log2 tx rings for port1 */
+ u8 steer_p1; /* port 1 steering mode */
+ u16 reserved2;
+ u8 log_vlan_p1; /* log2 vlan per rx port1 */
+ u8 log_mac_p1; /* log2 mac per rx port1 */
+
+ u8 log_rx_p2; /* log2 rx rings for port1 */
+ u8 log_cq_p2; /* log2 cq for port1 */
+ u8 log_tx_p2; /* log2 tx rings for port1 */
+ u8 steer_p2; /* port 1 steering mode */
+ u16 reserved3;
+ u8 log_vlan_p2; /* log2 vlan per rx port1 */
+ u8 log_mac_p2; /* log2 mac per rx port1 */
};
+
/* CMD CONFIG_RX */
struct mtnic_if_config_rx_in_imm {
u16 spkt_size; /* size of small packets interrupts enabled on CQ */
@@ -535,9 +546,9 @@ struct mtnic_if_config_send_in_imm {
/* CMD HEART_BEAT */
struct mtnic_if_heart_beat_out_imm {
- u32 flags; /* several flags */
+ u32 flags; /* several flags */
#define MTNIC_MASK_HEAR_BEAT_INT_ERROR MTNIC_BC(31,1)
- u32 reserved;
+ u32 reserved;
};
@@ -547,14 +558,14 @@ struct mtnic_if_heart_beat_out_imm {
/* CMD CONFIG_PORT_VLAN_FILTER */
/* in mbox is a 4K bits mask - bit per VLAN */
struct mtnic_if_config_port_vlan_filter_in_mbox {
- u64 filter[64]; /* vlans[63:0] sit in filter[0], vlans[127:64] sit in filter[1] .. */
+ u64 filter[64]; /* vlans[63:0] sit in filter[0], vlans[127:64] sit in filter[1] .. */
};
/* CMD SET_PORT_MTU */
struct mtnic_if_set_port_mtu_in_imm {
u16 reserved1;
- u16 mtu; /* The MTU of the port in bytes */
+ u16 mtu; /* The MTU of the port in bytes */
u32 reserved2;
};
@@ -574,17 +585,17 @@ struct mtnic_if_set_port_state_in_imm {
/* CMD CONFIG_CQ */
struct mtnic_if_config_cq_in_mbox {
- u8 reserved1;
- u8 cq;
- u8 size; /* Num CQs is 2^size (size <= 22) */
- u8 offset; /* start address of CQE in first page (11:6) */
- u16 tlast; /* interrupt moderation timer from last completion usec */
+ u8 reserved1;
+ u8 cq;
+ u8 size; /* Num CQs is 2^size (size <= 22) */
+ u8 offset; /* start address of CQE in first page (11:6) */
+ u16 tlast; /* interrupt moderation timer from last completion usec */
u8 flags; /* flags */
- u8 int_vector; /* MSI index if MSI is enabled, otherwise reserved */
+ u8 int_vector; /* MSI index if MSI is enabled, otherwise reserved */
u16 reserved2;
u16 max_cnt; /* interrupt moderation counter */
- u8 page_size; /* each mapped page is 2^(12+page_size) bytes */
- u8 reserved4[3];
+ u8 page_size; /* each mapped page is 2^(12+page_size) bytes */
+ u8 reserved4[3];
u32 db_record_addr_h; /*physical address of CQ doorbell record */
u32 db_record_addr_l; /*physical address of CQ doorbell record */
u32 page_address[0]; /* 64 bit page addresses of CQ buffer */
@@ -592,21 +603,21 @@ struct mtnic_if_config_cq_in_mbox {
/* CMD CONFIG_RX_RING */
struct mtnic_if_config_rx_ring_in_mbox {
- u8 reserved1;
- u8 ring; /* The ring index (with offset) */
- u8 stride_size; /* stride and size */
+ u8 reserved1;
+ u8 ring; /* The ring index (with offset) */
+ u8 stride_size; /* stride and size */
/* Entry size = 16* (2^stride) bytes */
#define MTNIC_MASK_CONFIG_RX_RING_STRIDE MTNIC_BC(4,3)
/* Rx ring size is 2^size entries */
#define MTNIC_MASK_CONFIG_RX_RING_SIZE MTNIC_BC(0,4)
- u8 flags; /* Bit0 - header separation */
- u8 page_size; /* Each mapped page is 2^(12+page_size) bytes */
- u8 reserved2[2];
- u8 cq; /* CQ associated with this ring */
- u32 db_record_addr_h;
- u32 db_record_addr_l;
- u32 page_address[0];/* Array of 2^size 64b page descriptor addresses */
- /* Must hold all Rx descriptors + doorbell record. */
+ u8 flags; /* Bit0 - header separation */
+ u8 page_size; /* Each mapped page is 2^(12+page_size) bytes */
+ u8 reserved2[2];
+ u8 cq; /* CQ associated with this ring */
+ u32 db_record_addr_h;
+ u32 db_record_addr_l;
+ u32 page_address[0];/* Array of 2^size 64b page descriptor addresses */
+ /* Must hold all Rx descriptors + doorbell record. */
};
/* The modifier for SET_RX_RING_ADDR */
@@ -619,27 +630,27 @@ struct mtnic_if_set_rx_ring_modifier {
/* CMD SET_RX_RING_ADDR */
struct mtnic_if_set_rx_ring_addr_in_imm {
- u16 mac_47_32; /* UCAST MAC Address bits 47:32 */
+ u16 mac_47_32; /* UCAST MAC Address bits 47:32 */
u16 flags_vlan_id; /* MAC/VLAN flags and vlan id */
#define MTNIC_MASK_SET_RX_RING_ADDR_VLAN_ID MTNIC_BC(0,12)
#define MTNIC_MASK_SET_RX_RING_ADDR_BY_MAC MTNIC_BC(12,1)
#define MTNIC_MASK_SET_RX_RING_ADDR_BY_VLAN MTNIC_BC(13,1)
- u32 mac_31_0; /* UCAST MAC Address bits 31:0 */
+ u32 mac_31_0; /* UCAST MAC Address bits 31:0 */
};
/* CMD CONFIG_TX_RING */
struct mtnic_if_config_send_ring_in_mbox {
- u16 ring; /* The ring index (with offset) */
+ u16 ring; /* The ring index (with offset) */
#define MTNIC_MASK_CONFIG_TX_RING_INDEX MTNIC_BC(0,8)
- u8 size; /* Tx ring size is 32*2^size bytes */
+ u8 size; /* Tx ring size is 32*2^size bytes */
#define MTNIC_MASK_CONFIG_TX_RING_SIZE MTNIC_BC(0,4)
- u8 reserved;
- u8 page_size; /* Each mapped page is 2^(12+page_size) bytes */
- u8 qos_class; /* The COS used for this Tx */
- u16 cq; /* CQ associated with this ring */
+ u8 reserved;
+ u8 page_size; /* Each mapped page is 2^(12+page_size) bytes */
+ u8 qos_class; /* The COS used for this Tx */
+ u16 cq; /* CQ associated with this ring */
#define MTNIC_MASK_CONFIG_TX_CQ_INDEX MTNIC_BC(0,8)
u32 page_address[0]; /* 64 bit page addresses of descriptor buffer. */
- /* The buffer must accommodate all Tx descriptors */
+ /* The buffer must accommodate all Tx descriptors */
};
/* CMD CONFIG_EQ */
@@ -647,9 +658,9 @@ struct mtnic_if_config_eq_in_mbox {
u8 reserved1;
u8 int_vector; /* MSI index if MSI enabled; otherwise reserved */
#define MTNIC_MASK_CONFIG_EQ_INT_VEC MTNIC_BC(0,6)
- u8 size; /* Num CQs is 2^size entries (size <= 22) */
+ u8 size; /* Num CQs is 2^size entries (size <= 22) */
#define MTNIC_MASK_CONFIG_EQ_SIZE MTNIC_BC(0,5)
- u8 offset; /* Start address of CQE in first page (11:6) */
+ u8 offset; /* Start address of CQE in first page (11:6) */
#define MTNIC_MASK_CONFIG_EQ_OFFSET MTNIC_BC(0,6)
u8 page_size; /* Each mapped page is 2^(12+page_size) bytes*/
u8 reserved[3];
diff --git a/gpxe/src/drivers/net/natsemi.c b/gpxe/src/drivers/net/natsemi.c
index 028b905c..3a776234 100644
--- a/gpxe/src/drivers/net/natsemi.c
+++ b/gpxe/src/drivers/net/natsemi.c
@@ -61,7 +61,8 @@
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
-#include <io.h>
+#include <string.h>
+#include <gpxe/io.h>
#include <errno.h>
#include <byteswap.h>
#include <unistd.h>
@@ -357,7 +358,7 @@ static int natsemi_open (struct net_device *netdev)
}
outl (virt_to_bus (&np->tx[0]),np->ioaddr + TxRingPtr);
- DBG ("Natsemi Tx descriptor loaded with: %#08lx\n",
+ DBG ("Natsemi Tx descriptor loaded with: %#08x\n",
inl (np->ioaddr + TxRingPtr));
/* Setup RX ring
@@ -376,7 +377,7 @@ static int natsemi_open (struct net_device *netdev)
}
outl (virt_to_bus (&np->rx[0]), np->ioaddr + RxRingPtr);
- DBG ("Natsemi Rx descriptor loaded with: %#08lx\n",
+ DBG ("Natsemi Rx descriptor loaded with: %#08x\n",
inl (np->ioaddr + RxRingPtr));
/* Setup RX Filter
@@ -400,7 +401,7 @@ static int natsemi_open (struct net_device *netdev)
outl (tx_config, np->ioaddr + TxConfig);
outl (rx_config, np->ioaddr + RxConfig);
- DBG ("Tx config register = %#08lx Rx config register = %#08lx\n",
+ DBG ("Tx config register = %#08x Rx config register = %#08x\n",
inl (np->ioaddr + TxConfig),
inl (np->ioaddr + RxConfig));
@@ -551,7 +552,7 @@ static void natsemi_poll (struct net_device *netdev)
netdev_rx_err (netdev, NULL, -EINVAL);
DBG ("natsemi_poll: Corrupted packet received!"
- " Status = %#08lx\n",
+ " Status = %#08x\n",
np->rx[np->rx_cur].cmdsts);
} else {
diff --git a/gpxe/src/drivers/net/ne2k_isa.c b/gpxe/src/drivers/net/ne2k_isa.c
new file mode 100644
index 00000000..f8a45cc8
--- /dev/null
+++ b/gpxe/src/drivers/net/ne2k_isa.c
@@ -0,0 +1,373 @@
+/**************************************************************************
+ ETHERBOOT - BOOTP/TFTP Bootstrap Program
+
+ Author: Martin Renters
+ Date: May/94
+
+ This code is based heavily on David Greenman's if_ed.c driver
+
+ Copyright (C) 1993-1994, David Greenman, Martin Renters.
+ This software may be used, modified, copied, distributed, and sold, in
+ both source and binary form provided that the above copyright and these
+ terms are retained. Under no circumstances are the authors responsible for
+ the proper functioning of this software, nor do the authors assume any
+ responsibility for damages incurred with its use.
+
+ Multicast support added by Timothy Legge (timlegge@users.sourceforge.net) 09/28/2003
+ Relocation support added by Ken Yap (ken_yap@users.sourceforge.net) 28/12/02
+ Card Detect support adapted from the eCos driver (Christian Plessl <cplessl@ee.ethz.ch>)
+ Extracted from ns8390.c and adapted by Pantelis Koukousoulas <pktoss@gmail.com>
+ **************************************************************************/
+
+#include "ns8390.h"
+#include "etherboot.h"
+#include "nic.h"
+#include <gpxe/ethernet.h>
+#include <gpxe/isa.h>
+#include <errno.h>
+
+#define ASIC_PIO NE_DATA
+
+static unsigned char eth_vendor, eth_flags;
+static unsigned short eth_nic_base, eth_asic_base;
+static unsigned char eth_memsize, eth_rx_start, eth_tx_start;
+static Address eth_bmem, eth_rmem;
+static unsigned char eth_drain_receiver;
+
+static struct nic_operations ne_operations;
+static void ne_reset(struct nic *nic, struct isa_device *isa);
+
+static isa_probe_addr_t ne_probe_addrs[] = { 0x300, 0x280, 0x320, 0x340, 0x380, 0x220, };
+
+/**************************************************************************
+ ETH_PIO_READ - Read a frame via Programmed I/O
+ **************************************************************************/
+static void eth_pio_read(unsigned int src, unsigned char *dst, unsigned int cnt) {
+ outb(D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
+ outb(cnt, eth_nic_base + D8390_P0_RBCR0);
+ outb(cnt >> 8, eth_nic_base + D8390_P0_RBCR1);
+ outb(src, eth_nic_base + D8390_P0_RSAR0);
+ outb(src >> 8, eth_nic_base + D8390_P0_RSAR1);
+ outb(D8390_COMMAND_RD0 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
+ if (eth_flags & FLAG_16BIT)
+ cnt = (cnt + 1) >> 1;
+
+ while (cnt--) {
+ if (eth_flags & FLAG_16BIT) {
+ *((unsigned short *) dst) = inw(eth_asic_base + ASIC_PIO);
+ dst += 2;
+ } else
+ *(dst++) = inb(eth_asic_base + ASIC_PIO);
+ }
+}
+
+/**************************************************************************
+ ETH_PIO_WRITE - Write a frame via Programmed I/O
+ **************************************************************************/
+static void eth_pio_write(const unsigned char *src, unsigned int dst,
+ unsigned int cnt) {
+ outb(D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
+ outb(D8390_ISR_RDC, eth_nic_base + D8390_P0_ISR);
+ outb(cnt, eth_nic_base + D8390_P0_RBCR0);
+ outb(cnt >> 8, eth_nic_base + D8390_P0_RBCR1);
+ outb(dst, eth_nic_base + D8390_P0_RSAR0);
+ outb(dst >> 8, eth_nic_base + D8390_P0_RSAR1);
+ outb(D8390_COMMAND_RD1 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
+ if (eth_flags & FLAG_16BIT)
+ cnt = (cnt + 1) >> 1;
+
+ while (cnt--) {
+
+ if (eth_flags & FLAG_16BIT) {
+ outw(*((unsigned short *) src), eth_asic_base + ASIC_PIO);
+ src += 2;
+ } else
+ outb(*(src++), eth_asic_base + ASIC_PIO);
+ }
+}
+
+/**************************************************************************
+ enable_multicast - Enable Multicast
+ **************************************************************************/
+static void enable_multicast(unsigned short eth_nic_base) {
+ unsigned char mcfilter[8];
+ int i;
+
+ memset(mcfilter, 0xFF, 8);
+ outb(4, eth_nic_base + D8390_P0_RCR);
+ outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS1, eth_nic_base + D8390_P0_COMMAND);
+ for (i = 0; i < 8; i++) {
+ outb(mcfilter[i], eth_nic_base + 8 + i);
+ if (inb(eth_nic_base + 8 + i) != mcfilter[i])
+ DBG("Error SMC 83C690 Multicast filter read/write mishap %d\n",
+ i);
+ }
+ outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS0, eth_nic_base + D8390_P0_COMMAND);
+ outb(4 | 0x08, eth_nic_base + D8390_P0_RCR);
+}
+
+/**************************************************************************
+ NE_PROBE1 - Look for an adapter on the ISA bus
+ **************************************************************************/
+static int ne_probe1(isa_probe_addr_t ioaddr) {
+ //From the eCos driver
+ unsigned int regd;
+ unsigned int state;
+
+ state = inb(ioaddr);
+ outb(ioaddr, D8390_COMMAND_RD2 | D8390_COMMAND_PS1 | D8390_COMMAND_STP);
+ regd = inb(ioaddr + D8390_P0_TCR);
+
+ if (inb(ioaddr + D8390_P0_TCR)) {
+ outb(ioaddr, state);
+ outb(ioaddr + 0x0d, regd);
+ return 0;
+ }
+
+ return 1;
+}
+
+/**************************************************************************
+ NE_PROBE - Initialize an adapter ???
+ **************************************************************************/
+static int ne_probe(struct nic *nic, struct isa_device *isa) {
+ int i;
+ unsigned char c;
+ unsigned char romdata[16];
+ unsigned char testbuf[32];
+
+ eth_vendor = VENDOR_NONE;
+ eth_drain_receiver = 0;
+
+ nic->irqno = 0;
+ nic->ioaddr = isa->ioaddr;
+ eth_nic_base = isa->ioaddr;
+
+ /******************************************************************
+ Search for NE1000/2000 if no WD/SMC or 3com cards
+ ******************************************************************/
+ if (eth_vendor == VENDOR_NONE) {
+
+ static unsigned char test[] = "NE*000 memory";
+
+ eth_bmem = 0; /* No shared memory */
+
+ eth_flags = FLAG_PIO;
+ eth_asic_base = eth_nic_base + NE_ASIC_OFFSET;
+ eth_memsize = MEM_16384;
+ eth_tx_start = 32;
+ eth_rx_start = 32 + D8390_TXBUF_SIZE;
+ c = inb(eth_asic_base + NE_RESET);
+ outb(c, eth_asic_base + NE_RESET);
+ (void) inb(0x84);
+ outb(D8390_COMMAND_STP | D8390_COMMAND_RD2, eth_nic_base
+ + D8390_P0_COMMAND);
+ outb(D8390_RCR_MON, eth_nic_base + D8390_P0_RCR);
+ outb(D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR);
+ outb(MEM_8192, eth_nic_base + D8390_P0_PSTART);
+ outb(MEM_16384, eth_nic_base + D8390_P0_PSTOP);
+ eth_pio_write((unsigned char *) test, 8192, sizeof(test));
+ eth_pio_read(8192, testbuf, sizeof(test));
+ if (!memcmp(test, testbuf, sizeof(test)))
+ goto out;
+ eth_flags |= FLAG_16BIT;
+ eth_memsize = MEM_32768;
+ eth_tx_start = 64;
+ eth_rx_start = 64 + D8390_TXBUF_SIZE;
+ outb(D8390_DCR_WTS | D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base
+ + D8390_P0_DCR);
+ outb(MEM_16384, eth_nic_base + D8390_P0_PSTART);
+ outb(MEM_32768, eth_nic_base + D8390_P0_PSTOP);
+ eth_pio_write((unsigned char *) test, 16384, sizeof(test));
+ eth_pio_read(16384, testbuf, sizeof(test));
+ if (!memcmp(testbuf, test, sizeof(test)))
+ goto out;
+
+
+out:
+ if (eth_nic_base == 0)
+ return (0);
+ if (eth_nic_base > ISA_MAX_ADDR) /* PCI probably */
+ eth_flags |= FLAG_16BIT;
+ eth_vendor = VENDOR_NOVELL;
+ eth_pio_read(0, romdata, sizeof(romdata));
+ for (i = 0; i < ETH_ALEN; i++) {
+ nic->node_addr[i] = romdata[i + ((eth_flags & FLAG_16BIT) ? i : 0)];
+ }
+ nic->ioaddr = eth_nic_base;
+ DBG("\nNE%c000 base %4.4x, MAC Addr %s\n",
+ (eth_flags & FLAG_16BIT) ? '2' : '1', eth_nic_base, eth_ntoa(
+ nic->node_addr));
+ }
+
+ if (eth_vendor == VENDOR_NONE)
+ return (0);
+
+ if (eth_vendor != VENDOR_3COM)
+ eth_rmem = eth_bmem;
+
+ ne_reset(nic, isa);
+ nic->nic_op = &ne_operations;
+ return 1;
+}
+
+
+/**************************************************************************
+ NE_DISABLE - Turn off adapter
+ **************************************************************************/
+static void ne_disable(struct nic *nic, struct isa_device *isa) {
+ ne_reset(nic, isa);
+}
+
+
+/**************************************************************************
+ NE_RESET - Reset adapter
+ **************************************************************************/
+static void ne_reset(struct nic *nic, struct isa_device *isa __unused)
+{
+ int i;
+
+ eth_drain_receiver = 0;
+ outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
+ D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
+ if (eth_flags & FLAG_16BIT)
+ outb(0x49, eth_nic_base+D8390_P0_DCR);
+ else
+ outb(0x48, eth_nic_base+D8390_P0_DCR);
+ outb(0, eth_nic_base+D8390_P0_RBCR0);
+ outb(0, eth_nic_base+D8390_P0_RBCR1);
+ outb(0x20, eth_nic_base+D8390_P0_RCR); /* monitor mode */
+ outb(2, eth_nic_base+D8390_P0_TCR);
+ outb(eth_tx_start, eth_nic_base+D8390_P0_TPSR);
+ outb(eth_rx_start, eth_nic_base+D8390_P0_PSTART);
+
+ outb(eth_memsize, eth_nic_base+D8390_P0_PSTOP);
+ outb(eth_memsize - 1, eth_nic_base+D8390_P0_BOUND);
+ outb(0xFF, eth_nic_base+D8390_P0_ISR);
+ outb(0, eth_nic_base+D8390_P0_IMR);
+ outb(D8390_COMMAND_PS1 |
+ D8390_COMMAND_RD2 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
+
+ for (i=0; i<ETH_ALEN; i++)
+ outb(nic->node_addr[i], eth_nic_base+D8390_P1_PAR0+i);
+ for (i=0; i<ETH_ALEN; i++)
+ outb(0xFF, eth_nic_base+D8390_P1_MAR0+i);
+ outb(eth_rx_start, eth_nic_base+D8390_P1_CURR);
+ outb(D8390_COMMAND_PS0 |
+ D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
+ outb(0xFF, eth_nic_base+D8390_P0_ISR);
+ outb(0, eth_nic_base+D8390_P0_TCR); /* transmitter on */
+ outb(4, eth_nic_base+D8390_P0_RCR); /* allow rx broadcast frames */
+
+ enable_multicast(eth_nic_base);
+}
+
+
+/**************************************************************************
+ NE_POLL - Wait for a frame
+ **************************************************************************/
+static int ne_poll(struct nic *nic __unused, int retrieve __unused)
+{
+ int ret = 0;
+ unsigned char rstat, curr, next;
+ unsigned short len, frag;
+ unsigned short pktoff;
+ unsigned char *p;
+ struct ringbuffer pkthdr;
+
+ rstat = inb(eth_nic_base+D8390_P0_RSR);
+ if (!(rstat & D8390_RSTAT_PRX)) return(0);
+ next = inb(eth_nic_base+D8390_P0_BOUND)+1;
+ if (next >= eth_memsize) next = eth_rx_start;
+ outb(D8390_COMMAND_PS1, eth_nic_base+D8390_P0_COMMAND);
+ curr = inb(eth_nic_base+D8390_P1_CURR);
+ outb(D8390_COMMAND_PS0, eth_nic_base+D8390_P0_COMMAND);
+ if (curr >= eth_memsize) curr=eth_rx_start;
+ if (curr == next) return(0);
+
+ if ( ! retrieve ) return 1;
+
+ pktoff = next << 8;
+ if (eth_flags & FLAG_PIO)
+ eth_pio_read(pktoff, (unsigned char *)&pkthdr, 4);
+ else
+ memcpy(&pkthdr, bus_to_virt(eth_rmem + pktoff), 4);
+ pktoff += sizeof(pkthdr);
+ /* incoming length includes FCS so must sub 4 */
+ len = pkthdr.len - 4;
+ if ((pkthdr.status & D8390_RSTAT_PRX) == 0 || len < ETH_ZLEN
+ || len> ETH_FRAME_LEN) {
+ DBG("Bogus packet, ignoring\n");
+ return (0);
+ }
+ else {
+ p = nic->packet;
+ nic->packetlen = len; /* available to caller */
+ frag = (eth_memsize << 8) - pktoff;
+ if (len> frag) { /* We have a wrap-around */
+ /* read first part */
+ if (eth_flags & FLAG_PIO)
+ eth_pio_read(pktoff, p, frag);
+ else
+ memcpy(p, bus_to_virt(eth_rmem + pktoff), frag);
+ pktoff = eth_rx_start << 8;
+ p += frag;
+ len -= frag;
+ }
+ /* read second part */
+ if (eth_flags & FLAG_PIO)
+ eth_pio_read(pktoff, p, len);
+ else
+ memcpy(p, bus_to_virt(eth_rmem + pktoff), len);
+ ret = 1;
+ }
+ next = pkthdr.next; /* frame number of next packet */
+ if (next == eth_rx_start)
+ next = eth_memsize;
+ outb(next-1, eth_nic_base+D8390_P0_BOUND);
+ return(ret);
+}
+
+
+/**************************************************************************
+ NE_TRANSMIT - Transmit a frame
+ **************************************************************************/
+static void ne_transmit(struct nic *nic, const char *d, /* Destination */
+unsigned int t, /* Type */
+unsigned int s, /* size */
+const char *p) { /* Packet */
+
+ /* Programmed I/O */
+ unsigned short type;
+ type = (t >> 8) | (t << 8);
+ eth_pio_write((unsigned char *) d, eth_tx_start << 8, ETH_ALEN);
+ eth_pio_write(nic->node_addr, (eth_tx_start << 8) + ETH_ALEN, ETH_ALEN);
+ /* bcc generates worse code without (const+const) below */
+ eth_pio_write((unsigned char *) &type, (eth_tx_start << 8) + (ETH_ALEN
+ + ETH_ALEN), 2);
+ eth_pio_write((unsigned char *) p, (eth_tx_start << 8) + ETH_HLEN, s);
+ s += ETH_HLEN;
+ if (s < ETH_ZLEN)
+ s = ETH_ZLEN;
+
+ outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 | D8390_COMMAND_STA,
+ eth_nic_base + D8390_P0_COMMAND);
+ outb(eth_tx_start, eth_nic_base + D8390_P0_TPSR);
+ outb(s, eth_nic_base + D8390_P0_TBCR0);
+ outb(s >> 8, eth_nic_base + D8390_P0_TBCR1);
+
+ outb(D8390_COMMAND_PS0 | D8390_COMMAND_TXP | D8390_COMMAND_RD2
+ | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
+}
+
+static struct nic_operations ne_operations = { .connect = dummy_connect,
+ .poll = ne_poll, .transmit = ne_transmit, .irq = dummy_irq,
+};
+
+ISA_DRIVER ( ne_driver, ne_probe_addrs, ne_probe1,
+ GENERIC_ISAPNP_VENDOR, 0x0600 );
+
+DRIVER ( "ne", nic_driver, isapnp_driver, ne_driver,
+ ne_probe, ne_disable );
+
+ISA_ROM("ne","NE1000/2000 and clones");
diff --git a/gpxe/src/drivers/net/phantom/phantom.c b/gpxe/src/drivers/net/phantom/phantom.c
index 6c7d1fc9..1d1637d8 100644
--- a/gpxe/src/drivers/net/phantom/phantom.c
+++ b/gpxe/src/drivers/net/phantom/phantom.c
@@ -25,12 +25,14 @@
#include <assert.h>
#include <byteswap.h>
#include <gpxe/pci.h>
+#include <gpxe/io.h>
#include <gpxe/malloc.h>
#include <gpxe/iobuf.h>
#include <gpxe/netdevice.h>
#include <gpxe/if_ether.h>
#include <gpxe/ethernet.h>
#include <gpxe/spi.h>
+#include <gpxe/settings.h>
#include "phantom.h"
/**
@@ -40,11 +42,8 @@
*
*/
-/** Maximum time to wait for SPI lock */
-#define PHN_SPI_LOCK_TIMEOUT_MS 100
-
-/** Maximum time to wait for SPI command to be issued */
-#define PHN_SPI_CMD_TIMEOUT_MS 100
+/** Maximum number of ports */
+#define PHN_MAX_NUM_PORTS 4
/** Maximum time to wait for command PEG to initialise
*
@@ -71,6 +70,9 @@
/** Maximum time to wait for test memory */
#define PHN_TEST_MEM_TIMEOUT_MS 100
+/** Maximum time to wait for CLP command to be issued */
+#define PHN_CLP_CMD_TIMEOUT_MS 500
+
/** Link state poll frequency
*
* The link state will be checked once in every N calls to poll().
@@ -105,10 +107,41 @@ struct phantom_descriptor_rings {
volatile uint32_t cmd_cons;
};
-/** A Phantom NIC port */
-struct phantom_nic_port {
- /** Phantom NIC containing this port */
- struct phantom_nic *phantom;
+/** RX context creation request and response buffers */
+struct phantom_create_rx_ctx_rqrsp {
+ struct {
+ struct nx_hostrq_rx_ctx_s rx_ctx;
+ struct nx_hostrq_rds_ring_s rds;
+ struct nx_hostrq_sds_ring_s sds;
+ } __unm_dma_aligned hostrq;
+ struct {
+ struct nx_cardrsp_rx_ctx_s rx_ctx;
+ struct nx_cardrsp_rds_ring_s rds;
+ struct nx_cardrsp_sds_ring_s sds;
+ } __unm_dma_aligned cardrsp;
+};
+
+/** TX context creation request and response buffers */
+struct phantom_create_tx_ctx_rqrsp {
+ struct {
+ struct nx_hostrq_tx_ctx_s tx_ctx;
+ } __unm_dma_aligned hostrq;
+ struct {
+ struct nx_cardrsp_tx_ctx_s tx_ctx;
+ } __unm_dma_aligned cardrsp;
+};
+
+/** A Phantom NIC */
+struct phantom_nic {
+ /** BAR 0 */
+ void *bar0;
+ /** Current CRB window */
+ unsigned long crb_window;
+ /** CRB window access method */
+ unsigned long ( *crb_access ) ( struct phantom_nic *phantom,
+ unsigned long reg );
+
+
/** Port number */
unsigned int port;
@@ -143,73 +176,18 @@ struct phantom_nic_port {
struct io_buffer *cds_iobuf[PHN_NUM_CDS];
- /** Link state poll timer */
- unsigned long link_poll_timer;
-
-
/** Descriptor rings */
struct phantom_descriptor_rings *desc;
-};
-
-/** RX context creation request and response buffers */
-struct phantom_create_rx_ctx_rqrsp {
- struct {
- struct nx_hostrq_rx_ctx_s rx_ctx;
- struct nx_hostrq_rds_ring_s rds;
- struct nx_hostrq_sds_ring_s sds;
- } __unm_dma_aligned hostrq;
- struct {
- struct nx_cardrsp_rx_ctx_s rx_ctx;
- struct nx_cardrsp_rds_ring_s rds;
- struct nx_cardrsp_sds_ring_s sds;
- } __unm_dma_aligned cardrsp;
-};
-
-/** TX context creation request and response buffers */
-struct phantom_create_tx_ctx_rqrsp {
- struct {
- struct nx_hostrq_tx_ctx_s tx_ctx;
- } __unm_dma_aligned hostrq;
- struct {
- struct nx_cardrsp_tx_ctx_s tx_ctx;
- } __unm_dma_aligned cardrsp;
-};
-
-/** A Phantom DMA buffer area */
-union phantom_dma_buffer {
- /** Dummy area required for (read-only) self-tests */
- uint8_t dummy_dma[UNM_DUMMY_DMA_SIZE];
- /** RX context creation request and response buffers */
- struct phantom_create_rx_ctx_rqrsp create_rx_ctx;
- /** TX context creation request and response buffers */
- struct phantom_create_tx_ctx_rqrsp create_tx_ctx;
-};
-
-/** A Phantom NIC */
-struct phantom_nic {
- /** BAR 0 */
- void *bar0;
- /** Current CRB window */
- unsigned long crb_window;
- /** CRB window access method */
- unsigned long ( *crb_access ) ( struct phantom_nic *phantom,
- unsigned long reg );
-
- /** Number of ports */
- int num_ports;
- /** Per-port network devices */
- struct net_device *netdev[UNM_FLASH_NUM_PORTS];
- /** DMA buffers */
- union phantom_dma_buffer *dma_buf;
-
- /** Flash memory SPI bus */
- struct spi_bus spi_bus;
- /** Flash memory SPI device */
- struct spi_device flash;
/** Last known link state */
uint32_t link_state;
+ /** Link state poll timer */
+ unsigned long link_poll_timer;
+
+
+ /** Non-volatile settings */
+ struct settings settings;
};
/***************************************************************************
@@ -227,21 +205,8 @@ struct phantom_nic {
*/
static unsigned long phantom_crb_access_128m ( struct phantom_nic *phantom,
unsigned long reg ) {
- static const uint32_t reg_window[] = {
- [UNM_CRB_BLK_PCIE] = 0x0000000,
- [UNM_CRB_BLK_CAM] = 0x2000000,
- [UNM_CRB_BLK_ROMUSB] = 0x2000000,
- [UNM_CRB_BLK_TEST] = 0x0000000,
- };
- static const uint32_t reg_bases[] = {
- [UNM_CRB_BLK_PCIE] = 0x6100000,
- [UNM_CRB_BLK_CAM] = 0x6200000,
- [UNM_CRB_BLK_ROMUSB] = 0x7300000,
- [UNM_CRB_BLK_TEST] = 0x6200000,
- };
- unsigned int block = UNM_CRB_BLK ( reg );
- unsigned long offset = UNM_CRB_OFFSET ( reg );
- uint32_t window = reg_window[block];
+ unsigned long offset = ( 0x6000000 + ( reg & 0x1ffffff ) );
+ uint32_t window = ( reg & 0x2000000 );
uint32_t verify_window;
if ( phantom->crb_window != window ) {
@@ -257,7 +222,7 @@ static unsigned long phantom_crb_access_128m ( struct phantom_nic *phantom,
phantom->crb_window = window;
}
- return ( reg_bases[block] + offset );
+ return offset;
}
/**
@@ -269,21 +234,8 @@ static unsigned long phantom_crb_access_128m ( struct phantom_nic *phantom,
*/
static unsigned long phantom_crb_access_32m ( struct phantom_nic *phantom,
unsigned long reg ) {
- static const uint32_t reg_window[] = {
- [UNM_CRB_BLK_PCIE] = 0x0000000,
- [UNM_CRB_BLK_CAM] = 0x2000000,
- [UNM_CRB_BLK_ROMUSB] = 0x2000000,
- [UNM_CRB_BLK_TEST] = 0x0000000,
- };
- static const uint32_t reg_bases[] = {
- [UNM_CRB_BLK_PCIE] = 0x0100000,
- [UNM_CRB_BLK_CAM] = 0x0200000,
- [UNM_CRB_BLK_ROMUSB] = 0x1300000,
- [UNM_CRB_BLK_TEST] = 0x0200000,
- };
- unsigned int block = UNM_CRB_BLK ( reg );
- unsigned long offset = UNM_CRB_OFFSET ( reg );
- uint32_t window = reg_window[block];
+ unsigned long offset = ( reg & 0x1ffffff );
+ uint32_t window = ( reg & 0x2000000 );
uint32_t verify_window;
if ( phantom->crb_window != window ) {
@@ -299,7 +251,7 @@ static unsigned long phantom_crb_access_32m ( struct phantom_nic *phantom,
phantom->crb_window = window;
}
- return ( reg_bases[block] + offset );
+ return offset;
}
/**
@@ -311,31 +263,54 @@ static unsigned long phantom_crb_access_32m ( struct phantom_nic *phantom,
*/
static unsigned long phantom_crb_access_2m ( struct phantom_nic *phantom,
unsigned long reg ) {
- static const uint32_t reg_window_hi[] = {
- [UNM_CRB_BLK_PCIE] = 0x77300000,
- [UNM_CRB_BLK_CAM] = 0x41600000,
- [UNM_CRB_BLK_ROMUSB] = 0x42100000,
- [UNM_CRB_BLK_TEST] = 0x29500000,
+ static const struct {
+ uint8_t block;
+ uint16_t window_hi;
+ } reg_window_hi[] = {
+ { UNM_CRB_BLK_PCIE, 0x773 },
+ { UNM_CRB_BLK_CAM, 0x416 },
+ { UNM_CRB_BLK_ROMUSB, 0x421 },
+ { UNM_CRB_BLK_TEST, 0x295 },
+ { UNM_CRB_BLK_PEG_0, 0x340 },
+ { UNM_CRB_BLK_PEG_1, 0x341 },
+ { UNM_CRB_BLK_PEG_2, 0x342 },
+ { UNM_CRB_BLK_PEG_3, 0x343 },
+ { UNM_CRB_BLK_PEG_4, 0x34b },
};
unsigned int block = UNM_CRB_BLK ( reg );
unsigned long offset = UNM_CRB_OFFSET ( reg );
- uint32_t window = ( reg_window_hi[block] | ( offset & 0x000f0000 ) );
+ uint32_t window;
uint32_t verify_window;
+ unsigned int i;
- if ( phantom->crb_window != window ) {
+ for ( i = 0 ; i < ( sizeof ( reg_window_hi ) /
+ sizeof ( reg_window_hi[0] ) ) ; i++ ) {
- /* Write to the CRB window register */
- writel ( window, phantom->bar0 + UNM_2M_CRB_WINDOW );
+ if ( reg_window_hi[i].block != block )
+ continue;
- /* Ensure that the write has reached the card */
- verify_window = readl ( phantom->bar0 + UNM_2M_CRB_WINDOW );
- assert ( verify_window == window );
+ window = ( ( reg_window_hi[i].window_hi << 20 ) |
+ ( offset & 0x000f0000 ) );
- /* Record new window */
- phantom->crb_window = window;
+ if ( phantom->crb_window != window ) {
+
+ /* Write to the CRB window register */
+ writel ( window, phantom->bar0 + UNM_2M_CRB_WINDOW );
+
+ /* Ensure that the write has reached the card */
+ verify_window = readl ( phantom->bar0 +
+ UNM_2M_CRB_WINDOW );
+ assert ( verify_window == window );
+
+ /* Record new window */
+ phantom->crb_window = window;
+ }
+
+ return ( 0x1e0000 + ( offset & 0xffff ) );
}
- return ( 0x1e0000 + ( offset & 0xffff ) );
+ assert ( 0 );
+ return 0;
}
/**
@@ -401,8 +376,9 @@ static inline void phantom_write_hilo ( struct phantom_nic *phantom,
* @v buf 8-byte buffer to fill
* @ret rc Return status code
*/
-static int phantom_read_test_mem ( struct phantom_nic *phantom,
- uint64_t offset, uint32_t buf[2] ) {
+static int phantom_read_test_mem_block ( struct phantom_nic *phantom,
+ unsigned long offset,
+ uint32_t buf[2] ) {
unsigned int retries;
uint32_t test_control;
@@ -429,199 +405,100 @@ static int phantom_read_test_mem ( struct phantom_nic *phantom,
}
/**
+ * Read single byte from Phantom test memory
+ *
+ * @v phantom Phantom NIC
+ * @v offset Offset within test memory
+ * @ret byte Byte read, or negative error
+ */
+static int phantom_read_test_mem ( struct phantom_nic *phantom,
+ unsigned long offset ) {
+ static union {
+ uint8_t bytes[8];
+ uint32_t dwords[2];
+ } cache;
+ static unsigned long cache_offset = -1UL;
+ unsigned long sub_offset;
+ int rc;
+
+ sub_offset = ( offset & ( sizeof ( cache ) - 1 ) );
+ offset = ( offset & ~( sizeof ( cache ) - 1 ) );
+
+ if ( cache_offset != offset ) {
+ if ( ( rc = phantom_read_test_mem_block ( phantom, offset,
+ cache.dwords )) !=0 )
+ return rc;
+ cache_offset = offset;
+ }
+
+ return cache.bytes[sub_offset];
+}
+
+/**
* Dump Phantom firmware dmesg log
*
* @v phantom Phantom NIC
* @v log Log number
+ * @v max_lines Maximum number of lines to show, or -1 to show all
+ * @ret rc Return status code
*/
-static void phantom_dmesg ( struct phantom_nic *phantom, unsigned int log ) {
+static int phantom_dmesg ( struct phantom_nic *phantom, unsigned int log,
+ unsigned int max_lines ) {
uint32_t head;
uint32_t tail;
uint32_t len;
uint32_t sig;
uint32_t offset;
- union {
- uint8_t bytes[8];
- uint32_t dwords[2];
- } buf;
- unsigned int i;
- int rc;
+ int byte;
/* Optimise out for non-debug builds */
if ( ! DBG_LOG )
- return;
+ return 0;
+ /* Locate log */
head = phantom_readl ( phantom, UNM_CAM_RAM_DMESG_HEAD ( log ) );
len = phantom_readl ( phantom, UNM_CAM_RAM_DMESG_LEN ( log ) );
tail = phantom_readl ( phantom, UNM_CAM_RAM_DMESG_TAIL ( log ) );
sig = phantom_readl ( phantom, UNM_CAM_RAM_DMESG_SIG ( log ) );
- DBGC ( phantom, "Phantom %p firmware dmesg buffer %d (%08lx-%08lx)\n",
+ DBGC ( phantom, "Phantom %p firmware dmesg buffer %d (%08x-%08x)\n",
phantom, log, head, tail );
assert ( ( head & 0x07 ) == 0 );
if ( sig != UNM_CAM_RAM_DMESG_SIG_MAGIC ) {
- DBGC ( phantom, "Warning: bad signature %08lx (want %08lx)\n",
+ DBGC ( phantom, "Warning: bad signature %08x (want %08lx)\n",
sig, UNM_CAM_RAM_DMESG_SIG_MAGIC );
}
- for ( offset = head ; offset < tail ; offset += 8 ) {
- if ( ( rc = phantom_read_test_mem ( phantom, offset,
- buf.dwords ) ) != 0 ) {
- DBGC ( phantom, "Phantom %p could not read from test "
- "memory: %s\n", phantom, strerror ( rc ) );
+ /* Locate start of last (max_lines) lines */
+ for ( offset = tail ; offset > head ; offset-- ) {
+ if ( ( byte = phantom_read_test_mem ( phantom,
+ ( offset - 1 ) ) ) < 0 )
+ return byte;
+ if ( ( byte == '\n' ) && ( max_lines-- == 0 ) )
break;
- }
- for ( i = 0 ; ( ( i < sizeof ( buf ) ) &&
- ( offset + i ) < tail ) ; i++ ) {
- DBG ( "%c", buf.bytes[i] );
- }
+ }
+
+ /* Print lines */
+ for ( ; offset < tail ; offset++ ) {
+ if ( ( byte = phantom_read_test_mem ( phantom, offset ) ) < 0 )
+ return byte;
+ DBG ( "%c", byte );
}
DBG ( "\n" );
+ return 0;
}
/**
* Dump Phantom firmware dmesg logs
*
* @v phantom Phantom NIC
+ * @v max_lines Maximum number of lines to show, or -1 to show all
*/
static void __attribute__ (( unused ))
-phantom_dmesg_all ( struct phantom_nic *phantom ) {
+phantom_dmesg_all ( struct phantom_nic *phantom, unsigned int max_lines ) {
unsigned int i;
for ( i = 0 ; i < UNM_CAM_RAM_NUM_DMESG_BUFFERS ; i++ )
- phantom_dmesg ( phantom, i );
-}
-
-/***************************************************************************
- *
- * SPI bus access (for flash memory)
- *
- */
-
-/**
- * Acquire Phantom SPI lock
- *
- * @v phantom Phantom NIC
- * @ret rc Return status code
- */
-static int phantom_spi_lock ( struct phantom_nic *phantom ) {
- unsigned int retries;
- uint32_t pcie_sem2_lock;
-
- for ( retries = 0 ; retries < PHN_SPI_LOCK_TIMEOUT_MS ; retries++ ) {
- pcie_sem2_lock = phantom_readl ( phantom, UNM_PCIE_SEM2_LOCK );
- if ( pcie_sem2_lock != 0 )
- return 0;
- mdelay ( 1 );
- }
-
- DBGC ( phantom, "Phantom %p timed out waiting for SPI lock\n",
- phantom );
- return -ETIMEDOUT;
-}
-
-/**
- * Wait for Phantom SPI command to complete
- *
- * @v phantom Phantom NIC
- * @ret rc Return status code
- */
-static int phantom_spi_wait ( struct phantom_nic *phantom ) {
- unsigned int retries;
- uint32_t glb_status;
-
- for ( retries = 0 ; retries < PHN_SPI_CMD_TIMEOUT_MS ; retries++ ) {
- glb_status = phantom_readl ( phantom, UNM_ROMUSB_GLB_STATUS );
- if ( glb_status & UNM_ROMUSB_GLB_STATUS_ROM_DONE )
- return 0;
- mdelay ( 1 );
- }
-
- DBGC ( phantom, "Phantom %p timed out waiting for SPI command\n",
- phantom );
- return -ETIMEDOUT;
-}
-
-/**
- * Release Phantom SPI lock
- *
- * @v phantom Phantom NIC
- */
-static void phantom_spi_unlock ( struct phantom_nic *phantom ) {
- phantom_readl ( phantom, UNM_PCIE_SEM2_UNLOCK );
-}
-
-/**
- * Read/write data via Phantom SPI bus
- *
- * @v bus SPI bus
- * @v device SPI device
- * @v command Command
- * @v address Address to read/write (<0 for no address)
- * @v data_out TX data buffer (or NULL)
- * @v data_in RX data buffer (or NULL)
- * @v len Length of data buffer(s)
- * @ret rc Return status code
- */
-static int phantom_spi_rw ( struct spi_bus *bus,
- struct spi_device *device,
- unsigned int command, int address,
- const void *data_out, void *data_in,
- size_t len ) {
- struct phantom_nic *phantom =
- container_of ( bus, struct phantom_nic, spi_bus );
- uint32_t data;
- int rc;
-
- DBGCP ( phantom, "Phantom %p SPI command %x at %x+%zx\n",
- phantom, command, address, len );
- if ( data_out )
- DBGCP_HDA ( phantom, address, data_out, len );
-
- /* We support only exactly 4-byte reads */
- if ( len != UNM_SPI_BLKSIZE ) {
- DBGC ( phantom, "Phantom %p invalid SPI length %zx\n",
- phantom, len );
- return -EINVAL;
- }
-
- /* Acquire SPI lock */
- if ( ( rc = phantom_spi_lock ( phantom ) ) != 0 )
- goto err_lock;
-
- /* Issue SPI command as per the PRM */
- if ( data_out ) {
- memcpy ( &data, data_out, sizeof ( data ) );
- phantom_writel ( phantom, data, UNM_ROMUSB_ROM_WDATA );
- }
- phantom_writel ( phantom, address, UNM_ROMUSB_ROM_ADDRESS );
- phantom_writel ( phantom, ( device->address_len / 8 ),
- UNM_ROMUSB_ROM_ABYTE_CNT );
- udelay ( 100 ); /* according to PRM */
- phantom_writel ( phantom, 0, UNM_ROMUSB_ROM_DUMMY_BYTE_CNT );
- phantom_writel ( phantom, command, UNM_ROMUSB_ROM_INSTR_OPCODE );
-
- /* Wait for SPI command to complete */
- if ( ( rc = phantom_spi_wait ( phantom ) ) != 0 )
- goto err_wait;
-
- /* Reset address byte count and dummy byte count, because the
- * PRM asks us to.
- */
- phantom_writel ( phantom, 0, UNM_ROMUSB_ROM_ABYTE_CNT );
- udelay ( 100 ); /* according to PRM */
- phantom_writel ( phantom, 0, UNM_ROMUSB_ROM_DUMMY_BYTE_CNT );
-
- /* Read data, if applicable */
- if ( data_in ) {
- data = phantom_readl ( phantom, UNM_ROMUSB_ROM_RDATA );
- memcpy ( data_in, &data, sizeof ( data ) );
- DBGCP_HDA ( phantom, address, data_in, len );
- }
-
- err_wait:
- phantom_spi_unlock ( phantom );
- err_lock:
- return rc;
+ phantom_dmesg ( phantom, i, max_lines );
}
/***************************************************************************
@@ -665,26 +542,24 @@ static int phantom_wait_for_cmd ( struct phantom_nic *phantom ) {
/**
* Issue command to firmware
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @v command Firmware command
* @v arg1 Argument 1
* @v arg2 Argument 2
* @v arg3 Argument 3
* @ret rc Return status code
*/
-static int phantom_issue_cmd ( struct phantom_nic_port *phantom_port,
+static int phantom_issue_cmd ( struct phantom_nic *phantom,
uint32_t command, uint32_t arg1, uint32_t arg2,
uint32_t arg3 ) {
- struct phantom_nic *phantom = phantom_port->phantom;
uint32_t signature;
int rc;
/* Issue command */
- signature = NX_CDRP_SIGNATURE_MAKE ( phantom_port->port,
+ signature = NX_CDRP_SIGNATURE_MAKE ( phantom->port,
NXHAL_VERSION );
- DBGC2 ( phantom, "Phantom %p port %d issuing command %08lx (%08lx, "
- "%08lx, %08lx)\n", phantom, phantom_port->port,
- command, arg1, arg2, arg3 );
+ DBGC2 ( phantom, "Phantom %p issuing command %08x (%08x, %08x, "
+ "%08x)\n", phantom, command, arg1, arg2, arg3 );
phantom_writel ( phantom, signature, UNM_NIC_REG_NX_SIGN );
phantom_writel ( phantom, arg1, UNM_NIC_REG_NX_ARG1 );
phantom_writel ( phantom, arg2, UNM_NIC_REG_NX_ARG2 );
@@ -705,36 +580,41 @@ static int phantom_issue_cmd ( struct phantom_nic_port *phantom_port,
/**
* Issue buffer-format command to firmware
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @v command Firmware command
* @v buffer Buffer to pass to firmware
* @v len Length of buffer
* @ret rc Return status code
*/
-static int phantom_issue_buf_cmd ( struct phantom_nic_port *phantom_port,
+static int phantom_issue_buf_cmd ( struct phantom_nic *phantom,
uint32_t command, void *buffer,
size_t len ) {
uint64_t physaddr;
physaddr = virt_to_bus ( buffer );
- return phantom_issue_cmd ( phantom_port, command, ( physaddr >> 32 ),
+ return phantom_issue_cmd ( phantom, command, ( physaddr >> 32 ),
( physaddr & 0xffffffffUL ), len );
}
/**
* Create Phantom RX context
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @ret rc Return status code
*/
-static int phantom_create_rx_ctx ( struct phantom_nic_port *phantom_port ) {
- struct phantom_nic *phantom = phantom_port->phantom;
+static int phantom_create_rx_ctx ( struct phantom_nic *phantom ) {
struct phantom_create_rx_ctx_rqrsp *buf;
int rc;
+
+ /* Allocate context creation buffer */
+ buf = malloc_dma ( sizeof ( *buf ), UNM_DMA_BUFFER_ALIGN );
+ if ( ! buf ) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ memset ( buf, 0, sizeof ( *buf ) );
/* Prepare request */
- buf = &phantom->dma_buf->create_rx_ctx;
- memset ( buf, 0, sizeof ( *buf ) );
buf->hostrq.rx_ctx.host_rsp_dma_addr =
cpu_to_le64 ( virt_to_bus ( &buf->cardrsp ) );
buf->hostrq.rx_ctx.capabilities[0] =
@@ -749,197 +629,194 @@ static int phantom_create_rx_ctx ( struct phantom_nic_port *phantom_port ) {
buf->hostrq.rx_ctx.num_rds_rings = cpu_to_le16 ( 1 );
buf->hostrq.rx_ctx.num_sds_rings = cpu_to_le16 ( 1 );
buf->hostrq.rds.host_phys_addr =
- cpu_to_le64 ( virt_to_bus ( phantom_port->desc->rds ) );
+ cpu_to_le64 ( virt_to_bus ( phantom->desc->rds ) );
buf->hostrq.rds.buff_size = cpu_to_le64 ( PHN_RX_BUFSIZE );
buf->hostrq.rds.ring_size = cpu_to_le32 ( PHN_NUM_RDS );
buf->hostrq.rds.ring_kind = cpu_to_le32 ( NX_RDS_RING_TYPE_NORMAL );
buf->hostrq.sds.host_phys_addr =
- cpu_to_le64 ( virt_to_bus ( phantom_port->desc->sds ) );
+ cpu_to_le64 ( virt_to_bus ( phantom->desc->sds ) );
buf->hostrq.sds.ring_size = cpu_to_le32 ( PHN_NUM_SDS );
- DBGC ( phantom, "Phantom %p port %d creating RX context\n",
- phantom, phantom_port->port );
+ DBGC ( phantom, "Phantom %p creating RX context\n", phantom );
DBGC2_HDA ( phantom, virt_to_bus ( &buf->hostrq ),
&buf->hostrq, sizeof ( buf->hostrq ) );
/* Issue request */
- if ( ( rc = phantom_issue_buf_cmd ( phantom_port,
+ if ( ( rc = phantom_issue_buf_cmd ( phantom,
NX_CDRP_CMD_CREATE_RX_CTX,
&buf->hostrq,
sizeof ( buf->hostrq ) ) ) != 0 ) {
- DBGC ( phantom, "Phantom %p port %d could not create RX "
- "context: %s\n",
- phantom, phantom_port->port, strerror ( rc ) );
+ DBGC ( phantom, "Phantom %p could not create RX context: "
+ "%s\n", phantom, strerror ( rc ) );
DBGC ( phantom, "Request:\n" );
DBGC_HDA ( phantom, virt_to_bus ( &buf->hostrq ),
&buf->hostrq, sizeof ( buf->hostrq ) );
DBGC ( phantom, "Response:\n" );
DBGC_HDA ( phantom, virt_to_bus ( &buf->cardrsp ),
&buf->cardrsp, sizeof ( buf->cardrsp ) );
- return rc;
+ goto out;
}
/* Retrieve context parameters */
- phantom_port->rx_context_id =
+ phantom->rx_context_id =
le16_to_cpu ( buf->cardrsp.rx_ctx.context_id );
- phantom_port->rds_producer_crb =
+ phantom->rds_producer_crb =
( UNM_CAM_RAM +
le32_to_cpu ( buf->cardrsp.rds.host_producer_crb ));
- phantom_port->sds_consumer_crb =
+ phantom->sds_consumer_crb =
( UNM_CAM_RAM +
le32_to_cpu ( buf->cardrsp.sds.host_consumer_crb ));
- DBGC ( phantom, "Phantom %p port %d created RX context (id %04x, "
- "port phys %02x virt %02x)\n", phantom, phantom_port->port,
- phantom_port->rx_context_id, buf->cardrsp.rx_ctx.phys_port,
- buf->cardrsp.rx_ctx.virt_port );
+ DBGC ( phantom, "Phantom %p created RX context (id %04x, port phys "
+ "%02x virt %02x)\n", phantom, phantom->rx_context_id,
+ buf->cardrsp.rx_ctx.phys_port, buf->cardrsp.rx_ctx.virt_port );
DBGC2_HDA ( phantom, virt_to_bus ( &buf->cardrsp ),
&buf->cardrsp, sizeof ( buf->cardrsp ) );
- DBGC ( phantom, "Phantom %p port %d RDS producer CRB is %08lx\n",
- phantom, phantom_port->port, phantom_port->rds_producer_crb );
- DBGC ( phantom, "Phantom %p port %d SDS consumer CRB is %08lx\n",
- phantom, phantom_port->port, phantom_port->sds_consumer_crb );
+ DBGC ( phantom, "Phantom %p RDS producer CRB is %08lx\n",
+ phantom, phantom->rds_producer_crb );
+ DBGC ( phantom, "Phantom %p SDS consumer CRB is %08lx\n",
+ phantom, phantom->sds_consumer_crb );
- return 0;
+ out:
+ free_dma ( buf, sizeof ( *buf ) );
+ return rc;
}
/**
* Destroy Phantom RX context
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @ret rc Return status code
*/
-static void phantom_destroy_rx_ctx ( struct phantom_nic_port *phantom_port ) {
- struct phantom_nic *phantom = phantom_port->phantom;
+static void phantom_destroy_rx_ctx ( struct phantom_nic *phantom ) {
int rc;
- DBGC ( phantom, "Phantom %p port %d destroying RX context (id %04x)\n",
- phantom, phantom_port->port, phantom_port->rx_context_id );
+ DBGC ( phantom, "Phantom %p destroying RX context (id %04x)\n",
+ phantom, phantom->rx_context_id );
/* Issue request */
- if ( ( rc = phantom_issue_cmd ( phantom_port,
+ if ( ( rc = phantom_issue_cmd ( phantom,
NX_CDRP_CMD_DESTROY_RX_CTX,
- phantom_port->rx_context_id,
+ phantom->rx_context_id,
NX_DESTROY_CTX_RESET, 0 ) ) != 0 ) {
- DBGC ( phantom, "Phantom %p port %d could not destroy RX "
- "context: %s\n",
- phantom, phantom_port->port, strerror ( rc ) );
+ DBGC ( phantom, "Phantom %p could not destroy RX context: "
+ "%s\n", phantom, strerror ( rc ) );
/* We're probably screwed */
return;
}
/* Clear context parameters */
- phantom_port->rx_context_id = 0;
- phantom_port->rds_producer_crb = 0;
- phantom_port->sds_consumer_crb = 0;
+ phantom->rx_context_id = 0;
+ phantom->rds_producer_crb = 0;
+ phantom->sds_consumer_crb = 0;
/* Reset software counters */
- phantom_port->rds_producer_idx = 0;
- phantom_port->rds_consumer_idx = 0;
- phantom_port->sds_consumer_idx = 0;
+ phantom->rds_producer_idx = 0;
+ phantom->rds_consumer_idx = 0;
+ phantom->sds_consumer_idx = 0;
}
/**
* Create Phantom TX context
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @ret rc Return status code
*/
-static int phantom_create_tx_ctx ( struct phantom_nic_port *phantom_port ) {
- struct phantom_nic *phantom = phantom_port->phantom;
+static int phantom_create_tx_ctx ( struct phantom_nic *phantom ) {
struct phantom_create_tx_ctx_rqrsp *buf;
int rc;
- /* Prepare request */
- buf = &phantom->dma_buf->create_tx_ctx;
+ /* Allocate context creation buffer */
+ buf = malloc_dma ( sizeof ( *buf ), UNM_DMA_BUFFER_ALIGN );
+ if ( ! buf ) {
+ rc = -ENOMEM;
+ goto out;
+ }
memset ( buf, 0, sizeof ( *buf ) );
+
+ /* Prepare request */
buf->hostrq.tx_ctx.host_rsp_dma_addr =
cpu_to_le64 ( virt_to_bus ( &buf->cardrsp ) );
buf->hostrq.tx_ctx.cmd_cons_dma_addr =
- cpu_to_le64 ( virt_to_bus ( &phantom_port->desc->cmd_cons ) );
- buf->hostrq.tx_ctx.dummy_dma_addr =
- cpu_to_le64 ( virt_to_bus ( phantom->dma_buf->dummy_dma ) );
+ cpu_to_le64 ( virt_to_bus ( &phantom->desc->cmd_cons ) );
buf->hostrq.tx_ctx.capabilities[0] =
cpu_to_le32 ( NX_CAP0_LEGACY_CONTEXT | NX_CAP0_LEGACY_MN );
buf->hostrq.tx_ctx.host_int_crb_mode =
cpu_to_le32 ( NX_HOST_INT_CRB_MODE_SHARED );
buf->hostrq.tx_ctx.cds_ring.host_phys_addr =
- cpu_to_le64 ( virt_to_bus ( phantom_port->desc->cds ) );
+ cpu_to_le64 ( virt_to_bus ( phantom->desc->cds ) );
buf->hostrq.tx_ctx.cds_ring.ring_size = cpu_to_le32 ( PHN_NUM_CDS );
- DBGC ( phantom, "Phantom %p port %d creating TX context\n",
- phantom, phantom_port->port );
+ DBGC ( phantom, "Phantom %p creating TX context\n", phantom );
DBGC2_HDA ( phantom, virt_to_bus ( &buf->hostrq ),
&buf->hostrq, sizeof ( buf->hostrq ) );
/* Issue request */
- if ( ( rc = phantom_issue_buf_cmd ( phantom_port,
+ if ( ( rc = phantom_issue_buf_cmd ( phantom,
NX_CDRP_CMD_CREATE_TX_CTX,
&buf->hostrq,
sizeof ( buf->hostrq ) ) ) != 0 ) {
- DBGC ( phantom, "Phantom %p port %d could not create TX "
- "context: %s\n",
- phantom, phantom_port->port, strerror ( rc ) );
+ DBGC ( phantom, "Phantom %p could not create TX context: "
+ "%s\n", phantom, strerror ( rc ) );
DBGC ( phantom, "Request:\n" );
DBGC_HDA ( phantom, virt_to_bus ( &buf->hostrq ),
&buf->hostrq, sizeof ( buf->hostrq ) );
DBGC ( phantom, "Response:\n" );
DBGC_HDA ( phantom, virt_to_bus ( &buf->cardrsp ),
&buf->cardrsp, sizeof ( buf->cardrsp ) );
- return rc;
+ goto out;
}
/* Retrieve context parameters */
- phantom_port->tx_context_id =
+ phantom->tx_context_id =
le16_to_cpu ( buf->cardrsp.tx_ctx.context_id );
- phantom_port->cds_producer_crb =
+ phantom->cds_producer_crb =
( UNM_CAM_RAM +
le32_to_cpu(buf->cardrsp.tx_ctx.cds_ring.host_producer_crb));
- DBGC ( phantom, "Phantom %p port %d created TX context (id %04x, "
- "port phys %02x virt %02x)\n", phantom, phantom_port->port,
- phantom_port->tx_context_id, buf->cardrsp.tx_ctx.phys_port,
- buf->cardrsp.tx_ctx.virt_port );
+ DBGC ( phantom, "Phantom %p created TX context (id %04x, port phys "
+ "%02x virt %02x)\n", phantom, phantom->tx_context_id,
+ buf->cardrsp.tx_ctx.phys_port, buf->cardrsp.tx_ctx.virt_port );
DBGC2_HDA ( phantom, virt_to_bus ( &buf->cardrsp ),
&buf->cardrsp, sizeof ( buf->cardrsp ) );
- DBGC ( phantom, "Phantom %p port %d CDS producer CRB is %08lx\n",
- phantom, phantom_port->port, phantom_port->cds_producer_crb );
+ DBGC ( phantom, "Phantom %p CDS producer CRB is %08lx\n",
+ phantom, phantom->cds_producer_crb );
- return 0;
+ out:
+ free_dma ( buf, sizeof ( *buf ) );
+ return rc;
}
/**
* Destroy Phantom TX context
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @ret rc Return status code
*/
-static void phantom_destroy_tx_ctx ( struct phantom_nic_port *phantom_port ) {
- struct phantom_nic *phantom = phantom_port->phantom;
+static void phantom_destroy_tx_ctx ( struct phantom_nic *phantom ) {
int rc;
- DBGC ( phantom, "Phantom %p port %d destroying TX context (id %04x)\n",
- phantom, phantom_port->port, phantom_port->tx_context_id );
+ DBGC ( phantom, "Phantom %p destroying TX context (id %04x)\n",
+ phantom, phantom->tx_context_id );
/* Issue request */
- if ( ( rc = phantom_issue_cmd ( phantom_port,
+ if ( ( rc = phantom_issue_cmd ( phantom,
NX_CDRP_CMD_DESTROY_TX_CTX,
- phantom_port->tx_context_id,
+ phantom->tx_context_id,
NX_DESTROY_CTX_RESET, 0 ) ) != 0 ) {
- DBGC ( phantom, "Phantom %p port %d could not destroy TX "
- "context: %s\n",
- phantom, phantom_port->port, strerror ( rc ) );
+ DBGC ( phantom, "Phantom %p could not destroy TX context: "
+ "%s\n", phantom, strerror ( rc ) );
/* We're probably screwed */
return;
}
/* Clear context parameters */
- phantom_port->tx_context_id = 0;
- phantom_port->cds_producer_crb = 0;
+ phantom->tx_context_id = 0;
+ phantom->cds_producer_crb = 0;
/* Reset software counters */
- phantom_port->cds_producer_idx = 0;
- phantom_port->cds_consumer_idx = 0;
+ phantom->cds_producer_idx = 0;
+ phantom->cds_consumer_idx = 0;
}
/***************************************************************************
@@ -951,11 +828,10 @@ static void phantom_destroy_tx_ctx ( struct phantom_nic_port *phantom_port ) {
/**
* Allocate Phantom RX descriptor
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @ret index RX descriptor index, or negative error
*/
-static int phantom_alloc_rds ( struct phantom_nic_port *phantom_port ) {
- struct phantom_nic *phantom = phantom_port->phantom;
+static int phantom_alloc_rds ( struct phantom_nic *phantom ) {
unsigned int rds_producer_idx;
unsigned int next_rds_producer_idx;
@@ -965,12 +841,11 @@ static int phantom_alloc_rds ( struct phantom_nic_port *phantom_port ) {
* guaranteed never to be an overestimate of the number of
* descriptors read by the hardware.
*/
- rds_producer_idx = phantom_port->rds_producer_idx;
+ rds_producer_idx = phantom->rds_producer_idx;
next_rds_producer_idx = ( ( rds_producer_idx + 1 ) % PHN_NUM_RDS );
- if ( next_rds_producer_idx == phantom_port->rds_consumer_idx ) {
- DBGC ( phantom, "Phantom %p port %d RDS ring full (index %d "
- "not consumed)\n", phantom, phantom_port->port,
- next_rds_producer_idx );
+ if ( next_rds_producer_idx == phantom->rds_consumer_idx ) {
+ DBGC ( phantom, "Phantom %p RDS ring full (index %d not "
+ "consumed)\n", phantom, next_rds_producer_idx );
return -ENOBUFS;
}
@@ -980,41 +855,38 @@ static int phantom_alloc_rds ( struct phantom_nic_port *phantom_port ) {
/**
* Post Phantom RX descriptor
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @v rds RX descriptor
*/
-static void phantom_post_rds ( struct phantom_nic_port *phantom_port,
+static void phantom_post_rds ( struct phantom_nic *phantom,
struct phantom_rds *rds ) {
- struct phantom_nic *phantom = phantom_port->phantom;
unsigned int rds_producer_idx;
unsigned int next_rds_producer_idx;
struct phantom_rds *entry;
/* Copy descriptor to ring */
- rds_producer_idx = phantom_port->rds_producer_idx;
- entry = &phantom_port->desc->rds[rds_producer_idx];
+ rds_producer_idx = phantom->rds_producer_idx;
+ entry = &phantom->desc->rds[rds_producer_idx];
memcpy ( entry, rds, sizeof ( *entry ) );
- DBGC2 ( phantom, "Phantom %p port %d posting RDS %ld (slot %d):\n",
- phantom, phantom_port->port, NX_GET ( rds, handle ),
- rds_producer_idx );
+ DBGC2 ( phantom, "Phantom %p posting RDS %ld (slot %d):\n",
+ phantom, NX_GET ( rds, handle ), rds_producer_idx );
DBGC2_HDA ( phantom, virt_to_bus ( entry ), entry, sizeof ( *entry ) );
/* Update producer index */
next_rds_producer_idx = ( ( rds_producer_idx + 1 ) % PHN_NUM_RDS );
- phantom_port->rds_producer_idx = next_rds_producer_idx;
+ phantom->rds_producer_idx = next_rds_producer_idx;
wmb();
- phantom_writel ( phantom, phantom_port->rds_producer_idx,
- phantom_port->rds_producer_crb );
+ phantom_writel ( phantom, phantom->rds_producer_idx,
+ phantom->rds_producer_crb );
}
/**
* Allocate Phantom TX descriptor
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @ret index TX descriptor index, or negative error
*/
-static int phantom_alloc_cds ( struct phantom_nic_port *phantom_port ) {
- struct phantom_nic *phantom = phantom_port->phantom;
+static int phantom_alloc_cds ( struct phantom_nic *phantom ) {
unsigned int cds_producer_idx;
unsigned int next_cds_producer_idx;
@@ -1022,12 +894,11 @@ static int phantom_alloc_cds ( struct phantom_nic_port *phantom_port ) {
* in strict order, so we just check for a collision against
* the consumer index.
*/
- cds_producer_idx = phantom_port->cds_producer_idx;
+ cds_producer_idx = phantom->cds_producer_idx;
next_cds_producer_idx = ( ( cds_producer_idx + 1 ) % PHN_NUM_CDS );
- if ( next_cds_producer_idx == phantom_port->cds_consumer_idx ) {
- DBGC ( phantom, "Phantom %p port %d CDS ring full (index %d "
- "not consumed)\n", phantom, phantom_port->port,
- next_cds_producer_idx );
+ if ( next_cds_producer_idx == phantom->cds_consumer_idx ) {
+ DBGC ( phantom, "Phantom %p CDS ring full (index %d not "
+ "consumed)\n", phantom, next_cds_producer_idx );
return -ENOBUFS;
}
@@ -1037,30 +908,29 @@ static int phantom_alloc_cds ( struct phantom_nic_port *phantom_port ) {
/**
* Post Phantom TX descriptor
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @v cds TX descriptor
*/
-static void phantom_post_cds ( struct phantom_nic_port *phantom_port,
+static void phantom_post_cds ( struct phantom_nic *phantom,
union phantom_cds *cds ) {
- struct phantom_nic *phantom = phantom_port->phantom;
unsigned int cds_producer_idx;
unsigned int next_cds_producer_idx;
union phantom_cds *entry;
/* Copy descriptor to ring */
- cds_producer_idx = phantom_port->cds_producer_idx;
- entry = &phantom_port->desc->cds[cds_producer_idx];
+ cds_producer_idx = phantom->cds_producer_idx;
+ entry = &phantom->desc->cds[cds_producer_idx];
memcpy ( entry, cds, sizeof ( *entry ) );
- DBGC2 ( phantom, "Phantom %p port %d posting CDS %d:\n",
- phantom, phantom_port->port, cds_producer_idx );
+ DBGC2 ( phantom, "Phantom %p posting CDS %d:\n",
+ phantom, cds_producer_idx );
DBGC2_HDA ( phantom, virt_to_bus ( entry ), entry, sizeof ( *entry ) );
/* Update producer index */
next_cds_producer_idx = ( ( cds_producer_idx + 1 ) % PHN_NUM_CDS );
- phantom_port->cds_producer_idx = next_cds_producer_idx;
+ phantom->cds_producer_idx = next_cds_producer_idx;
wmb();
- phantom_writel ( phantom, phantom_port->cds_producer_idx,
- phantom_port->cds_producer_crb );
+ phantom_writel ( phantom, phantom->cds_producer_idx,
+ phantom->cds_producer_crb );
}
/***************************************************************************
@@ -1072,19 +942,19 @@ static void phantom_post_cds ( struct phantom_nic_port *phantom_port,
/**
* Add/remove MAC address
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @v ll_addr MAC address to add or remove
* @v opcode MAC request opcode
* @ret rc Return status code
*/
-static int phantom_update_macaddr ( struct phantom_nic_port *phantom_port,
+static int phantom_update_macaddr ( struct phantom_nic *phantom,
const uint8_t *ll_addr,
unsigned int opcode ) {
union phantom_cds cds;
int index;
/* Get descriptor ring entry */
- index = phantom_alloc_cds ( phantom_port );
+ index = phantom_alloc_cds ( phantom );
if ( index < 0 )
return index;
@@ -1094,7 +964,7 @@ static int phantom_update_macaddr ( struct phantom_nic_port *phantom_port,
nic_request.common.opcode, UNM_NIC_REQUEST );
NX_FILL_2 ( &cds, 1,
nic_request.header.opcode, UNM_MAC_EVENT,
- nic_request.header.context_id, phantom_port->port );
+ nic_request.header.context_id, phantom->port );
NX_FILL_7 ( &cds, 2,
nic_request.body.mac_request.opcode, opcode,
nic_request.body.mac_request.mac_addr_0, ll_addr[0],
@@ -1105,7 +975,7 @@ static int phantom_update_macaddr ( struct phantom_nic_port *phantom_port,
nic_request.body.mac_request.mac_addr_5, ll_addr[5] );
/* Post descriptor */
- phantom_post_cds ( phantom_port, &cds );
+ phantom_post_cds ( phantom, &cds );
return 0;
}
@@ -1113,35 +983,33 @@ static int phantom_update_macaddr ( struct phantom_nic_port *phantom_port,
/**
* Add MAC address
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @v ll_addr MAC address to add or remove
* @ret rc Return status code
*/
-static inline int phantom_add_macaddr ( struct phantom_nic_port *phantom_port,
+static inline int phantom_add_macaddr ( struct phantom_nic *phantom,
const uint8_t *ll_addr ) {
- struct phantom_nic *phantom = phantom_port->phantom;
- DBGC ( phantom, "Phantom %p port %d adding MAC address %s\n",
- phantom, phantom_port->port, eth_ntoa ( ll_addr ) );
+ DBGC ( phantom, "Phantom %p adding MAC address %s\n",
+ phantom, eth_ntoa ( ll_addr ) );
- return phantom_update_macaddr ( phantom_port, ll_addr, UNM_MAC_ADD );
+ return phantom_update_macaddr ( phantom, ll_addr, UNM_MAC_ADD );
}
/**
* Remove MAC address
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @v ll_addr MAC address to add or remove
* @ret rc Return status code
*/
-static inline int phantom_del_macaddr ( struct phantom_nic_port *phantom_port,
+static inline int phantom_del_macaddr ( struct phantom_nic *phantom,
const uint8_t *ll_addr ) {
- struct phantom_nic *phantom = phantom_port->phantom;
- DBGC ( phantom, "Phantom %p port %d removing MAC address %s\n",
- phantom, phantom_port->port, eth_ntoa ( ll_addr ) );
+ DBGC ( phantom, "Phantom %p removing MAC address %s\n",
+ phantom, eth_ntoa ( ll_addr ) );
- return phantom_update_macaddr ( phantom_port, ll_addr, UNM_MAC_DEL );
+ return phantom_update_macaddr ( phantom, ll_addr, UNM_MAC_DEL );
}
/***************************************************************************
@@ -1153,14 +1021,12 @@ static inline int phantom_del_macaddr ( struct phantom_nic_port *phantom_port,
/**
* Poll link state
*
- * @v phantom Phantom NIC
+ * @v netdev Network device
*/
-static void phantom_poll_link_state ( struct phantom_nic *phantom ) {
- struct net_device *netdev;
- struct phantom_nic_port *phantom_port;
+static void phantom_poll_link_state ( struct net_device *netdev ) {
+ struct phantom_nic *phantom = netdev_priv ( netdev );
uint32_t xg_state_p3;
unsigned int link;
- int i;
/* Read link state */
xg_state_p3 = phantom_readl ( phantom, UNM_NIC_REG_XG_STATE_P3 );
@@ -1170,32 +1036,26 @@ static void phantom_poll_link_state ( struct phantom_nic *phantom ) {
return;
/* Record new link state */
- DBGC ( phantom, "Phantom %p new link state %08lx (was %08lx)\n",
+ DBGC ( phantom, "Phantom %p new link state %08x (was %08x)\n",
phantom, xg_state_p3, phantom->link_state );
phantom->link_state = xg_state_p3;
- /* Indicate per-port link state to gPXE */
- for ( i = 0 ; i < phantom->num_ports ; i++ ) {
- netdev = phantom->netdev[i];
- phantom_port = netdev_priv ( netdev );
- link = UNM_NIC_REG_XG_STATE_P3_LINK ( phantom_port->port,
- phantom->link_state );
- switch ( link ) {
- case UNM_NIC_REG_XG_STATE_P3_LINK_UP:
- DBGC ( phantom, "Phantom %p port %d link is up\n",
- phantom, phantom_port->port );
- netdev_link_up ( netdev );
- break;
- case UNM_NIC_REG_XG_STATE_P3_LINK_DOWN:
- DBGC ( phantom, "Phantom %p port %d link is down\n",
- phantom, phantom_port->port );
- netdev_link_down ( netdev );
- break;
- default:
- DBGC ( phantom, "Phantom %p port %d bad link state "
- "%d\n", phantom, phantom_port->port, link );
- break;
- }
+ /* Indicate link state to gPXE */
+ link = UNM_NIC_REG_XG_STATE_P3_LINK ( phantom->port,
+ phantom->link_state );
+ switch ( link ) {
+ case UNM_NIC_REG_XG_STATE_P3_LINK_UP:
+ DBGC ( phantom, "Phantom %p link is up\n", phantom );
+ netdev_link_up ( netdev );
+ break;
+ case UNM_NIC_REG_XG_STATE_P3_LINK_DOWN:
+ DBGC ( phantom, "Phantom %p link is down\n", phantom );
+ netdev_link_down ( netdev );
+ break;
+ default:
+ DBGC ( phantom, "Phantom %p bad link state %d\n",
+ phantom, link );
+ break;
}
}
@@ -1211,7 +1071,7 @@ static void phantom_poll_link_state ( struct phantom_nic *phantom ) {
* @v netdev Net device
*/
static void phantom_refill_rx_ring ( struct net_device *netdev ) {
- struct phantom_nic_port *phantom_port = netdev_priv ( netdev );
+ struct phantom_nic *phantom = netdev_priv ( netdev );
struct io_buffer *iobuf;
struct phantom_rds rds;
unsigned int handle;
@@ -1222,11 +1082,11 @@ static void phantom_refill_rx_ring ( struct net_device *netdev ) {
/* Skip this index if the descriptor has not yet been
* consumed.
*/
- if ( phantom_port->rds_iobuf[handle] != NULL )
+ if ( phantom->rds_iobuf[handle] != NULL )
continue;
/* Allocate descriptor ring entry */
- index = phantom_alloc_rds ( phantom_port );
+ index = phantom_alloc_rds ( phantom );
assert ( PHN_RDS_MAX_FILL < PHN_NUM_RDS );
assert ( index >= 0 ); /* Guaranteed by MAX_FILL < NUM_RDS ) */
@@ -1247,11 +1107,11 @@ static void phantom_refill_rx_ring ( struct net_device *netdev ) {
dma_addr, virt_to_bus ( iobuf->data ) );
/* Record I/O buffer */
- assert ( phantom_port->rds_iobuf[handle] == NULL );
- phantom_port->rds_iobuf[handle] = iobuf;
+ assert ( phantom->rds_iobuf[handle] == NULL );
+ phantom->rds_iobuf[handle] = iobuf;
/* Post descriptor */
- phantom_post_rds ( phantom_port, &rds );
+ phantom_post_rds ( phantom, &rds );
}
}
@@ -1262,24 +1122,24 @@ static void phantom_refill_rx_ring ( struct net_device *netdev ) {
* @ret rc Return status code
*/
static int phantom_open ( struct net_device *netdev ) {
- struct phantom_nic_port *phantom_port = netdev_priv ( netdev );
+ struct phantom_nic *phantom = netdev_priv ( netdev );
int rc;
/* Allocate and zero descriptor rings */
- phantom_port->desc = malloc_dma ( sizeof ( *(phantom_port->desc) ),
+ phantom->desc = malloc_dma ( sizeof ( *(phantom->desc) ),
UNM_DMA_BUFFER_ALIGN );
- if ( ! phantom_port->desc ) {
+ if ( ! phantom->desc ) {
rc = -ENOMEM;
goto err_alloc_desc;
}
- memset ( phantom_port->desc, 0, sizeof ( *(phantom_port->desc) ) );
+ memset ( phantom->desc, 0, sizeof ( *(phantom->desc) ) );
/* Create RX context */
- if ( ( rc = phantom_create_rx_ctx ( phantom_port ) ) != 0 )
+ if ( ( rc = phantom_create_rx_ctx ( phantom ) ) != 0 )
goto err_create_rx_ctx;
/* Create TX context */
- if ( ( rc = phantom_create_tx_ctx ( phantom_port ) ) != 0 )
+ if ( ( rc = phantom_create_tx_ctx ( phantom ) ) != 0 )
goto err_create_tx_ctx;
/* Fill the RX descriptor ring */
@@ -1293,26 +1153,26 @@ static int phantom_open ( struct net_device *netdev ) {
* packets (or, failing that, promiscuous mode), but the
* firmware doesn't currently support this.
*/
- if ( ( rc = phantom_add_macaddr ( phantom_port,
+ if ( ( rc = phantom_add_macaddr ( phantom,
netdev->ll_protocol->ll_broadcast ) ) != 0 )
goto err_add_macaddr_broadcast;
- if ( ( rc = phantom_add_macaddr ( phantom_port,
+ if ( ( rc = phantom_add_macaddr ( phantom,
netdev->ll_addr ) ) != 0 )
goto err_add_macaddr_unicast;
return 0;
- phantom_del_macaddr ( phantom_port, netdev->ll_addr );
+ phantom_del_macaddr ( phantom, netdev->ll_addr );
err_add_macaddr_unicast:
- phantom_del_macaddr ( phantom_port,
+ phantom_del_macaddr ( phantom,
netdev->ll_protocol->ll_broadcast );
err_add_macaddr_broadcast:
- phantom_destroy_tx_ctx ( phantom_port );
+ phantom_destroy_tx_ctx ( phantom );
err_create_tx_ctx:
- phantom_destroy_rx_ctx ( phantom_port );
+ phantom_destroy_rx_ctx ( phantom );
err_create_rx_ctx:
- free_dma ( phantom_port->desc, sizeof ( *(phantom_port->desc) ) );
- phantom_port->desc = NULL;
+ free_dma ( phantom->desc, sizeof ( *(phantom->desc) ) );
+ phantom->desc = NULL;
err_alloc_desc:
return rc;
}
@@ -1323,32 +1183,32 @@ static int phantom_open ( struct net_device *netdev ) {
* @v netdev Net device
*/
static void phantom_close ( struct net_device *netdev ) {
- struct phantom_nic_port *phantom_port = netdev_priv ( netdev );
+ struct phantom_nic *phantom = netdev_priv ( netdev );
struct io_buffer *iobuf;
unsigned int i;
/* Shut down the port */
- phantom_del_macaddr ( phantom_port, netdev->ll_addr );
- phantom_del_macaddr ( phantom_port,
+ phantom_del_macaddr ( phantom, netdev->ll_addr );
+ phantom_del_macaddr ( phantom,
netdev->ll_protocol->ll_broadcast );
- phantom_destroy_tx_ctx ( phantom_port );
- phantom_destroy_rx_ctx ( phantom_port );
- free_dma ( phantom_port->desc, sizeof ( *(phantom_port->desc) ) );
- phantom_port->desc = NULL;
+ phantom_destroy_tx_ctx ( phantom );
+ phantom_destroy_rx_ctx ( phantom );
+ free_dma ( phantom->desc, sizeof ( *(phantom->desc) ) );
+ phantom->desc = NULL;
/* Flush any uncompleted descriptors */
for ( i = 0 ; i < PHN_RDS_MAX_FILL ; i++ ) {
- iobuf = phantom_port->rds_iobuf[i];
+ iobuf = phantom->rds_iobuf[i];
if ( iobuf ) {
free_iob ( iobuf );
- phantom_port->rds_iobuf[i] = NULL;
+ phantom->rds_iobuf[i] = NULL;
}
}
for ( i = 0 ; i < PHN_NUM_CDS ; i++ ) {
- iobuf = phantom_port->cds_iobuf[i];
+ iobuf = phantom->cds_iobuf[i];
if ( iobuf ) {
netdev_tx_complete_err ( netdev, iobuf, -ECANCELED );
- phantom_port->cds_iobuf[i] = NULL;
+ phantom->cds_iobuf[i] = NULL;
}
}
}
@@ -1362,12 +1222,12 @@ static void phantom_close ( struct net_device *netdev ) {
*/
static int phantom_transmit ( struct net_device *netdev,
struct io_buffer *iobuf ) {
- struct phantom_nic_port *phantom_port = netdev_priv ( netdev );
+ struct phantom_nic *phantom = netdev_priv ( netdev );
union phantom_cds cds;
int index;
/* Get descriptor ring entry */
- index = phantom_alloc_cds ( phantom_port );
+ index = phantom_alloc_cds ( phantom );
if ( index < 0 )
return index;
@@ -1378,19 +1238,19 @@ static int phantom_transmit ( struct net_device *netdev,
tx.num_buffers, 1,
tx.length, iob_len ( iobuf ) );
NX_FILL_2 ( &cds, 2,
- tx.port, phantom_port->port,
- tx.context_id, phantom_port->port );
+ tx.port, phantom->port,
+ tx.context_id, phantom->port );
NX_FILL_1 ( &cds, 4,
tx.buffer1_dma_addr, virt_to_bus ( iobuf->data ) );
NX_FILL_1 ( &cds, 5,
tx.buffer1_length, iob_len ( iobuf ) );
/* Record I/O buffer */
- assert ( phantom_port->cds_iobuf[index] == NULL );
- phantom_port->cds_iobuf[index] = iobuf;
+ assert ( phantom->cds_iobuf[index] == NULL );
+ phantom->cds_iobuf[index] = iobuf;
/* Post descriptor */
- phantom_post_cds ( phantom_port, &cds );
+ phantom_post_cds ( phantom, &cds );
return 0;
}
@@ -1401,8 +1261,7 @@ static int phantom_transmit ( struct net_device *netdev,
* @v netdev Network device
*/
static void phantom_poll ( struct net_device *netdev ) {
- struct phantom_nic_port *phantom_port = netdev_priv ( netdev );
- struct phantom_nic *phantom = phantom_port->phantom;
+ struct phantom_nic *phantom = netdev_priv ( netdev );
struct io_buffer *iobuf;
unsigned int cds_consumer_idx;
unsigned int raw_new_cds_consumer_idx;
@@ -1414,33 +1273,33 @@ static void phantom_poll ( struct net_device *netdev ) {
unsigned int sds_opcode;
/* Check for TX completions */
- cds_consumer_idx = phantom_port->cds_consumer_idx;
- raw_new_cds_consumer_idx = phantom_port->desc->cmd_cons;
+ cds_consumer_idx = phantom->cds_consumer_idx;
+ raw_new_cds_consumer_idx = phantom->desc->cmd_cons;
new_cds_consumer_idx = le32_to_cpu ( raw_new_cds_consumer_idx );
while ( cds_consumer_idx != new_cds_consumer_idx ) {
- DBGC2 ( phantom, "Phantom %p port %d CDS %d complete\n",
- phantom, phantom_port->port, cds_consumer_idx );
+ DBGC2 ( phantom, "Phantom %p CDS %d complete\n",
+ phantom, cds_consumer_idx );
/* Completions may be for commands other than TX, so
* there may not always be an associated I/O buffer.
*/
- if ( ( iobuf = phantom_port->cds_iobuf[cds_consumer_idx] ) ) {
+ if ( ( iobuf = phantom->cds_iobuf[cds_consumer_idx] ) ) {
netdev_tx_complete ( netdev, iobuf );
- phantom_port->cds_iobuf[cds_consumer_idx] = NULL;
+ phantom->cds_iobuf[cds_consumer_idx] = NULL;
}
cds_consumer_idx = ( ( cds_consumer_idx + 1 ) % PHN_NUM_CDS );
- phantom_port->cds_consumer_idx = cds_consumer_idx;
+ phantom->cds_consumer_idx = cds_consumer_idx;
}
/* Check for received packets */
- rds_consumer_idx = phantom_port->rds_consumer_idx;
- sds_consumer_idx = phantom_port->sds_consumer_idx;
+ rds_consumer_idx = phantom->rds_consumer_idx;
+ sds_consumer_idx = phantom->sds_consumer_idx;
while ( 1 ) {
- sds = &phantom_port->desc->sds[sds_consumer_idx];
+ sds = &phantom->desc->sds[sds_consumer_idx];
if ( NX_GET ( sds, owner ) == 0 )
break;
- DBGC2 ( phantom, "Phantom %p port %d SDS %d status:\n",
- phantom, phantom_port->port, sds_consumer_idx );
+ DBGC2 ( phantom, "Phantom %p SDS %d status:\n",
+ phantom, sds_consumer_idx );
DBGC2_HDA ( phantom, virt_to_bus ( sds ), sds, sizeof (*sds) );
/* Check received opcode */
@@ -1452,24 +1311,23 @@ static void phantom_poll ( struct net_device *netdev ) {
* descriptor has been written.
*/
if ( NX_GET ( sds, total_length ) == 0 ) {
- DBGC ( phantom, "Phantom %p port %d SDS %d "
- "incomplete; deferring\n", phantom,
- phantom_port->port, sds_consumer_idx );
+ DBGC ( phantom, "Phantom %p SDS %d "
+ "incomplete; deferring\n",
+ phantom, sds_consumer_idx );
/* Leave for next poll() */
break;
}
/* Process received packet */
sds_handle = NX_GET ( sds, handle );
- iobuf = phantom_port->rds_iobuf[sds_handle];
+ iobuf = phantom->rds_iobuf[sds_handle];
assert ( iobuf != NULL );
iob_put ( iobuf, NX_GET ( sds, total_length ) );
iob_pull ( iobuf, NX_GET ( sds, pkt_offset ) );
- DBGC2 ( phantom, "Phantom %p port %d RDS %d "
- "complete\n",
- phantom, phantom_port->port, sds_handle );
+ DBGC2 ( phantom, "Phantom %p RDS %d complete\n",
+ phantom, sds_handle );
netdev_rx ( netdev, iobuf );
- phantom_port->rds_iobuf[sds_handle] = NULL;
+ phantom->rds_iobuf[sds_handle] = NULL;
/* Update RDS consumer counter. This is a
* lower bound for the number of descriptors
@@ -1480,13 +1338,12 @@ static void phantom_poll ( struct net_device *netdev ) {
*/
rds_consumer_idx =
( ( rds_consumer_idx + 1 ) % PHN_NUM_RDS );
- phantom_port->rds_consumer_idx = rds_consumer_idx;
+ phantom->rds_consumer_idx = rds_consumer_idx;
} else {
- DBGC ( phantom, "Phantom %p port %d unexpected SDS "
- "opcode %02x\n",
- phantom, phantom_port->port, sds_opcode );
+ DBGC ( phantom, "Phantom %p unexpected SDS opcode "
+ "%02x\n", phantom, sds_opcode );
DBGC_HDA ( phantom, virt_to_bus ( sds ),
sds, sizeof ( *sds ) );
}
@@ -1496,20 +1353,20 @@ static void phantom_poll ( struct net_device *netdev ) {
/* Update SDS consumer index */
sds_consumer_idx = ( ( sds_consumer_idx + 1 ) % PHN_NUM_SDS );
- phantom_port->sds_consumer_idx = sds_consumer_idx;
+ phantom->sds_consumer_idx = sds_consumer_idx;
wmb();
- phantom_writel ( phantom, phantom_port->sds_consumer_idx,
- phantom_port->sds_consumer_crb );
+ phantom_writel ( phantom, phantom->sds_consumer_idx,
+ phantom->sds_consumer_crb );
}
/* Refill the RX descriptor ring */
phantom_refill_rx_ring ( netdev );
/* Occasionally poll the link state */
- if ( phantom_port->link_poll_timer-- == 0 ) {
- phantom_poll_link_state ( phantom );
+ if ( phantom->link_poll_timer-- == 0 ) {
+ phantom_poll_link_state ( netdev );
/* Reset the link poll timer */
- phantom_port->link_poll_timer = PHN_LINK_POLL_FREQUENCY;
+ phantom->link_poll_timer = PHN_LINK_POLL_FREQUENCY;
}
}
@@ -1520,9 +1377,8 @@ static void phantom_poll ( struct net_device *netdev ) {
* @v enable Interrupts should be enabled
*/
static void phantom_irq ( struct net_device *netdev, int enable ) {
- struct phantom_nic_port *phantom_port = netdev_priv ( netdev );
- struct phantom_nic *phantom = phantom_port->phantom;
- static const unsigned long sw_int_mask_reg[UNM_FLASH_NUM_PORTS] = {
+ struct phantom_nic *phantom = netdev_priv ( netdev );
+ static const unsigned long sw_int_mask_reg[PHN_MAX_NUM_PORTS] = {
UNM_NIC_REG_SW_INT_MASK_0,
UNM_NIC_REG_SW_INT_MASK_1,
UNM_NIC_REG_SW_INT_MASK_2,
@@ -1531,7 +1387,7 @@ static void phantom_irq ( struct net_device *netdev, int enable ) {
phantom_writel ( phantom,
( enable ? 1 : 0 ),
- sw_int_mask_reg[phantom_port->port] );
+ sw_int_mask_reg[phantom->port] );
}
/** Phantom net device operations */
@@ -1543,6 +1399,336 @@ static struct net_device_operations phantom_operations = {
.irq = phantom_irq,
};
+/***************************************************************************
+ *
+ * CLP settings
+ *
+ */
+
+/** Phantom CLP settings tag magic */
+#define PHN_CLP_TAG_MAGIC 0xc19c1900UL
+
+/** Phantom CLP settings tag magic mask */
+#define PHN_CLP_TAG_MAGIC_MASK 0xffffff00UL
+
+/** Phantom CLP data
+ *
+ */
+union phantom_clp_data {
+ /** Data bytes
+ *
+ * This field is right-aligned; if only N bytes are present
+ * then bytes[0]..bytes[7-N] should be zero, and the data
+ * should be in bytes[7-N+1] to bytes[7];
+ */
+ uint8_t bytes[8];
+ /** Dwords for the CLP interface */
+ struct {
+ /** High dword, in network byte order */
+ uint32_t hi;
+ /** Low dword, in network byte order */
+ uint32_t lo;
+ } dwords;
+};
+#define PHN_CLP_BLKSIZE ( sizeof ( union phantom_clp_data ) )
+
+/**
+ * Wait for Phantom CLP command to complete
+ *
+ * @v phantom Phantom NIC
+ * @ret rc Return status code
+ */
+static int phantom_clp_wait ( struct phantom_nic *phantom ) {
+ unsigned int retries;
+ uint32_t status;
+
+ for ( retries = 0 ; retries < PHN_CLP_CMD_TIMEOUT_MS ; retries++ ) {
+ status = phantom_readl ( phantom, UNM_CAM_RAM_CLP_STATUS );
+ if ( status & UNM_CAM_RAM_CLP_STATUS_DONE )
+ return 0;
+ mdelay ( 1 );
+ }
+
+ DBGC ( phantom, "Phantom %p timed out waiting for CLP command\n",
+ phantom );
+ return -ETIMEDOUT;
+}
+
+/**
+ * Issue Phantom CLP command
+ *
+ * @v phantom Phantom NIC
+ * @v port Virtual port number
+ * @v opcode Opcode
+ * @v data_in Data in, or NULL
+ * @v data_out Data out, or NULL
+ * @v offset Offset within data
+ * @v len Data buffer length
+ * @ret len Total transfer length (for reads), or negative error
+ */
+static int phantom_clp_cmd ( struct phantom_nic *phantom, unsigned int port,
+ unsigned int opcode, const void *data_in,
+ void *data_out, size_t offset, size_t len ) {
+ union phantom_clp_data data;
+ unsigned int index = ( offset / sizeof ( data ) );
+ unsigned int last = 0;
+ size_t in_frag_len;
+ uint8_t *in_frag;
+ uint32_t command;
+ uint32_t status;
+ size_t read_len;
+ unsigned int error;
+ size_t out_frag_len;
+ uint8_t *out_frag;
+ int rc;
+
+ /* Sanity checks */
+ assert ( ( offset % sizeof ( data ) ) == 0 );
+ if ( len > 255 ) {
+ DBGC ( phantom, "Phantom %p invalid CLP length %zd\n",
+ phantom, len );
+ return -EINVAL;
+ }
+
+ /* Check that CLP interface is ready */
+ if ( ( rc = phantom_clp_wait ( phantom ) ) != 0 )
+ return rc;
+
+ /* Copy data in */
+ memset ( &data, 0, sizeof ( data ) );
+ if ( data_in ) {
+ assert ( offset < len );
+ in_frag_len = ( len - offset );
+ if ( in_frag_len > sizeof ( data ) ) {
+ in_frag_len = sizeof ( data );
+ } else {
+ last = 1;
+ }
+ in_frag = &data.bytes[ sizeof ( data ) - in_frag_len ];
+ memcpy ( in_frag, ( data_in + offset ), in_frag_len );
+ phantom_writel ( phantom, be32_to_cpu ( data.dwords.lo ),
+ UNM_CAM_RAM_CLP_DATA_LO );
+ phantom_writel ( phantom, be32_to_cpu ( data.dwords.hi ),
+ UNM_CAM_RAM_CLP_DATA_HI );
+ }
+
+ /* Issue CLP command */
+ command = ( ( index << 24 ) | ( ( data_in ? len : 0 ) << 16 ) |
+ ( port << 8 ) | ( last << 7 ) | ( opcode << 0 ) );
+ phantom_writel ( phantom, command, UNM_CAM_RAM_CLP_COMMAND );
+ mb();
+ phantom_writel ( phantom, UNM_CAM_RAM_CLP_STATUS_START,
+ UNM_CAM_RAM_CLP_STATUS );
+
+ /* Wait for command to complete */
+ if ( ( rc = phantom_clp_wait ( phantom ) ) != 0 )
+ return rc;
+
+ /* Get command status */
+ status = phantom_readl ( phantom, UNM_CAM_RAM_CLP_STATUS );
+ read_len = ( ( status >> 16 ) & 0xff );
+ error = ( ( status >> 8 ) & 0xff );
+ if ( error ) {
+ DBGC ( phantom, "Phantom %p CLP command error %02x\n",
+ phantom, error );
+ return -EIO;
+ }
+
+ /* Copy data out */
+ if ( data_out ) {
+ data.dwords.lo = cpu_to_be32 ( phantom_readl ( phantom,
+ UNM_CAM_RAM_CLP_DATA_LO ) );
+ data.dwords.hi = cpu_to_be32 ( phantom_readl ( phantom,
+ UNM_CAM_RAM_CLP_DATA_HI ) );
+ out_frag_len = ( read_len - offset );
+ if ( out_frag_len > sizeof ( data ) )
+ out_frag_len = sizeof ( data );
+ out_frag = &data.bytes[ sizeof ( data ) - out_frag_len ];
+ if ( out_frag_len > ( len - offset ) )
+ out_frag_len = ( len - offset );
+ memcpy ( ( data_out + offset ), out_frag, out_frag_len );
+ }
+
+ return read_len;
+}
+
+/**
+ * Store Phantom CLP setting
+ *
+ * @v phantom Phantom NIC
+ * @v port Virtual port number
+ * @v setting Setting number
+ * @v data Data buffer
+ * @v len Length of data buffer
+ * @ret rc Return status code
+ */
+static int phantom_clp_store ( struct phantom_nic *phantom, unsigned int port,
+ unsigned int setting, const void *data,
+ size_t len ) {
+ unsigned int opcode = setting;
+ size_t offset;
+ int rc;
+
+ for ( offset = 0 ; offset < len ; offset += PHN_CLP_BLKSIZE ) {
+ if ( ( rc = phantom_clp_cmd ( phantom, port, opcode, data,
+ NULL, offset, len ) ) < 0 )
+ return rc;
+ }
+ return 0;
+}
+
+/**
+ * Fetch Phantom CLP setting
+ *
+ * @v phantom Phantom NIC
+ * @v port Virtual port number
+ * @v setting Setting number
+ * @v data Data buffer
+ * @v len Length of data buffer
+ * @ret len Length of setting, or negative error
+ */
+static int phantom_clp_fetch ( struct phantom_nic *phantom, unsigned int port,
+ unsigned int setting, void *data, size_t len ) {
+ unsigned int opcode = ( setting + 1 );
+ size_t offset = 0;
+ int read_len;
+
+ while ( 1 ) {
+ read_len = phantom_clp_cmd ( phantom, port, opcode, NULL,
+ data, offset, len );
+ if ( read_len < 0 )
+ return read_len;
+ offset += PHN_CLP_BLKSIZE;
+ if ( offset >= ( unsigned ) read_len )
+ break;
+ if ( offset >= len )
+ break;
+ }
+ return read_len;
+}
+
+/** A Phantom CLP setting */
+struct phantom_clp_setting {
+ /** gPXE setting */
+ struct setting *setting;
+ /** Setting number */
+ unsigned int clp_setting;
+};
+
+/** Phantom CLP settings */
+static struct phantom_clp_setting clp_settings[] = {
+ { &mac_setting, 0x01 },
+};
+
+/**
+ * Find Phantom CLP setting
+ *
+ * @v setting gPXE setting
+ * @v clp_setting Setting number, or 0 if not found
+ */
+static unsigned int
+phantom_clp_setting ( struct phantom_nic *phantom, struct setting *setting ) {
+ struct phantom_clp_setting *clp_setting;
+ unsigned int i;
+
+ /* Search the list of explicitly-defined settings */
+ for ( i = 0 ; i < ( sizeof ( clp_settings ) /
+ sizeof ( clp_settings[0] ) ) ; i++ ) {
+ clp_setting = &clp_settings[i];
+ if ( setting_cmp ( setting, clp_setting->setting ) == 0 )
+ return clp_setting->clp_setting;
+ }
+
+ /* Allow for use of numbered settings */
+ if ( ( setting->tag & PHN_CLP_TAG_MAGIC_MASK ) == PHN_CLP_TAG_MAGIC )
+ return ( setting->tag & ~PHN_CLP_TAG_MAGIC_MASK );
+
+ DBGC2 ( phantom, "Phantom %p has no \"%s\" setting\n",
+ phantom, setting->name );
+
+ return 0;
+}
+
+/**
+ * Store Phantom CLP setting
+ *
+ * @v settings Settings block
+ * @v setting Setting to store
+ * @v data Setting data, or NULL to clear setting
+ * @v len Length of setting data
+ * @ret rc Return status code
+ */
+static int phantom_store_setting ( struct settings *settings,
+ struct setting *setting,
+ const void *data, size_t len ) {
+ struct phantom_nic *phantom =
+ container_of ( settings, struct phantom_nic, settings );
+ unsigned int clp_setting;
+ int rc;
+
+ /* Find Phantom setting equivalent to gPXE setting */
+ clp_setting = phantom_clp_setting ( phantom, setting );
+ if ( ! clp_setting )
+ return -ENOTSUP;
+
+ /* Store setting */
+ if ( ( rc = phantom_clp_store ( phantom, phantom->port,
+ clp_setting, data, len ) ) != 0 ) {
+ DBGC ( phantom, "Phantom %p could not store setting \"%s\": "
+ "%s\n", phantom, setting->name, strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Fetch Phantom CLP setting
+ *
+ * @v settings Settings block
+ * @v setting Setting to fetch
+ * @v data Buffer to fill with setting data
+ * @v len Length of buffer
+ * @ret len Length of setting data, or negative error
+ */
+static int phantom_fetch_setting ( struct settings *settings,
+ struct setting *setting,
+ void *data, size_t len ) {
+ struct phantom_nic *phantom =
+ container_of ( settings, struct phantom_nic, settings );
+ unsigned int clp_setting;
+ int read_len;
+ int rc;
+
+ /* Find Phantom setting equivalent to gPXE setting */
+ clp_setting = phantom_clp_setting ( phantom, setting );
+ if ( ! clp_setting )
+ return -ENOTSUP;
+
+ /* Fetch setting */
+ if ( ( read_len = phantom_clp_fetch ( phantom, phantom->port,
+ clp_setting, data, len ) ) < 0 ){
+ rc = read_len;
+ DBGC ( phantom, "Phantom %p could not fetch setting \"%s\": "
+ "%s\n", phantom, setting->name, strerror ( rc ) );
+ return rc;
+ }
+
+ return read_len;
+}
+
+/** Phantom CLP settings operations */
+static struct settings_operations phantom_settings_operations = {
+ .store = phantom_store_setting,
+ .fetch = phantom_fetch_setting,
+};
+
+/***************************************************************************
+ *
+ * Initialisation
+ *
+ */
+
/**
* Map Phantom CRB window
*
@@ -1556,8 +1742,15 @@ static int phantom_map_crb ( struct phantom_nic *phantom,
bar0_start = pci_bar_start ( pci, PCI_BASE_ADDRESS_0 );
bar0_size = pci_bar_size ( pci, PCI_BASE_ADDRESS_0 );
- DBGC ( phantom, "Phantom %p BAR0 is %08lx+%lx\n",
- phantom, bar0_start, bar0_size );
+ DBGC ( phantom, "Phantom %p is PCI %02x:%02x.%x with BAR0 at "
+ "%08lx+%lx\n", phantom, pci->bus, PCI_SLOT ( pci->devfn ),
+ PCI_FUNC ( pci->devfn ), bar0_start, bar0_size );
+
+ if ( ! bar0_start ) {
+ DBGC ( phantom, "Phantom %p BAR not assigned; ignoring\n",
+ phantom );
+ return -EINVAL;
+ }
switch ( bar0_size ) {
case ( 128 * 1024 * 1024 ) :
@@ -1592,71 +1785,23 @@ static int phantom_map_crb ( struct phantom_nic *phantom,
}
/**
- * Read Phantom flash contents
+ * Unhalt all PEGs
*
* @v phantom Phantom NIC
- * @ret rc Return status code
*/
-static int phantom_read_flash ( struct phantom_nic *phantom ) {
- struct unm_board_info board_info;
- int rc;
-
- /* Initialise flash access */
- phantom->spi_bus.rw = phantom_spi_rw;
- phantom->flash.bus = &phantom->spi_bus;
- init_m25p32 ( &phantom->flash );
- /* Phantom doesn't support greater than 4-byte block sizes */
- phantom->flash.nvs.block_size = UNM_SPI_BLKSIZE;
-
- /* Read and verify board information */
- if ( ( rc = nvs_read ( &phantom->flash.nvs, UNM_BRDCFG_START,
- &board_info, sizeof ( board_info ) ) ) != 0 ) {
- DBGC ( phantom, "Phantom %p could not read board info: %s\n",
- phantom, strerror ( rc ) );
- return rc;
- }
- if ( board_info.magic != UNM_BDINFO_MAGIC ) {
- DBGC ( phantom, "Phantom %p has bad board info magic %lx\n",
- phantom, board_info.magic );
- DBGC_HD ( phantom, &board_info, sizeof ( board_info ) );
- return -EINVAL;
- }
- if ( board_info.header_version != UNM_BDINFO_VERSION ) {
- DBGC ( phantom, "Phantom %p has bad board info version %lx\n",
- phantom, board_info.header_version );
- DBGC_HD ( phantom, &board_info, sizeof ( board_info ) );
- return -EINVAL;
- }
-
- /* Identify board type and number of ports */
- switch ( board_info.board_type ) {
- case UNM_BRDTYPE_P3_4_GB:
- case UNM_BRDTYPE_P3_4_GB_MM:
- phantom->num_ports = 4;
- break;
- case UNM_BRDTYPE_P3_HMEZ:
- case UNM_BRDTYPE_P3_IMEZ:
- case UNM_BRDTYPE_P3_10G_CX4:
- case UNM_BRDTYPE_P3_10G_CX4_LP:
- case UNM_BRDTYPE_P3_10G_SFP_PLUS:
- case UNM_BRDTYPE_P3_XG_LOM:
- phantom->num_ports = 2;
- break;
- case UNM_BRDTYPE_P3_10000_BASE_T:
- case UNM_BRDTYPE_P3_10G_XFP:
- phantom->num_ports = 1;
- break;
- default:
- DBGC ( phantom, "Phantom %p unrecognised board type %#lx; "
- "assuming single-port\n",
- phantom, board_info.board_type );
- phantom->num_ports = 1;
- break;
- }
- DBGC ( phantom, "Phantom %p board type is %#lx (%d ports)\n",
- phantom, board_info.board_type, phantom->num_ports );
-
- return 0;
+static void phantom_unhalt_pegs ( struct phantom_nic *phantom ) {
+ uint32_t halt_status;
+
+ halt_status = phantom_readl ( phantom, UNM_PEG_0_HALT_STATUS );
+ phantom_writel ( phantom, halt_status, UNM_PEG_0_HALT_STATUS );
+ halt_status = phantom_readl ( phantom, UNM_PEG_1_HALT_STATUS );
+ phantom_writel ( phantom, halt_status, UNM_PEG_1_HALT_STATUS );
+ halt_status = phantom_readl ( phantom, UNM_PEG_2_HALT_STATUS );
+ phantom_writel ( phantom, halt_status, UNM_PEG_2_HALT_STATUS );
+ halt_status = phantom_readl ( phantom, UNM_PEG_3_HALT_STATUS );
+ phantom_writel ( phantom, halt_status, UNM_PEG_3_HALT_STATUS );
+ halt_status = phantom_readl ( phantom, UNM_PEG_4_HALT_STATUS );
+ phantom_writel ( phantom, halt_status, UNM_PEG_4_HALT_STATUS );
}
/**
@@ -1668,7 +1813,6 @@ static int phantom_read_flash ( struct phantom_nic *phantom ) {
static int phantom_init_cmdpeg ( struct phantom_nic *phantom ) {
uint32_t cold_boot;
uint32_t sw_reset;
- physaddr_t dummy_dma_phys;
unsigned int retries;
uint32_t cmdpeg_state;
uint32_t last_cmdpeg_state = 0;
@@ -1681,6 +1825,11 @@ static int phantom_init_cmdpeg ( struct phantom_nic *phantom ) {
if ( cmdpeg_state == UNM_NIC_REG_CMDPEG_STATE_INITIALIZE_ACK ) {
DBGC ( phantom, "Phantom %p command PEG already initialized\n",
phantom );
+ /* Unhalt the PEGs. Previous firmware (e.g. BOFM) may
+ * have halted the PEGs to prevent internal bus
+ * collisions when the BIOS re-reads the expansion ROM.
+ */
+ phantom_unhalt_pegs ( phantom );
return 0;
}
@@ -1691,13 +1840,13 @@ static int phantom_init_cmdpeg ( struct phantom_nic *phantom ) {
phantom );
sw_reset = phantom_readl ( phantom, UNM_ROMUSB_GLB_SW_RESET );
if ( sw_reset != UNM_ROMUSB_GLB_SW_RESET_MAGIC ) {
- DBGC ( phantom, "Phantom %p reset failed: %08lx\n",
+ DBGC ( phantom, "Phantom %p reset failed: %08x\n",
phantom, sw_reset );
return -EIO;
}
} else {
DBGC ( phantom, "Phantom %p coming up from warm boot "
- "(%08lx)\n", phantom, cold_boot );
+ "(%08x)\n", phantom, cold_boot );
}
/* Clear cold-boot flag */
phantom_writel ( phantom, 0, UNM_CAM_RAM_COLD_BOOT );
@@ -1707,10 +1856,7 @@ static int phantom_init_cmdpeg ( struct phantom_nic *phantom ) {
UNM_CAM_RAM_WOL_PORT_MODE );
/* Pass dummy DMA area to card */
- dummy_dma_phys = virt_to_bus ( phantom->dma_buf->dummy_dma );
- DBGC ( phantom, "Phantom %p dummy DMA at %08lx\n",
- phantom, dummy_dma_phys );
- phantom_write_hilo ( phantom, dummy_dma_phys,
+ phantom_write_hilo ( phantom, 0,
UNM_NIC_REG_DUMMY_BUF_ADDR_LO,
UNM_NIC_REG_DUMMY_BUF_ADDR_HI );
phantom_writel ( phantom, UNM_NIC_REG_DUMMY_BUF_INIT,
@@ -1728,7 +1874,7 @@ static int phantom_init_cmdpeg ( struct phantom_nic *phantom ) {
UNM_NIC_REG_CMDPEG_STATE );
if ( cmdpeg_state != last_cmdpeg_state ) {
DBGC ( phantom, "Phantom %p command PEG state is "
- "%08lx after %d seconds...\n",
+ "%08x after %d seconds...\n",
phantom, cmdpeg_state, retries );
last_cmdpeg_state = cmdpeg_state;
}
@@ -1743,19 +1889,18 @@ static int phantom_init_cmdpeg ( struct phantom_nic *phantom ) {
}
DBGC ( phantom, "Phantom %p timed out waiting for command PEG to "
- "initialise (status %08lx)\n", phantom, cmdpeg_state );
+ "initialise (status %08x)\n", phantom, cmdpeg_state );
return -ETIMEDOUT;
}
/**
* Read Phantom MAC address
*
- * @v phanton_port Phantom NIC port
+ * @v phanton_port Phantom NIC
* @v ll_addr Buffer to fill with MAC address
*/
-static void phantom_get_macaddr ( struct phantom_nic_port *phantom_port,
+static void phantom_get_macaddr ( struct phantom_nic *phantom,
uint8_t *ll_addr ) {
- struct phantom_nic *phantom = phantom_port->phantom;
union {
uint8_t mac_addr[2][ETH_ALEN];
uint32_t dwords[3];
@@ -1765,7 +1910,7 @@ static void phantom_get_macaddr ( struct phantom_nic_port *phantom_port,
/* Read the three dwords that include this MAC address and one other */
offset = ( UNM_CAM_RAM_MAC_ADDRS +
- ( 12 * ( phantom_port->port / 2 ) ) );
+ ( 12 * ( phantom->port / 2 ) ) );
for ( i = 0 ; i < 3 ; i++, offset += 4 ) {
u.dwords[i] = phantom_readl ( phantom, offset );
}
@@ -1773,10 +1918,36 @@ static void phantom_get_macaddr ( struct phantom_nic_port *phantom_port,
/* Copy out the relevant MAC address */
for ( i = 0 ; i < ETH_ALEN ; i++ ) {
ll_addr[ ETH_ALEN - i - 1 ] =
- u.mac_addr[ phantom_port->port & 1 ][i];
+ u.mac_addr[ phantom->port & 1 ][i];
}
- DBGC ( phantom, "Phantom %p port %d MAC address is %s\n",
- phantom, phantom_port->port, eth_ntoa ( ll_addr ) );
+ DBGC ( phantom, "Phantom %p MAC address is %s\n",
+ phantom, eth_ntoa ( ll_addr ) );
+}
+
+/**
+ * Check Phantom is enabled for boot
+ *
+ * @v phanton_port Phantom NIC
+ * @ret rc Return status code
+ *
+ * This is something of an ugly hack to accommodate an OEM
+ * requirement. The NIC has only one expansion ROM BAR, rather than
+ * one per port. To allow individual ports to be selectively
+ * enabled/disabled for PXE boot (as required), we must therefore
+ * leave the expansion ROM always enabled, and place the per-port
+ * enable/disable logic within the gPXE driver.
+ */
+static int phantom_check_boot_enable ( struct phantom_nic *phantom ) {
+ unsigned long boot_enable;
+
+ boot_enable = phantom_readl ( phantom, UNM_CAM_RAM_BOOT_ENABLE );
+ if ( ! ( boot_enable & ( 1 << phantom->port ) ) ) {
+ DBGC ( phantom, "Phantom %p PXE boot is disabled\n",
+ phantom );
+ return -ENOTSUP;
+ }
+
+ return 0;
}
/**
@@ -1797,7 +1968,7 @@ static int phantom_init_rcvpeg ( struct phantom_nic *phantom ) {
UNM_NIC_REG_RCVPEG_STATE );
if ( rcvpeg_state != last_rcvpeg_state ) {
DBGC ( phantom, "Phantom %p receive PEG state is "
- "%08lx after %d seconds...\n",
+ "%08x after %d seconds...\n",
phantom, rcvpeg_state, retries );
last_rcvpeg_state = rcvpeg_state;
}
@@ -1807,7 +1978,7 @@ static int phantom_init_rcvpeg ( struct phantom_nic *phantom ) {
}
DBGC ( phantom, "Phantom %p timed out waiting for receive PEG to "
- "initialise (status %08lx)\n", phantom, rcvpeg_state );
+ "initialise (status %08x)\n", phantom, rcvpeg_state );
return -ETIMEDOUT;
}
@@ -1820,25 +1991,27 @@ static int phantom_init_rcvpeg ( struct phantom_nic *phantom ) {
*/
static int phantom_probe ( struct pci_device *pci,
const struct pci_device_id *id __unused ) {
- struct phantom_nic *phantom;
struct net_device *netdev;
- struct phantom_nic_port *phantom_port;
- int i;
+ struct phantom_nic *phantom;
+ struct settings *parent_settings;
int rc;
- /* Phantom NICs expose multiple PCI functions, used for
- * virtualisation. Ignore everything except function 0.
- */
- if ( PCI_FUNC ( pci->devfn ) != 0 )
- return -ENODEV;
-
/* Allocate Phantom device */
- phantom = zalloc ( sizeof ( *phantom ) );
- if ( ! phantom ) {
+ netdev = alloc_etherdev ( sizeof ( *phantom ) );
+ if ( ! netdev ) {
rc = -ENOMEM;
- goto err_alloc_phantom;
+ goto err_alloc_etherdev;
}
- pci_set_drvdata ( pci, phantom );
+ netdev_init ( netdev, &phantom_operations );
+ phantom = netdev_priv ( netdev );
+ pci_set_drvdata ( pci, netdev );
+ netdev->dev = &pci->dev;
+ memset ( phantom, 0, sizeof ( *phantom ) );
+ phantom->port = PCI_FUNC ( pci->devfn );
+ assert ( phantom->port < PHN_MAX_NUM_PORTS );
+ settings_init ( &phantom->settings,
+ &phantom_settings_operations,
+ &netdev->refcnt, "clp", PHN_CLP_TAG_MAGIC );
/* Fix up PCI device */
adjust_pci_device ( pci );
@@ -1847,87 +2020,66 @@ static int phantom_probe ( struct pci_device *pci,
if ( ( rc = phantom_map_crb ( phantom, pci ) ) != 0 )
goto err_map_crb;
- /* Read flash information */
- if ( ( rc = phantom_read_flash ( phantom ) ) != 0 )
- goto err_read_flash;
-
- /* Allocate net devices for each port */
- for ( i = 0 ; i < phantom->num_ports ; i++ ) {
- netdev = alloc_etherdev ( sizeof ( *phantom_port ) );
- if ( ! netdev ) {
- rc = -ENOMEM;
- goto err_alloc_etherdev;
- }
- phantom->netdev[i] = netdev;
- netdev_init ( netdev, &phantom_operations );
- phantom_port = netdev_priv ( netdev );
- netdev->dev = &pci->dev;
- phantom_port->phantom = phantom;
- phantom_port->port = i;
- }
-
/* BUG5945 - need to hack PCI config space on P3 B1 silicon.
* B2 will have this fixed; remove this hack when B1 is no
* longer in use.
*/
- for ( i = 0 ; i < 8 ; i++ ) {
- uint32_t temp;
- pci->devfn = PCI_DEVFN ( PCI_SLOT ( pci->devfn ), i );
- pci_read_config_dword ( pci, 0xc8, &temp );
- pci_read_config_dword ( pci, 0xc8, &temp );
- pci_write_config_dword ( pci, 0xc8, 0xf1000 );
+ if ( PCI_FUNC ( pci->devfn ) == 0 ) {
+ unsigned int i;
+ for ( i = 0 ; i < 8 ; i++ ) {
+ uint32_t temp;
+ pci->devfn = PCI_DEVFN ( PCI_SLOT ( pci->devfn ), i );
+ pci_read_config_dword ( pci, 0xc8, &temp );
+ pci_read_config_dword ( pci, 0xc8, &temp );
+ pci_write_config_dword ( pci, 0xc8, 0xf1000 );
+ }
+ pci->devfn = PCI_DEVFN ( PCI_SLOT ( pci->devfn ), 0 );
}
- pci->devfn = PCI_DEVFN ( PCI_SLOT ( pci->devfn ), 0 );
- /* Allocate dummy DMA buffer and perform initial hardware handshake */
- phantom->dma_buf = malloc_dma ( sizeof ( *(phantom->dma_buf) ),
- UNM_DMA_BUFFER_ALIGN );
- if ( ! phantom->dma_buf )
- goto err_dma_buf;
+ /* Initialise the command PEG */
if ( ( rc = phantom_init_cmdpeg ( phantom ) ) != 0 )
goto err_init_cmdpeg;
- /* Initialise the receive firmware */
+ /* Initialise the receive PEG */
if ( ( rc = phantom_init_rcvpeg ( phantom ) ) != 0 )
goto err_init_rcvpeg;
/* Read MAC addresses */
- for ( i = 0 ; i < phantom->num_ports ; i++ ) {
- phantom_port = netdev_priv ( phantom->netdev[i] );
- phantom_get_macaddr ( phantom_port,
- phantom->netdev[i]->ll_addr );
- }
+ phantom_get_macaddr ( phantom, netdev->ll_addr );
+
+ /* Skip if boot disabled on NIC */
+ if ( ( rc = phantom_check_boot_enable ( phantom ) ) != 0 )
+ goto err_check_boot_enable;
/* Register network devices */
- for ( i = 0 ; i < phantom->num_ports ; i++ ) {
- if ( ( rc = register_netdev ( phantom->netdev[i] ) ) != 0 ) {
- DBGC ( phantom, "Phantom %p could not register port "
- "%d: %s\n", phantom, i, strerror ( rc ) );
- goto err_register_netdev;
- }
+ if ( ( rc = register_netdev ( netdev ) ) != 0 ) {
+ DBGC ( phantom, "Phantom %p could not register net device: "
+ "%s\n", phantom, strerror ( rc ) );
+ goto err_register_netdev;
+ }
+
+ /* Register settings blocks */
+ parent_settings = netdev_settings ( netdev );
+ if ( ( rc = register_settings ( &phantom->settings,
+ parent_settings ) ) != 0 ) {
+ DBGC ( phantom, "Phantom %p could not register settings: "
+ "%s\n", phantom, strerror ( rc ) );
+ goto err_register_settings;
}
return 0;
- i = ( phantom->num_ports - 1 );
+ unregister_settings ( &phantom->settings );
+ err_register_settings:
+ unregister_netdev ( netdev );
err_register_netdev:
- for ( ; i >= 0 ; i-- )
- unregister_netdev ( phantom->netdev[i] );
+ err_check_boot_enable:
err_init_rcvpeg:
err_init_cmdpeg:
- free_dma ( phantom->dma_buf, sizeof ( *(phantom->dma_buf) ) );
- phantom->dma_buf = NULL;
- err_dma_buf:
- i = ( phantom->num_ports - 1 );
- err_alloc_etherdev:
- for ( ; i >= 0 ; i-- ) {
- netdev_nullify ( phantom->netdev[i] );
- netdev_put ( phantom->netdev[i] );
- }
- err_read_flash:
err_map_crb:
- free ( phantom );
- err_alloc_phantom:
+ netdev_nullify ( netdev );
+ netdev_put ( netdev );
+ err_alloc_etherdev:
return rc;
}
@@ -1937,18 +2089,13 @@ static int phantom_probe ( struct pci_device *pci,
* @v pci PCI device
*/
static void phantom_remove ( struct pci_device *pci ) {
- struct phantom_nic *phantom = pci_get_drvdata ( pci );
- int i;
+ struct net_device *netdev = pci_get_drvdata ( pci );
+ struct phantom_nic *phantom = netdev_priv ( netdev );
- for ( i = ( phantom->num_ports - 1 ) ; i >= 0 ; i-- )
- unregister_netdev ( phantom->netdev[i] );
- free_dma ( phantom->dma_buf, sizeof ( *(phantom->dma_buf) ) );
- phantom->dma_buf = NULL;
- for ( i = ( phantom->num_ports - 1 ) ; i >= 0 ; i-- ) {
- netdev_nullify ( phantom->netdev[i] );
- netdev_put ( phantom->netdev[i] );
- }
- free ( phantom );
+ unregister_settings ( &phantom->settings );
+ unregister_netdev ( netdev );
+ netdev_nullify ( netdev );
+ netdev_put ( netdev );
}
/** Phantom PCI IDs */
diff --git a/gpxe/src/drivers/net/phantom/phantom.h b/gpxe/src/drivers/net/phantom/phantom.h
index 110c1226..974eecae 100644
--- a/gpxe/src/drivers/net/phantom/phantom.h
+++ b/gpxe/src/drivers/net/phantom/phantom.h
@@ -45,18 +45,12 @@ typedef uint32_t nx_rcode_t;
#define NXHAL_VERSION 1
#include "nxhal_nic_interface.h"
-/** SPI controller maximum block size */
-#define UNM_SPI_BLKSIZE 4
-
/** DMA buffer alignment */
#define UNM_DMA_BUFFER_ALIGN 16
/** Mark structure as DMA-aligned */
#define __unm_dma_aligned __attribute__ (( aligned ( UNM_DMA_BUFFER_ALIGN ) ))
-/** Dummy DMA buffer size */
-#define UNM_DUMMY_DMA_SIZE 1024
-
/******************************************************************************
*
* Register definitions
@@ -76,14 +70,19 @@ typedef uint32_t nx_rcode_t;
* address by the phantom_crb_access_xxx() methods.
*/
enum unm_reg_blocks {
- UNM_CRB_BLK_PCIE,
- UNM_CRB_BLK_CAM,
- UNM_CRB_BLK_ROMUSB,
- UNM_CRB_BLK_TEST,
+ UNM_CRB_BLK_PCIE = 0x01,
+ UNM_CRB_BLK_CAM = 0x22,
+ UNM_CRB_BLK_ROMUSB = 0x33,
+ UNM_CRB_BLK_TEST = 0x02,
+ UNM_CRB_BLK_PEG_0 = 0x11,
+ UNM_CRB_BLK_PEG_1 = 0x12,
+ UNM_CRB_BLK_PEG_2 = 0x13,
+ UNM_CRB_BLK_PEG_3 = 0x14,
+ UNM_CRB_BLK_PEG_4 = 0x0f,
};
-#define UNM_CRB_BASE(blk) ( (blk) << 24 )
-#define UNM_CRB_BLK(reg) ( (reg) >> 24 )
-#define UNM_CRB_OFFSET(reg) ( (reg) & 0x00ffffff )
+#define UNM_CRB_BASE(blk) ( (blk) << 20 )
+#define UNM_CRB_BLK(reg) ( (reg) >> 20 )
+#define UNM_CRB_OFFSET(reg) ( (reg) & 0x000fffff )
#define UNM_CRB_PCIE UNM_CRB_BASE ( UNM_CRB_BLK_PCIE )
#define UNM_PCIE_SEM2_LOCK ( UNM_CRB_PCIE + 0x1c010 )
@@ -101,6 +100,16 @@ enum unm_reg_blocks {
#define UNM_CAM_RAM_DMESG_SIG(n) ( UNM_CAM_RAM + 0x0003c + (n) * 0x10 )
#define UNM_CAM_RAM_DMESG_SIG_MAGIC 0xcafebabeUL
#define UNM_CAM_RAM_NUM_DMESG_BUFFERS 5
+#define UNM_CAM_RAM_CLP_COMMAND ( UNM_CAM_RAM + 0x000c0 )
+#define UNM_CAM_RAM_CLP_COMMAND_LAST 0x00000080UL
+#define UNM_CAM_RAM_CLP_DATA_LO ( UNM_CAM_RAM + 0x000c4 )
+#define UNM_CAM_RAM_CLP_DATA_HI ( UNM_CAM_RAM + 0x000c8 )
+#define UNM_CAM_RAM_CLP_STATUS ( UNM_CAM_RAM + 0x000cc )
+#define UNM_CAM_RAM_CLP_STATUS_START 0x00000001UL
+#define UNM_CAM_RAM_CLP_STATUS_DONE 0x00000002UL
+#define UNM_CAM_RAM_CLP_STATUS_ERROR 0x0000ff00UL
+#define UNM_CAM_RAM_CLP_STATUS_UNINITIALISED 0xffffffffUL
+#define UNM_CAM_RAM_BOOT_ENABLE ( UNM_CAM_RAM + 0x000fc )
#define UNM_CAM_RAM_WOL_PORT_MODE ( UNM_CAM_RAM + 0x00198 )
#define UNM_CAM_RAM_MAC_ADDRS ( UNM_CAM_RAM + 0x001c0 )
#define UNM_CAM_RAM_COLD_BOOT ( UNM_CAM_RAM + 0x001fc )
@@ -160,114 +169,24 @@ enum unm_reg_blocks {
#define UNM_TEST_RDDATA_LO ( UNM_CRB_TEST + 0x000a8 )
#define UNM_TEST_RDDATA_HI ( UNM_CRB_TEST + 0x000ac )
-/******************************************************************************
- *
- * Flash layout
- *
- */
-
-/* Board configuration */
-
-#define UNM_BRDCFG_START 0x4000
-
-struct unm_board_info {
- uint32_t header_version;
- uint32_t board_mfg;
- uint32_t board_type;
- uint32_t board_num;
- uint32_t chip_id;
- uint32_t chip_minor;
- uint32_t chip_major;
- uint32_t chip_pkg;
- uint32_t chip_lot;
- uint32_t port_mask;
- uint32_t peg_mask;
- uint32_t icache_ok;
- uint32_t dcache_ok;
- uint32_t casper_ok;
- uint32_t mac_addr_lo_0;
- uint32_t mac_addr_lo_1;
- uint32_t mac_addr_lo_2;
- uint32_t mac_addr_lo_3;
- uint32_t mn_sync_mode;
- uint32_t mn_sync_shift_cclk;
- uint32_t mn_sync_shift_mclk;
- uint32_t mn_wb_en;
- uint32_t mn_crystal_freq;
- uint32_t mn_speed;
- uint32_t mn_org;
- uint32_t mn_depth;
- uint32_t mn_ranks_0;
- uint32_t mn_ranks_1;
- uint32_t mn_rd_latency_0;
- uint32_t mn_rd_latency_1;
- uint32_t mn_rd_latency_2;
- uint32_t mn_rd_latency_3;
- uint32_t mn_rd_latency_4;
- uint32_t mn_rd_latency_5;
- uint32_t mn_rd_latency_6;
- uint32_t mn_rd_latency_7;
- uint32_t mn_rd_latency_8;
- uint32_t mn_dll_val[18];
- uint32_t mn_mode_reg;
- uint32_t mn_ext_mode_reg;
- uint32_t mn_timing_0;
- uint32_t mn_timing_1;
- uint32_t mn_timing_2;
- uint32_t sn_sync_mode;
- uint32_t sn_pt_mode;
- uint32_t sn_ecc_en;
- uint32_t sn_wb_en;
- uint32_t sn_crystal_freq;
- uint32_t sn_speed;
- uint32_t sn_org;
- uint32_t sn_depth;
- uint32_t sn_dll_tap;
- uint32_t sn_rd_latency;
- uint32_t mac_addr_hi_0;
- uint32_t mac_addr_hi_1;
- uint32_t mac_addr_hi_2;
- uint32_t mac_addr_hi_3;
- uint32_t magic;
- uint32_t mn_rdimm;
- uint32_t mn_dll_override;
-};
-
-#define UNM_BDINFO_VERSION 1
-#define UNM_BRDTYPE_P3_HMEZ 0x0022
-#define UNM_BRDTYPE_P3_10G_CX4_LP 0x0023
-#define UNM_BRDTYPE_P3_4_GB 0x0024
-#define UNM_BRDTYPE_P3_IMEZ 0x0025
-#define UNM_BRDTYPE_P3_10G_SFP_PLUS 0x0026
-#define UNM_BRDTYPE_P3_10000_BASE_T 0x0027
-#define UNM_BRDTYPE_P3_XG_LOM 0x0028
-#define UNM_BRDTYPE_P3_4_GB_MM 0x0029
-#define UNM_BRDTYPE_P3_10G_CX4 0x0031
-#define UNM_BRDTYPE_P3_10G_XFP 0x0032
-#define UNM_BDINFO_MAGIC 0x12345678
+#define UNM_CRB_PEG_0 UNM_CRB_BASE ( UNM_CRB_BLK_PEG_0 )
+#define UNM_PEG_0_HALT_STATUS ( UNM_CRB_PEG_0 + 0x00030 )
+#define UNM_PEG_0_HALT ( UNM_CRB_PEG_0 + 0x0003c )
-/* User defined region */
+#define UNM_CRB_PEG_1 UNM_CRB_BASE ( UNM_CRB_BLK_PEG_1 )
+#define UNM_PEG_1_HALT_STATUS ( UNM_CRB_PEG_1 + 0x00030 )
+#define UNM_PEG_1_HALT ( UNM_CRB_PEG_1 + 0x0003c )
-#define UNM_USER_START 0x3e8000
+#define UNM_CRB_PEG_2 UNM_CRB_BASE ( UNM_CRB_BLK_PEG_2 )
+#define UNM_PEG_2_HALT_STATUS ( UNM_CRB_PEG_2 + 0x00030 )
+#define UNM_PEG_2_HALT ( UNM_CRB_PEG_2 + 0x0003c )
-#define UNM_FLASH_NUM_PORTS 4
-#define UNM_FLASH_NUM_MAC_PER_PORT 32
+#define UNM_CRB_PEG_3 UNM_CRB_BASE ( UNM_CRB_BLK_PEG_3 )
+#define UNM_PEG_3_HALT_STATUS ( UNM_CRB_PEG_3 + 0x00030 )
+#define UNM_PEG_3_HALT ( UNM_CRB_PEG_3 + 0x0003c )
-struct unm_user_info {
- uint8_t flash_md5[16 * 64];
- uint32_t bootld_version;
- uint32_t bootld_size;
- uint32_t image_version;
- uint32_t image_size;
- uint32_t primary_status;
- uint32_t secondary_present;
- /* MAC address , 4 ports, 32 address per port */
- uint64_t mac_addr[UNM_FLASH_NUM_PORTS * UNM_FLASH_NUM_MAC_PER_PORT];
- uint32_t sub_sys_id;
- uint8_t serial_num[32];
- uint32_t bios_version;
- uint32_t pxe_enable;
- uint32_t vlan_tag[UNM_FLASH_NUM_PORTS];
-};
+#define UNM_CRB_PEG_4 UNM_CRB_BASE ( UNM_CRB_BLK_PEG_4 )
+#define UNM_PEG_4_HALT_STATUS ( UNM_CRB_PEG_4 + 0x00030 )
+#define UNM_PEG_4_HALT ( UNM_CRB_PEG_4 + 0x0003c )
#endif /* _PHANTOM_H */
diff --git a/gpxe/src/drivers/net/pnic.c b/gpxe/src/drivers/net/pnic.c
index c7f08670..3a4af967 100644
--- a/gpxe/src/drivers/net/pnic.c
+++ b/gpxe/src/drivers/net/pnic.c
@@ -14,7 +14,7 @@ Bochs Pseudo NIC driver for Etherboot
#include <stdint.h>
#include <stdio.h>
-#include <io.h>
+#include <gpxe/io.h>
#include <errno.h>
#include <gpxe/pci.h>
#include <gpxe/if_ether.h>
diff --git a/gpxe/src/drivers/net/prism2.c b/gpxe/src/drivers/net/prism2.c
index aaf4c968..c54dba5d 100644
--- a/gpxe/src/drivers/net/prism2.c
+++ b/gpxe/src/drivers/net/prism2.c
@@ -118,7 +118,7 @@ static const char hardcoded_ssid[] = "";
typedef struct hfa384x
{
UINT32 iobase;
- UINT32 membase;
+ void *membase;
UINT16 lastcmd;
UINT16 status; /* in host order */
UINT16 resp0; /* in host order */
diff --git a/gpxe/src/drivers/net/prism2_pci.c b/gpxe/src/drivers/net/prism2_pci.c
index 63cc22e3..eda7bf50 100644
--- a/gpxe/src/drivers/net/prism2_pci.c
+++ b/gpxe/src/drivers/net/prism2_pci.c
@@ -22,14 +22,11 @@ $Id$
static int prism2_pci_probe ( struct nic *nic, struct pci_device *pci ) {
hfa384x_t *hw = &hw_global;
- uint32_t membase = 0; /* Prism2.5 Memory Base */
- pci_read_config_dword( pci, PRISM2_PCI_MEM_BASE, &membase);
- membase &= PCI_BASE_ADDRESS_MEM_MASK;
- hw->membase = (uint32_t) phys_to_virt(membase);
- printf ( "Prism2.5 has registers at %#lx\n", hw->membase );
+ printf ( "Prism2.5 has registers at %#lx\n", pci->membase );
+ hw->membase = ioremap ( pci->membase, 0x100 );
- nic->ioaddr = hw->membase;
+ nic->ioaddr = pci->membase;
nic->irqno = 0;
return prism2_probe ( nic, hw );
diff --git a/gpxe/src/drivers/net/prism2_plx.c b/gpxe/src/drivers/net/prism2_plx.c
index 150bbe69..a10eef29 100644
--- a/gpxe/src/drivers/net/prism2_plx.c
+++ b/gpxe/src/drivers/net/prism2_plx.c
@@ -48,10 +48,9 @@ static int prism2_find_plx ( hfa384x_t *hw, struct pci_device *p )
iobase &= PCI_BASE_ADDRESS_IO_MASK;
/* Fill out hw structure */
- hw->membase = attr_mem;
hw->iobase = iobase;
- printf ( "PLX9052 has local config registers at %#lx\n", plx_lcr );
- printf ( "Prism2 has attribute memory at %#lx and I/O base at %#lx\n", attr_mem, iobase );
+ printf ( "PLX9052 has local config registers at %#x\n", plx_lcr );
+ printf ( "Prism2 has attribute memory at %#x and I/O base at %#x\n", attr_mem, iobase );
/* Search for CIS strings */
printf ( "Searching for PCMCIA card...\n" );
diff --git a/gpxe/src/drivers/net/r8169.c b/gpxe/src/drivers/net/r8169.c
index 885f054a..4315f47a 100644
--- a/gpxe/src/drivers/net/r8169.c
+++ b/gpxe/src/drivers/net/r8169.c
@@ -1,1159 +1,434 @@
-/**************************************************************************
-* r8169.c: Etherboot device driver for the RealTek RTL-8169 Gigabit
-* Written 2003 by Timothy Legge <tlegge@rogers.com>
-*
-* This program is free software; you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published by
-* the Free Software Foundation; either version 2 of the License, or
-* (at your option) any later version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program; if not, write to the Free Software
-* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*
-* Portions of this code based on:
-* r8169.c: A RealTek RTL-8169 Gigabit Ethernet driver
-* for Linux kernel 2.4.x.
-*
-* Written 2002 ShuChen <shuchen@realtek.com.tw>
-* See Linux Driver for full information
-*
-* Linux Driver Versions:
-* 1.27a, 10.02.2002
-* RTL8169_VERSION "2.2" <2004/08/09>
-*
-* Thanks to:
-* Jean Chen of RealTek Semiconductor Corp. for
-* providing the evaluation NIC used to develop
-* this driver. RealTek's support for Etherboot
-* is appreciated.
-*
-* REVISION HISTORY:
-* ================
-*
-* v1.0 11-26-2003 timlegge Initial port of Linux driver
-* v1.5 01-17-2004 timlegge Initial driver output cleanup
-* v1.6 03-27-2004 timlegge Additional Cleanup
-* v1.7 11-22-2005 timlegge Update to RealTek Driver Version 2.2
-*
-* 03-19-2008 Hilko Bengen Cleanups and fixes for newer cards
-* (successfully tested with 8110SC-d onboard NIC)
-*
-* Indent Options: indent -kr -i8
-***************************************************************************/
-
-#include "etherboot.h"
-#include "nic.h"
-#include <gpxe/pci.h>
+/*
+ * Copyright (c) 2008 Marty Connor <mdc@etherboot.org>
+ * Copyright (c) 2008 Entity Cyber, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * This driver is based on rtl8169 data sheets and work by:
+ *
+ * Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
+ * Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
+ * Copyright (c) a lot of people too. Please respect their work.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <errno.h>
#include <gpxe/ethernet.h>
+#include <gpxe/if_ether.h>
+#include <gpxe/io.h>
+#include <gpxe/iobuf.h>
#include <gpxe/malloc.h>
+#include <gpxe/netdevice.h>
+#include <gpxe/pci.h>
+#include <gpxe/timer.h>
-#define drv_version "v1.7+"
-#define drv_date "03-19-2008"
-
-#define HZ 1000
-
-static u32 ioaddr;
-
-/* Condensed operations for readability. */
-#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr))
-#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr))
-
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-
-#undef RTL8169_DEBUG
-#undef RTL8169_JUMBO_FRAME_SUPPORT
-#undef RTL8169_HW_FLOW_CONTROL_SUPPORT
-
-
-#undef RTL8169_IOCTL_SUPPORT
-#undef RTL8169_DYNAMIC_CONTROL
-#define RTL8169_USE_IO
-
-#if 0
-/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 20;
-#endif
-
-#if 0
-/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
- The RTL chips use a 64 element hash table based on the Ethernet CRC. */
-static int multicast_filter_limit = 32;
-#endif
-
-/* MAC address length*/
-#define MAC_ADDR_LEN 6
-
-/* max supported gigabit ethernet frame size -- must be at least (dev->mtu+14+4).*/
-#define MAX_ETH_FRAME_SIZE 1536
-
-#define TX_FIFO_THRESH 256 /* In bytes */
-
-#define RX_FIFO_THRESH 7 /* 7 means NO threshold, Rx buffer level before first PCI xfer. */
-#define RX_DMA_BURST 7 /* Maximum PCI burst, '6' is 1024 */
-#define TX_DMA_BURST 7 /* Maximum PCI burst, '6' is 1024 */
-#define ETTh 0x3F /* 0x3F means NO threshold */
-
-#define EarlyTxThld 0x3F /* 0x3F means NO early transmit */
-#define RxPacketMaxSize 0x0800 /* Maximum size supported is 16K-1 */
-#define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */
-
-#define NUM_TX_DESC 1 /* Number of Tx descriptor registers */
-#define NUM_RX_DESC 4 /* Number of Rx descriptor registers */
-#define RX_BUF_SIZE 1536 /* Rx Buffer size */
-
-#define RTL_MIN_IO_SIZE 0x80
-#define TX_TIMEOUT (6*HZ)
-
-#define RTL8169_TIMER_EXPIRE_TIME 100 //100
-
-#define ETH_HDR_LEN 14
-#define DEFAULT_MTU 1500
-#define DEFAULT_RX_BUF_LEN 1536
-
-
-#ifdef RTL8169_JUMBO_FRAME_SUPPORT
-#define MAX_JUMBO_FRAME_MTU ( 10000 )
-#define MAX_RX_SKBDATA_SIZE ( MAX_JUMBO_FRAME_MTU + ETH_HDR_LEN )
-#else
-#define MAX_RX_SKBDATA_SIZE 1600
-#endif //end #ifdef RTL8169_JUMBO_FRAME_SUPPORT
-
-#ifdef RTL8169_USE_IO
-#define RTL_W8(reg, val8) outb ((val8), ioaddr + (reg))
-#define RTL_W16(reg, val16) outw ((val16), ioaddr + (reg))
-#define RTL_W32(reg, val32) outl ((val32), ioaddr + (reg))
-#define RTL_R8(reg) inb (ioaddr + (reg))
-#define RTL_R16(reg) inw (ioaddr + (reg))
-#define RTL_R32(reg) ((unsigned long) inl (ioaddr + (reg)))
-#else
-/* write/read MMIO register */
-#define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg))
-#define RTL_W16(reg, val16) writew ((val16), ioaddr + (reg))
-#define RTL_W32(reg, val32) writel ((val32), ioaddr + (reg))
-#define RTL_R8(reg) readb (ioaddr + (reg))
-#define RTL_R16(reg) readw (ioaddr + (reg))
-#define RTL_R32(reg) ((unsigned long) readl (ioaddr + (reg)))
-#endif
-
-enum mac_version {
- RTL_GIGA_MAC_VER_01 = 0x01, // 8169
- RTL_GIGA_MAC_VER_02 = 0x02, // 8169S
- RTL_GIGA_MAC_VER_03 = 0x03, // 8110S
- RTL_GIGA_MAC_VER_04 = 0x04, // 8169SB
- RTL_GIGA_MAC_VER_05 = 0x05, // 8110SCd
- RTL_GIGA_MAC_VER_06 = 0x06, // 8110SCe
- RTL_GIGA_MAC_VER_11 = 0x0b, // 8168Bb
- RTL_GIGA_MAC_VER_12 = 0x0c, // 8168Be
- RTL_GIGA_MAC_VER_13 = 0x0d, // 8101Eb
- RTL_GIGA_MAC_VER_14 = 0x0e, // 8101 ?
- RTL_GIGA_MAC_VER_15 = 0x0f, // 8101 ?
- RTL_GIGA_MAC_VER_16 = 0x11, // 8101Ec
- RTL_GIGA_MAC_VER_17 = 0x10, // 8168Bf
- RTL_GIGA_MAC_VER_18 = 0x12, // 8168CP
- RTL_GIGA_MAC_VER_19 = 0x13, // 8168C
- RTL_GIGA_MAC_VER_20 = 0x14 // 8168C
-};
-
-enum cfg_version {
- RTL_CFG_0 = 0x00,
- RTL_CFG_1,
- RTL_CFG_2
-};
-
-static struct {
- const char *name;
- u8 mac_version; /* depend on RTL8169 docs */
- u32 RxConfigMask; /* should clear the bits supported by this chip */
-} rtl_chip_info[] = {
- {"RTL8169", RTL_GIGA_MAC_VER_01, 0xff7e1880}, // 8169
- {"RTL8169s", RTL_GIGA_MAC_VER_02, 0xff7e1880}, // 8169S
- {"RTL8110s", RTL_GIGA_MAC_VER_03, 0xff7e1880}, // 8110S
- {"RTL8169sb/8110sb", RTL_GIGA_MAC_VER_04, 0xff7e1880}, // 8169SB
- {"RTL8169sc/8110sc-d",RTL_GIGA_MAC_VER_05, 0xff7e1880}, // 8110SCd
- {"RTL8169sc/8110sc-e",RTL_GIGA_MAC_VER_06, 0xff7e1880}, // 8110SCe
- {"RTL8168b/8111b", RTL_GIGA_MAC_VER_11, 0xff7e1880}, // PCI-E
- {"RTL8168b/8111b", RTL_GIGA_MAC_VER_12, 0xff7e1880}, // PCI-E
- {"RTL8101e", RTL_GIGA_MAC_VER_13, 0xff7e1880}, // PCI-E 8139
- {"RTL8100e", RTL_GIGA_MAC_VER_14, 0xff7e1880}, // PCI-E 8139
- {"RTL8100e", RTL_GIGA_MAC_VER_15, 0xff7e1880}, // PCI-E 8139
- {"RTL8168b/8111b", RTL_GIGA_MAC_VER_17, 0xff7e1880}, // PCI-E
- {"RTL8101e", RTL_GIGA_MAC_VER_16, 0xff7e1880}, // PCI-E
- {"RTL8168cp/8111cp", RTL_GIGA_MAC_VER_18, 0xff7e1880}, // PCI-E
- {"RTL8168c/8111c", RTL_GIGA_MAC_VER_19, 0xff7e1880}, // PCI-E
- {"RTL8168c/8111c", RTL_GIGA_MAC_VER_20, 0xff7e1880}, // PCI-E
-};
-
-enum RTL8169_registers {
- MAC0 = 0x0, /* Ethernet hardware address. */
- MAR0 = 0x8, /* Multicast filter. */
- TxDescAddrLow = 0x20,
- TxDescAddrHigh = 0x24,
- TxHDescStartAddr = 0x28,
- FLASH = 0x30,
- ERSR = 0x36,
- ChipCmd = 0x37,
- TxPoll = 0x38,
- IntrMask = 0x3C,
- IntrStatus = 0x3E,
- TxConfig = 0x40,
- RxConfig = 0x44,
- RxMissed = 0x4C,
- Cfg9346 = 0x50,
- Config0 = 0x51,
- Config1 = 0x52,
- Config2 = 0x53,
- Config3 = 0x54,
- Config4 = 0x55,
- Config5 = 0x56,
- MultiIntr = 0x5C,
- PHYAR = 0x60,
- TBICSR = 0x64,
- TBI_ANAR = 0x68,
- TBI_LPAR = 0x6A,
- PHYstatus = 0x6C,
- RxMaxSize = 0xda,
- CPlusCmd = 0xe0,
- IntrMitigate = 0xe2,
- RxDescAddrLow = 0xe4,
- RxDescAddrHigh = 0xe8,
- ETThReg = 0xEC,
- FuncEvent = 0xF0,
- FuncEventMask = 0xF4,
- FuncPresetState = 0xF8,
- FuncForceEvent = 0xFC,
-};
-
-enum RTL8169_register_content {
- /*InterruptStatusBits */
- SYSErr = 0x8000,
- PCSTimeout = 0x4000,
- SWInt = 0x0100,
- TxDescUnavail = 0x80,
- RxFIFOOver = 0x40,
- LinkChg = 0x20,
- RxOverflow = 0x10,
- TxErr = 0x08,
- TxOK = 0x04,
- RxErr = 0x02,
- RxOK = 0x01,
-
- /*RxStatusDesc */
- RxRES = 0x00200000,
- RxCRC = 0x00080000,
- RxRUNT = 0x00100000,
- RxRWT = 0x00400000,
-
- /*ChipCmdBits */
- CmdReset = 0x10,
- CmdRxEnb = 0x08,
- CmdTxEnb = 0x04,
- RxBufEmpty = 0x01,
-
- /*Cfg9346Bits */
- Cfg9346_Lock = 0x00,
- Cfg9346_Unlock = 0xC0,
-
- /*rx_mode_bits */
- AcceptErr = 0x20,
- AcceptRunt = 0x10,
- AcceptBroadcast = 0x08,
- AcceptMulticast = 0x04,
- AcceptMyPhys = 0x02,
- AcceptAllPhys = 0x01,
-
- /*RxConfigBits */
- RxCfgFIFOShift = 13,
- RxCfgDMAShift = 8,
-
- /*TxConfigBits */
- TxInterFrameGapShift = 24,
- TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */
-
- /*rtl8169_PHYstatus */
- TBI_Enable = 0x80,
- TxFlowCtrl = 0x40,
- RxFlowCtrl = 0x20,
- _1000bpsF = 0x10,
- _100bps = 0x08,
- _10bps = 0x04,
- LinkStatus = 0x02,
- FullDup = 0x01,
-
- /*GIGABIT_PHY_registers */
- PHY_CTRL_REG = 0,
- PHY_STAT_REG = 1,
- PHY_AUTO_NEGO_REG = 4,
- PHY_1000_CTRL_REG = 9,
-
- /*GIGABIT_PHY_REG_BIT */
- PHY_Restart_Auto_Nego = 0x0200,
- PHY_Enable_Auto_Nego = 0x1000,
-
- /* PHY_STAT_REG = 1; */
- PHY_Auto_Neco_Comp = 0x0020,
-
- /* PHY_AUTO_NEGO_REG = 4; */
- PHY_Cap_10_Half = 0x0020,
- PHY_Cap_10_Full = 0x0040,
- PHY_Cap_100_Half = 0x0080,
- PHY_Cap_100_Full = 0x0100,
-
- /* PHY_1000_CTRL_REG = 9; */
- PHY_Cap_1000_Full = 0x0200,
- PHY_Cap_1000_Half = 0x0100,
-
- PHY_Cap_PAUSE = 0x0400,
- PHY_Cap_ASYM_PAUSE = 0x0800,
-
- PHY_Cap_Null = 0x0,
-
- /*_MediaType*/
- _10_Half = 0x01,
- _10_Full = 0x02,
- _100_Half = 0x04,
- _100_Full = 0x08,
- _1000_Full = 0x10,
-
- /*_TBICSRBit*/
- TBILinkOK = 0x02000000,
-};
-
-enum _DescStatusBit {
- OWNbit = 0x80000000,
- EORbit = 0x40000000,
- FSbit = 0x20000000,
- LSbit = 0x10000000,
-};
-
-struct TxDesc {
- u32 status;
- u32 vlan_tag;
- u32 buf_addr;
- u32 buf_Haddr;
-};
-
-struct RxDesc {
- u32 status;
- u32 vlan_tag;
- u32 buf_addr;
- u32 buf_Haddr;
-};
+#include "r8169.h"
-/* The descriptors for this card are required to be aligned on 256
- * byte boundaries. As the align attribute does not do more than 16
- * bytes of alignment it requires some extra steps. Add 256 to the
- * size of the array and the init_ring adjusts the alignment.
- *
- * UPDATE: This is no longer true; we can request arbitrary alignment.
- */
+/*** Low level hardware routines ***/
-/* Define the TX and RX Descriptors and Buffers */
-#define __align_256 __attribute__ (( aligned ( 256 ) ))
-struct {
- struct TxDesc tx_ring[NUM_TX_DESC] __align_256;
- unsigned char txb[NUM_TX_DESC * RX_BUF_SIZE];
- struct RxDesc rx_ring[NUM_RX_DESC] __align_256;
- unsigned char rxb[NUM_RX_DESC * RX_BUF_SIZE];
-} *r8169_bufs;
-#define tx_ring r8169_bufs->tx_ring
-#define rx_ring r8169_bufs->rx_ring
-#define txb r8169_bufs->txb
-#define rxb r8169_bufs->rxb
-
-static struct rtl8169_private {
- void *mmio_addr; /* memory map physical address */
- int chipset;
- int pcfg;
- int mac_version;
- unsigned long cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
- unsigned long cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
- struct TxDesc *TxDescArray; /* Index of 256-alignment Tx Descriptor buffer */
- struct RxDesc *RxDescArray; /* Index of 256-alignment Rx Descriptor buffer */
- unsigned char *RxBufferRing[NUM_RX_DESC]; /* Index of Rx Buffer array */
- unsigned char *Tx_skbuff[NUM_TX_DESC];
-} tpx;
-
-static const u16 rtl8169_intr_mask =
- LinkChg | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK;
-static const unsigned int rtl8169_rx_config =
- (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift) |
- 0x0000000E;
-
-static void rtl8169_hw_phy_config(struct nic *nic __unused);
-//static void rtl8169_hw_phy_reset(struct net_device *dev);
-
-#define RTL8169_WRITE_GMII_REG_BIT( ioaddr, reg, bitnum, bitval )\
-{ \
- int val; \
- if( bitval == 1 ){ val = ( RTL8169_READ_GMII_REG( ioaddr, reg ) | (bitval<<bitnum) ) & 0xffff ; } \
- else{ val = ( RTL8169_READ_GMII_REG( ioaddr, reg ) & (~(0x0001<<bitnum)) ) & 0xffff ; } \
- RTL8169_WRITE_GMII_REG( ioaddr, reg, val ); \
- }
-
-//=================================================================
-// PHYAR
-// bit Symbol
-// 31 Flag
-// 30-21 reserved
-// 20-16 5-bit GMII/MII register address
-// 15-0 16-bit GMII/MII register data
-//=================================================================
-static void RTL8169_WRITE_GMII_REG(unsigned long ioaddr, int RegAddr, int value)
+static void mdio_write(void *ioaddr, int reg_addr, int value)
{
int i;
- RTL_W32(PHYAR, 0x80000000 | (RegAddr & 0xFF) << 16 | value);
- udelay(1000);
+ DBGP ( "mdio_write\n" );
- for (i = 2000; i > 0; i--) {
- // Check if the RTL8169 has completed writing to the specified MII register
- if (!(RTL_R32(PHYAR) & 0x80000000)) {
+ RTL_W32(PHYAR, 0x80000000 | (reg_addr & 0x1f) << 16 | (value & 0xffff));
+
+ for (i = 20; i > 0; i--) {
+ /*
+ * Check if the RTL8169 has completed writing to the specified
+ * MII register.
+ */
+ if (!(RTL_R32(PHYAR) & 0x80000000))
break;
- } else {
- udelay(100);
- } // end of if( ! (RTL_R32(PHYAR)&0x80000000) )
- } // end of for() loop
+ udelay(25);
+ }
}
-//=================================================================
-static int RTL8169_READ_GMII_REG(unsigned long ioaddr, int RegAddr)
+static int mdio_read(void *ioaddr, int reg_addr)
{
int i, value = -1;
- RTL_W32(PHYAR, 0x0 | (RegAddr & 0xFF) << 16);
- udelay(1000);
+ DBGP ( "mdio_read\n" );
+
+ RTL_W32(PHYAR, 0x0 | (reg_addr & 0x1f) << 16);
- for (i = 2000; i > 0; i--) {
- // Check if the RTL8169 has completed retrieving data from the specified MII register
+ for (i = 20; i > 0; i--) {
+ /*
+ * Check if the RTL8169 has completed retrieving data from
+ * the specified MII register.
+ */
if (RTL_R32(PHYAR) & 0x80000000) {
- value = (int) (RTL_R32(PHYAR) & 0xFFFF);
+ value = RTL_R32(PHYAR) & 0xffff;
break;
- } else {
- udelay(100);
- } // end of if( RTL_R32(PHYAR) & 0x80000000 )
- } // end of for() loop
+ }
+ udelay(25);
+ }
return value;
}
+static void mdio_patch(void *ioaddr, int reg_addr, int value)
+{
+ DBGP ( "mdio_patch\n" );
+
+ mdio_write(ioaddr, reg_addr, mdio_read(ioaddr, reg_addr) | value);
+}
-#if 0
-static void mdio_write(int RegAddr, int value)
+static void rtl_ephy_write(void *ioaddr, int reg_addr, int value)
{
- int i;
+ unsigned int i;
+
+ DBGP ( "rtl_ephy_write\n" );
- RTL_W32(PHYAR, 0x80000000 | (RegAddr & 0xFF) << 16 | value);
- udelay(1000);
+ RTL_W32(EPHYAR, EPHYAR_WRITE_CMD | (value & EPHYAR_DATA_MASK) |
+ (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT);
- for (i = 2000; i > 0; i--) {
- /* Check if the RTL8169 has completed writing to the specified MII register */
- if (!(RTL_R32(PHYAR) & 0x80000000)) {
+ for (i = 0; i < 100; i++) {
+ if (!(RTL_R32(EPHYAR) & EPHYAR_FLAG))
break;
- } else {
- udelay(100);
- }
+ udelay(10);
}
}
-static int mdio_read(int RegAddr)
+static u16 rtl_ephy_read(void *ioaddr, int reg_addr)
{
- int i, value = -1;
+ u16 value = 0xffff;
+ unsigned int i;
- RTL_W32(PHYAR, 0x0 | (RegAddr & 0xFF) << 16);
- udelay(1000);
+ DBGP ( "rtl_ephy_read\n" );
- for (i = 2000; i > 0; i--) {
- /* Check if the RTL8169 has completed retrieving data from the specified MII register */
- if (RTL_R32(PHYAR) & 0x80000000) {
- value = (int) (RTL_R32(PHYAR) & 0xFFFF);
+ RTL_W32(EPHYAR, (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT);
+
+ for (i = 0; i < 100; i++) {
+ if (RTL_R32(EPHYAR) & EPHYAR_FLAG) {
+ value = RTL_R32(EPHYAR) & EPHYAR_DATA_MASK;
break;
- } else {
- udelay(100);
}
+ udelay(10);
}
+
return value;
}
-#endif
-static void rtl8169_get_mac_version( struct rtl8169_private *tp,
- u32 ioaddr )
+static void rtl_csi_write(void *ioaddr, int addr, int value)
{
- /*
- * The driver currently handles the 8168Bf and the 8168Be identically
- * but they can be identified more specifically through the test below
- * if needed:
- *
- * (RTL_R32(TxConfig) & 0x700000) == 0x500000 ? 8168Bf : 8168Be
- *
- * Same thing for the 8101Eb and the 8101Ec:
- *
- * (RTL_R32(TxConfig) & 0x700000) == 0x200000 ? 8101Eb : 8101Ec
- */
- const struct {
- u32 mask;
- u32 val;
- int mac_version;
- } mac_info[] = {
- /* 8168B family. */
- { 0x7c800000, 0x3c800000, RTL_GIGA_MAC_VER_18 },
- { 0x7cf00000, 0x3c000000, RTL_GIGA_MAC_VER_19 },
- { 0x7cf00000, 0x3c200000, RTL_GIGA_MAC_VER_20 },
- { 0x7c800000, 0x3c000000, RTL_GIGA_MAC_VER_20 },
- /* 8168B family. */
- { 0x7cf00000, 0x38000000, RTL_GIGA_MAC_VER_12 },
- { 0x7cf00000, 0x38500000, RTL_GIGA_MAC_VER_17 },
- { 0x7c800000, 0x38000000, RTL_GIGA_MAC_VER_17 },
- { 0x7c800000, 0x30000000, RTL_GIGA_MAC_VER_11 },
- /* 8101 family. */
- { 0x7cf00000, 0x34000000, RTL_GIGA_MAC_VER_13 },
- { 0x7cf00000, 0x34200000, RTL_GIGA_MAC_VER_16 },
- { 0x7c800000, 0x34000000, RTL_GIGA_MAC_VER_16 },
- /* FIXME: where did these entries come from ? -- FR */
- { 0xfc800000, 0x38800000, RTL_GIGA_MAC_VER_15 },
- { 0xfc800000, 0x30800000, RTL_GIGA_MAC_VER_14 },
- /* 8110 family. */
- { 0xfc800000, 0x98000000, RTL_GIGA_MAC_VER_06 },
- { 0xfc800000, 0x18000000, RTL_GIGA_MAC_VER_05 },
- { 0xfc800000, 0x10000000, RTL_GIGA_MAC_VER_04 },
- { 0xfc800000, 0x04000000, RTL_GIGA_MAC_VER_03 },
- { 0xfc800000, 0x00800000, RTL_GIGA_MAC_VER_02 },
- { 0xfc800000, 0x00000000, RTL_GIGA_MAC_VER_01 },
- { 0x00000000, 0x00000000, RTL_GIGA_MAC_VER_01 } /* Catch-all */
- }, *p = mac_info;
+ unsigned int i;
- unsigned long rv;
+ DBGP ( "rtl_csi_write\n" );
- rv = (RTL_R32(TxConfig));
+ RTL_W32(CSIDR, value);
+ RTL_W32(CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) |
+ CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
- while ((rv & p->mask) != p->val)
- p++;
- tp->mac_version = p->mac_version;
-
- if (p->mask == 0x00000000) {
- DBG("unknown MAC (%08lx)\n", rv);
+ for (i = 0; i < 100; i++) {
+ if (!(RTL_R32(CSIAR) & CSIAR_FLAG))
+ break;
+ udelay(10);
}
}
-#define IORESOURCE_MEM 0x00000200
-
-static int rtl8169_init_board(struct pci_device *pdev)
+static u32 rtl_csi_read(void *ioaddr, int addr)
{
- int i;
-// unsigned long mmio_end, mmio_flags
- unsigned long mmio_start, mmio_len;
- struct rtl8169_private *tp = &tpx;
-
- adjust_pci_device(pdev);
-
- mmio_start = pci_bar_start(pdev, PCI_BASE_ADDRESS_1);
-// mmio_end = pci_resource_end (pdev, 1);
-// mmio_flags = pci_resource_flags (pdev, PCI_BASE_ADDRESS_1);
- mmio_len = pci_bar_size(pdev, PCI_BASE_ADDRESS_1);
-
- // make sure PCI base addr 1 is MMIO
-// if (!(mmio_flags & IORESOURCE_MEM)) {
-// printf ("region #1 not an MMIO resource, aborting\n");
-// return 0;
-// }
-
- // check for weird/broken PCI region reporting
- if (mmio_len < RTL_MIN_IO_SIZE) {
- printf("Invalid PCI region size(s), aborting\n");
- return 0;
- }
-#ifdef RTL8169_USE_IO
- ioaddr = pci_bar_start(pdev, PCI_BASE_ADDRESS_0);
-#else
- // ioremap MMIO region
- ioaddr = (unsigned long) ioremap(mmio_start, mmio_len);
- if (ioaddr == 0) {
- printk("cannot remap MMIO, aborting\n");
- return 0;
- }
-#endif
+ u32 value = ~0x00;
+ unsigned int i;
- tp->mmio_addr = (void*)ioaddr;
- /* Soft reset the chip. */
- RTL_W8(ChipCmd, CmdReset);
+ DBGP ( "rtl_csi_read\n" );
- /* Check that the chip has finished the reset. */
- for (i = 1000; i > 0; i--)
- if ((RTL_R8(ChipCmd) & CmdReset) == 0)
- break;
- else
- udelay(10);
+ RTL_W32(CSIAR, (addr & CSIAR_ADDR_MASK) |
+ CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
- /* Identify chip attached to board */
- rtl8169_get_mac_version( tp, ioaddr );
-
- // rtl8169_print_mac_version(tp);
-
- {
- unsigned char val8 =
- (unsigned char) (RTL8169_READ_GMII_REG(ioaddr, 3) &
- 0x000f);
- if (val8 == 0x00) {
- tp->pcfg = RTL_CFG_0;
- } else if (val8 == 0x01) {
- tp->pcfg = RTL_CFG_1;
- } else if (val8 == 0x02) {
- tp->pcfg = RTL_CFG_2;
- } else {
- tp->pcfg = RTL_CFG_2;
+ for (i = 0; i < 100; i++) {
+ if (RTL_R32(CSIAR) & CSIAR_FLAG) {
+ value = RTL_R32(CSIDR);
+ break;
}
+ udelay(10);
}
- /* identify chip attached to board */
-
- for (i = ARRAY_SIZE(rtl_chip_info) - 1; i >= 0; i--)
- if (tp->mac_version == rtl_chip_info[i].mac_version) {
- tp->chipset = i;
- goto match;
- }
- /* if unknown chip, assume array element #0, original RTL-8169 in this case */
- DBG ( "PCI device: unknown chip version, assuming RTL-8169\n" );
- DBG ( "PCI device: TxConfig = %#lX\n", ( unsigned long ) RTL_R32 ( TxConfig ) );
+ return value;
+}
- tp->chipset = 0;
- return 1;
+static void rtl8169_irq_mask_and_ack(void *ioaddr)
+{
+ DBGP ( "rtl8169_irq_mask_and_ack\n" );
- match:
- return 0;
+ RTL_W16(IntrMask, 0x0000);
+ RTL_W16(IntrStatus, 0xffff);
}
-/**************************************************************************
-IRQ - Wait for a frame
-***************************************************************************/
-static void r8169_irq(struct nic *nic __unused, irq_action_t action)
+static unsigned int rtl8169_tbi_reset_pending(void *ioaddr)
{
- int intr_status = 0;
- int interested = RxOverflow | RxFIFOOver | RxErr | RxOK;
+ DBGP ( "rtl8169_tbi_reset_pending\n" );
- switch (action) {
- case DISABLE:
- case ENABLE:
- intr_status = RTL_R16(IntrStatus);
- /* h/w no longer present (hotplug?) or major error,
- bail */
- if (intr_status == 0xFFFF)
- break;
-
- intr_status = intr_status & ~interested;
- if (action == ENABLE)
- intr_status = intr_status | interested;
- RTL_W16(IntrMask, intr_status);
- break;
- case FORCE:
- RTL_W8(TxPoll, (RTL_R8(TxPoll) | 0x01));
- break;
- }
+ return RTL_R32(TBICSR) & TBIReset;
}
-/**************************************************************************
-POLL - Wait for a frame
-***************************************************************************/
-static int r8169_poll(struct nic *nic, int retrieve)
-{
- /* return true if there's an ethernet packet ready to read */
- /* nic->packet should contain data on return */
- /* nic->packetlen should contain length of data */
- int cur_rx;
- unsigned int intr_status = 0;
- struct rtl8169_private *tp = &tpx;
-
- cur_rx = tp->cur_rx;
- if ((tp->RxDescArray[cur_rx].status & OWNbit) == 0) {
- /* There is a packet ready */
- DBG("r8169_poll(): packet ready\n");
- if (!retrieve)
- return 1;
- intr_status = RTL_R16(IntrStatus);
- /* h/w no longer present (hotplug?) or major error,
- bail */
- if (intr_status == 0xFFFF) {
- DBG("r8169_poll(): unknown error\n");
- return 0;
- }
- RTL_W16(IntrStatus, intr_status &
- ~(RxFIFOOver | RxOverflow | RxOK));
-
- if (!(tp->RxDescArray[cur_rx].status & RxRES)) {
- nic->packetlen = (int) (tp->RxDescArray[cur_rx].
- status & 0x00001FFF) - 4;
- memcpy(nic->packet, tp->RxBufferRing[cur_rx],
- nic->packetlen);
- if (cur_rx == NUM_RX_DESC - 1)
- tp->RxDescArray[cur_rx].status =
- (OWNbit | EORbit) + RX_BUF_SIZE;
- else
- tp->RxDescArray[cur_rx].status =
- OWNbit + RX_BUF_SIZE;
- tp->RxDescArray[cur_rx].buf_addr =
- virt_to_bus(tp->RxBufferRing[cur_rx]);
- tp->RxDescArray[cur_rx].buf_Haddr = 0;
- } else
- printf("Error Rx");
- /* FIXME: shouldn't I reset the status on an error */
- cur_rx = (cur_rx + 1) % NUM_RX_DESC;
- tp->cur_rx = cur_rx;
- RTL_W16(IntrStatus, intr_status &
- (RxFIFOOver | RxOverflow | RxOK));
-
- return 1;
+static unsigned int rtl8169_xmii_reset_pending(void *ioaddr)
+{
+ DBGP ( "rtl8169_xmii_reset_pending\n" );
- }
- tp->cur_rx = cur_rx;
- /* FIXME: There is no reason to do this as cur_rx did not change */
-
- return (0); /* initially as this is called to flush the input */
-
-}
-
-/**************************************************************************
-TRANSMIT - Transmit a frame
-***************************************************************************/
-static void r8169_transmit(struct nic *nic, const char *d, /* Destination */
- unsigned int t, /* Type */
- unsigned int s, /* size */
- const char *p)
-{ /* Packet */
- /* send the packet to destination */
-
- u16 nstype;
- u32 to;
- u8 *ptxb;
- struct rtl8169_private *tp = &tpx;
- int entry = tp->cur_tx % NUM_TX_DESC;
-
- /* point to the current txb incase multiple tx_rings are used */
- ptxb = tp->Tx_skbuff[entry * MAX_ETH_FRAME_SIZE];
- memcpy(ptxb, d, ETH_ALEN);
- memcpy(ptxb + ETH_ALEN, nic->node_addr, ETH_ALEN);
- nstype = htons((u16) t);
- memcpy(ptxb + 2 * ETH_ALEN, (u8 *) & nstype, 2);
- memcpy(ptxb + ETH_HLEN, p, s);
- s += ETH_HLEN;
- s &= 0x0FFF;
- while (s < ETH_ZLEN)
- ptxb[s++] = '\0';
-
- tp->TxDescArray[entry].buf_addr = virt_to_bus(ptxb);
- tp->TxDescArray[entry].buf_Haddr = 0;
- if (entry != (NUM_TX_DESC - 1))
- tp->TxDescArray[entry].status =
- (OWNbit | FSbit | LSbit) | ((s > ETH_ZLEN) ? s :
- ETH_ZLEN);
- else
- tp->TxDescArray[entry].status =
- (OWNbit | EORbit | FSbit | LSbit) | ((s > ETH_ZLEN) ? s
- : ETH_ZLEN);
- RTL_W8(TxPoll, 0x40); /* set polling bit */
-
- tp->cur_tx++;
- to = currticks() + TX_TIMEOUT;
- while ((tp->TxDescArray[entry].status & OWNbit) && (currticks() < to)); /* wait */
-
- if (currticks() >= to) {
- printf("TX Time Out");
- }
+ return mdio_read(ioaddr, MII_BMCR) & BMCR_RESET;
}
-static void rtl8169_set_rx_mode(struct nic *nic __unused)
+static unsigned int rtl8169_tbi_link_ok(void *ioaddr)
{
- u32 mc_filter[2]; /* Multicast hash filter */
- int rx_mode;
- u32 tmp = 0;
- struct rtl8169_private *tp = &tpx;
+ DBGP ( "rtl8169_tbi_link_ok\n" );
- /* IFF_ALLMULTI */
- /* Too many to filter perfectly -- accept all multicasts. */
- rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
- mc_filter[1] = mc_filter[0] = 0xffffffff;
+ return RTL_R32(TBICSR) & TBILinkOk;
+}
- tmp =
- rtl8169_rx_config | rx_mode | (RTL_R32(RxConfig) &
- rtl_chip_info[tp->chipset].
- RxConfigMask);
+static unsigned int rtl8169_xmii_link_ok(void *ioaddr)
+{
+ DBGP ( "rtl8169_xmii_link_ok\n" );
- RTL_W32(RxConfig, tmp);
- RTL_W32(MAR0 + 0, mc_filter[0]);
- RTL_W32(MAR0 + 4, mc_filter[1]);
+ return RTL_R8(PHYstatus) & LinkStatus;
}
-static void rtl8169_hw_start(struct nic *nic)
+
+static void rtl8169_tbi_reset_enable(void *ioaddr)
{
- u32 i;
- struct rtl8169_private *tp = &tpx;
+ DBGP ( "rtl8169_tbi_reset_enable\n" );
- /* Soft reset the chip. */
- RTL_W8(ChipCmd, CmdReset);
+ RTL_W32(TBICSR, RTL_R32(TBICSR) | TBIReset);
+}
- /* Check that the chip has finished the reset. */
- for (i = 1000; i > 0; i--) {
- if ((RTL_R8(ChipCmd) & CmdReset) == 0)
- break;
- else
- udelay(10);
- }
+static void rtl8169_xmii_reset_enable(void *ioaddr)
+{
+ unsigned int val;
- RTL_W8(Cfg9346, Cfg9346_Unlock);
- RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
- RTL_W8(ETThReg, ETTh);
+ DBGP ( "rtl8169_xmii_reset_enable\n" );
- /* For gigabit rtl8169 */
- RTL_W16(RxMaxSize, RxPacketMaxSize);
+ val = mdio_read(ioaddr, MII_BMCR) | BMCR_RESET;
+ mdio_write(ioaddr, MII_BMCR, val & 0xffff);
+}
- /* Set Rx Config register */
- i = rtl8169_rx_config | (RTL_R32(RxConfig) &
- rtl_chip_info[tp->chipset].RxConfigMask);
- RTL_W32(RxConfig, i);
+static int rtl8169_set_speed_tbi(struct net_device *dev,
+ u8 autoneg, u16 speed, u8 duplex)
+{
+ struct rtl8169_private *tp = netdev_priv(dev);
+ void *ioaddr = tp->mmio_addr;
+ int ret = 0;
+ u32 reg;
+
+ DBGP ( "rtl8169_set_speed_tbi\n" );
+
+ reg = RTL_R32(TBICSR);
+ if ((autoneg == AUTONEG_DISABLE) && (speed == SPEED_1000) &&
+ (duplex == DUPLEX_FULL)) {
+ RTL_W32(TBICSR, reg & ~(TBINwEnable | TBINwRestart));
+ } else if (autoneg == AUTONEG_ENABLE)
+ RTL_W32(TBICSR, reg | TBINwEnable | TBINwRestart);
+ else {
+ DBG ( "incorrect speed setting refused in TBI mode\n" );
+ ret = -EOPNOTSUPP;
+ }
+ return ret;
+}
- /* Set DMA burst size and Interframe Gap Time */
- RTL_W32(TxConfig,
- (TX_DMA_BURST << TxDMAShift) | (InterFrameGap <<
- TxInterFrameGapShift));
+static int rtl8169_set_speed_xmii(struct net_device *dev,
+ u8 autoneg, u16 speed, u8 duplex)
+{
+ struct rtl8169_private *tp = netdev_priv(dev);
+ void *ioaddr = tp->mmio_addr;
+ int auto_nego, giga_ctrl;
+ DBGP ( "rtl8169_set_speed_xmii\n" );
- RTL_W16(CPlusCmd, RTL_R16(CPlusCmd));
+ auto_nego = mdio_read(ioaddr, MII_ADVERTISE);
+ auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL |
+ ADVERTISE_100HALF | ADVERTISE_100FULL);
+ giga_ctrl = mdio_read(ioaddr, MII_CTRL1000);
+ giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
- if (tp->mac_version == RTL_GIGA_MAC_VER_02 || tp->mac_version == RTL_GIGA_MAC_VER_03) {
- RTL_W16(CPlusCmd,
- (RTL_R16(CPlusCmd) | (1 << 14) | (1 << 3)));
- DBG
- ("Set MAC Reg C+CR Offset 0xE0: bit-3 and bit-14\n");
+ if (autoneg == AUTONEG_ENABLE) {
+ auto_nego |= (ADVERTISE_10HALF | ADVERTISE_10FULL |
+ ADVERTISE_100HALF | ADVERTISE_100FULL);
+ giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF;
} else {
- RTL_W16(CPlusCmd, (RTL_R16(CPlusCmd) | (1 << 3)));
- DBG("Set MAC Reg C+CR Offset 0xE0: bit-3.\n");
+ if (speed == SPEED_10)
+ auto_nego |= ADVERTISE_10HALF | ADVERTISE_10FULL;
+ else if (speed == SPEED_100)
+ auto_nego |= ADVERTISE_100HALF | ADVERTISE_100FULL;
+ else if (speed == SPEED_1000)
+ giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF;
+
+ if (duplex == DUPLEX_HALF)
+ auto_nego &= ~(ADVERTISE_10FULL | ADVERTISE_100FULL);
+
+ if (duplex == DUPLEX_FULL)
+ auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_100HALF);
+
+ /* This tweak comes straight from Realtek's driver. */
+ if ((speed == SPEED_100) && (duplex == DUPLEX_HALF) &&
+ ((tp->mac_version == RTL_GIGA_MAC_VER_13) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_16))) {
+ auto_nego = ADVERTISE_100HALF | ADVERTISE_CSMA;
+ }
}
- {
- //RTL_W16(IntrMitigate, 0x1517);
- //RTL_W16(IntrMitigate, 0x152a);
- //RTL_W16(IntrMitigate, 0x282a);
- RTL_W16(IntrMitigate, 0x0000);
+ /* The 8100e/8101e/8102e do Fast Ethernet only. */
+ if ((tp->mac_version == RTL_GIGA_MAC_VER_07) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_08) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_09) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_10) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_13) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_14) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_15) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_16)) {
+ if ((giga_ctrl & (ADVERTISE_1000FULL | ADVERTISE_1000HALF))) {
+ DBG ( "PHY does not support 1000Mbps.\n" );
+ }
+ giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
}
- tp->cur_rx = 0;
-
- RTL_W32(TxDescAddrLow, virt_to_le32desc(tp->TxDescArray));
- RTL_W32(TxDescAddrHigh, virt_to_le32desc(NULL));
- RTL_W32(RxDescAddrLow, virt_to_le32desc(tp->RxDescArray));
- RTL_W32(RxDescAddrHigh, virt_to_le32desc(NULL));
- RTL_W8(Cfg9346, Cfg9346_Lock);
- udelay(10);
-
- RTL_W32(RxMissed, 0);
-
- rtl8169_set_rx_mode(nic);
-
- /* no early-rx interrupts */
- RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
+ auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
+
+ if ((tp->mac_version == RTL_GIGA_MAC_VER_11) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_12) ||
+ (tp->mac_version >= RTL_GIGA_MAC_VER_17)) {
+ /*
+ * Wake up the PHY.
+ * Vendor specific (0x1f) and reserved (0x0e) MII registers.
+ */
+ mdio_write(ioaddr, 0x1f, 0x0000);
+ mdio_write(ioaddr, 0x0e, 0x0000);
+ }
- RTL_W16(IntrMask, rtl8169_intr_mask);
+ tp->phy_auto_nego_reg = auto_nego;
+ tp->phy_1000_ctrl_reg = giga_ctrl;
+ mdio_write(ioaddr, MII_ADVERTISE, auto_nego);
+ mdio_write(ioaddr, MII_CTRL1000, giga_ctrl);
+ mdio_write(ioaddr, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART);
+ return 0;
}
-static void rtl8169_init_ring(struct nic *nic __unused)
+static int rtl8169_set_speed(struct net_device *dev,
+ u8 autoneg, u16 speed, u8 duplex)
{
- int i;
- struct rtl8169_private *tp = &tpx;
+ struct rtl8169_private *tp = netdev_priv(dev);
+ int ret;
- tp->cur_rx = 0;
- tp->cur_tx = 0;
- memset(tp->TxDescArray, 0x0, NUM_TX_DESC * sizeof(struct TxDesc));
- memset(tp->RxDescArray, 0x0, NUM_RX_DESC * sizeof(struct RxDesc));
+ DBGP ( "rtl8169_set_speed\n" );
- for (i = 0; i < NUM_TX_DESC; i++) {
- tp->Tx_skbuff[i] = &txb[i];
- }
+ ret = tp->set_speed(dev, autoneg, speed, duplex);
- for (i = 0; i < NUM_RX_DESC; i++) {
- if (i == (NUM_RX_DESC - 1))
- tp->RxDescArray[i].status =
- (OWNbit | EORbit) | RX_BUF_SIZE;
- else
- tp->RxDescArray[i].status = OWNbit | RX_BUF_SIZE;
-
- tp->RxBufferRing[i] = &rxb[i * RX_BUF_SIZE];
- tp->RxDescArray[i].buf_addr =
- virt_to_bus(tp->RxBufferRing[i]);
- tp->RxDescArray[i].buf_Haddr = 0;
- }
+ return ret;
}
-/**************************************************************************
-RESET - Finish setting up the ethernet interface
-***************************************************************************/
-static void r8169_reset(struct nic *nic)
+static void rtl8169_write_gmii_reg_bit(void *ioaddr, int reg,
+ int bitnum, int bitval)
{
- int i;
- struct rtl8169_private *tp = &tpx;
-
- tp->TxDescArray = tx_ring;
- tp->RxDescArray = rx_ring;
-
- rtl8169_init_ring(nic);
- rtl8169_hw_start(nic);
- /* Construct a perfect filter frame with the mac address as first match
- * and broadcast for all others */
- for (i = 0; i < 192; i++)
- txb[i] = 0xFF;
-
- txb[0] = nic->node_addr[0];
- txb[1] = nic->node_addr[1];
- txb[2] = nic->node_addr[2];
- txb[3] = nic->node_addr[3];
- txb[4] = nic->node_addr[4];
- txb[5] = nic->node_addr[5];
-}
-
-/**************************************************************************
-DISABLE - Turn off ethernet interface
-***************************************************************************/
-static void r8169_disable ( struct nic *nic __unused ) {
- int i;
- struct rtl8169_private *tp = &tpx;
+ int val;
- /* Stop the chip's Tx and Rx DMA processes. */
- RTL_W8(ChipCmd, 0x00);
-
- /* Disable interrupts by clearing the interrupt mask. */
- RTL_W16(IntrMask, 0x0000);
+ DBGP ( "rtl8169_write_gmii_reg_bit\n" );
- RTL_W32(RxMissed, 0);
-
- tp->TxDescArray = NULL;
- tp->RxDescArray = NULL;
- for (i = 0; i < NUM_RX_DESC; i++) {
- tp->RxBufferRing[i] = NULL;
- }
+ val = mdio_read(ioaddr, reg);
+ val = (bitval == 1) ?
+ val | (bitval << bitnum) : val & ~(0x0001 << bitnum);
+ mdio_write(ioaddr, reg, val & 0xffff);
}
-static struct nic_operations r8169_operations = {
- .connect = dummy_connect,
- .poll = r8169_poll,
- .transmit = r8169_transmit,
- .irq = r8169_irq,
-
-};
-
-static struct pci_device_id r8169_nics[] = {
- PCI_ROM(0x10ec, 0x8169, "r8169", "RealTek RTL8169 Gigabit Ethernet"),
- PCI_ROM(0x16ec, 0x0116, "usr-r8169", "US Robotics RTL8169 Gigabit Ethernet"),
- PCI_ROM(0x1186, 0x4300, "dlink-r8169", "D-Link RTL8169 Gigabit Ethernet"),
- PCI_ROM(0x1737, 0x1032, "linksys-r8169", "Linksys RTL8169 Gigabit Ethernet"),
- PCI_ROM(0x10ec, 0x8129, "r8169-8129", "RealTek RT8129 Fast Ethernet Adapter"),
- PCI_ROM(0x10ec, 0x8136, "r8169-8101e", "RealTek RTL8101E PCI Express Fast Ethernet controller"),
- PCI_ROM(0x10ec, 0x8167, "r8169-8110sc/8169sc", "RealTek RTL-8110SC/8169SC Gigabit Ethernet"),
- PCI_ROM(0x10ec, 0x8168, "r8169-8168b", "RealTek RTL8111/8168B PCI Express Gigabit Ethernet controller"),
-};
-
-PCI_DRIVER ( r8169_driver, r8169_nics, PCI_NO_CLASS );
-
-/**************************************************************************
-PROBE - Look for an adapter, this routine's visible to the outside
-***************************************************************************/
-
-#define board_found 1
-#define valid_link 0
-static int r8169_probe ( struct nic *nic, struct pci_device *pci ) {
-
- static int board_idx = -1;
- static int printed_version = 0;
- struct rtl8169_private *tp = &tpx;
- int i, rc;
- int option = -1, Cap10_100 = 0, Cap1000 = 0;
-
- printf ( "r8169.c: Found %s, Vendor=%hX Device=%hX\n",
- pci->driver_name, pci->vendor, pci->device );
-
- board_idx++;
-
- printed_version = 1;
-
- /* Quick and very dirty hack to get r8169 driver working
- * again, pre-rewrite
+static void rtl8169_get_mac_version(struct rtl8169_private *tp,
+ void *ioaddr)
+{
+ /*
+ * The driver currently handles the 8168Bf and the 8168Be identically
+ * but they can be identified more specifically through the test below
+ * if needed:
+ *
+ * (RTL_R32(TxConfig) & 0x700000) == 0x500000 ? 8168Bf : 8168Be
+ *
+ * Same thing for the 8101Eb and the 8101Ec:
+ *
+ * (RTL_R32(TxConfig) & 0x700000) == 0x200000 ? 8101Eb : 8101Ec
*/
- if ( ! r8169_bufs )
- r8169_bufs = malloc_dma ( sizeof ( *r8169_bufs ), 256 );
- if ( ! r8169_bufs )
- return 0;
- memset ( r8169_bufs, 0, sizeof ( *r8169_bufs ) );
-
- rc = rtl8169_init_board(pci); /* Return code is meaningless */
-
- /* Get MAC address. FIXME: read EEPROM */
- for (i = 0; i < MAC_ADDR_LEN; i++)
- nic->node_addr[i] = RTL_R8(MAC0 + i);
-
- DBG ( "%s: Identified chip type is '%s'.\n", pci->driver_name,
- rtl_chip_info[tp->chipset].name );
-
- /* Print out some hardware info */
- DBG ( "%s: %s at ioaddr %#hx, ", pci->driver_name, eth_ntoa ( nic->node_addr ),
- (unsigned int) ioaddr );
+ const struct {
+ u32 mask;
+ u32 val;
+ int mac_version;
+ } mac_info[] = {
+ /* 8168D family. */
+ { 0x7c800000, 0x28000000, RTL_GIGA_MAC_VER_25 },
+
+ /* 8168C family. */
+ { 0x7cf00000, 0x3ca00000, RTL_GIGA_MAC_VER_24 },
+ { 0x7cf00000, 0x3c900000, RTL_GIGA_MAC_VER_23 },
+ { 0x7cf00000, 0x3c800000, RTL_GIGA_MAC_VER_18 },
+ { 0x7c800000, 0x3c800000, RTL_GIGA_MAC_VER_24 },
+ { 0x7cf00000, 0x3c000000, RTL_GIGA_MAC_VER_19 },
+ { 0x7cf00000, 0x3c200000, RTL_GIGA_MAC_VER_20 },
+ { 0x7cf00000, 0x3c300000, RTL_GIGA_MAC_VER_21 },
+ { 0x7cf00000, 0x3c400000, RTL_GIGA_MAC_VER_22 },
+ { 0x7c800000, 0x3c000000, RTL_GIGA_MAC_VER_22 },
- /* Config PHY */
- rtl8169_hw_phy_config(nic);
-
- DBG("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
- RTL_W8(0x82, 0x01);
+ /* 8168B family. */
+ { 0x7cf00000, 0x38000000, RTL_GIGA_MAC_VER_12 },
+ { 0x7cf00000, 0x38500000, RTL_GIGA_MAC_VER_17 },
+ { 0x7c800000, 0x38000000, RTL_GIGA_MAC_VER_17 },
+ { 0x7c800000, 0x30000000, RTL_GIGA_MAC_VER_11 },
- pci_write_config_byte(pci, PCI_LATENCY_TIMER, 0x40);
+ /* 8101 family. */
+ { 0x7cf00000, 0x34a00000, RTL_GIGA_MAC_VER_09 },
+ { 0x7cf00000, 0x24a00000, RTL_GIGA_MAC_VER_09 },
+ { 0x7cf00000, 0x34900000, RTL_GIGA_MAC_VER_08 },
+ { 0x7cf00000, 0x24900000, RTL_GIGA_MAC_VER_08 },
+ { 0x7cf00000, 0x34800000, RTL_GIGA_MAC_VER_07 },
+ { 0x7cf00000, 0x24800000, RTL_GIGA_MAC_VER_07 },
+ { 0x7cf00000, 0x34000000, RTL_GIGA_MAC_VER_13 },
+ { 0x7cf00000, 0x34300000, RTL_GIGA_MAC_VER_10 },
+ { 0x7cf00000, 0x34200000, RTL_GIGA_MAC_VER_16 },
+ { 0x7c800000, 0x34800000, RTL_GIGA_MAC_VER_09 },
+ { 0x7c800000, 0x24800000, RTL_GIGA_MAC_VER_09 },
+ { 0x7c800000, 0x34000000, RTL_GIGA_MAC_VER_16 },
+ /* FIXME: where did these entries come from ? -- FR */
+ { 0xfc800000, 0x38800000, RTL_GIGA_MAC_VER_15 },
+ { 0xfc800000, 0x30800000, RTL_GIGA_MAC_VER_14 },
- if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
- pci_write_config_byte(pci, PCI_CACHE_LINE_SIZE, 0x08);
+ /* 8110 family. */
+ { 0xfc800000, 0x98000000, RTL_GIGA_MAC_VER_06 },
+ { 0xfc800000, 0x18000000, RTL_GIGA_MAC_VER_05 },
+ { 0xfc800000, 0x10000000, RTL_GIGA_MAC_VER_04 },
+ { 0xfc800000, 0x04000000, RTL_GIGA_MAC_VER_03 },
+ { 0xfc800000, 0x00800000, RTL_GIGA_MAC_VER_02 },
+ { 0xfc800000, 0x00000000, RTL_GIGA_MAC_VER_01 },
- if (tp->mac_version == RTL_GIGA_MAC_VER_02) {
- DBG("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
- RTL_W8(0x82, 0x01);
- DBG("Set PHY Reg 0x0bh = 0x00h\n");
- RTL8169_WRITE_GMII_REG(ioaddr, 0x0b, 0x0000); //w 0x0b 15 0 0
- }
+ { 0x00000000, 0x00000000, RTL_GIGA_MAC_VER_01 } /* Catch-all */
+ }, *p = mac_info;
+ u32 reg;
- r8169_reset(nic);
-
- /* if TBI is not endbled */
- if (!(RTL_R8(PHYstatus) & TBI_Enable)) {
- int val = RTL8169_READ_GMII_REG(ioaddr, PHY_AUTO_NEGO_REG);
-
-#ifdef RTL8169_HW_FLOW_CONTROL_SUPPORT
- val |= PHY_Cap_PAUSE | PHY_Cap_ASYM_PAUSE;
-#endif //end #define RTL8169_HW_FLOW_CONTROL_SUPPORT
-
- /* Force RTL8169 in 10/100/1000 Full/Half mode. */
- if (option > 0) {
- printf(" Force-mode Enabled.\n");
- Cap10_100 = 0, Cap1000 = 0;
- switch (option) {
- case _10_Half:
- Cap10_100 = PHY_Cap_10_Half;
- Cap1000 = PHY_Cap_Null;
- break;
- case _10_Full:
- Cap10_100 = PHY_Cap_10_Full;
- Cap1000 = PHY_Cap_Null;
- break;
- case _100_Half:
- Cap10_100 = PHY_Cap_100_Half;
- Cap1000 = PHY_Cap_Null;
- break;
- case _100_Full:
- Cap10_100 = PHY_Cap_100_Full;
- Cap1000 = PHY_Cap_Null;
- break;
- case _1000_Full:
- Cap10_100 = PHY_Cap_Null;
- Cap1000 = PHY_Cap_1000_Full;
- break;
- default:
- break;
- }
- RTL8169_WRITE_GMII_REG(ioaddr, PHY_AUTO_NEGO_REG, Cap10_100 | (val & 0xC1F)); //leave PHY_AUTO_NEGO_REG bit4:0 unchanged
- RTL8169_WRITE_GMII_REG(ioaddr, PHY_1000_CTRL_REG,
- Cap1000);
- } else {
- DBG ( "%s: Auto-negotiation Enabled.\n", pci->driver_name );
-
- // enable 10/100 Full/Half Mode, leave PHY_AUTO_NEGO_REG bit4:0 unchanged
- RTL8169_WRITE_GMII_REG(ioaddr, PHY_AUTO_NEGO_REG,
- PHY_Cap_10_Half |
- PHY_Cap_10_Full |
- PHY_Cap_100_Half |
- PHY_Cap_100_Full | (val &
- 0xC1F));
-
- // enable 1000 Full Mode
-// RTL8169_WRITE_GMII_REG( ioaddr, PHY_1000_CTRL_REG, PHY_Cap_1000_Full );
- RTL8169_WRITE_GMII_REG(ioaddr, PHY_1000_CTRL_REG, PHY_Cap_1000_Full | PHY_Cap_1000_Half); //rtl8168
-
- } // end of if( option > 0 )
-
- // Enable auto-negotiation and restart auto-nigotiation
- RTL8169_WRITE_GMII_REG(ioaddr, PHY_CTRL_REG,
- PHY_Enable_Auto_Nego |
- PHY_Restart_Auto_Nego);
- udelay(100);
-
- // wait for auto-negotiation process
- for (i = 10000; i > 0; i--) {
- //check if auto-negotiation complete
- if (RTL8169_READ_GMII_REG(ioaddr, PHY_STAT_REG) &
- PHY_Auto_Neco_Comp) {
- udelay(100);
- option = RTL_R8(PHYstatus);
- if (option & _1000bpsF) {
- printf
- ("1000Mbps Full-duplex operation.\n");
- } else {
- printf
- ("%sMbps %s-duplex operation.\n",
- (option & _100bps) ? "100" :
- "10",
- (option & FullDup) ? "Full" :
- "Half");
- }
- break;
- } else {
- udelay(100);
- } // end of if( RTL8169_READ_GMII_REG(ioaddr, 1) & 0x20 )
- } // end for-loop to wait for auto-negotiation process
+ DBGP ( "rtl8169_get_mac_version\n" );
+ reg = RTL_R32(TxConfig);
+ while ((reg & p->mask) != p->val)
+ p++;
+ tp->mac_version = p->mac_version;
- } else {
- udelay(100);
- printf
- ("%s: 1000Mbps Full-duplex operation, TBI Link %s!\n",
- pci->driver_name,
- (RTL_R32(TBICSR) & TBILinkOK) ? "OK" : "Failed");
+ DBG ( "tp->mac_version = %d\n", tp->mac_version );
+ if (p->mask == 0x00000000) {
+ DBG ( "unknown MAC (%08x)\n", reg );
}
-
- r8169_reset(nic);
-
- /* point to NIC specific routines */
- nic->nic_op = &r8169_operations;
-
- nic->irqno = pci->irq;
- nic->ioaddr = ioaddr;
-
- return 1;
-}
-
-//======================================================================================================
-/*
-static void rtl8169_hw_PHY_reset(struct nic *nic __unused)
-{
- int val, phy_reset_expiretime = 50;
- struct rtl8169_private *priv = dev->priv;
- unsigned long ioaddr = priv->ioaddr;
-
- DBG("%s: Reset RTL8169s PHY\n", dev->name);
-
- val = ( RTL8169_READ_GMII_REG( ioaddr, 0 ) | 0x8000 ) & 0xffff;
- RTL8169_WRITE_GMII_REG( ioaddr, 0, val );
-
- do //waiting for phy reset
- {
- if( RTL8169_READ_GMII_REG( ioaddr, 0 ) & 0x8000 ){
- phy_reset_expiretime --;
- udelay(100);
- }
- else{
- break;
- }
- }while( phy_reset_expiretime >= 0 );
-
- assert( phy_reset_expiretime > 0 );
}
-*/
-
struct phy_reg {
u16 reg;
u16 val;
@@ -1161,8 +436,10 @@ struct phy_reg {
static void rtl_phy_write(void *ioaddr, struct phy_reg *regs, int len)
{
+ DBGP ( "rtl_phy_write\n" );
+
while (len-- > 0) {
- RTL8169_WRITE_GMII_REG((u32)ioaddr, regs->reg, regs->val);
+ mdio_write(ioaddr, regs->reg, regs->val);
regs++;
}
}
@@ -1201,22 +478,24 @@ static void rtl8169s_hw_phy_config(void *ioaddr)
}, *p = phy_magic;
unsigned int i;
- RTL8169_WRITE_GMII_REG((u32)ioaddr, 0x1f, 0x0001); //w 31 2 0 1
- RTL8169_WRITE_GMII_REG((u32)ioaddr, 0x15, 0x1000); //w 21 15 0 1000
- RTL8169_WRITE_GMII_REG((u32)ioaddr, 0x18, 0x65c7); //w 24 15 0 65c7
- RTL8169_WRITE_GMII_REG_BIT((u32)ioaddr, 4, 11, 0); //w 4 11 11 0
+ DBGP ( "rtl8169s_hw_phy_config\n" );
+
+ mdio_write(ioaddr, 0x1f, 0x0001); //w 31 2 0 1
+ mdio_write(ioaddr, 0x15, 0x1000); //w 21 15 0 1000
+ mdio_write(ioaddr, 0x18, 0x65c7); //w 24 15 0 65c7
+ rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0); //w 4 11 11 0
for (i = 0; i < ARRAY_SIZE(phy_magic); i++, p++) {
int val, pos = 4;
- val = (RTL8169_READ_GMII_REG((u32)ioaddr, pos) & 0x0fff) | (p->regs[0] & 0xffff);
- RTL8169_WRITE_GMII_REG((u32)ioaddr, pos, val);
+ val = (mdio_read(ioaddr, pos) & 0x0fff) | (p->regs[0] & 0xffff);
+ mdio_write(ioaddr, pos, val);
while (--pos >= 0)
- RTL8169_WRITE_GMII_REG((u32)ioaddr, pos, p->regs[4 - pos] & 0xffff);
- RTL8169_WRITE_GMII_REG_BIT((u32)ioaddr, 4, 11, 1); //w 4 11 11 1
- RTL8169_WRITE_GMII_REG_BIT((u32)ioaddr, 4, 11, 0); //w 4 11 11 0
+ mdio_write(ioaddr, pos, p->regs[4 - pos] & 0xffff);
+ rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 1); //w 4 11 11 1
+ rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0); //w 4 11 11 0
}
- RTL8169_WRITE_GMII_REG((u32)ioaddr, 0x1f, 0x0000); //w 31 2 0 0
+ mdio_write(ioaddr, 0x1f, 0x0000); //w 31 2 0 0
}
static void rtl8169sb_hw_phy_config(void *ioaddr)
@@ -1227,10 +506,40 @@ static void rtl8169sb_hw_phy_config(void *ioaddr)
{ 0x1f, 0x0000 }
};
+ DBGP ( "rtl8169sb_hw_phy_config\n" );
+
+ rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+}
+
+static void rtl8168bb_hw_phy_config(void *ioaddr)
+{
+ struct phy_reg phy_reg_init[] = {
+ { 0x10, 0xf41b },
+ { 0x1f, 0x0000 }
+ };
+
+ mdio_write(ioaddr, 0x1f, 0x0001);
+ mdio_patch(ioaddr, 0x16, 1 << 0);
+
+ DBGP ( "rtl8168bb_hw_phy_config\n" );
+
+ rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+}
+
+static void rtl8168bef_hw_phy_config(void *ioaddr)
+{
+ struct phy_reg phy_reg_init[] = {
+ { 0x1f, 0x0001 },
+ { 0x10, 0xf41b },
+ { 0x1f, 0x0000 }
+ };
+
+ DBGP ( "rtl8168bef_hw_phy_config\n" );
+
rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
}
-static void rtl8168cp_hw_phy_config(void *ioaddr)
+static void rtl8168cp_1_hw_phy_config(void *ioaddr)
{
struct phy_reg phy_reg_init[] = {
{ 0x1f, 0x0000 },
@@ -1240,10 +549,29 @@ static void rtl8168cp_hw_phy_config(void *ioaddr)
{ 0x1f, 0x0000 }
};
+ DBGP ( "rtl8168cp_1_hw_phy_config\n" );
+
+ rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+}
+
+static void rtl8168cp_2_hw_phy_config(void *ioaddr)
+{
+ struct phy_reg phy_reg_init[] = {
+ { 0x1f, 0x0001 },
+ { 0x1d, 0x3d98 },
+ { 0x1f, 0x0000 }
+ };
+
+ DBGP ( "rtl8168cp_2_hw_phy_config\n" );
+
+ mdio_write(ioaddr, 0x1f, 0x0000);
+ mdio_patch(ioaddr, 0x14, 1 << 5);
+ mdio_patch(ioaddr, 0x0d, 1 << 5);
+
rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
}
-static void rtl8168c_hw_phy_config(void *ioaddr)
+static void rtl8168c_1_hw_phy_config(void *ioaddr)
{
struct phy_reg phy_reg_init[] = {
{ 0x1f, 0x0001 },
@@ -1259,33 +587,180 @@ static void rtl8168c_hw_phy_config(void *ioaddr)
{ 0x1f, 0x0003 },
{ 0x12, 0xc096 },
{ 0x16, 0x000a },
- { 0x1f, 0x0000 }
+ { 0x1f, 0x0000 },
+ { 0x1f, 0x0000 },
+ { 0x09, 0x2000 },
+ { 0x09, 0x0000 }
};
+ DBGP ( "rtl8168c_1_hw_phy_config\n" );
+
rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+
+ mdio_patch(ioaddr, 0x14, 1 << 5);
+ mdio_patch(ioaddr, 0x0d, 1 << 5);
+ mdio_write(ioaddr, 0x1f, 0x0000);
}
-static void rtl8168cx_hw_phy_config(void *ioaddr)
+static void rtl8168c_2_hw_phy_config(void *ioaddr)
{
struct phy_reg phy_reg_init[] = {
- { 0x1f, 0x0000 },
+ { 0x1f, 0x0001 },
{ 0x12, 0x2300 },
+ { 0x03, 0x802f },
+ { 0x02, 0x4f02 },
+ { 0x01, 0x0409 },
+ { 0x00, 0xf099 },
+ { 0x04, 0x9800 },
+ { 0x04, 0x9000 },
+ { 0x1d, 0x3d98 },
+ { 0x1f, 0x0002 },
+ { 0x0c, 0x7eb8 },
+ { 0x06, 0x0761 },
{ 0x1f, 0x0003 },
{ 0x16, 0x0f0a },
- { 0x1f, 0x0000 },
+ { 0x1f, 0x0000 }
+ };
+
+ DBGP ( "rtl8168c_2_hw_phy_config\n" );
+
+ rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+
+ mdio_patch(ioaddr, 0x16, 1 << 0);
+ mdio_patch(ioaddr, 0x14, 1 << 5);
+ mdio_patch(ioaddr, 0x0d, 1 << 5);
+ mdio_write(ioaddr, 0x1f, 0x0000);
+}
+
+static void rtl8168c_3_hw_phy_config(void *ioaddr)
+{
+ struct phy_reg phy_reg_init[] = {
+ { 0x1f, 0x0001 },
+ { 0x12, 0x2300 },
+ { 0x1d, 0x3d98 },
{ 0x1f, 0x0002 },
{ 0x0c, 0x7eb8 },
+ { 0x06, 0x5461 },
+ { 0x1f, 0x0003 },
+ { 0x16, 0x0f0a },
{ 0x1f, 0x0000 }
};
+ DBGP ( "rtl8168c_3_hw_phy_config\n" );
+
+ rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+
+ mdio_patch(ioaddr, 0x16, 1 << 0);
+ mdio_patch(ioaddr, 0x14, 1 << 5);
+ mdio_patch(ioaddr, 0x0d, 1 << 5);
+ mdio_write(ioaddr, 0x1f, 0x0000);
+}
+
+static void rtl8168c_4_hw_phy_config(void *ioaddr)
+{
+ DBGP ( "rtl8168c_4_hw_phy_config\n" );
+
+ rtl8168c_3_hw_phy_config(ioaddr);
+}
+
+static void rtl8168d_hw_phy_config(void *ioaddr)
+{
+ struct phy_reg phy_reg_init_0[] = {
+ { 0x1f, 0x0001 },
+ { 0x09, 0x2770 },
+ { 0x08, 0x04d0 },
+ { 0x0b, 0xad15 },
+ { 0x0c, 0x5bf0 },
+ { 0x1c, 0xf101 },
+ { 0x1f, 0x0003 },
+ { 0x14, 0x94d7 },
+ { 0x12, 0xf4d6 },
+ { 0x09, 0xca0f },
+ { 0x1f, 0x0002 },
+ { 0x0b, 0x0b10 },
+ { 0x0c, 0xd1f7 },
+ { 0x1f, 0x0002 },
+ { 0x06, 0x5461 },
+ { 0x1f, 0x0002 },
+ { 0x05, 0x6662 },
+ { 0x1f, 0x0000 },
+ { 0x14, 0x0060 },
+ { 0x1f, 0x0000 },
+ { 0x0d, 0xf8a0 },
+ { 0x1f, 0x0005 },
+ { 0x05, 0xffc2 }
+ };
+
+ DBGP ( "rtl8168d_hw_phy_config\n" );
+
+ rtl_phy_write(ioaddr, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
+
+ if (mdio_read(ioaddr, 0x06) == 0xc400) {
+ struct phy_reg phy_reg_init_1[] = {
+ { 0x1f, 0x0005 },
+ { 0x01, 0x0300 },
+ { 0x1f, 0x0000 },
+ { 0x11, 0x401c },
+ { 0x16, 0x4100 },
+ { 0x1f, 0x0005 },
+ { 0x07, 0x0010 },
+ { 0x05, 0x83dc },
+ { 0x06, 0x087d },
+ { 0x05, 0x8300 },
+ { 0x06, 0x0101 },
+ { 0x06, 0x05f8 },
+ { 0x06, 0xf9fa },
+ { 0x06, 0xfbef },
+ { 0x06, 0x79e2 },
+ { 0x06, 0x835f },
+ { 0x06, 0xe0f8 },
+ { 0x06, 0x9ae1 },
+ { 0x06, 0xf89b },
+ { 0x06, 0xef31 },
+ { 0x06, 0x3b65 },
+ { 0x06, 0xaa07 },
+ { 0x06, 0x81e4 },
+ { 0x06, 0xf89a },
+ { 0x06, 0xe5f8 },
+ { 0x06, 0x9baf },
+ { 0x06, 0x06ae },
+ { 0x05, 0x83dc },
+ { 0x06, 0x8300 },
+ };
+
+ rtl_phy_write(ioaddr, phy_reg_init_1,
+ ARRAY_SIZE(phy_reg_init_1));
+ }
+
+ mdio_write(ioaddr, 0x1f, 0x0000);
+}
+
+static void rtl8102e_hw_phy_config(void *ioaddr)
+{
+ struct phy_reg phy_reg_init[] = {
+ { 0x1f, 0x0003 },
+ { 0x08, 0x441d },
+ { 0x01, 0x9100 },
+ { 0x1f, 0x0000 }
+ };
+
+ DBGP ( "rtl8102e_hw_phy_config\n" );
+
+ mdio_write(ioaddr, 0x1f, 0x0000);
+ mdio_patch(ioaddr, 0x11, 1 << 12);
+ mdio_patch(ioaddr, 0x19, 1 << 13);
+
rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
}
-static void rtl8169_hw_phy_config(struct nic *nic __unused)
+static void rtl_hw_phy_config(struct net_device *dev)
{
- struct rtl8169_private *tp = &tpx;
+ struct rtl8169_private *tp = netdev_priv(dev);
void *ioaddr = tp->mmio_addr;
- DBG("rtl8169_hw_phy_config(): card at addr=0x%lx: priv->mac_version=%d, priv->pcfg=%d\n", (unsigned long) ioaddr, tp->mac_version, tp->pcfg);
+
+ DBGP ( "rtl_hw_phy_config\n" );
+
+ DBG ( "mac_version = 0x%02x\n", tp->mac_version );
switch (tp->mac_version) {
case RTL_GIGA_MAC_VER_01:
@@ -1297,22 +772,1506 @@ static void rtl8169_hw_phy_config(struct nic *nic __unused)
case RTL_GIGA_MAC_VER_04:
rtl8169sb_hw_phy_config(ioaddr);
break;
+ case RTL_GIGA_MAC_VER_07:
+ case RTL_GIGA_MAC_VER_08:
+ case RTL_GIGA_MAC_VER_09:
+ rtl8102e_hw_phy_config(ioaddr);
+ break;
+ case RTL_GIGA_MAC_VER_11:
+ rtl8168bb_hw_phy_config(ioaddr);
+ break;
+ case RTL_GIGA_MAC_VER_12:
+ rtl8168bef_hw_phy_config(ioaddr);
+ break;
+ case RTL_GIGA_MAC_VER_17:
+ rtl8168bef_hw_phy_config(ioaddr);
+ break;
case RTL_GIGA_MAC_VER_18:
- rtl8168cp_hw_phy_config(ioaddr);
+ rtl8168cp_1_hw_phy_config(ioaddr);
break;
case RTL_GIGA_MAC_VER_19:
- rtl8168c_hw_phy_config(ioaddr);
+ rtl8168c_1_hw_phy_config(ioaddr);
break;
case RTL_GIGA_MAC_VER_20:
- rtl8168cx_hw_phy_config(ioaddr);
+ rtl8168c_2_hw_phy_config(ioaddr);
+ break;
+ case RTL_GIGA_MAC_VER_21:
+ rtl8168c_3_hw_phy_config(ioaddr);
+ break;
+ case RTL_GIGA_MAC_VER_22:
+ rtl8168c_4_hw_phy_config(ioaddr);
break;
+ case RTL_GIGA_MAC_VER_23:
+ case RTL_GIGA_MAC_VER_24:
+ rtl8168cp_2_hw_phy_config(ioaddr);
+ break;
+ case RTL_GIGA_MAC_VER_25:
+ rtl8168d_hw_phy_config(ioaddr);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void rtl8169_phy_reset(struct net_device *dev __unused,
+ struct rtl8169_private *tp)
+{
+ void *ioaddr = tp->mmio_addr;
+ unsigned int i;
+
+ DBGP ( "rtl8169_phy_reset\n" );
+
+ tp->phy_reset_enable(ioaddr);
+ for (i = 0; i < 100; i++) {
+ if (!tp->phy_reset_pending(ioaddr))
+ return;
+ mdelay ( 1 );
+ }
+ DBG ( "PHY reset failed.\n" );
+}
+
+static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp)
+{
+ void *ioaddr = tp->mmio_addr;
+
+ DBGP ( "rtl8169_init_phy\n" );
+
+ rtl_hw_phy_config(dev);
+
+ if (tp->mac_version <= RTL_GIGA_MAC_VER_06) {
+ DBG ( "Set MAC Reg C+CR Offset 0x82h = 0x01h\n" );
+ RTL_W8(0x82, 0x01);
+ }
+
+ pci_write_config_byte(tp->pci_dev, PCI_LATENCY_TIMER, 0x40);
+
+ if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
+ pci_write_config_byte(tp->pci_dev, PCI_CACHE_LINE_SIZE, 0x08);
+
+ if (tp->mac_version == RTL_GIGA_MAC_VER_02) {
+ DBG ( "Set MAC Reg C+CR Offset 0x82h = 0x01h\n" );
+ RTL_W8(0x82, 0x01);
+ DBG ( "Set PHY Reg 0x0bh = 0x00h\n" );
+ mdio_write(ioaddr, 0x0b, 0x0000); //w 0x0b 15 0 0
+ }
+
+ rtl8169_phy_reset(dev, tp);
+
+ /*
+ * rtl8169_set_speed_xmii takes good care of the Fast Ethernet
+ * only 8101. Don't panic.
+ */
+ rtl8169_set_speed(dev, AUTONEG_ENABLE, SPEED_1000, DUPLEX_FULL);
+
+ if ((RTL_R8(PHYstatus) & TBI_Enable))
+ DBG ( "TBI auto-negotiating\n" );
+}
+
+static const struct rtl_cfg_info {
+ void (*hw_start)(struct net_device *);
+ unsigned int region;
+ unsigned int align;
+ u16 intr_event;
+ u16 napi_event;
+ unsigned features;
+} rtl_cfg_infos [] = {
+ [RTL_CFG_0] = {
+ .hw_start = rtl_hw_start_8169,
+ .region = 1,
+ .align = 0,
+ .intr_event = SYSErr | LinkChg | RxOverflow |
+ RxFIFOOver | TxErr | TxOK | RxOK | RxErr,
+ .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow,
+ .features = RTL_FEATURE_GMII
+ },
+ [RTL_CFG_1] = {
+ .hw_start = rtl_hw_start_8168,
+ .region = 2,
+ .align = 8,
+ .intr_event = SYSErr | LinkChg | RxOverflow |
+ TxErr | TxOK | RxOK | RxErr,
+ .napi_event = TxErr | TxOK | RxOK | RxOverflow,
+ .features = RTL_FEATURE_GMII
+ },
+ [RTL_CFG_2] = {
+ .hw_start = rtl_hw_start_8101,
+ .region = 2,
+ .align = 8,
+ .intr_event = SYSErr | LinkChg | RxOverflow | PCSTimeout |
+ RxFIFOOver | TxErr | TxOK | RxOK | RxErr,
+ .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow,
+ }
+};
+
+static void rtl8169_hw_reset(void *ioaddr)
+{
+ DBGP ( "rtl8169_hw_reset\n" );
+
+ /* Disable interrupts */
+ rtl8169_irq_mask_and_ack(ioaddr);
+
+ /* Reset the chipset */
+ RTL_W8(ChipCmd, CmdReset);
+
+ /* PCI commit */
+ RTL_R8(ChipCmd);
+}
+
+static void rtl_set_rx_tx_config_registers(struct rtl8169_private *tp)
+{
+ void *ioaddr = tp->mmio_addr;
+ u32 cfg = rtl8169_rx_config;
+
+ DBGP ( "rtl_set_rx_tx_config_registers\n" );
+
+ cfg |= (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask);
+ RTL_W32(RxConfig, cfg);
+
+ /* Set DMA burst size and Interframe Gap Time */
+ RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) |
+ (InterFrameGap << TxInterFrameGapShift));
+}
+
+static void rtl_soft_reset ( struct net_device *dev )
+{
+ struct rtl8169_private *tp = netdev_priv(dev);
+ void *ioaddr = tp->mmio_addr;
+ unsigned int i;
+
+ DBGP ( "rtl_hw_soft_reset\n" );
+
+ /* Soft reset the chip. */
+ RTL_W8(ChipCmd, CmdReset);
+
+ /* Check that the chip has finished the reset. */
+ for (i = 0; i < 100; i++) {
+ if ((RTL_R8(ChipCmd) & CmdReset) == 0)
+ break;
+ mdelay ( 1 );
+ }
+
+ if ( i == 100 ) {
+ DBG ( "Reset Failed! (> 100 iterations)\n" );
+ }
+}
+
+static void rtl_hw_start ( struct net_device *dev )
+{
+ struct rtl8169_private *tp = netdev_priv ( dev );
+
+ DBGP ( "rtl_hw_start\n" );
+
+ /* Soft reset NIC */
+ rtl_soft_reset ( dev );
+
+ tp->hw_start ( dev );
+}
+
+static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp,
+ void *ioaddr)
+{
+ DBGP ( "rtl_set_rx_tx_desc_registers\n" );
+
+ /*
+ * Magic spell: some iop3xx ARM board needs the TxDescAddrHigh
+ * register to be written before TxDescAddrLow to work.
+ * Switching from MMIO to I/O access fixes the issue as well.
+ */
+ RTL_W32 ( TxDescStartAddrHigh, 0 );
+ RTL_W32 ( TxDescStartAddrLow, virt_to_bus ( tp->tx_base ) );
+ RTL_W32 ( RxDescAddrHigh, 0 );
+ RTL_W32 ( RxDescAddrLow, virt_to_bus ( tp->rx_base ) );
+}
+
+static u16 rtl_rw_cpluscmd(void *ioaddr)
+{
+ u16 cmd;
+
+ DBGP ( "rtl_rw_cpluscmd\n" );
+
+ cmd = RTL_R16(CPlusCmd);
+ RTL_W16(CPlusCmd, cmd);
+ return cmd;
+}
+
+static void rtl_set_rx_max_size(void *ioaddr)
+{
+ DBGP ( "rtl_set_rx_max_size\n" );
+
+ RTL_W16 ( RxMaxSize, RX_BUF_SIZE );
+}
+
+static void rtl8169_set_magic_reg(void *ioaddr, unsigned mac_version)
+{
+ struct {
+ u32 mac_version;
+ u32 clk;
+ u32 val;
+ } cfg2_info [] = {
+ { RTL_GIGA_MAC_VER_05, PCI_Clock_33MHz, 0x000fff00 }, // 8110SCd
+ { RTL_GIGA_MAC_VER_05, PCI_Clock_66MHz, 0x000fffff },
+ { RTL_GIGA_MAC_VER_06, PCI_Clock_33MHz, 0x00ffff00 }, // 8110SCe
+ { RTL_GIGA_MAC_VER_06, PCI_Clock_66MHz, 0x00ffffff }
+ }, *p = cfg2_info;
+ unsigned int i;
+ u32 clk;
+
+ DBGP ( "rtl8169_set_magic_reg\n" );
+
+ clk = RTL_R8(Config2) & PCI_Clock_66MHz;
+ for (i = 0; i < ARRAY_SIZE(cfg2_info); i++, p++) {
+ if ((p->mac_version == mac_version) && (p->clk == clk)) {
+ RTL_W32(0x7c, p->val);
+ break;
+ }
+ }
+}
+
+static void rtl_set_rx_mode ( struct net_device *netdev )
+{
+ struct rtl8169_private *tp = netdev_priv ( netdev );
+ void *ioaddr = tp->mmio_addr;
+ u32 tmp;
+
+ DBGP ( "rtl_set_rx_mode\n" );
+
+ /* Accept all Multicast Packets */
+
+ RTL_W32 ( MAR0 + 0, 0xffffffff );
+ RTL_W32 ( MAR0 + 4, 0xffffffff );
+
+ tmp = rtl8169_rx_config | AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
+ ( RTL_R32 ( RxConfig ) & rtl_chip_info[tp->chipset].RxConfigMask );
+
+ RTL_W32 ( RxConfig, tmp );
+}
+
+static void rtl_hw_start_8169(struct net_device *dev)
+{
+ struct rtl8169_private *tp = netdev_priv(dev);
+ void *ioaddr = tp->mmio_addr;
+ struct pci_device *pdev = tp->pci_dev;
+
+ DBGP ( "rtl_hw_start_8169\n" );
+
+ if (tp->mac_version == RTL_GIGA_MAC_VER_05) {
+ RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | PCIMulRW);
+ pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x08);
+ }
+
+ RTL_W8(Cfg9346, Cfg9346_Unlock);
+
+ if ((tp->mac_version == RTL_GIGA_MAC_VER_01) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_02) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_03) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_04))
+ RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+
+ RTL_W8(EarlyTxThres, EarlyTxThld);
+
+ rtl_set_rx_max_size(ioaddr);
+
+ if ((tp->mac_version == RTL_GIGA_MAC_VER_01) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_02) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_03) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_04))
+ rtl_set_rx_tx_config_registers(tp);
+
+ tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW;
+
+ if ((tp->mac_version == RTL_GIGA_MAC_VER_02) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_03)) {
+ DBG ( "Set MAC Reg C+CR Offset 0xE0. "
+ "Bit-3 and bit-14 MUST be 1\n" );
+ tp->cp_cmd |= (1 << 14);
+ }
+
+ RTL_W16(CPlusCmd, tp->cp_cmd);
+
+ rtl8169_set_magic_reg(ioaddr, tp->mac_version);
+
+ /*
+ * Undocumented corner. Supposedly:
+ * (TxTimer << 12) | (TxPackets << 8) | (RxTimer << 4) | RxPackets
+ */
+ RTL_W16(IntrMitigate, 0x0000);
+
+ rtl_set_rx_tx_desc_registers(tp, ioaddr);
+
+ if ((tp->mac_version != RTL_GIGA_MAC_VER_01) &&
+ (tp->mac_version != RTL_GIGA_MAC_VER_02) &&
+ (tp->mac_version != RTL_GIGA_MAC_VER_03) &&
+ (tp->mac_version != RTL_GIGA_MAC_VER_04)) {
+ RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+ rtl_set_rx_tx_config_registers(tp);
+ }
+
+ RTL_W8(Cfg9346, Cfg9346_Lock);
+
+ /* Initially a 10 us delay. Turned it into a PCI commit. - FR */
+ RTL_R8(IntrMask);
+
+ RTL_W32(RxMissed, 0);
+
+ rtl_set_rx_mode(dev);
+
+ /* no early-rx interrupts */
+ RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
+
+ // RTL_W16(IntrMask, tp->intr_event);
+}
+
+static void rtl_tx_performance_tweak(struct pci_device *pdev, u16 force)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct rtl8169_private *tp = netdev_priv(dev);
+ int cap = tp->pcie_cap;
+
+ DBGP ( "rtl_tx_performance_tweak\n" );
+
+ if (cap) {
+ u16 ctl;
+
+ pci_read_config_word(pdev, cap + PCI_EXP_DEVCTL, &ctl);
+ ctl = (ctl & ~PCI_EXP_DEVCTL_READRQ) | force;
+ pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, ctl);
+ }
+}
+
+static void rtl_csi_access_enable(void *ioaddr)
+{
+ u32 csi;
+
+ DBGP ( "rtl_csi_access_enable\n" );
+
+ csi = rtl_csi_read(ioaddr, 0x070c) & 0x00ffffff;
+ rtl_csi_write(ioaddr, 0x070c, csi | 0x27000000);
+}
+
+struct ephy_info {
+ unsigned int offset;
+ u16 mask;
+ u16 bits;
+};
+
+static void rtl_ephy_init(void *ioaddr, struct ephy_info *e, int len)
+{
+ u16 w;
+
+ DBGP ( "rtl_ephy_init\n" );
+
+ while (len-- > 0) {
+ w = (rtl_ephy_read(ioaddr, e->offset) & ~e->mask) | e->bits;
+ rtl_ephy_write(ioaddr, e->offset, w);
+ e++;
+ }
+}
+
+static void rtl_disable_clock_request(struct pci_device *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct rtl8169_private *tp = netdev_priv(dev);
+ int cap = tp->pcie_cap;
+
+ DBGP ( "rtl_disable_clock_request\n" );
+
+ if (cap) {
+ u16 ctl;
+
+ pci_read_config_word(pdev, cap + PCI_EXP_LNKCTL, &ctl);
+ ctl &= ~PCI_EXP_LNKCTL_CLKREQ_EN;
+ pci_write_config_word(pdev, cap + PCI_EXP_LNKCTL, ctl);
+ }
+}
+
+#define R8168_CPCMD_QUIRK_MASK (\
+ EnableBist | \
+ Mac_dbgo_oe | \
+ Force_half_dup | \
+ Force_rxflow_en | \
+ Force_txflow_en | \
+ Cxpl_dbg_sel | \
+ ASF | \
+ PktCntrDisable | \
+ Mac_dbgo_sel)
+
+static void rtl_hw_start_8168bb(void *ioaddr, struct pci_device *pdev)
+{
+ DBGP ( "rtl_hw_start_8168bb\n" );
+
+ RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
+
+ RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
+
+ rtl_tx_performance_tweak(pdev,
+ (0x5 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN);
+}
+
+static void rtl_hw_start_8168bef(void *ioaddr, struct pci_device *pdev)
+{
+ DBGP ( "rtl_hw_start_8168bef\n" );
+
+ rtl_hw_start_8168bb(ioaddr, pdev);
+
+ RTL_W8(EarlyTxThres, EarlyTxThld);
+
+ RTL_W8(Config4, RTL_R8(Config4) & ~(1 << 0));
+}
+
+static void __rtl_hw_start_8168cp(void *ioaddr, struct pci_device *pdev)
+{
+ DBGP ( "__rtl_hw_start_8168cp\n" );
+
+ RTL_W8(Config1, RTL_R8(Config1) | Speed_down);
+
+ RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
+
+ rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+ rtl_disable_clock_request(pdev);
+
+ RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
+}
+
+static void rtl_hw_start_8168cp_1(void *ioaddr, struct pci_device *pdev)
+{
+ static struct ephy_info e_info_8168cp[] = {
+ { 0x01, 0, 0x0001 },
+ { 0x02, 0x0800, 0x1000 },
+ { 0x03, 0, 0x0042 },
+ { 0x06, 0x0080, 0x0000 },
+ { 0x07, 0, 0x2000 }
+ };
+
+ DBGP ( "rtl_hw_start_8168cp_1\n" );
+
+ rtl_csi_access_enable(ioaddr);
+
+ rtl_ephy_init(ioaddr, e_info_8168cp, ARRAY_SIZE(e_info_8168cp));
+
+ __rtl_hw_start_8168cp(ioaddr, pdev);
+}
+
+static void rtl_hw_start_8168cp_2(void *ioaddr, struct pci_device *pdev)
+{
+ DBGP ( "rtl_hw_start_8168cp_2\n" );
+
+ rtl_csi_access_enable(ioaddr);
+
+ RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
+
+ rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+ RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
+}
+
+static void rtl_hw_start_8168cp_3(void *ioaddr, struct pci_device *pdev)
+{
+ DBGP ( "rtl_hw_start_8168cp_3\n" );
+
+ rtl_csi_access_enable(ioaddr);
+
+ RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
+
+ /* Magic. */
+ RTL_W8(DBG_REG, 0x20);
+
+ RTL_W8(EarlyTxThres, EarlyTxThld);
+
+ rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+ RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
+}
+
+static void rtl_hw_start_8168c_1(void *ioaddr, struct pci_device *pdev)
+{
+ static struct ephy_info e_info_8168c_1[] = {
+ { 0x02, 0x0800, 0x1000 },
+ { 0x03, 0, 0x0002 },
+ { 0x06, 0x0080, 0x0000 }
+ };
+
+ DBGP ( "rtl_hw_start_8168c_1\n" );
+
+ rtl_csi_access_enable(ioaddr);
+
+ RTL_W8(DBG_REG, 0x06 | FIX_NAK_1 | FIX_NAK_2);
+
+ rtl_ephy_init(ioaddr, e_info_8168c_1, ARRAY_SIZE(e_info_8168c_1));
+
+ __rtl_hw_start_8168cp(ioaddr, pdev);
+}
+
+static void rtl_hw_start_8168c_2(void *ioaddr, struct pci_device *pdev)
+{
+ static struct ephy_info e_info_8168c_2[] = {
+ { 0x01, 0, 0x0001 },
+ { 0x03, 0x0400, 0x0220 }
+ };
+
+ DBGP ( "rtl_hw_start_8168c_2\n" );
+
+ rtl_csi_access_enable(ioaddr);
+
+ rtl_ephy_init(ioaddr, e_info_8168c_2, ARRAY_SIZE(e_info_8168c_2));
+
+ __rtl_hw_start_8168cp(ioaddr, pdev);
+}
+
+static void rtl_hw_start_8168c_3(void *ioaddr, struct pci_device *pdev)
+{
+ DBGP ( "rtl_hw_start_8168c_3\n" );
+
+ rtl_hw_start_8168c_2(ioaddr, pdev);
+}
+
+static void rtl_hw_start_8168c_4(void *ioaddr, struct pci_device *pdev)
+{
+ DBGP ( "rtl_hw_start_8168c_4\n" );
+
+ rtl_csi_access_enable(ioaddr);
+
+ __rtl_hw_start_8168cp(ioaddr, pdev);
+}
+
+static void rtl_hw_start_8168d(void *ioaddr, struct pci_device *pdev)
+{
+ DBGP ( "rtl_hw_start_8168d\n" );
+
+ rtl_csi_access_enable(ioaddr);
+
+ rtl_disable_clock_request(pdev);
+
+ RTL_W8(EarlyTxThres, EarlyTxThld);
+
+ rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+ RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
+}
+
+static void rtl_hw_start_8168(struct net_device *dev)
+{
+ struct rtl8169_private *tp = netdev_priv(dev);
+ void *ioaddr = tp->mmio_addr;
+ struct pci_device *pdev = tp->pci_dev;
+
+ DBGP ( "rtl_hw_start_8168\n" );
+
+ RTL_W8(Cfg9346, Cfg9346_Unlock);
+
+ RTL_W8(EarlyTxThres, EarlyTxThld);
+
+ rtl_set_rx_max_size(ioaddr);
+
+ tp->cp_cmd |= RTL_R16(CPlusCmd) | PktCntrDisable | INTT_1;
+
+ RTL_W16(CPlusCmd, tp->cp_cmd);
+
+ RTL_W16(IntrMitigate, 0x5151);
+
+ /* Work around for RxFIFO overflow. */
+ if (tp->mac_version == RTL_GIGA_MAC_VER_11) {
+ tp->intr_event |= RxFIFOOver | PCSTimeout;
+ tp->intr_event &= ~RxOverflow;
+ }
+
+ rtl_set_rx_tx_desc_registers(tp, ioaddr);
+
+ rtl_set_rx_mode(dev);
+
+ RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) |
+ (InterFrameGap << TxInterFrameGapShift));
+
+ RTL_R8(IntrMask);
+
+ switch (tp->mac_version) {
+ case RTL_GIGA_MAC_VER_11:
+ rtl_hw_start_8168bb(ioaddr, pdev);
+ break;
+
+ case RTL_GIGA_MAC_VER_12:
+ case RTL_GIGA_MAC_VER_17:
+ rtl_hw_start_8168bef(ioaddr, pdev);
+ break;
+
+ case RTL_GIGA_MAC_VER_18:
+ rtl_hw_start_8168cp_1(ioaddr, pdev);
+ break;
+
+ case RTL_GIGA_MAC_VER_19:
+ rtl_hw_start_8168c_1(ioaddr, pdev);
+ break;
+
+ case RTL_GIGA_MAC_VER_20:
+ rtl_hw_start_8168c_2(ioaddr, pdev);
+ break;
+
+ case RTL_GIGA_MAC_VER_21:
+ rtl_hw_start_8168c_3(ioaddr, pdev);
+ break;
+
+ case RTL_GIGA_MAC_VER_22:
+ rtl_hw_start_8168c_4(ioaddr, pdev);
+ break;
+
+ case RTL_GIGA_MAC_VER_23:
+ rtl_hw_start_8168cp_2(ioaddr, pdev);
+ break;
+
+ case RTL_GIGA_MAC_VER_24:
+ rtl_hw_start_8168cp_3(ioaddr, pdev);
+ break;
+
+ case RTL_GIGA_MAC_VER_25:
+ rtl_hw_start_8168d(ioaddr, pdev);
+ break;
+
default:
+ DBG ( "Unknown chipset (mac_version = %d).\n",
+ tp->mac_version );
+ break;
+ }
+
+ RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+
+ RTL_W8(Cfg9346, Cfg9346_Lock);
+
+ RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
+
+ // RTL_W16(IntrMask, tp->intr_event);
+}
+
+#define R810X_CPCMD_QUIRK_MASK (\
+ EnableBist | \
+ Mac_dbgo_oe | \
+ Force_half_dup | \
+ Force_half_dup | \
+ Force_txflow_en | \
+ Cxpl_dbg_sel | \
+ ASF | \
+ PktCntrDisable | \
+ PCIDAC | \
+ PCIMulRW)
+
+static void rtl_hw_start_8102e_1(void *ioaddr, struct pci_device *pdev)
+{
+ static struct ephy_info e_info_8102e_1[] = {
+ { 0x01, 0, 0x6e65 },
+ { 0x02, 0, 0x091f },
+ { 0x03, 0, 0xc2f9 },
+ { 0x06, 0, 0xafb5 },
+ { 0x07, 0, 0x0e00 },
+ { 0x19, 0, 0xec80 },
+ { 0x01, 0, 0x2e65 },
+ { 0x01, 0, 0x6e65 }
+ };
+ u8 cfg1;
+
+ DBGP ( "rtl_hw_start_8102e_1\n" );
+
+ rtl_csi_access_enable(ioaddr);
+
+ RTL_W8(DBG_REG, FIX_NAK_1);
+
+ rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+ RTL_W8(Config1,
+ LEDS1 | LEDS0 | Speed_down | MEMMAP | IOMAP | VPD | PMEnable);
+ RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
+
+ cfg1 = RTL_R8(Config1);
+ if ((cfg1 & LEDS0) && (cfg1 & LEDS1))
+ RTL_W8(Config1, cfg1 & ~LEDS0);
+
+ RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R810X_CPCMD_QUIRK_MASK);
+
+ rtl_ephy_init(ioaddr, e_info_8102e_1, ARRAY_SIZE(e_info_8102e_1));
+}
+
+static void rtl_hw_start_8102e_2(void *ioaddr, struct pci_device *pdev)
+{
+ DBGP ( "rtl_hw_start_8102e_2\n" );
+
+ rtl_csi_access_enable(ioaddr);
+
+ rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+ RTL_W8(Config1, MEMMAP | IOMAP | VPD | PMEnable);
+ RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
+
+ RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R810X_CPCMD_QUIRK_MASK);
+}
+
+static void rtl_hw_start_8102e_3(void *ioaddr, struct pci_device *pdev)
+{
+ DBGP ( "rtl_hw_start_8102e_3\n" );
+
+ rtl_hw_start_8102e_2(ioaddr, pdev);
+
+ rtl_ephy_write(ioaddr, 0x03, 0xc2f9);
+}
+
+static void rtl_hw_start_8101(struct net_device *dev)
+{
+ struct rtl8169_private *tp = netdev_priv(dev);
+ void *ioaddr = tp->mmio_addr;
+ struct pci_device *pdev = tp->pci_dev;
+
+ DBGP ( "rtl_hw_start_8101\n" );
+
+ if ((tp->mac_version == RTL_GIGA_MAC_VER_13) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_16)) {
+ int cap = tp->pcie_cap;
+
+ if (cap) {
+ pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL,
+ PCI_EXP_DEVCTL_NOSNOOP_EN);
+ }
+ }
+
+ switch (tp->mac_version) {
+ case RTL_GIGA_MAC_VER_07:
+ rtl_hw_start_8102e_1(ioaddr, pdev);
+ break;
+
+ case RTL_GIGA_MAC_VER_08:
+ rtl_hw_start_8102e_3(ioaddr, pdev);
+ break;
+
+ case RTL_GIGA_MAC_VER_09:
+ rtl_hw_start_8102e_2(ioaddr, pdev);
+ break;
+ }
+
+ RTL_W8(Cfg9346, Cfg9346_Unlock);
+
+ RTL_W8(EarlyTxThres, EarlyTxThld);
+
+ rtl_set_rx_max_size(ioaddr);
+
+ tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW;
+
+ RTL_W16(CPlusCmd, tp->cp_cmd);
+
+ RTL_W16(IntrMitigate, 0x0000);
+
+ rtl_set_rx_tx_desc_registers(tp, ioaddr);
+
+ RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+ rtl_set_rx_tx_config_registers(tp);
+
+ RTL_W8(Cfg9346, Cfg9346_Lock);
+
+ RTL_R8(IntrMask);
+
+ rtl_set_rx_mode(dev);
+
+ RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+
+ RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xf000);
+
+ // RTL_W16(IntrMask, tp->intr_event);
+}
+
+/*** gPXE API Support Routines ***/
+
+/**
+ * setup_tx_resources - allocate tx resources (descriptors)
+ *
+ * @v tp Driver private storage
+ *
+ * @ret rc Returns 0 on success, negative on failure
+ **/
+static int
+rtl8169_setup_tx_resources ( struct rtl8169_private *tp )
+{
+ DBGP ( "rtl8169_setup_tx_resources\n" );
+
+ tp->tx_base = malloc_dma ( R8169_TX_RING_BYTES, TX_RING_ALIGN );
+
+ if ( ! tp->tx_base ) {
+ return -ENOMEM;
+ }
+
+ memset ( tp->tx_base, 0, R8169_TX_RING_BYTES );
+
+ DBG ( "tp->tx_base = %#08lx\n", virt_to_bus ( tp->tx_base ) );
+
+ tp->tx_fill_ctr = 0;
+ tp->tx_curr = 0;
+ tp->tx_tail = 0;
+
+ return 0;
+}
+
+static void
+rtl8169_process_tx_packets ( struct net_device *netdev )
+{
+ struct rtl8169_private *tp = netdev_priv ( netdev );
+
+ uint32_t tx_status;
+ struct TxDesc *tx_curr_desc;
+
+ DBGP ( "rtl8169_process_tx_packets\n" );
+
+ while ( tp->tx_tail != tp->tx_curr ) {
+
+ tx_curr_desc = tp->tx_base + tp->tx_tail;
+
+ tx_status = tx_curr_desc->opts1;
+
+ DBG2 ( "Before DescOwn check tx_status: %#08x\n", tx_status );
+
+ /* if the packet at tx_tail is not owned by hardware it is for us */
+ if ( tx_status & DescOwn )
+ break;
+
+ DBG ( "Transmitted packet.\n" );
+ DBG ( "tp->tx_fill_ctr = %d\n", tp->tx_fill_ctr );
+ DBG ( "tp->tx_tail = %d\n", tp->tx_tail );
+ DBG ( "tp->tx_curr = %d\n", tp->tx_curr );
+ DBG ( "tx_status = %d\n", tx_status );
+ DBG ( "tx_curr_desc = %#08lx\n", virt_to_bus ( tx_curr_desc ) );
+
+ /* Pass packet to core for processing */
+ netdev_tx_complete ( netdev, tp->tx_iobuf[tp->tx_tail] );
+
+ memset ( tx_curr_desc, 0, sizeof ( *tx_curr_desc ) );
+
+ /* Decrement count of used descriptors */
+ tp->tx_fill_ctr--;
+
+ /* Increment sent packets index */
+ tp->tx_tail = ( tp->tx_tail + 1 ) % NUM_TX_DESC;
+ }
+}
+
+static void
+rtl8169_free_tx_resources ( struct rtl8169_private *tp )
+{
+ DBGP ( "rtl8169_free_tx_resources\n" );
+
+ free_dma ( tp->tx_base, R8169_TX_RING_BYTES );
+}
+
+static void
+rtl8169_populate_rx_descriptor ( struct rtl8169_private *tp, struct RxDesc *rx_desc, uint32_t index )
+{
+ DBGP ( "rtl8169_populate_rx_descriptor\n" );
+
+ DBG ( "Populating rx descriptor %d\n", index );
+
+ memset ( rx_desc, 0, sizeof ( *rx_desc ) );
+
+ rx_desc->addr_hi = 0;
+ rx_desc->addr_lo = virt_to_bus ( tp->rx_iobuf[index]->data );
+ rx_desc->opts2 = 0;
+ rx_desc->opts1 = ( index == ( NUM_RX_DESC - 1 ) ? RingEnd : 0 ) |
+ RX_BUF_SIZE;
+ rx_desc->opts1 |= DescOwn;
+}
+
+/**
+ * Refill descriptor ring
+ *
+ * @v netdev Net device
+ */
+static void rtl8169_refill_rx_ring ( struct rtl8169_private *tp )
+{
+ struct RxDesc *rx_curr_desc;
+ int i;
+
+ DBGP ( "rtl8169_refill_rx_ring\n" );
+
+ for ( i = 0; i < NUM_RX_DESC; i++ ) {
+
+ rx_curr_desc = ( tp->rx_base ) + i;
+
+ /* Don't touch descriptors owned by the NIC */
+ if ( rx_curr_desc->opts1 & DescOwn )
+ continue;
+
+ /* Don't touch descriptors with iobufs, they still need to be
+ processed by the poll routine */
+ if ( tp->rx_iobuf[tp->rx_curr] != NULL )
+ continue;
+
+ /** If we can't get an iobuf for this descriptor
+ try again later (next poll).
+ */
+ if ( ! ( tp->rx_iobuf[i] = alloc_iob ( RX_BUF_SIZE ) ) ) {
+ DBG ( "Refill rx ring failed!!\n" );
+ break;
+ }
+
+ rtl8169_populate_rx_descriptor ( tp, rx_curr_desc, i );
+ }
+}
+
+/**
+ * setup_rx_resources - allocate Rx resources (Descriptors)
+ *
+ * @v tp: Driver private structure
+ *
+ * @ret rc Returns 0 on success, negative on failure
+ *
+ **/
+static int
+rtl8169_setup_rx_resources ( struct rtl8169_private *tp )
+{
+ DBGP ( "rtl8169_setup_rx_resources\n" );
+
+ tp->rx_base = malloc_dma ( R8169_RX_RING_BYTES, RX_RING_ALIGN );
+
+ DBG ( "tp->rx_base = %#08lx\n", virt_to_bus ( tp->rx_base ) );
+
+ if ( ! tp->rx_base ) {
+ return -ENOMEM;
+ }
+ memset ( tp->rx_base, 0, R8169_RX_RING_BYTES );
+
+ rtl8169_refill_rx_ring ( tp );
+
+ tp->rx_curr = 0;
+
+ return 0;
+}
+
+static void
+rtl8169_process_rx_packets ( struct net_device *netdev )
+{
+ struct rtl8169_private *tp = netdev_priv ( netdev );
+ uint32_t rx_status;
+ uint16_t rx_len;
+ struct RxDesc *rx_curr_desc;
+ int i;
+
+ DBGP ( "rtl8169_process_rx_packets\n" );
+
+ for ( i = 0; i < NUM_RX_DESC; i++ ) {
+
+ rx_curr_desc = tp->rx_base + tp->rx_curr;
+
+ rx_status = rx_curr_desc->opts1;
+
+ DBG2 ( "Before DescOwn check rx_status: %#08x\n", rx_status );
+
+ /* Hardware still owns the descriptor */
+ if ( rx_status & DescOwn )
+ break;
+
+ /* We own the descriptor, but it has not been refilled yet */
+ if ( tp->rx_iobuf[tp->rx_curr] == NULL )
+ break;
+
+ rx_len = rx_status & 0x3fff;
+
+ DBG ( "Received packet.\n" );
+ DBG ( "tp->rx_curr = %d\n", tp->rx_curr );
+ DBG ( "rx_len = %d\n", rx_len );
+ DBG ( "rx_status = %#08x\n", rx_status );
+ DBG ( "rx_curr_desc = %#08lx\n", virt_to_bus ( rx_curr_desc ) );
+
+ if ( rx_status & RxRES ) {
+
+ netdev_rx_err ( netdev, tp->rx_iobuf[tp->rx_curr], -EINVAL );
+
+ DBG ( "rtl8169_poll: Corrupted packet received!\n"
+ " rx_status: %#08x\n", rx_status );
+
+ } else {
+
+ /* Adjust size of the iobuf to reflect received data */
+ iob_put ( tp->rx_iobuf[tp->rx_curr], rx_len );
+
+ /* Add this packet to the receive queue. */
+ netdev_rx ( netdev, tp->rx_iobuf[tp->rx_curr] );
+ }
+
+ /* Invalidate this iobuf and descriptor */
+ tp->rx_iobuf[tp->rx_curr] = NULL;
+ memset ( rx_curr_desc, 0, sizeof ( *rx_curr_desc ) );
+
+ /* Update pointer to next available rx descriptor */
+ tp->rx_curr = ( tp->rx_curr + 1 ) % NUM_RX_DESC;
+ }
+ rtl8169_refill_rx_ring ( tp );
+}
+
+static void
+rtl8169_free_rx_resources ( struct rtl8169_private *tp )
+{
+ int i;
+
+ DBGP ( "rtl8169_free_rx_resources\n" );
+
+ free_dma ( tp->rx_base, R8169_RX_RING_BYTES );
+
+ for ( i = 0; i < NUM_RX_DESC; i++ ) {
+ free_iob ( tp->rx_iobuf[i] );
+ tp->rx_iobuf[i] = NULL;
+ }
+}
+
+/**
+ FIXME: Because gPXE's pci_device_id structure does not contain a
+ field to contain arbitrary data, we need the following table to
+ associate PCI IDs with nic variants, because a lot of driver
+ routines depend on knowing which kind of variant they are dealing
+ with. --mdc
+ **/
+
+#define _R(VENDOR,DEVICE,INDEX) \
+ { .vendor = VENDOR, .device = DEVICE, .index = INDEX }
+
+static const struct {
+ uint16_t vendor;
+ uint16_t device;
+ int index;
+} nic_variant_table[] = {
+ _R(0x10ec, 0x8129, RTL_CFG_0),
+ _R(0x10ec, 0x8136, RTL_CFG_2),
+ _R(0x10ec, 0x8167, RTL_CFG_0),
+ _R(0x10ec, 0x8168, RTL_CFG_1),
+ _R(0x10ec, 0x8169, RTL_CFG_0),
+ _R(0x1186, 0x4300, RTL_CFG_0),
+ _R(0x1259, 0xc107, RTL_CFG_0),
+ _R(0x16ec, 0x0116, RTL_CFG_0),
+ _R(0x1737, 0x1032, RTL_CFG_0),
+ _R(0x0001, 0x8168, RTL_CFG_2),
+};
+#undef _R
+
+static int
+rtl8169_get_nic_variant ( uint16_t vendor, uint16_t device )
+{
+ u32 i;
+
+ DBGP ( "rtl8169_get_nic_variant\n" );
+
+ for (i = 0; i < ARRAY_SIZE(nic_variant_table); i++) {
+ if ( ( nic_variant_table[i].vendor == vendor ) &&
+ ( nic_variant_table[i].device == device ) ) {
+ return ( nic_variant_table[i].index );
+ }
+ }
+ DBG ( "No matching NIC variant found!\n" );
+ return ( RTL_CFG_0 );
+}
+
+static void rtl8169_irq_enable ( struct rtl8169_private *tp )
+{
+ void *ioaddr = tp->mmio_addr;
+
+ DBGP ( "rtl8169_irq_enable\n" );
+
+ RTL_W16 ( IntrMask, tp->intr_event );
+}
+
+static void rtl8169_irq_disable ( struct rtl8169_private *tp )
+{
+ void *ioaddr = tp->mmio_addr;
+
+ DBGP ( "rtl8169_irq_disable\n" );
+
+ rtl8169_irq_mask_and_ack ( ioaddr );
+}
+
+/*** gPXE Core API Routines ***/
+
+/**
+ * open - Called when a network interface is made active
+ *
+ * @v netdev network interface device structure
+ * @ret rc Return status code, 0 on success, negative value on failure
+ *
+ **/
+static int
+rtl8169_open ( struct net_device *netdev )
+{
+ struct rtl8169_private *tp = netdev_priv ( netdev );
+ void *ioaddr = tp->mmio_addr;
+ int rc;
+
+ DBGP ( "rtl8169_open\n" );
+
+ /* allocate transmit descriptors */
+ rc = rtl8169_setup_tx_resources ( tp );
+ if ( rc ) {
+ DBG ( "Error setting up TX resources!\n" );
+ goto err_setup_tx;
+ }
+
+ /* allocate receive descriptors */
+ rc = rtl8169_setup_rx_resources ( tp );
+ if ( rc ) {
+ DBG ( "Error setting up RX resources!\n" );
+ goto err_setup_rx;
+ }
+
+ rtl_hw_start ( netdev );
+
+ DBG ( "TxDescStartAddrHigh = %#08lx\n", RTL_R32 ( TxDescStartAddrHigh ) );
+ DBG ( "TxDescStartAddrLow = %#08lx\n", RTL_R32 ( TxDescStartAddrLow ) );
+ DBG ( "RxDescAddrHigh = %#08lx\n", RTL_R32 ( RxDescAddrHigh ) );
+ DBG ( "RxDescAddrLow = %#08lx\n", RTL_R32 ( RxDescAddrLow ) );
+
+ return 0;
+
+err_setup_rx:
+ rtl8169_free_tx_resources ( tp );
+err_setup_tx:
+ rtl8169_hw_reset ( ioaddr );
+
+ return rc;
+}
+
+/**
+ * transmit - Transmit a packet
+ *
+ * @v netdev Network device
+ * @v iobuf I/O buffer
+ *
+ * @ret rc Returns 0 on success, negative on failure
+ */
+static int
+rtl8169_transmit ( struct net_device *netdev, struct io_buffer *iobuf )
+{
+ struct rtl8169_private *tp = netdev_priv ( netdev );
+ void *ioaddr = tp->mmio_addr;
+ uint32_t tx_len = iob_len ( iobuf );
+
+ struct TxDesc *tx_curr_desc;
+
+ DBGP ("rtl8169_transmit\n");
+
+ if ( tp->tx_fill_ctr == NUM_TX_DESC ) {
+ DBG ("TX overflow\n");
+ return -ENOBUFS;
+ }
+
+ /**
+ * The rtl8169 family automatically pads short packets to a
+ * minimum size, but if it did not, like some older cards,
+ * we could do:
+ * iob_pad ( iobuf, ETH_ZLEN );
+ */
+
+ /* Save pointer to this iobuf we have been given to transmit so
+ we can pass it to netdev_tx_complete() later */
+ tp->tx_iobuf[tp->tx_curr] = iobuf;
+
+ tx_curr_desc = tp->tx_base + tp->tx_curr;
+
+ DBG ( "tp->tx_fill_ctr = %d\n", tp->tx_fill_ctr );
+ DBG ( "tp->tx_curr = %d\n", tp->tx_curr );
+ DBG ( "tx_curr_desc = %#08lx\n", virt_to_bus ( tx_curr_desc ) );
+ DBG ( "iobuf->data = %#08lx\n", virt_to_bus ( iobuf->data ) );
+ DBG ( "tx_len = %d\n", tx_len );
+
+ /* Configure current descriptor to transmit supplied packet */
+ tx_curr_desc->addr_hi = 0;
+ tx_curr_desc->addr_lo = virt_to_bus ( iobuf->data );
+ tx_curr_desc->opts2 = 0;
+ tx_curr_desc->opts1 = FirstFrag | LastFrag |
+ ( tp->tx_curr == ( NUM_TX_DESC - 1 ) ? RingEnd : 0 ) |
+ tx_len;
+
+ /* Mark descriptor as owned by NIC */
+ tx_curr_desc->opts1 |= DescOwn;
+
+ DBG ( "tx_curr_desc->opts1 = %#08x\n", tx_curr_desc->opts1 );
+ DBG ( "tx_curr_desc->opts2 = %#08x\n", tx_curr_desc->opts2 );
+ DBG ( "tx_curr_desc->addr_hi = %#08x\n", tx_curr_desc->addr_hi );
+ DBG ( "tx_curr_desc->addr_lo = %#08x\n", tx_curr_desc->addr_lo );
+
+ RTL_W8 ( TxPoll, NPQ ); /* set polling bit */
+
+ /* Point to next free descriptor */
+ tp->tx_curr = ( tp->tx_curr + 1 ) % NUM_TX_DESC;
+
+ /* Increment number of tx descriptors in use */
+ tp->tx_fill_ctr++;
+
+ return 0;
+}
+
+/**
+ * poll - Poll for received packets
+ *
+ * @v netdev Network device
+ */
+static void
+rtl8169_poll ( struct net_device *netdev )
+{
+ struct rtl8169_private *tp = netdev_priv ( netdev );
+ void *ioaddr = tp->mmio_addr;
+
+ uint16_t intr_status;
+ uint16_t intr_mask;
+
+ DBGP ( "rtl8169_poll\n" );
+
+ intr_status = RTL_R16 ( IntrStatus );
+ intr_mask = RTL_R16 ( IntrMask );
+
+ DBG2 ( "rtl8169_poll (before): intr_mask = %#04x intr_status = %#04x\n",
+ intr_mask, intr_status );
+
+ RTL_W16 ( IntrStatus, 0xffff );
+
+ /* hotplug / major error / no more work / shared irq */
+ if ( intr_status == 0xffff )
+ return;
+
+ /* Process transmitted packets */
+ rtl8169_process_tx_packets ( netdev );
+
+ /* Process received packets */
+ rtl8169_process_rx_packets ( netdev );
+}
+
+/**
+ * close - Disable network interface
+ *
+ * @v netdev network interface device structure
+ *
+ **/
+static void
+rtl8169_close ( struct net_device *netdev )
+{
+ struct rtl8169_private *tp = netdev_priv ( netdev );
+ void *ioaddr = tp->mmio_addr;
+
+ DBGP ( "r8169_close\n" );
+
+ rtl8169_hw_reset ( ioaddr );
+
+ rtl8169_free_tx_resources ( tp );
+ rtl8169_free_rx_resources ( tp );
+}
+
+/**
+ * irq - enable or Disable interrupts
+ *
+ * @v netdev network adapter
+ * @v action requested interrupt action
+ *
+ **/
+static void
+rtl8169_irq ( struct net_device *netdev, int action )
+{
+ struct rtl8169_private *tp = netdev_priv ( netdev );
+
+ DBGP ( "rtl8169_irq\n" );
+
+ switch ( action ) {
+ case 0 :
+ rtl8169_irq_disable ( tp );
+ break;
+ default :
+ rtl8169_irq_enable ( tp );
break;
}
}
-DRIVER ( "r8169/PCI", nic_driver, pci_driver, r8169_driver,
- r8169_probe, r8169_disable );
+static struct net_device_operations rtl8169_operations = {
+ .open = rtl8169_open,
+ .transmit = rtl8169_transmit,
+ .poll = rtl8169_poll,
+ .close = rtl8169_close,
+ .irq = rtl8169_irq,
+};
+
+/**
+ * probe - Initial configuration of NIC
+ *
+ * @v pci PCI device
+ * @v id PCI IDs
+ *
+ * @ret rc Return status code
+ **/
+static int
+rtl8169_probe ( struct pci_device *pdev, const struct pci_device_id *ent )
+{
+ int i, rc;
+ struct net_device *netdev;
+ struct rtl8169_private *tp;
+ void *ioaddr;
+
+ /** FIXME: This lookup is necessary because gPXE does not have a "data"
+ element in the structure pci_device_id which can pass an arbitrary
+ piece of data to the driver. It might be useful to add it. Then we
+ could just use ent->data instead of having to look up cfg_index.
+ **/
+ int cfg_index = rtl8169_get_nic_variant ( ent->vendor, ent->device );
+ const struct rtl_cfg_info *cfg = rtl_cfg_infos + cfg_index;
+
+ DBGP ( "rtl8169_probe\n" );
+
+ DBG ( "ent->vendor = %#04x, ent->device = %#04x\n", ent->vendor, ent->device );
+
+ DBG ( "cfg_index = %d\n", cfg_index );
+ DBG ( "cfg->intr_event = %#04x\n", cfg->intr_event );
+
+ rc = -ENOMEM;
+
+ /* Allocate net device ( also allocates memory for netdev->priv
+ and makes netdev-priv point to it )
+ */
+ netdev = alloc_etherdev ( sizeof ( *tp ) );
+
+ if ( ! netdev )
+ goto err_alloc_etherdev;
+
+ /* Associate driver-specific network operations with
+ generic network device layer
+ */
+ netdev_init ( netdev, &rtl8169_operations );
+
+ /* Associate this network device with the given PCI device */
+ pci_set_drvdata ( pdev, netdev );
+ netdev->dev = &pdev->dev;
+
+ /* Initialize driver private storage */
+ tp = netdev_priv ( netdev );
+ memset ( tp, 0, ( sizeof ( *tp ) ) );
+
+ tp->pci_dev = pdev;
+ tp->irqno = pdev->irq;
+ tp->netdev = netdev;
+ tp->cfg_index = cfg_index;
+ tp->intr_event = cfg->intr_event;
+ tp->cp_cmd = PCIMulRW;
+
+ tp->hw_start = cfg->hw_start;
+
+ rc = -EIO;
+
+ adjust_pci_device ( pdev );
+
+ /* ioremap MMIO region */
+ ioaddr = ioremap ( pdev->membase, R8169_REGS_SIZE );
+
+ if ( ! ioaddr ) {
+ DBG ( "cannot remap MMIO\n" );
+ rc = -EIO;
+ goto err_ioremap;
+ }
+
+ tp->mmio_addr = ioaddr;
+
+ tp->pcie_cap = pci_find_capability ( pdev, PCI_CAP_ID_EXP );
+ if ( tp->pcie_cap ) {
+ DBG ( "PCI Express capability\n" );
+ } else {
+ DBG ( "No PCI Express capability\n" );
+ }
+
+ /* Mask interrupts just in case */
+ rtl8169_irq_mask_and_ack ( ioaddr );
+
+ /* Soft reset NIC */
+ rtl_soft_reset ( netdev );
+
+ /* Identify chip attached to board */
+ rtl8169_get_mac_version ( tp, ioaddr );
+
+ for ( i = 0; (u32) i < ARRAY_SIZE ( rtl_chip_info ); i++ ) {
+ if ( tp->mac_version == rtl_chip_info[i].mac_version )
+ break;
+ }
+ if ( i == ARRAY_SIZE(rtl_chip_info ) ) {
+ /* Unknown chip: assume array element #0, original RTL-8169 */
+ DBG ( "Unknown chip version, assuming %s\n", rtl_chip_info[0].name );
+ i = 0;
+ }
+ tp->chipset = i;
+
+ if ((tp->mac_version <= RTL_GIGA_MAC_VER_06) &&
+ (RTL_R8(PHYstatus) & TBI_Enable)) {
+ tp->set_speed = rtl8169_set_speed_tbi;
+ tp->phy_reset_enable = rtl8169_tbi_reset_enable;
+ tp->phy_reset_pending = rtl8169_tbi_reset_pending;
+ tp->link_ok = rtl8169_tbi_link_ok;
+
+ tp->phy_1000_ctrl_reg = ADVERTISE_1000FULL; /* Implied by TBI */
+ } else {
+ tp->set_speed = rtl8169_set_speed_xmii;
+ tp->phy_reset_enable = rtl8169_xmii_reset_enable;
+ tp->phy_reset_pending = rtl8169_xmii_reset_pending;
+ tp->link_ok = rtl8169_xmii_link_ok;
+ }
+
+ /* Get MAC address */
+ for ( i = 0; i < MAC_ADDR_LEN; i++ )
+ netdev->ll_addr[i] = RTL_R8 ( MAC0 + i );
+
+ DBG ( "%s\n", eth_ntoa ( netdev->ll_addr ) );
+
+ rtl8169_init_phy ( netdev, tp );
+
+ if ( ( rc = register_netdev ( netdev ) ) != 0 )
+ goto err_register;
+
+ /* Mark as link up; we don't yet handle link state */
+ netdev_link_up ( netdev );
+
+ DBG ( "rtl8169_probe succeeded!\n" );
+
+ /* No errors, return success */
+ return 0;
+
+/* Error return paths */
+err_register:
+err_ioremap:
+ netdev_put ( netdev );
+err_alloc_etherdev:
+ return rc;
+}
+
+/**
+ * remove - Device Removal Routine
+ *
+ * @v pdev PCI device information struct
+ *
+ **/
+static void
+rtl8169_remove ( struct pci_device *pdev )
+{
+ struct net_device *netdev = pci_get_drvdata ( pdev );
+ struct rtl8169_private *tp = netdev_priv ( netdev );
+ void *ioaddr = tp->mmio_addr;
+
+ DBGP ( "rtl8169_remove\n" );
+
+ rtl8169_hw_reset ( ioaddr );
+
+ unregister_netdev ( netdev );
+ netdev_nullify ( netdev );
+ netdev_put ( netdev );
+}
+
+static struct pci_device_id rtl8169_nics[] = {
+ PCI_ROM(0x10ec, 0x8129, "rtl8169-0x8129", "rtl8169-0x8129"),
+ PCI_ROM(0x10ec, 0x8136, "rtl8169-0x8136", "rtl8169-0x8136"),
+ PCI_ROM(0x10ec, 0x8167, "rtl8169-0x8167", "rtl8169-0x8167"),
+ PCI_ROM(0x10ec, 0x8168, "rtl8169-0x8168", "rtl8169-0x8168"),
+ PCI_ROM(0x10ec, 0x8169, "rtl8169-0x8169", "rtl8169-0x8169"),
+ PCI_ROM(0x1186, 0x4300, "rtl8169-0x4300", "rtl8169-0x4300"),
+ PCI_ROM(0x1259, 0xc107, "rtl8169-0xc107", "rtl8169-0xc107"),
+ PCI_ROM(0x16ec, 0x0116, "rtl8169-0x0116", "rtl8169-0x0116"),
+ PCI_ROM(0x1737, 0x1032, "rtl8169-0x1032", "rtl8169-0x1032"),
+ PCI_ROM(0x0001, 0x8168, "rtl8169-0x8168", "rtl8169-0x8168"),
+};
+
+struct pci_driver rtl8169_driver __pci_driver = {
+ .ids = rtl8169_nics,
+ .id_count = ( sizeof ( rtl8169_nics ) / sizeof ( rtl8169_nics[0] ) ),
+ .probe = rtl8169_probe,
+ .remove = rtl8169_remove,
+};
/*
* Local variables:
diff --git a/gpxe/src/drivers/net/r8169.h b/gpxe/src/drivers/net/r8169.h
new file mode 100644
index 00000000..d3536326
--- /dev/null
+++ b/gpxe/src/drivers/net/r8169.h
@@ -0,0 +1,566 @@
+/*
+ * Copyright (c) 2008 Marty Connor <mdc@etherboot.org>
+ * Copyright (c) 2008 Entity Cyber, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * This driver is based on rtl8169 data sheets and work by:
+ *
+ * Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
+ * Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
+ * Copyright (c) a lot of people too. Please respect their work.
+ *
+ */
+
+#ifndef _R8169_H_
+#define _R8169_H_
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+/** FIXME: include/linux/pci_regs.h has these PCI regs, maybe
+ we need such a file in gPXE?
+**/
+#define PCI_EXP_DEVCTL 8 /* Device Control */
+#define PCI_EXP_DEVCTL_READRQ 0x7000 /* Max_Read_Request_Size */
+#define PCI_EXP_LNKCTL 16 /* Link Control */
+#define PCI_EXP_LNKCTL_CLKREQ_EN 0x100 /* Enable clkreq */
+#define PCI_EXP_DEVCTL_NOSNOOP_EN 0x0800 /* Enable No Snoop */
+
+/** FIXME: update mii.h in src/include/mii.h from Linux sources
+ so we don't have to include these definitiions.
+**/
+/* The forced speed, 10Mb, 100Mb, gigabit, 2.5Gb, 10GbE. */
+#define SPEED_10 10
+#define SPEED_100 100
+#define SPEED_1000 1000
+#define SPEED_2500 2500
+#define SPEED_10000 10000
+
+/* Duplex, half or full. */
+#define DUPLEX_HALF 0x00
+#define DUPLEX_FULL 0x01
+
+/* Generic MII registers. */
+
+#define MII_BMCR 0x00 /* Basic mode control register */
+#define MII_BMSR 0x01 /* Basic mode status register */
+#define MII_PHYSID1 0x02 /* PHYS ID 1 */
+#define MII_PHYSID2 0x03 /* PHYS ID 2 */
+#define MII_ADVERTISE 0x04 /* Advertisement control reg */
+#define MII_LPA 0x05 /* Link partner ability reg */
+#define MII_EXPANSION 0x06 /* Expansion register */
+#define MII_CTRL1000 0x09 /* 1000BASE-T control */
+#define MII_STAT1000 0x0a /* 1000BASE-T status */
+#define MII_ESTATUS 0x0f /* Extended Status */
+#define MII_DCOUNTER 0x12 /* Disconnect counter */
+#define MII_FCSCOUNTER 0x13 /* False carrier counter */
+#define MII_NWAYTEST 0x14 /* N-way auto-neg test reg */
+#define MII_RERRCOUNTER 0x15 /* Receive error counter */
+#define MII_SREVISION 0x16 /* Silicon revision */
+#define MII_RESV1 0x17 /* Reserved... */
+#define MII_LBRERROR 0x18 /* Lpback, rx, bypass error */
+#define MII_PHYADDR 0x19 /* PHY address */
+#define MII_RESV2 0x1a /* Reserved... */
+#define MII_TPISTATUS 0x1b /* TPI status for 10mbps */
+#define MII_NCONFIG 0x1c /* Network interface config */
+
+/* Basic mode control register. */
+#define BMCR_RESV 0x003f /* Unused... */
+#define BMCR_SPEED1000 0x0040 /* MSB of Speed (1000) */
+#define BMCR_CTST 0x0080 /* Collision test */
+#define BMCR_FULLDPLX 0x0100 /* Full duplex */
+#define BMCR_ANRESTART 0x0200 /* Auto negotiation restart */
+#define BMCR_ISOLATE 0x0400 /* Disconnect DP83840 from MII */
+#define BMCR_PDOWN 0x0800 /* Powerdown the DP83840 */
+#define BMCR_ANENABLE 0x1000 /* Enable auto negotiation */
+#define BMCR_SPEED100 0x2000 /* Select 100Mbps */
+#define BMCR_LOOPBACK 0x4000 /* TXD loopback bits */
+#define BMCR_RESET 0x8000 /* Reset the DP83840 */
+
+/* Basic mode status register. */
+#define BMSR_ERCAP 0x0001 /* Ext-reg capability */
+#define BMSR_JCD 0x0002 /* Jabber detected */
+#define BMSR_LSTATUS 0x0004 /* Link status */
+#define BMSR_ANEGCAPABLE 0x0008 /* Able to do auto-negotiation */
+#define BMSR_RFAULT 0x0010 /* Remote fault detected */
+#define BMSR_ANEGCOMPLETE 0x0020 /* Auto-negotiation complete */
+#define BMSR_RESV 0x00c0 /* Unused... */
+#define BMSR_ESTATEN 0x0100 /* Extended Status in R15 */
+#define BMSR_100HALF2 0x0200 /* Can do 100BASE-T2 HDX */
+#define BMSR_100FULL2 0x0400 /* Can do 100BASE-T2 FDX */
+#define BMSR_10HALF 0x0800 /* Can do 10mbps, half-duplex */
+#define BMSR_10FULL 0x1000 /* Can do 10mbps, full-duplex */
+#define BMSR_100HALF 0x2000 /* Can do 100mbps, half-duplex */
+#define BMSR_100FULL 0x4000 /* Can do 100mbps, full-duplex */
+#define BMSR_100BASE4 0x8000 /* Can do 100mbps, 4k packets */
+
+#define AUTONEG_DISABLE 0x00
+#define AUTONEG_ENABLE 0x01
+
+#define MII_ADVERTISE 0x04 /* Advertisement control reg */
+#define ADVERTISE_SLCT 0x001f /* Selector bits */
+#define ADVERTISE_CSMA 0x0001 /* Only selector supported */
+#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */
+#define ADVERTISE_1000XFULL 0x0020 /* Try for 1000BASE-X full-duplex */
+#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */
+#define ADVERTISE_1000XHALF 0x0040 /* Try for 1000BASE-X half-duplex */
+#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */
+#define ADVERTISE_1000XPAUSE 0x0080 /* Try for 1000BASE-X pause */
+#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */
+#define ADVERTISE_1000XPSE_ASYM 0x0100 /* Try for 1000BASE-X asym pause */
+#define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */
+#define ADVERTISE_PAUSE_CAP 0x0400 /* Try for pause */
+#define ADVERTISE_PAUSE_ASYM 0x0800 /* Try for asymetric pause */
+#define ADVERTISE_RESV 0x1000 /* Unused... */
+#define ADVERTISE_RFAULT 0x2000 /* Say we can detect faults */
+#define ADVERTISE_LPACK 0x4000 /* Ack link partners response */
+#define ADVERTISE_NPAGE 0x8000 /* Next page bit */
+#define ADVERTISE_FULL (ADVERTISE_100FULL | ADVERTISE_10FULL | \
+ ADVERTISE_CSMA)
+#define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \
+ ADVERTISE_100HALF | ADVERTISE_100FULL)
+
+/* 1000BASE-T Control register */
+#define ADVERTISE_1000FULL 0x0200 /* Advertise 1000BASE-T full duplex */
+#define ADVERTISE_1000HALF 0x0100 /* Advertise 1000BASE-T half duplex */
+
+/* MAC address length */
+#define MAC_ADDR_LEN 6
+
+#define MAX_READ_REQUEST_SHIFT 12
+#define RX_FIFO_THRESH 7 /* 7 means NO threshold, Rx buffer level before first PCI xfer. */
+#define RX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */
+#define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */
+#define EarlyTxThld 0x3F /* 0x3F means NO early transmit */
+#define RxPacketMaxSize 0x3FE8 /* 16K - 1 - ETH_HLEN - VLAN - CRC... */
+#define SafeMtu 0x1c20 /* ... actually life sucks beyond ~7k */
+#define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */
+
+#define R8169_REGS_SIZE 256
+#define R8169_NAPI_WEIGHT 64
+#define NUM_TX_DESC 8 /* Number of Tx descriptor registers */
+#define NUM_RX_DESC 8 /* Number of Rx descriptor registers */
+#define RX_BUF_SIZE 1536 /* Rx Buffer size */
+#define R8169_TX_RING_BYTES (NUM_TX_DESC * sizeof(struct TxDesc))
+#define R8169_RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc))
+
+#define TX_RING_ALIGN 256
+#define RX_RING_ALIGN 256
+
+#define RTL8169_TX_TIMEOUT (6*HZ)
+#define RTL8169_PHY_TIMEOUT (10*HZ)
+
+#define RTL_EEPROM_SIG cpu_to_le32(0x8129)
+#define RTL_EEPROM_SIG_MASK cpu_to_le32(0xffff)
+#define RTL_EEPROM_SIG_ADDR 0x0000
+
+/* write/read MMIO register */
+#define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg))
+#define RTL_W16(reg, val16) writew ((val16), ioaddr + (reg))
+#define RTL_W32(reg, val32) writel ((val32), ioaddr + (reg))
+#define RTL_R8(reg) readb (ioaddr + (reg))
+#define RTL_R16(reg) readw (ioaddr + (reg))
+#define RTL_R32(reg) ((unsigned long) readl (ioaddr + (reg)))
+
+enum mac_version {
+ RTL_GIGA_MAC_VER_01 = 0x01, // 8169
+ RTL_GIGA_MAC_VER_02 = 0x02, // 8169S
+ RTL_GIGA_MAC_VER_03 = 0x03, // 8110S
+ RTL_GIGA_MAC_VER_04 = 0x04, // 8169SB
+ RTL_GIGA_MAC_VER_05 = 0x05, // 8110SCd
+ RTL_GIGA_MAC_VER_06 = 0x06, // 8110SCe
+ RTL_GIGA_MAC_VER_07 = 0x07, // 8102e
+ RTL_GIGA_MAC_VER_08 = 0x08, // 8102e
+ RTL_GIGA_MAC_VER_09 = 0x09, // 8102e
+ RTL_GIGA_MAC_VER_10 = 0x0a, // 8101e
+ RTL_GIGA_MAC_VER_11 = 0x0b, // 8168Bb
+ RTL_GIGA_MAC_VER_12 = 0x0c, // 8168Be
+ RTL_GIGA_MAC_VER_13 = 0x0d, // 8101Eb
+ RTL_GIGA_MAC_VER_14 = 0x0e, // 8101 ?
+ RTL_GIGA_MAC_VER_15 = 0x0f, // 8101 ?
+ RTL_GIGA_MAC_VER_16 = 0x11, // 8101Ec
+ RTL_GIGA_MAC_VER_17 = 0x10, // 8168Bf
+ RTL_GIGA_MAC_VER_18 = 0x12, // 8168CP
+ RTL_GIGA_MAC_VER_19 = 0x13, // 8168C
+ RTL_GIGA_MAC_VER_20 = 0x14, // 8168C
+ RTL_GIGA_MAC_VER_21 = 0x15, // 8168C
+ RTL_GIGA_MAC_VER_22 = 0x16, // 8168C
+ RTL_GIGA_MAC_VER_23 = 0x17, // 8168CP
+ RTL_GIGA_MAC_VER_24 = 0x18, // 8168CP
+ RTL_GIGA_MAC_VER_25 = 0x19, // 8168D
+};
+
+#define _R(NAME,MAC,MASK) \
+ { .name = NAME, .mac_version = MAC, .RxConfigMask = MASK }
+
+static const struct {
+ const char *name;
+ u8 mac_version;
+ u32 RxConfigMask; /* Clears the bits supported by this chip */
+} rtl_chip_info[] = {
+ _R("RTL8169", RTL_GIGA_MAC_VER_01, 0xff7e1880), // 8169
+ _R("RTL8169s", RTL_GIGA_MAC_VER_02, 0xff7e1880), // 8169S
+ _R("RTL8110s", RTL_GIGA_MAC_VER_03, 0xff7e1880), // 8110S
+ _R("RTL8169sb/8110sb", RTL_GIGA_MAC_VER_04, 0xff7e1880), // 8169SB
+ _R("RTL8169sc/8110sc", RTL_GIGA_MAC_VER_05, 0xff7e1880), // 8110SCd
+ _R("RTL8169sc/8110sc", RTL_GIGA_MAC_VER_06, 0xff7e1880), // 8110SCe
+ _R("RTL8102e", RTL_GIGA_MAC_VER_07, 0xff7e1880), // PCI-E
+ _R("RTL8102e", RTL_GIGA_MAC_VER_08, 0xff7e1880), // PCI-E
+ _R("RTL8102e", RTL_GIGA_MAC_VER_09, 0xff7e1880), // PCI-E
+ _R("RTL8101e", RTL_GIGA_MAC_VER_10, 0xff7e1880), // PCI-E
+ _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_11, 0xff7e1880), // PCI-E
+ _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_12, 0xff7e1880), // PCI-E
+ _R("RTL8101e", RTL_GIGA_MAC_VER_13, 0xff7e1880), // PCI-E 8139
+ _R("RTL8100e", RTL_GIGA_MAC_VER_14, 0xff7e1880), // PCI-E 8139
+ _R("RTL8100e", RTL_GIGA_MAC_VER_15, 0xff7e1880), // PCI-E 8139
+ _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_17, 0xff7e1880), // PCI-E
+ _R("RTL8101e", RTL_GIGA_MAC_VER_16, 0xff7e1880), // PCI-E
+ _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_18, 0xff7e1880), // PCI-E
+ _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_19, 0xff7e1880), // PCI-E
+ _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_20, 0xff7e1880), // PCI-E
+ _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_21, 0xff7e1880), // PCI-E
+ _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_22, 0xff7e1880), // PCI-E
+ _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_23, 0xff7e1880), // PCI-E
+ _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_24, 0xff7e1880), // PCI-E
+ _R("RTL8168d/8111d", RTL_GIGA_MAC_VER_25, 0xff7e1880) // PCI-E
+};
+#undef _R
+
+enum cfg_version {
+ RTL_CFG_0 = 0x00,
+ RTL_CFG_1,
+ RTL_CFG_2
+};
+
+#if 0
+/** Device Table from Linux Driver **/
+static struct pci_device_id rtl8169_pci_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8129), 0, 0, RTL_CFG_0 },
+ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8136), 0, 0, RTL_CFG_2 },
+ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8167), 0, 0, RTL_CFG_0 },
+ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168), 0, 0, RTL_CFG_1 },
+ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169), 0, 0, RTL_CFG_0 },
+ { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4300), 0, 0, RTL_CFG_0 },
+ { PCI_DEVICE(PCI_VENDOR_ID_AT, 0xc107), 0, 0, RTL_CFG_0 },
+ { PCI_DEVICE(0x16ec, 0x0116), 0, 0, RTL_CFG_0 },
+ { PCI_VENDOR_ID_LINKSYS, 0x1032,
+ PCI_ANY_ID, 0x0024, 0, 0, RTL_CFG_0 },
+ { 0x0001, 0x8168,
+ PCI_ANY_ID, 0x2410, 0, 0, RTL_CFG_2 },
+ {0,},
+};
+#endif
+
+enum rtl_registers {
+ MAC0 = 0, /* Ethernet hardware address. */
+ MAC4 = 4,
+ MAR0 = 8, /* Multicast filter. */
+ CounterAddrLow = 0x10,
+ CounterAddrHigh = 0x14,
+ TxDescStartAddrLow = 0x20,
+ TxDescStartAddrHigh = 0x24,
+ TxHDescStartAddrLow = 0x28,
+ TxHDescStartAddrHigh = 0x2c,
+ FLASH = 0x30,
+ ERSR = 0x36,
+ ChipCmd = 0x37,
+ TxPoll = 0x38,
+ IntrMask = 0x3c,
+ IntrStatus = 0x3e,
+ TxConfig = 0x40,
+ RxConfig = 0x44,
+ RxMissed = 0x4c,
+ Cfg9346 = 0x50,
+ Config0 = 0x51,
+ Config1 = 0x52,
+ Config2 = 0x53,
+ Config3 = 0x54,
+ Config4 = 0x55,
+ Config5 = 0x56,
+ MultiIntr = 0x5c,
+ PHYAR = 0x60,
+ PHYstatus = 0x6c,
+ RxMaxSize = 0xda,
+ CPlusCmd = 0xe0,
+ IntrMitigate = 0xe2,
+ RxDescAddrLow = 0xe4,
+ RxDescAddrHigh = 0xe8,
+ EarlyTxThres = 0xec,
+ FuncEvent = 0xf0,
+ FuncEventMask = 0xf4,
+ FuncPresetState = 0xf8,
+ FuncForceEvent = 0xfc,
+};
+
+enum rtl8110_registers {
+ TBICSR = 0x64,
+ TBI_ANAR = 0x68,
+ TBI_LPAR = 0x6a,
+};
+
+enum rtl8168_8101_registers {
+ CSIDR = 0x64,
+ CSIAR = 0x68,
+#define CSIAR_FLAG 0x80000000
+#define CSIAR_WRITE_CMD 0x80000000
+#define CSIAR_BYTE_ENABLE 0x0f
+#define CSIAR_BYTE_ENABLE_SHIFT 12
+#define CSIAR_ADDR_MASK 0x0fff
+
+ EPHYAR = 0x80,
+#define EPHYAR_FLAG 0x80000000
+#define EPHYAR_WRITE_CMD 0x80000000
+#define EPHYAR_REG_MASK 0x1f
+#define EPHYAR_REG_SHIFT 16
+#define EPHYAR_DATA_MASK 0xffff
+ DBG_REG = 0xd1,
+#define FIX_NAK_1 (1 << 4)
+#define FIX_NAK_2 (1 << 3)
+};
+
+enum rtl_register_content {
+ /* InterruptStatusBits */
+ SYSErr = 0x8000,
+ PCSTimeout = 0x4000,
+ SWInt = 0x0100,
+ TxDescUnavail = 0x0080,
+ RxFIFOOver = 0x0040,
+ LinkChg = 0x0020,
+ RxOverflow = 0x0010,
+ TxErr = 0x0008,
+ TxOK = 0x0004,
+ RxErr = 0x0002,
+ RxOK = 0x0001,
+
+ /* RxStatusDesc */
+ RxFOVF = (1 << 23),
+ RxRWT = (1 << 22),
+ RxRES = (1 << 21),
+ RxRUNT = (1 << 20),
+ RxCRC = (1 << 19),
+
+ /* ChipCmdBits */
+ CmdReset = 0x10,
+ CmdRxEnb = 0x08,
+ CmdTxEnb = 0x04,
+ RxBufEmpty = 0x01,
+
+ /* TXPoll register p.5 */
+ HPQ = 0x80, /* Poll cmd on the high prio queue */
+ NPQ = 0x40, /* Poll cmd on the low prio queue */
+ FSWInt = 0x01, /* Forced software interrupt */
+
+ /* Cfg9346Bits */
+ Cfg9346_Lock = 0x00,
+ Cfg9346_Unlock = 0xc0,
+
+ /* rx_mode_bits */
+ AcceptErr = 0x20,
+ AcceptRunt = 0x10,
+ AcceptBroadcast = 0x08,
+ AcceptMulticast = 0x04,
+ AcceptMyPhys = 0x02,
+ AcceptAllPhys = 0x01,
+
+ /* RxConfigBits */
+ RxCfgFIFOShift = 13,
+ RxCfgDMAShift = 8,
+
+ /* TxConfigBits */
+ TxInterFrameGapShift = 24,
+ TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */
+
+ /* Config1 register p.24 */
+ LEDS1 = (1 << 7),
+ LEDS0 = (1 << 6),
+ MSIEnable = (1 << 5), /* Enable Message Signaled Interrupt */
+ Speed_down = (1 << 4),
+ MEMMAP = (1 << 3),
+ IOMAP = (1 << 2),
+ VPD = (1 << 1),
+ PMEnable = (1 << 0), /* Power Management Enable */
+
+ /* Config2 register p. 25 */
+ PCI_Clock_66MHz = 0x01,
+ PCI_Clock_33MHz = 0x00,
+
+ /* Config3 register p.25 */
+ MagicPacket = (1 << 5), /* Wake up when receives a Magic Packet */
+ LinkUp = (1 << 4), /* Wake up when the cable connection is re-established */
+ Beacon_en = (1 << 0), /* 8168 only. Reserved in the 8168b */
+
+ /* Config5 register p.27 */
+ BWF = (1 << 6), /* Accept Broadcast wakeup frame */
+ MWF = (1 << 5), /* Accept Multicast wakeup frame */
+ UWF = (1 << 4), /* Accept Unicast wakeup frame */
+ LanWake = (1 << 1), /* LanWake enable/disable */
+ PMEStatus = (1 << 0), /* PME status can be reset by PCI RST# */
+
+ /* TBICSR p.28 */
+ TBIReset = 0x80000000,
+ TBILoopback = 0x40000000,
+ TBINwEnable = 0x20000000,
+ TBINwRestart = 0x10000000,
+ TBILinkOk = 0x02000000,
+ TBINwComplete = 0x01000000,
+
+ /* CPlusCmd p.31 */
+ EnableBist = (1 << 15), // 8168 8101
+ Mac_dbgo_oe = (1 << 14), // 8168 8101
+ Normal_mode = (1 << 13), // unused
+ Force_half_dup = (1 << 12), // 8168 8101
+ Force_rxflow_en = (1 << 11), // 8168 8101
+ Force_txflow_en = (1 << 10), // 8168 8101
+ Cxpl_dbg_sel = (1 << 9), // 8168 8101
+ ASF = (1 << 8), // 8168 8101
+ PktCntrDisable = (1 << 7), // 8168 8101
+ Mac_dbgo_sel = 0x001c, // 8168
+ RxVlan = (1 << 6),
+ RxChkSum = (1 << 5),
+ PCIDAC = (1 << 4),
+ PCIMulRW = (1 << 3),
+ INTT_0 = 0x0000, // 8168
+ INTT_1 = 0x0001, // 8168
+ INTT_2 = 0x0002, // 8168
+ INTT_3 = 0x0003, // 8168
+
+ /* rtl8169_PHYstatus */
+ TBI_Enable = 0x80,
+ TxFlowCtrl = 0x40,
+ RxFlowCtrl = 0x20,
+ _1000bpsF = 0x10,
+ _100bps = 0x08,
+ _10bps = 0x04,
+ LinkStatus = 0x02,
+ FullDup = 0x01,
+
+ /* _TBICSRBit */
+ TBILinkOK = 0x02000000,
+
+ /* DumpCounterCommand */
+ CounterDump = 0x8,
+};
+
+enum desc_status_bit {
+ DescOwn = (1 << 31), /* Descriptor is owned by NIC */
+ RingEnd = (1 << 30), /* End of descriptor ring */
+ FirstFrag = (1 << 29), /* First segment of a packet */
+ LastFrag = (1 << 28), /* Final segment of a packet */
+
+ /* Tx private */
+ LargeSend = (1 << 27), /* TCP Large Send Offload (TSO) */
+ MSSShift = 16, /* MSS value position */
+ MSSMask = 0xfff, /* MSS value + LargeSend bit: 12 bits */
+ IPCS = (1 << 18), /* Calculate IP checksum */
+ UDPCS = (1 << 17), /* Calculate UDP/IP checksum */
+ TCPCS = (1 << 16), /* Calculate TCP/IP checksum */
+ TxVlanTag = (1 << 17), /* Add VLAN tag */
+
+ /* Rx private */
+ PID1 = (1 << 18), /* Protocol ID bit 1/2 */
+ PID0 = (1 << 17), /* Protocol ID bit 2/2 */
+
+#define RxProtoUDP (PID1)
+#define RxProtoTCP (PID0)
+#define RxProtoIP (PID1 | PID0)
+#define RxProtoMask RxProtoIP
+
+ IPFail = (1 << 16), /* IP checksum failed */
+ UDPFail = (1 << 15), /* UDP/IP checksum failed */
+ TCPFail = (1 << 14), /* TCP/IP checksum failed */
+ RxVlanTag = (1 << 16), /* VLAN tag available */
+};
+
+#define RsvdMask 0x3fffc000
+
+struct TxDesc {
+ volatile uint32_t opts1;
+ volatile uint32_t opts2;
+ volatile uint32_t addr_lo;
+ volatile uint32_t addr_hi;
+};
+
+struct RxDesc {
+ volatile uint32_t opts1;
+ volatile uint32_t opts2;
+ volatile uint32_t addr_lo;
+ volatile uint32_t addr_hi;
+};
+
+enum features {
+ RTL_FEATURE_WOL = (1 << 0),
+ RTL_FEATURE_MSI = (1 << 1),
+ RTL_FEATURE_GMII = (1 << 2),
+};
+
+static void rtl_hw_start_8169(struct net_device *);
+static void rtl_hw_start_8168(struct net_device *);
+static void rtl_hw_start_8101(struct net_device *);
+
+struct rtl8169_private {
+
+ struct pci_device *pci_dev;
+ struct net_device *netdev;
+ uint8_t *hw_addr;
+ void *mmio_addr;
+ uint32_t irqno;
+
+ int chipset;
+ int mac_version;
+ int cfg_index;
+ u16 intr_event;
+
+ struct io_buffer *tx_iobuf[NUM_TX_DESC];
+ struct io_buffer *rx_iobuf[NUM_RX_DESC];
+
+ struct TxDesc *tx_base;
+ struct RxDesc *rx_base;
+
+ uint32_t tx_curr;
+ uint32_t rx_curr;
+
+ uint32_t tx_tail;
+
+ uint32_t tx_fill_ctr;
+
+ u16 cp_cmd;
+
+ int phy_auto_nego_reg;
+ int phy_1000_ctrl_reg;
+
+ int ( *set_speed ) (struct net_device *, u8 autoneg, u16 speed, u8 duplex );
+ void ( *phy_reset_enable ) ( void *ioaddr );
+ void ( *hw_start ) ( struct net_device * );
+ unsigned int ( *phy_reset_pending ) ( void *ioaddr );
+ unsigned int ( *link_ok ) ( void *ioaddr );
+
+ int pcie_cap;
+
+ unsigned features;
+
+};
+
+static const unsigned int rtl8169_rx_config =
+ (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);
+
+#endif /* _R8169_H_ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * c-indent-level: 8
+ * tab-width: 8
+ * End:
+ */
diff --git a/gpxe/src/drivers/net/rtl8139.c b/gpxe/src/drivers/net/rtl8139.c
index 509047a9..2dff324c 100644
--- a/gpxe/src/drivers/net/rtl8139.c
+++ b/gpxe/src/drivers/net/rtl8139.c
@@ -69,7 +69,8 @@
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
-#include <io.h>
+#include <string.h>
+#include <gpxe/io.h>
#include <errno.h>
#include <unistd.h>
#include <byteswap.h>
diff --git a/gpxe/src/drivers/net/sis900.c b/gpxe/src/drivers/net/sis900.c
index 58526506..008b9cf7 100644
--- a/gpxe/src/drivers/net/sis900.c
+++ b/gpxe/src/drivers/net/sis900.c
@@ -695,7 +695,7 @@ sis900_init_rxfilter(struct nic *nic)
outl(w, ioaddr + rfdr);
if (sis900_debug > 0)
- printf("sis900_init_rxfilter: Receive Filter Addrss[%d]=%lX\n",
+ printf("sis900_init_rxfilter: Receive Filter Addrss[%d]=%X\n",
i, inl(ioaddr + rfdr));
}
@@ -724,7 +724,7 @@ sis900_init_txd(struct nic *nic __unused)
/* load Transmit Descriptor Register */
outl(virt_to_bus(&txd), ioaddr + txdp);
if (sis900_debug > 0)
- printf("sis900_init_txd: TX descriptor register loaded with: %lX\n",
+ printf("sis900_init_txd: TX descriptor register loaded with: %X\n",
inl(ioaddr + txdp));
}
@@ -760,7 +760,7 @@ sis900_init_rxd(struct nic *nic __unused)
outl(virt_to_bus(&rxd[0]), ioaddr + rxdp);
if (sis900_debug > 0)
- printf("sis900_init_rxd: RX descriptor register loaded with: %lX\n",
+ printf("sis900_init_rxd: RX descriptor register loaded with: %X\n",
inl(ioaddr + rxdp));
}
@@ -1114,7 +1114,7 @@ sis900_transmit(struct nic *nic,
/* load Transmit Descriptor Register */
outl(virt_to_bus(&txd), ioaddr + txdp);
if (sis900_debug > 1)
- printf("sis900_transmit: TX descriptor register loaded with: %lX\n",
+ printf("sis900_transmit: TX descriptor register loaded with: %X\n",
inl(ioaddr + txdp));
memcpy(txb, d, ETH_ALEN);
diff --git a/gpxe/src/drivers/net/sundance.c b/gpxe/src/drivers/net/sundance.c
index 3b6f5a88..eb750fb1 100644
--- a/gpxe/src/drivers/net/sundance.c
+++ b/gpxe/src/drivers/net/sundance.c
@@ -689,9 +689,9 @@ static int sundance_probe ( struct nic *nic, struct pci_device *pci ) {
}
/* Reset the chip to erase previous misconfiguration */
- DBG ( "ASIC Control is %#lx\n", inl(BASE + ASICCtrl) );
+ DBG ( "ASIC Control is %#x\n", inl(BASE + ASICCtrl) );
outw(0x007f, BASE + ASICCtrl + 2);
- DBG ( "ASIC Control is now %#lx.\n", inl(BASE + ASICCtrl) );
+ DBG ( "ASIC Control is now %#x.\n", inl(BASE + ASICCtrl) );
sundance_reset(nic);
if (sdc->an_enable) {
@@ -869,6 +869,7 @@ static void set_rx_mode(struct nic *nic __unused)
static struct pci_device_id sundance_nics[] = {
PCI_ROM(0x13f0, 0x0201, "sundance", "ST201 Sundance 'Alta' based Adaptor"),
PCI_ROM(0x1186, 0x1002, "dfe530txs", "D-Link DFE530TXS (Sundance ST201 Alta)"),
+ PCI_ROM(0x13f0, 0x0200, "ip100a", "IC+ IP100A"),
};
PCI_DRIVER ( sundance_driver, sundance_nics, PCI_NO_CLASS );
diff --git a/gpxe/src/drivers/net/tg3.c b/gpxe/src/drivers/net/tg3.c
index bda832e8..14093bb2 100644
--- a/gpxe/src/drivers/net/tg3.c
+++ b/gpxe/src/drivers/net/tg3.c
@@ -1460,7 +1460,7 @@ static int tg3_stop_block(struct tg3 *tp, unsigned long ofs, uint32_t enable_bit
}
if (i == MAX_WAIT_CNT) {
- printf( "tg3_stop_block timed out, ofs=%#lx enable_bit=%3lx\n",
+ printf( "tg3_stop_block timed out, ofs=%#lx enable_bit=%3x\n",
ofs, enable_bit );
return -ENODEV;
}
@@ -1665,7 +1665,7 @@ static int tg3_restart_fw(struct tg3 *tp, uint32_t state)
if (i >= 100000 &&
!(tp->tg3_flags2 & TG3_FLG2_SUN_5704) &&
!(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)) {
- printf ( "Firmware will not restart magic=%#lx\n",
+ printf ( "Firmware will not restart magic=%#x\n",
val );
return -ENODEV;
}
@@ -3399,6 +3399,7 @@ PCI_ROM(0x14e4, 0x1677, "tg3-5751", "Broadcom Tigon 3 5751"),
PCI_ROM(0x14e4, 0x167a, "tg3-5754", "Broadcom Tigon 3 5754"),
PCI_ROM(0x14e4, 0x1693, "tg3-5787", "Broadcom Tigon 3 5787"),
PCI_ROM(0x14e4, 0x1696, "tg3-5782", "Broadcom Tigon 3 5782"),
+PCI_ROM(0x14e4, 0x169a, "tg3-5786", "Broadcom Tigon 3 5786"),
PCI_ROM(0x14e4, 0x169c, "tg3-5788", "Broadcom Tigon 3 5788"),
PCI_ROM(0x14e4, 0x169d, "tg3-5789", "Broadcom Tigon 3 5789"),
PCI_ROM(0x14e4, 0x16a6, "tg3-5702X", "Broadcom Tigon 3 5702X"),
diff --git a/gpxe/src/drivers/net/tulip.c b/gpxe/src/drivers/net/tulip.c
index 53cfb85f..afd7d45b 100644
--- a/gpxe/src/drivers/net/tulip.c
+++ b/gpxe/src/drivers/net/tulip.c
@@ -1201,7 +1201,7 @@ static void tulip_disable ( struct nic *nic ) {
outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6);
/* Clear the missed-packet counter. */
- (volatile unsigned long)inl(ioaddr + CSR8);
+ inl(ioaddr + CSR8);
}
/*********************************************************************/
@@ -1265,7 +1265,7 @@ static int tulip_probe ( struct nic *nic, struct pci_device *pci ) {
outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6);
/* Clear the missed-packet counter. */
- (volatile unsigned long)inl(ioaddr + CSR8);
+ inl(ioaddr + CSR8);
printf("\n"); /* so we start on a fresh line */
#ifdef TULIP_DEBUG_WHERE
diff --git a/gpxe/src/drivers/net/via-rhine.c b/gpxe/src/drivers/net/via-rhine.c
index fb43a924..d9880c32 100644
--- a/gpxe/src/drivers/net/via-rhine.c
+++ b/gpxe/src/drivers/net/via-rhine.c
@@ -784,7 +784,7 @@ ReadMII (int byMIIIndex, int ioaddr)
char byMIIAdrbak;
char byMIICRbak;
char byMIItemp;
- tick_t ct;
+ unsigned long ct;
byMIIAdrbak = inb (byMIIAD);
byMIICRbak = inb (byMIICR);
@@ -800,7 +800,7 @@ ReadMII (int byMIIIndex, int ioaddr)
byMIItemp = byMIItemp & 0x40;
ct = currticks();
- while (byMIItemp != 0 && ct + 2*USECS_IN_MSEC < currticks())
+ while (byMIItemp != 0 && ct + 2*1000 < currticks())
{
byMIItemp = inb (byMIICR);
byMIItemp = byMIItemp & 0x40;
@@ -825,7 +825,7 @@ WriteMII (char byMIISetByte, char byMIISetBit, char byMIIOP, int ioaddr)
char byMIIAdrbak;
char byMIICRbak;
char byMIItemp;
- tick_t ct;
+ unsigned long ct;
byMIIAdrbak = inb (byMIIAD);
@@ -842,7 +842,7 @@ WriteMII (char byMIISetByte, char byMIISetBit, char byMIIOP, int ioaddr)
byMIItemp = byMIItemp & 0x40;
ct = currticks();
- while (byMIItemp != 0 && ct + 2*USECS_IN_MSEC < currticks())
+ while (byMIItemp != 0 && ct + 2*1000 < currticks())
{
byMIItemp = inb (byMIICR);
byMIItemp = byMIItemp & 0x40;
@@ -872,7 +872,7 @@ WriteMII (char byMIISetByte, char byMIISetBit, char byMIIOP, int ioaddr)
byMIItemp = byMIItemp & 0x20;
ct = currticks();
- while (byMIItemp != 0 && ct + 2*USECS_IN_MSEC < currticks())
+ while (byMIItemp != 0 && ct + 2*1000 < currticks())
{
byMIItemp = inb (byMIICR);
byMIItemp = byMIItemp & 0x20;
@@ -1008,7 +1008,7 @@ rhine_probe1 (struct nic *nic, struct pci_device *pci, int ioaddr, int chip_id,
unsigned char mode3_reg;
if (rhine_debug > 0 && did_version++ == 0)
- printf (version);
+ printf ("%s",version);
// get revision id.
pci_read_config_byte(pci, PCI_REVISION, &revision_id);
@@ -1194,40 +1194,44 @@ rhine_reset (struct nic *nic)
int ioaddr = tp->ioaddr;
int i, j;
int FDXFlag, CRbak;
- int rx_ring_tmp, rx_ring_tmp1;
- int tx_ring_tmp, tx_ring_tmp1;
- int rx_bufs_tmp, rx_bufs_tmp1;
- int tx_bufs_tmp, tx_bufs_tmp1;
+ void *rx_ring_tmp;
+ void *tx_ring_tmp;
+ void *rx_bufs_tmp;
+ void *tx_bufs_tmp;
+ unsigned long rx_ring_tmp1;
+ unsigned long tx_ring_tmp1;
+ unsigned long rx_bufs_tmp1;
+ unsigned long tx_bufs_tmp1;
/* printf ("rhine_reset\n"); */
/* Soft reset the chip. */
/*outb(CmdReset, ioaddr + ChipCmd); */
- tx_bufs_tmp = (int) rhine_buffers.txbuf;
- tx_ring_tmp = (int) rhine_buffers.txdesc;
- rx_bufs_tmp = (int) rhine_buffers.rxbuf;
- rx_ring_tmp = (int) rhine_buffers.rxdesc;
+ tx_bufs_tmp = rhine_buffers.txbuf;
+ tx_ring_tmp = rhine_buffers.txdesc;
+ rx_bufs_tmp = rhine_buffers.rxbuf;
+ rx_ring_tmp = rhine_buffers.rxdesc;
/* tune RD TD 32 byte alignment */
- rx_ring_tmp1 = (int) virt_to_bus ((char *) rx_ring_tmp);
+ rx_ring_tmp1 = virt_to_bus ( rx_ring_tmp );
j = (rx_ring_tmp1 + 32) & (~0x1f);
/* printf ("txring[%d]", j); */
tp->rx_ring = (struct rhine_rx_desc *) bus_to_virt (j);
- tx_ring_tmp1 = (int) virt_to_bus ((char *) tx_ring_tmp);
+ tx_ring_tmp1 = virt_to_bus ( tx_ring_tmp );
j = (tx_ring_tmp1 + 32) & (~0x1f);
tp->tx_ring = (struct rhine_tx_desc *) bus_to_virt (j);
/* printf ("rxring[%X]", j); */
- tx_bufs_tmp1 = (int) virt_to_bus ((char *) tx_bufs_tmp);
+ tx_bufs_tmp1 = virt_to_bus ( tx_bufs_tmp );
j = (int) (tx_bufs_tmp1 + 32) & (~0x1f);
- tx_bufs_tmp = (int) bus_to_virt (j);
+ tx_bufs_tmp = bus_to_virt (j);
/* printf ("txb[%X]", j); */
- rx_bufs_tmp1 = (int) virt_to_bus ((char *) rx_bufs_tmp);
+ rx_bufs_tmp1 = virt_to_bus ( rx_bufs_tmp );
j = (int) (rx_bufs_tmp1 + 32) & (~0x1f);
- rx_bufs_tmp = (int) bus_to_virt (j);
+ rx_bufs_tmp = bus_to_virt (j);
/* printf ("rxb[%X][%X]", rx_bufs_tmp1, j); */
for (i = 0; i < RX_RING_SIZE; i++)
@@ -1346,7 +1350,7 @@ rhine_transmit (struct nic *nic,
unsigned char CR1bak;
unsigned char CR0bak;
unsigned int nstype;
- tick_t ct;
+ unsigned long ct;
/*printf ("rhine_transmit\n"); */
@@ -1390,7 +1394,7 @@ rhine_transmit (struct nic *nic,
ct = currticks();
/* Wait until transmit is finished or timeout*/
while((tp->tx_ring[entry].tx_status.bits.own_bit !=0) &&
- ct + 10*USECS_IN_MSEC < currticks())
+ ct + 10*1000 < currticks())
;
if(tp->tx_ring[entry].tx_status.bits.terr == 0)
diff --git a/gpxe/src/drivers/net/via-velocity.c b/gpxe/src/drivers/net/via-velocity.c
index 428f609c..4473ed15 100644
--- a/gpxe/src/drivers/net/via-velocity.c
+++ b/gpxe/src/drivers/net/via-velocity.c
@@ -550,7 +550,7 @@ static void velocity_transmit(struct nic *nic, const char *dest, /* Destination
vptr->td_rings[entry].tdesc0.pktsize = pktlen;
vptr->td_rings[entry].td_buf[0].pa_low = virt_to_bus(ptxb);
vptr->td_rings[entry].td_buf[0].pa_high &=
- cpu_to_le32(0xffff0000L);
+ cpu_to_le32(0xffff0000UL);
vptr->td_rings[entry].td_buf[0].bufsize =
vptr->td_rings[entry].tdesc0.pktsize;
vptr->td_rings[entry].tdesc1.CMDZ = 2;
@@ -1234,7 +1234,7 @@ static int velocity_open(struct nic *nic, struct pci_device *pci __unused)
/* Tx Descriptor needs 64 bytes alignment; */
TxPhyAddr = virt_to_bus(vptr->TxDescArrays);
- printf("Unaligned Address : %lX\n", TxPhyAddr);
+ printf("Unaligned Address : %X\n", TxPhyAddr);
diff = 64 - (TxPhyAddr - ((TxPhyAddr >> 6) << 6));
TxPhyAddr += diff;
vptr->td_rings = (struct tx_desc *) (vptr->TxDescArrays + diff);
diff --git a/gpxe/src/drivers/net/virtio-net.c b/gpxe/src/drivers/net/virtio-net.c
index 4ec154df..f0afd3f6 100644
--- a/gpxe/src/drivers/net/virtio-net.c
+++ b/gpxe/src/drivers/net/virtio-net.c
@@ -21,8 +21,8 @@
#include "etherboot.h"
#include "nic.h"
-#include "virtio-ring.h"
-#include "virtio-pci.h"
+#include "gpxe/virtio-ring.h"
+#include "gpxe/virtio-pci.h"
#include "virtio-net.h"
#define BUG() do { \
@@ -45,8 +45,6 @@ struct eth_frame {
unsigned char data[ETH_FRAME_LEN];
};
-typedef unsigned char virtio_queue_t[PAGE_MASK + vring_size(MAX_QUEUE_NUM)];
-
/* TX: virtio header and eth buffer */
static struct virtio_net_hdr tx_virtio_hdr;
@@ -66,209 +64,7 @@ enum {
QUEUE_NB
};
-static virtio_queue_t queue[QUEUE_NB];
-static struct vring vring[QUEUE_NB];
-static u16 free_head[QUEUE_NB];
-static u16 last_used_idx[QUEUE_NB];
-static u16 vdata[QUEUE_NB][MAX_QUEUE_NUM];
-
-/*
- * Virtio PCI interface
- *
- */
-
-static int vp_find_vq(struct nic *nic, int queue_index)
-{
- struct vring * vr = &vring[queue_index];
- u16 num;
-
- /* select the queue */
-
- outw(queue_index, nic->ioaddr + VIRTIO_PCI_QUEUE_SEL);
-
- /* check if the queue is available */
-
- num = inw(nic->ioaddr + VIRTIO_PCI_QUEUE_NUM);
- if (!num) {
- printf("ERROR: queue size is 0\n");
- return -1;
- }
-
- if (num > MAX_QUEUE_NUM) {
- printf("ERROR: queue size %d > %d\n", num, MAX_QUEUE_NUM);
- return -1;
- }
-
- /* check if the queue is already active */
-
- if (inl(nic->ioaddr + VIRTIO_PCI_QUEUE_PFN)) {
- printf("ERROR: queue already active\n");
- return -1;
- }
-
- /* initialize the queue */
-
- vring_init(vr, num, (unsigned char*)&queue[queue_index]);
-
- /* activate the queue
- *
- * NOTE: vr->desc is initialized by vring_init()
- */
-
- outl((unsigned long)virt_to_phys(vr->desc) >> PAGE_SHIFT,
- nic->ioaddr + VIRTIO_PCI_QUEUE_PFN);
-
- return num;
-}
-
-/*
- * Virtual ring management
- *
- */
-
-static void vring_enable_cb(int queue_index)
-{
- vring[queue_index].avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;
-}
-
-static void vring_disable_cb(int queue_index)
-{
- vring[queue_index].avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
-}
-
-/*
- * vring_free
- *
- * put at the begin of the free list the current desc[head]
- */
-
-static void vring_detach(int queue_index, unsigned int head)
-{
- struct vring *vr = &vring[queue_index];
- unsigned int i;
-
- /* find end of given descriptor */
-
- i = head;
- while (vr->desc[i].flags & VRING_DESC_F_NEXT)
- i = vr->desc[i].next;
-
- /* link it with free list and point to it */
-
- vr->desc[i].next = free_head[queue_index];
- wmb();
- free_head[queue_index] = head;
-}
-
-/*
- * vring_more_used
- *
- * is there some used buffers ?
- *
- */
-
-static inline int vring_more_used(int queue_index)
-{
- wmb();
- return last_used_idx[queue_index] != vring[queue_index].used->idx;
-}
-
-/*
- * vring_get_buf
- *
- * get a buffer from the used list
- *
- */
-
-static int vring_get_buf(int queue_index, unsigned int *len)
-{
- struct vring *vr = &vring[queue_index];
- struct vring_used_elem *elem;
- u32 id;
- int ret;
-
- elem = &vr->used->ring[last_used_idx[queue_index] % vr->num];
- wmb();
- id = elem->id;
- if (len != NULL)
- *len = elem->len;
-
- ret = vdata[queue_index][id];
-
- vring_detach(queue_index, id);
-
- last_used_idx[queue_index]++;
-
- return ret;
-}
-
-static void vring_add_buf(int queue_index, int index, int num_added)
-{
- struct vring *vr = &vring[queue_index];
- int i, avail, head;
-
- BUG_ON(queue_index >= QUEUE_NB);
-
- head = free_head[queue_index];
- i = head;
-
- if (queue_index == TX_INDEX) {
-
- BUG_ON(index != 0);
-
- /* add header into vring */
-
- vr->desc[i].flags = VRING_DESC_F_NEXT;
- vr->desc[i].addr = (u64)virt_to_phys(&tx_virtio_hdr);
- vr->desc[i].len = sizeof(struct virtio_net_hdr);
- i = vr->desc[i].next;
-
- /* add frame buffer into vring */
-
- vr->desc[i].flags = 0;
- vr->desc[i].addr = (u64)virt_to_phys(&tx_eth_frame);
- vr->desc[i].len = ETH_FRAME_LEN;
- i = vr->desc[i].next;
-
- } else if (queue_index == RX_INDEX) {
-
- BUG_ON(index >= RX_BUF_NB);
-
- /* add header into vring */
-
- vr->desc[i].flags = VRING_DESC_F_NEXT|VRING_DESC_F_WRITE;
- vr->desc[i].addr = (u64)virt_to_phys(&rx_hdr[index]);
- vr->desc[i].len = sizeof(struct virtio_net_hdr);
- i = vr->desc[i].next;
-
- /* add frame buffer into vring */
-
- vr->desc[i].flags = VRING_DESC_F_WRITE;
- vr->desc[i].addr = (u64)virt_to_phys(&rx_buffer[index]);
- vr->desc[i].len = ETH_FRAME_LEN;
- i = vr->desc[i].next;
- }
-
- free_head[queue_index] = i;
-
- vdata[queue_index][head] = index;
-
- avail = (vr->avail->idx + num_added) % vr->num;
- vr->avail->ring[avail] = head;
- wmb();
-}
-
-static void vring_kick(struct nic *nic, int queue_index, int num_added)
-{
- struct vring *vr = &vring[queue_index];
-
- wmb();
- vr->avail->idx += num_added;
-
- mb();
- if (!(vr->used->flags & VRING_USED_F_NO_NOTIFY))
- vp_notify(nic, queue_index);
-}
+static struct vring_virtqueue virtqueue[QUEUE_NB];
/*
* virtnet_disable
@@ -282,10 +78,10 @@ static void virtnet_disable(struct nic *nic)
int i;
for (i = 0; i < QUEUE_NB; i++) {
- vring_disable_cb(i);
- vp_del_vq(nic, i);
+ vring_disable_cb(&virtqueue[i]);
+ vp_del_vq(nic->ioaddr, i);
}
- vp_reset(nic);
+ vp_reset(nic->ioaddr);
}
/*
@@ -304,27 +100,33 @@ static int virtnet_poll(struct nic *nic, int retrieve)
unsigned int len;
u16 token;
struct virtio_net_hdr *hdr;
+ struct vring_list list[2];
- if (!vring_more_used(RX_INDEX))
+ if (!vring_more_used(&virtqueue[RX_INDEX]))
return 0;
if (!retrieve)
return 1;
- token = vring_get_buf(RX_INDEX, &len);
+ token = vring_get_buf(&virtqueue[RX_INDEX], &len);
BUG_ON(len > sizeof(struct virtio_net_hdr) + ETH_FRAME_LEN);
hdr = &rx_hdr[token]; /* FIXME: check flags */
len -= sizeof(struct virtio_net_hdr);
- nic->packetlen = len;
+ nic->packetlen = len;
memcpy(nic->packet, (char *)rx_buffer[token], nic->packetlen);
/* add buffer to desc */
- vring_add_buf(RX_INDEX, token, 0);
- vring_kick(nic, RX_INDEX, 1);
+ list[0].addr = (char*)&rx_hdr[token];
+ list[0].length = sizeof(struct virtio_net_hdr);
+ list[1].addr = (char*)&rx_buffer[token];
+ list[1].length = ETH_FRAME_LEN;
+
+ vring_add_buf(&virtqueue[RX_INDEX], list, 0, 2, token, 0);
+ vring_kick(nic->ioaddr, &virtqueue[RX_INDEX], 1);
return 1;
}
@@ -340,6 +142,8 @@ static int virtnet_poll(struct nic *nic, int retrieve)
static void virtnet_transmit(struct nic *nic, const char *destaddr,
unsigned int type, unsigned int len, const char *data)
{
+ struct vring_list list[2];
+
/*
* from http://www.etherboot.org/wiki/dev/devmanual :
* "You do not need more than one transmit buffer."
@@ -363,7 +167,14 @@ static void virtnet_transmit(struct nic *nic, const char *destaddr,
tx_eth_frame.hdr.type = htons(type);
memcpy(tx_eth_frame.data, data, len);
- vring_add_buf(TX_INDEX, 0, 0);
+ list[0].addr = (char*)&tx_virtio_hdr;
+ list[0].length = sizeof(struct virtio_net_hdr);
+ list[1].addr = (char*)&tx_eth_frame;
+ list[1].length = ETH_FRAME_LEN;
+
+ vring_add_buf(&virtqueue[TX_INDEX], list, 2, 0, 0, 0);
+
+ vring_kick(nic->ioaddr, &virtqueue[TX_INDEX], 1);
/*
* http://www.etherboot.org/wiki/dev/devmanual
@@ -372,28 +183,26 @@ static void virtnet_transmit(struct nic *nic, const char *destaddr,
* before returning from this routine"
*/
- while (vring_more_used(TX_INDEX)) {
+ while (!vring_more_used(&virtqueue[TX_INDEX])) {
mb();
udelay(10);
}
- vring_kick(nic, TX_INDEX, 1);
-
/* free desc */
- (void)vring_get_buf(TX_INDEX, NULL);
+ (void)vring_get_buf(&virtqueue[TX_INDEX], NULL);
}
static void virtnet_irq(struct nic *nic __unused, irq_action_t action)
{
switch ( action ) {
case DISABLE :
- vring_disable_cb(RX_INDEX);
- vring_disable_cb(TX_INDEX);
+ vring_disable_cb(&virtqueue[RX_INDEX]);
+ vring_disable_cb(&virtqueue[TX_INDEX]);
break;
case ENABLE :
- vring_enable_cb(RX_INDEX);
- vring_enable_cb(TX_INDEX);
+ vring_enable_cb(&virtqueue[RX_INDEX]);
+ vring_enable_cb(&virtqueue[TX_INDEX]);
break;
case FORCE :
break;
@@ -403,13 +212,19 @@ static void virtnet_irq(struct nic *nic __unused, irq_action_t action)
static void provide_buffers(struct nic *nic)
{
int i;
-
- for (i = 0; i < RX_BUF_NB; i++)
- vring_add_buf(RX_INDEX, i, i);
+ struct vring_list list[2];
+
+ for (i = 0; i < RX_BUF_NB; i++) {
+ list[0].addr = (char*)&rx_hdr[i];
+ list[0].length = sizeof(struct virtio_net_hdr);
+ list[1].addr = (char*)&rx_buffer[i];
+ list[1].length = ETH_FRAME_LEN;
+ vring_add_buf(&virtqueue[RX_INDEX], list, 0, 2, i, i);
+ }
/* nofify */
- vring_kick(nic, RX_INDEX, i);
+ vring_kick(nic->ioaddr, &virtqueue[RX_INDEX], i);
}
static struct nic_operations virtnet_operations = {
@@ -443,11 +258,11 @@ static int virtnet_probe(struct nic *nic, struct pci_device *pci)
adjust_pci_device(pci);
- vp_reset(nic);
+ vp_reset(nic->ioaddr);
- features = vp_get_features(nic);
+ features = vp_get_features(nic->ioaddr);
if (features & (1 << VIRTIO_NET_F_MAC)) {
- vp_get(nic, offsetof(struct virtio_net_config, mac),
+ vp_get(nic->ioaddr, offsetof(struct virtio_net_config, mac),
nic->node_addr, ETH_ALEN);
printf("MAC address ");
for (i = 0; i < ETH_ALEN; i++) {
@@ -459,10 +274,10 @@ static int virtnet_probe(struct nic *nic, struct pci_device *pci)
/* initialize emit/receive queue */
for (i = 0; i < QUEUE_NB; i++) {
- free_head[i] = 0;
- last_used_idx[i] = 0;
- memset((char*)&queue[i], 0, sizeof(queue[i]));
- if (vp_find_vq(nic, i) == -1)
+ virtqueue[i].free_head = 0;
+ virtqueue[i].last_used_idx = 0;
+ memset((char*)&virtqueue[i].queue, 0, sizeof(virtqueue[i].queue));
+ if (vp_find_vq(nic->ioaddr, i, &virtqueue[i]) == -1)
printf("Cannot register queue #%d\n", i);
}
@@ -476,8 +291,8 @@ static int virtnet_probe(struct nic *nic, struct pci_device *pci)
/* driver is ready */
- vp_set_features(nic, features & (1 << VIRTIO_NET_F_MAC));
- vp_set_status(nic, VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK);
+ vp_set_features(nic->ioaddr, features & (1 << VIRTIO_NET_F_MAC));
+ vp_set_status(nic->ioaddr, VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK);
return 1;
}
diff --git a/gpxe/src/drivers/net/w89c840.c b/gpxe/src/drivers/net/w89c840.c
index 14497640..5abc0b35 100644
--- a/gpxe/src/drivers/net/w89c840.c
+++ b/gpxe/src/drivers/net/w89c840.c
@@ -112,7 +112,7 @@ static const char *w89c840_version = "driver Version 0.94 - December 12, 2003";
/* Operational parameters that usually are not changed. */
/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT (10*USECS_IN_MSEC)
+#define TX_TIMEOUT (10*1000)
#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
@@ -486,7 +486,7 @@ static void w89c840_transmit(
/* send the packet to destination */
unsigned entry;
int transmit_status;
- tick_t ct;
+ unsigned long ct;
/* Caution: the write order is important here, set the field
with the "ownership" bits last. */
diff --git a/gpxe/src/hci/commands/config_cmd.c b/gpxe/src/hci/commands/config_cmd.c
index 660c6423..87abb05a 100644
--- a/gpxe/src/hci/commands/config_cmd.c
+++ b/gpxe/src/hci/commands/config_cmd.c
@@ -16,7 +16,7 @@ static int config_exec ( int argc, char **argv ) {
}
settings_name = ( ( argc == 2 ) ? argv[1] : "" );
- settings = find_settings ( argv[1] );
+ settings = find_settings ( settings_name );
if ( ! settings ) {
printf ( "No such scope \"%s\"\n", settings_name );
return 1;
diff --git a/gpxe/src/hci/commands/dhcp_cmd.c b/gpxe/src/hci/commands/dhcp_cmd.c
index 07acc615..9b577c86 100644
--- a/gpxe/src/hci/commands/dhcp_cmd.c
+++ b/gpxe/src/hci/commands/dhcp_cmd.c
@@ -26,6 +26,7 @@
#include <assert.h>
#include <getopt.h>
#include <gpxe/netdevice.h>
+#include <gpxe/in.h>
#include <gpxe/command.h>
#include <usr/dhcpmgmt.h>
@@ -60,7 +61,7 @@ static int dhcp_exec ( int argc, char **argv ) {
{ "help", 0, NULL, 'h' },
{ NULL, 0, NULL, 0 },
};
- const char *name;
+ const char *netdev_txt;
struct net_device *netdev;
int c;
int rc;
@@ -82,14 +83,16 @@ static int dhcp_exec ( int argc, char **argv ) {
dhcp_syntax ( argv );
return 1;
}
- name = argv[optind];
+ netdev_txt = argv[optind];
- /* Perform DHCP */
- netdev = find_netdev ( name );
+ /* Parse arguments */
+ netdev = find_netdev ( netdev_txt );
if ( ! netdev ) {
- printf ( "No such interface: %s\n", name );
+ printf ( "No such interface: %s\n", netdev_txt );
return 1;
}
+
+ /* Perform DHCP */
if ( ( rc = dhcp ( netdev ) ) != 0 ) {
printf ( "Could not configure %s: %s\n", netdev->name,
strerror ( rc ) );
@@ -99,10 +102,87 @@ static int dhcp_exec ( int argc, char **argv ) {
return 0;
}
+/**
+ * "pxebs" command syntax message
+ *
+ * @v argv Argument list
+ */
+static void pxebs_syntax ( char **argv ) {
+ printf ( "Usage:\n"
+ " %s <interface> <server_type>\n"
+ "\n"
+ "Perform PXE Boot Server discovery\n",
+ argv[0] );
+}
+
+/**
+ * The "pxebs" command
+ *
+ * @v argc Argument count
+ * @v argv Argument list
+ * @ret rc Exit code
+ */
+static int pxebs_exec ( int argc, char **argv ) {
+ static struct option longopts[] = {
+ { "help", 0, NULL, 'h' },
+ { NULL, 0, NULL, 0 },
+ };
+ const char *netdev_txt;
+ const char *pxe_type_txt;
+ struct net_device *netdev;
+ unsigned int pxe_type;
+ char *end;
+ int c;
+ int rc;
+
+ /* Parse options */
+ while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){
+ switch ( c ) {
+ case 'h':
+ /* Display help text */
+ default:
+ /* Unrecognised/invalid option */
+ pxebs_syntax ( argv );
+ return 1;
+ }
+ }
+ if ( optind != ( argc - 2 ) ) {
+ pxebs_syntax ( argv );
+ return 1;
+ }
+ netdev_txt = argv[optind];
+ pxe_type_txt = argv[ optind + 1 ];
+
+ /* Parse arguments */
+ netdev = find_netdev ( netdev_txt );
+ if ( ! netdev ) {
+ printf ( "No such interface: %s\n", netdev_txt );
+ return 1;
+ }
+ pxe_type = strtoul ( pxe_type_txt, &end, 0 );
+ if ( *end ) {
+ printf ( "Bad server type: %s\n", pxe_type_txt );
+ return 1;
+ }
+
+ /* Perform Boot Server Discovery */
+ if ( ( rc = pxebs ( netdev, pxe_type ) ) != 0 ) {
+ printf ( "Could not discover boot server on %s: %s\n",
+ netdev->name, strerror ( rc ) );
+ return 1;
+ }
+
+ return 0;
+}
+
/** DHCP management commands */
struct command dhcp_commands[] __command = {
{
.name = "dhcp",
.exec = dhcp_exec,
},
+ {
+ .name = "pxebs",
+ .exec = pxebs_exec,
+ },
};
diff --git a/gpxe/src/hci/commands/login_cmd.c b/gpxe/src/hci/commands/login_cmd.c
new file mode 100644
index 00000000..e425247d
--- /dev/null
+++ b/gpxe/src/hci/commands/login_cmd.c
@@ -0,0 +1,27 @@
+#include <string.h>
+#include <stdio.h>
+#include <gpxe/command.h>
+#include <gpxe/login_ui.h>
+
+static int login_exec ( int argc, char **argv ) {
+ int rc;
+
+ if ( argc > 1 ) {
+ printf ( "Usage: %s\n"
+ "Prompt for login credentials\n", argv[0] );
+ return 1;
+ }
+
+ if ( ( rc = login_ui() ) != 0 ) {
+ printf ( "Could not set credentials: %s\n",
+ strerror ( rc ) );
+ return 1;
+ }
+
+ return 0;
+}
+
+struct command login_command __command = {
+ .name = "login",
+ .exec = login_exec,
+};
diff --git a/gpxe/src/hci/mucurses/ansi_screen.c b/gpxe/src/hci/mucurses/ansi_screen.c
index 0742a7d4..468bac02 100644
--- a/gpxe/src/hci/mucurses/ansi_screen.c
+++ b/gpxe/src/hci/mucurses/ansi_screen.c
@@ -15,7 +15,7 @@ static void ansiscr_reset ( struct _curses_screen *scr ) {
scr->attrs = 0;
scr->curs_x = 0;
scr->curs_y = 0;
- printf ( "\033[0m\033[2J\033[1;1H" );
+ printf ( "\033[0m" );
}
static void ansiscr_movetoyx ( struct _curses_screen *scr,
diff --git a/gpxe/src/hci/mucurses/widgets/editbox.c b/gpxe/src/hci/mucurses/widgets/editbox.c
index 5c066fda..a52089ce 100644
--- a/gpxe/src/hci/mucurses/widgets/editbox.c
+++ b/gpxe/src/hci/mucurses/widgets/editbox.c
@@ -38,11 +38,11 @@
* @v row Row
* @v col Starting column
* @v width Width
- *
+ * @v flags Flags
*/
void init_editbox ( struct edit_box *box, char *buf, size_t len,
WINDOW *win, unsigned int row, unsigned int col,
- unsigned int width ) {
+ unsigned int width, unsigned int flags ) {
memset ( box, 0, sizeof ( *box ) );
box->string.buf = buf;
box->string.len = len;
@@ -51,6 +51,7 @@ void init_editbox ( struct edit_box *box, char *buf, size_t len,
box->row = row;
box->col = col;
box->width = width;
+ box->flags = flags;
}
/**
@@ -86,7 +87,11 @@ void draw_editbox ( struct edit_box *box ) {
len = ( strlen ( box->string.buf ) - first );
if ( len > width )
len = width;
- memcpy ( buf, ( box->string.buf + first ), len );
+ if ( box->flags & EDITBOX_STARS ) {
+ memset ( buf, '*', len );
+ } else {
+ memcpy ( buf, ( box->string.buf + first ), len );
+ }
/* Print box content and move cursor */
if ( ! box->win )
diff --git a/gpxe/src/hci/mucurses/wininit.c b/gpxe/src/hci/mucurses/wininit.c
index dfd0ca0a..cd27f9fe 100644
--- a/gpxe/src/hci/mucurses/wininit.c
+++ b/gpxe/src/hci/mucurses/wininit.c
@@ -18,7 +18,7 @@ WINDOW *initscr ( void ) {
stdscr->scr->init( stdscr->scr );
stdscr->height = LINES;
stdscr->width = COLS;
- erase();
+ move ( 0, 0 );
return stdscr;
}
@@ -29,7 +29,7 @@ WINDOW *initscr ( void ) {
int endwin ( void ) {
attrset ( 0 );
color_set ( 0, NULL );
- erase();
+ mvprintw ( ( LINES - 1 ), 0, "\n" );
stdscr->scr->exit( stdscr->scr );
return OK;
}
diff --git a/gpxe/src/hci/tui/login_ui.c b/gpxe/src/hci/tui/login_ui.c
new file mode 100644
index 00000000..c14a2c03
--- /dev/null
+++ b/gpxe/src/hci/tui/login_ui.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/** @file
+ *
+ * Login UI
+ *
+ */
+
+#include <string.h>
+#include <errno.h>
+#include <curses.h>
+#include <console.h>
+#include <gpxe/settings.h>
+#include <gpxe/editbox.h>
+#include <gpxe/keys.h>
+#include <gpxe/login_ui.h>
+
+/* Colour pairs */
+#define CPAIR_NORMAL 1
+#define CPAIR_LABEL 2
+#define CPAIR_EDITBOX 3
+
+/* Screen layout */
+#define USERNAME_LABEL_ROW 8
+#define USERNAME_ROW 10
+#define PASSWORD_LABEL_ROW 14
+#define PASSWORD_ROW 16
+#define LABEL_COL 36
+#define EDITBOX_COL 30
+#define EDITBOX_WIDTH 20
+
+int login_ui ( void ) {
+ char username[64];
+ char password[64];
+ struct edit_box username_box;
+ struct edit_box password_box;
+ struct edit_box *current_box = &username_box;
+ int key;
+ int rc = -EINPROGRESS;
+
+ /* Fetch current setting values */
+ fetch_string_setting ( NULL, &username_setting, username,
+ sizeof ( username ) );
+ fetch_string_setting ( NULL, &password_setting, password,
+ sizeof ( password ) );
+
+ /* Initialise UI */
+ initscr();
+ start_color();
+ init_pair ( CPAIR_NORMAL, COLOR_WHITE, COLOR_BLACK );
+ init_pair ( CPAIR_LABEL, COLOR_WHITE, COLOR_BLACK );
+ init_pair ( CPAIR_EDITBOX, COLOR_WHITE, COLOR_BLUE );
+ init_editbox ( &username_box, username, sizeof ( username ), NULL,
+ USERNAME_ROW, EDITBOX_COL, EDITBOX_WIDTH, 0 );
+ init_editbox ( &password_box, password, sizeof ( password ), NULL,
+ PASSWORD_ROW, EDITBOX_COL, EDITBOX_WIDTH,
+ EDITBOX_STARS );
+
+ /* Draw initial UI */
+ erase();
+ color_set ( CPAIR_LABEL, NULL );
+ mvprintw ( USERNAME_LABEL_ROW, LABEL_COL, "Username:" );
+ mvprintw ( PASSWORD_LABEL_ROW, LABEL_COL, "Password:" );
+ color_set ( CPAIR_EDITBOX, NULL );
+ draw_editbox ( &username_box );
+ draw_editbox ( &password_box );
+
+ /* Main loop */
+ while ( rc == -EINPROGRESS ) {
+
+ draw_editbox ( current_box );
+
+ key = getkey();
+ switch ( key ) {
+ case KEY_DOWN:
+ current_box = &password_box;
+ break;
+ case KEY_UP:
+ current_box = &username_box;
+ break;
+ case TAB:
+ current_box = ( ( current_box == &username_box ) ?
+ &password_box : &username_box );
+ break;
+ case KEY_ENTER:
+ if ( current_box == &username_box ) {
+ current_box = &password_box;
+ } else {
+ rc = 0;
+ }
+ break;
+ case CTRL_C:
+ case ESC:
+ rc = -ECANCELED;
+ break;
+ default:
+ edit_editbox ( current_box, key );
+ break;
+ }
+ }
+
+ /* Terminate UI */
+ color_set ( CPAIR_NORMAL, NULL );
+ erase();
+ endwin();
+
+ if ( rc != 0 )
+ return rc;
+
+ /* Store settings */
+ if ( ( rc = store_setting ( NULL, &username_setting, username,
+ strlen ( username ) ) ) != 0 )
+ return rc;
+ if ( ( rc = store_setting ( NULL, &password_setting, password,
+ strlen ( password ) ) ) != 0 )
+ return rc;
+
+ return 0;
+}
diff --git a/gpxe/src/hci/tui/settings_ui.c b/gpxe/src/hci/tui/settings_ui.c
index 0907bfd3..4ab38270 100644
--- a/gpxe/src/hci/tui/settings_ui.c
+++ b/gpxe/src/hci/tui/settings_ui.c
@@ -123,7 +123,7 @@ static void load_setting ( struct setting_widget *widget ) {
init_editbox ( &widget->editbox, widget->value,
sizeof ( widget->value ), NULL, widget->row,
( widget->col + offsetof ( struct setting_row, value )),
- sizeof ( ( ( struct setting_row * ) NULL )->value ) );
+ sizeof ( ( ( struct setting_row * ) NULL )->value ), 0);
}
/**
diff --git a/gpxe/src/image/default.gpxe b/gpxe/src/image/default.gpxe
new file mode 100644
index 00000000..0b080b58
--- /dev/null
+++ b/gpxe/src/image/default.gpxe
@@ -0,0 +1,2 @@
+#!gpxe
+autoboot
diff --git a/gpxe/src/image/efi_image.c b/gpxe/src/image/efi_image.c
new file mode 100644
index 00000000..ae95debc
--- /dev/null
+++ b/gpxe/src/image/efi_image.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <errno.h>
+#include <gpxe/efi/efi.h>
+#include <gpxe/image.h>
+#include <gpxe/features.h>
+
+FEATURE ( FEATURE_IMAGE, "EFI", DHCP_EB_FEATURE_EFI, 1 );
+
+struct image_type efi_image_type __image_type ( PROBE_NORMAL );
+
+/**
+ * Execute EFI image
+ *
+ * @v image EFI image
+ * @ret rc Return status code
+ */
+static int efi_image_exec ( struct image *image ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_HANDLE handle;
+ UINTN exit_data_size;
+ CHAR16 *exit_data;
+ EFI_STATUS efirc;
+
+ /* Attempt loading image */
+ if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, NULL,
+ user_to_virt ( image->data, 0 ),
+ image->len, &handle ) ) != 0 ) {
+ /* Not an EFI image */
+ DBGC ( image, "EFIIMAGE %p could not load: %s\n",
+ image, efi_strerror ( efirc ) );
+ return -ENOEXEC;
+ }
+
+ /* Start the image */
+ if ( ( efirc = bs->StartImage ( handle, &exit_data_size,
+ &exit_data ) ) != 0 ) {
+ DBGC ( image, "EFIIMAGE %p returned with status %s\n",
+ image, efi_strerror ( efirc ) );
+ goto done;
+ }
+
+ done:
+ /* Unload the image. We can't leave it loaded, because we
+ * have no "unload" operation.
+ */
+ bs->UnloadImage ( handle );
+
+ return EFIRC_TO_RC ( efirc );
+}
+
+/**
+ * Load EFI image into memory
+ *
+ * @v image EFI file
+ * @ret rc Return status code
+ */
+static int efi_image_load ( struct image *image ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_HANDLE handle;
+ EFI_STATUS efirc;
+
+ /* Attempt loading image */
+ if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, NULL,
+ user_to_virt ( image->data, 0 ),
+ image->len, &handle ) ) != 0 ) {
+ /* Not an EFI image */
+ DBGC ( image, "EFIIMAGE %p could not load: %s\n",
+ image, efi_strerror ( efirc ) );
+ return -ENOEXEC;
+ }
+
+ /* This is an EFI image */
+ if ( ! image->type )
+ image->type = &efi_image_type;
+
+ /* Unload the image. We can't leave it loaded, because we
+ * have no "unload" operation.
+ */
+ bs->UnloadImage ( handle );
+
+ return 0;
+}
+
+/** EFI image type */
+struct image_type efi_image_type __image_type ( PROBE_NORMAL ) = {
+ .name = "EFI",
+ .load = efi_image_load,
+ .exec = efi_image_exec,
+};
diff --git a/gpxe/src/image/elf.c b/gpxe/src/image/elf.c
index b932ff58..cb2b0f5b 100644
--- a/gpxe/src/image/elf.c
+++ b/gpxe/src/image/elf.c
@@ -72,7 +72,7 @@ static int elf_load_segment ( struct image *image, Elf_Phdr *phdr ) {
}
buffer = phys_to_user ( dest );
- DBG ( "ELF loading segment [%lx,%lx) to [%lx,%lx,%lx)\n",
+ DBG ( "ELF loading segment [%x,%x) to [%x,%x,%x)\n",
phdr->p_offset, ( phdr->p_offset + phdr->p_filesz ),
phdr->p_paddr, ( phdr->p_paddr + phdr->p_filesz ),
( phdr->p_paddr + phdr->p_memsz ) );
diff --git a/gpxe/src/image/embed.S b/gpxe/src/image/embed.S
deleted file mode 100644
index 4541bfdc..00000000
--- a/gpxe/src/image/embed.S
+++ /dev/null
@@ -1,7 +0,0 @@
- .section ".data", "aw"
- .balign 4
- .globl _embedded_image_start
-_embedded_image_start:
- .incbin EMBEDIMG
- .globl _embedded_image_end
-_embedded_image_end:
diff --git a/gpxe/src/image/embedded.c b/gpxe/src/image/embedded.c
index 0ce09783..f76ca11b 100644
--- a/gpxe/src/image/embedded.c
+++ b/gpxe/src/image/embedded.c
@@ -1,49 +1,94 @@
/** @file
*
- * Take a possible embedded image and put it in a struct image
- * data structure.
+ * Embedded image support
+ *
+ * Embedded images are images built into the gPXE binary and do not require
+ * fetching over the network.
*/
+#include <string.h>
#include <gpxe/image.h>
-#include <gpxe/malloc.h>
#include <gpxe/uaccess.h>
-#include <gpxe/umalloc.h>
-#include <gpxe/embedded.h>
+#include <gpxe/init.h>
-extern char _embedded_image_start[], _embedded_image_end[];
+/**
+ * Free embedded image
+ *
+ * @v refcnt Reference counter
+ */
+static void embedded_image_free ( struct refcnt *refcnt __unused ) {
+ /* Do nothing */
+}
-struct image *embedded_image(void)
-{
- static int reclaimed = 0;
- struct image *image;
- size_t eisize = _embedded_image_end - _embedded_image_start;
+/* Raw image data for all embedded images */
+#undef EMBED
+#define EMBED( _index, _path, _name ) \
+ extern char embedded_image_ ## _index ## _data[]; \
+ extern char embedded_image_ ## _index ## _len[]; \
+ __asm__ ( ".section \".rodata\", \"a\", @progbits\n\t" \
+ "\nembedded_image_" #_index "_data:\n\t" \
+ ".incbin \"" _path "\"\n\t" \
+ "\nembedded_image_" #_index "_end:\n\t" \
+ ".equ embedded_image_" #_index "_len, " \
+ "( embedded_image_" #_index "_end - " \
+ " embedded_image_" #_index "_data )\n\t" \
+ ".previous\n\t" );
+EMBED_ALL
- if ( !eisize )
- return NULL; /* No embedded image */
+/* Image structures for all embedded images */
+#undef EMBED
+#define EMBED( _index, _path, _name ) { \
+ .refcnt = { .free = embedded_image_free, }, \
+ .name = _name, \
+ .data = ( userptr_t ) ( embedded_image_ ## _index ## _data ), \
+ .len = ( size_t ) embedded_image_ ## _index ## _len, \
+},
+static struct image embedded_images[] = {
+ EMBED_ALL
+};
- if ( reclaimed )
- return NULL; /* Already reclaimed */
+/**
+ * Register all embedded images
+ */
+static void embedded_init ( void ) {
+ unsigned int i;
+ struct image *image;
+ void *data;
+ int rc;
- DBG ( "Embedded image: %zd bytes at %p\n",
- eisize, _embedded_image_start );
+ /* Fix up data pointers and register images */
+ for ( i = 0 ; i < ( sizeof ( embedded_images ) /
+ sizeof ( embedded_images[0] ) ) ; i++ ) {
+ image = &embedded_images[i];
- image = alloc_image();
- if (!image)
- return NULL;
+ /* virt_to_user() cannot be used in a static
+ * initialiser, so we cast the pointer to a userptr_t
+ * in the initialiser and fix it up here. (This will
+ * actually be a no-op on most platforms.)
+ */
+ data = ( ( void * ) image->data );
+ image->data = virt_to_user ( data );
- image->len = eisize;
- image->data = umalloc(eisize);
- if (image->data == UNULL) {
- image_put(image);
- return image = NULL;
- }
- copy_to_user(image->data, 0, _embedded_image_start, eisize);
- register_image(image);
+ DBG ( "Embedded image \"%s\": %zd bytes at %p\n",
+ image->name, image->len, data );
- /* Reclaim embedded image memory */
- reclaimed = 1;
- mpopulate(_embedded_image_start, eisize);
+ if ( ( rc = register_image ( image ) ) != 0 ) {
+ DBG ( "Could not register embedded image \"%s\": "
+ "%s\n", image->name, strerror ( rc ) );
+ return;
+ }
+ }
- return image;
+ /* Load the first image */
+ image = &embedded_images[0];
+ if ( ( rc = image_autoload ( image ) ) != 0 ) {
+ DBG ( "Could not load embedded image \"%s\": %s\n",
+ image->name, strerror ( rc ) );
+ return;
+ }
}
+/** Embedded image initialisation function */
+struct init_fn embedded_init_fn __init_fn ( INIT_NORMAL ) = {
+ .initialise = embedded_init,
+};
diff --git a/gpxe/src/image/script.c b/gpxe/src/image/script.c
index 749131d6..2d242746 100644
--- a/gpxe/src/image/script.c
+++ b/gpxe/src/image/script.c
@@ -43,10 +43,8 @@ static int script_exec ( struct image *image ) {
int rc;
/* Temporarily de-register image, so that a "boot" command
- * doesn't throw us into an execution loop. Hold a reference
- * to avoid the image's being freed.
+ * doesn't throw us into an execution loop.
*/
- image_get ( image );
unregister_image ( image );
while ( offset < image->len ) {
@@ -80,7 +78,6 @@ static int script_exec ( struct image *image ) {
done:
/* Re-register image and return */
register_image ( image );
- image_put ( image );
return rc;
}
@@ -94,6 +91,12 @@ static int script_load ( struct image *image ) {
static const char magic[] = "#!gpxe\n";
char test[ sizeof ( magic ) - 1 ];
+ /* Sanity check */
+ if ( image->len < sizeof ( test ) ) {
+ DBG ( "Too short to be a script\n" );
+ return -ENOEXEC;
+ }
+
/* Check for magic signature */
copy_from_user ( test, image->data, 0, sizeof ( test ) );
if ( memcmp ( test, magic, sizeof ( test ) ) != 0 ) {
diff --git a/gpxe/src/include/byteswap.h b/gpxe/src/include/byteswap.h
index 72b5a01d..6c3ced25 100644
--- a/gpxe/src/include/byteswap.h
+++ b/gpxe/src/include/byteswap.h
@@ -4,6 +4,41 @@
#include "endian.h"
#include "bits/byteswap.h"
+#define __bswap_constant_16(x) \
+ ((uint16_t)((((uint16_t)(x) & 0x00ff) << 8) | \
+ (((uint16_t)(x) & 0xff00) >> 8)))
+
+#define __bswap_constant_32(x) \
+ ((uint32_t)((((uint32_t)(x) & 0x000000ffU) << 24) | \
+ (((uint32_t)(x) & 0x0000ff00U) << 8) | \
+ (((uint32_t)(x) & 0x00ff0000U) >> 8) | \
+ (((uint32_t)(x) & 0xff000000U) >> 24)))
+
+#define __bswap_constant_64(x) \
+ ((uint64_t)((((uint64_t)(x) & 0x00000000000000ffULL) << 56) | \
+ (((uint64_t)(x) & 0x000000000000ff00ULL) << 40) | \
+ (((uint64_t)(x) & 0x0000000000ff0000ULL) << 24) | \
+ (((uint64_t)(x) & 0x00000000ff000000ULL) << 8) | \
+ (((uint64_t)(x) & 0x000000ff00000000ULL) >> 8) | \
+ (((uint64_t)(x) & 0x0000ff0000000000ULL) >> 24) | \
+ (((uint64_t)(x) & 0x00ff000000000000ULL) >> 40) | \
+ (((uint64_t)(x) & 0xff00000000000000ULL) >> 56)))
+
+#define __bswap_16(x) \
+ ((uint16_t)(__builtin_constant_p(x) ? \
+ __bswap_constant_16(x) : \
+ __bswap_variable_16(x)))
+
+#define __bswap_32(x) \
+ ((uint32_t)(__builtin_constant_p(x) ? \
+ __bswap_constant_32(x) : \
+ __bswap_variable_32(x)))
+
+#define __bswap_64(x) \
+ ((uint64_t)(__builtin_constant_p(x) ? \
+ __bswap_constant_64(x) : \
+ __bswap_variable_64(x)))
+
#if __BYTE_ORDER == __LITTLE_ENDIAN
#include "little_bswap.h"
#endif
diff --git a/gpxe/src/include/compiler.h b/gpxe/src/include/compiler.h
index 8ab7b8ae..889c2404 100644
--- a/gpxe/src/include/compiler.h
+++ b/gpxe/src/include/compiler.h
@@ -59,6 +59,17 @@ __asm__ ( ".equ\t" OBJECT_SYMBOL_STR ", 0" );
#define REQUIRE_OBJECT(object) \
__asm__ ( ".equ\tneed_" #object ", obj_" #object );
+/* Force visibility of all symbols to "hidden", i.e. inform gcc that
+ * all symbol references resolve strictly within our final binary.
+ * This avoids unnecessary PLT/GOT entries on x86_64.
+ *
+ * This is a stronger claim than specifying "-fvisibility=hidden",
+ * since it also affects symbols marked with "extern".
+ */
+#if __GNUC__ >= 4
+#pragma GCC visibility push(hidden)
+#endif
+
/** @def DBG
*
* Print a debugging message.
@@ -131,11 +142,26 @@ extern void dbg_decolourise ( void );
extern void dbg_hex_dump_da ( unsigned long dispaddr,
const void *data, unsigned long len );
-/* Compatibility with existing Makefile */
#if DEBUG_SYMBOL
-#define DBGLVL DEBUG_SYMBOL
+#define DBGLVL_MAX DEBUG_SYMBOL
+#else
+#define DBGLVL_MAX 0
+#endif
+
+/* Allow for selective disabling of enabled debug levels */
+#if DBGLVL_MAX
+int __debug_disable;
+#define DBGLVL ( DBGLVL_MAX & ~__debug_disable )
+#define DBG_DISABLE( level ) do { \
+ __debug_disable |= ( (level) & DBGLVL_MAX ); \
+ } while ( 0 )
+#define DBG_ENABLE( level ) do { \
+ __debug_disable &= ~( (level) & DBGLVL_MAX ); \
+ } while ( 0 )
#else
#define DBGLVL 0
+#define DBG_DISABLE( level ) do { } while ( 0 )
+#define DBG_ENABLE( level ) do { } while ( 0 )
#endif
#define DBGLVL_LOG 1
@@ -287,9 +313,6 @@ extern void dbg_hex_dump_da ( unsigned long dispaddr,
/** Declare a variable or data structure as unused. */
#define __unused __attribute__ (( unused ))
-/** Apply standard C calling conventions */
-#define __cdecl __attribute__ (( cdecl , regparm(0) ))
-
/**
* Declare a function as pure - i.e. without side effects
*/
@@ -325,6 +348,9 @@ extern void dbg_hex_dump_da ( unsigned long dispaddr,
/** Declare a data structure to be aligned with 16-byte alignment */
#define __aligned __attribute__ (( aligned ( 16 ) ))
+/** Declare a function to be always inline */
+#define __always_inline __attribute__ (( always_inline ))
+
/**
* Shared data.
*
@@ -354,4 +380,6 @@ extern void dbg_hex_dump_da ( unsigned long dispaddr,
#endif /* ASSEMBLY */
+#include <bits/compiler.h>
+
#endif /* COMPILER_H */
diff --git a/gpxe/src/include/elf.h b/gpxe/src/include/elf.h
index a6eb5d9c..fadc0bdb 100644
--- a/gpxe/src/include/elf.h
+++ b/gpxe/src/include/elf.h
@@ -227,10 +227,6 @@ typedef struct {
/* Standardized Elf image notes for booting... The name for all of these is ELFBoot */
-
-/* ELF Defines for the current architecture */
-#include "bits/elf.h"
-
#endif /* ASSEMBLY */
#endif /* ELF_H */
diff --git a/gpxe/src/include/gpxe/aoe.h b/gpxe/src/include/gpxe/aoe.h
index 4aab4291..6de6b965 100644
--- a/gpxe/src/include/gpxe/aoe.h
+++ b/gpxe/src/include/gpxe/aoe.h
@@ -13,8 +13,24 @@
#include <gpxe/retry.h>
#include <gpxe/ata.h>
+/** An AoE config command */
+struct aoecfg {
+ /** AoE Queue depth */
+ uint16_t bufcnt;
+ /** ATA target firmware version */
+ uint16_t fwver;
+ /** ATA target sector count */
+ uint8_t scnt;
+ /** AoE config string subcommand */
+ uint8_t aoeccmd;
+ /** AoE config string length */
+ uint16_t cfglen;
+ /** AoE config string */
+ uint8_t data[0];
+} __attribute__ (( packed ));
+
/** An AoE ATA command */
-struct aoecmd {
+struct aoeata {
/** AoE command flags */
uint8_t aflags;
/** ATA error/feature register */
@@ -37,6 +53,14 @@ struct aoecmd {
#define AOE_FL_ASYNC 0x02 /**< Asynchronous write */
#define AOE_FL_WRITE 0x01 /**< Write command */
+/** An AoE command */
+union aoecmd {
+ /** Config command */
+ struct aoecfg cfg;
+ /** ATA command */
+ struct aoeata ata;
+};
+
/** An AoE header */
struct aoehdr {
/** Protocol version number and flags */
@@ -52,10 +76,7 @@ struct aoehdr {
/** Tag, in network byte order */
uint32_t tag;
/** Payload */
- union {
- /** ATA command */
- struct aoecmd command[0];
- } arg;
+ union aoecmd cmd[0];
} __attribute__ (( packed ));
#define AOE_VERSION 0x10 /**< Version 1 */
@@ -99,6 +120,8 @@ struct aoe_session {
/** Tag for current AoE command */
uint32_t tag;
+ /** Current AOE command */
+ uint8_t aoe_cmd_type;
/** Current ATA command */
struct ata_command *command;
/** Overall status of current ATA command */
diff --git a/gpxe/src/include/gpxe/api.h b/gpxe/src/include/gpxe/api.h
new file mode 100644
index 00000000..df5d1ae3
--- /dev/null
+++ b/gpxe/src/include/gpxe/api.h
@@ -0,0 +1,82 @@
+#ifndef _GPXE_API_H
+#define _GPXE_API_H
+
+/** @file
+ *
+ * gPXE internal APIs
+ *
+ * There are various formally-defined APIs internal to gPXE, with
+ * several differing implementations specific to particular execution
+ * environments (e.g. PC BIOS, EFI, LinuxBIOS).
+ *
+ */
+
+/** @defgroup Single-implementation APIs
+ *
+ * These are APIs for which only a single implementation may be
+ * compiled in at any given time.
+ *
+ * @{
+ */
+
+/**
+ * Calculate function implementation name
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ * @ret _subsys_func Subsystem API function
+ *
+ * The subsystem prefix should be an empty string for the currently
+ * selected subsystem, and should be a subsystem-unique string for all
+ * other subsystems.
+ */
+#define SINGLE_API_NAME( _prefix, _api_func ) _prefix ## _api_func
+
+/**
+ * Calculate static inline function name
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ * @ret _subsys_func Subsystem API function
+ */
+#define SINGLE_API_INLINE( _prefix, _api_func ) \
+ SINGLE_API_NAME ( _prefix, _api_func )
+
+/**
+ * Provide an API implementation
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ * @v _func Implementing function
+ */
+#define PROVIDE_SINGLE_API( _prefix, _api_func, _func ) \
+ /* Ensure that _api_func exists */ \
+ typeof ( _api_func ) _api_func; \
+ /* Ensure that _func exists */ \
+ typeof ( _func ) _func; \
+ /* Ensure that _func is type-compatible with _api_func */ \
+ typeof ( _api_func ) _func; \
+ /* Ensure that _subsys_func is non-static */ \
+ extern typeof ( _api_func ) SINGLE_API_NAME ( _prefix, _api_func ); \
+ /* Provide symbol alias from _subsys_func to _func */ \
+ typeof ( _api_func ) SINGLE_API_NAME ( _prefix, _api_func ) \
+ __attribute__ (( alias ( #_func ) ));
+
+/**
+ * Provide a static inline API implementation
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ */
+#define PROVIDE_SINGLE_API_INLINE( _prefix, _api_func ) \
+ /* Ensure that _api_func exists */ \
+ typeof ( _api_func ) _api_func; \
+ /* Ensure that _subsys_func exists and is static */ \
+ static typeof ( SINGLE_API_INLINE ( _prefix, _api_func ) ) \
+ SINGLE_API_INLINE ( _prefix, _api_func ); \
+ /* Ensure that _subsys_func is type-compatible with _api_func */ \
+ typeof ( _api_func ) SINGLE_API_INLINE ( _prefix, _api_func );
+
+/** @} */
+
+#endif /* _GPXE_API_H */
diff --git a/gpxe/src/include/gpxe/asn1.h b/gpxe/src/include/gpxe/asn1.h
index 1ad90050..5440c48c 100644
--- a/gpxe/src/include/gpxe/asn1.h
+++ b/gpxe/src/include/gpxe/asn1.h
@@ -21,12 +21,12 @@
*/
struct asn1_cursor {
/** Start of data */
- uint8_t *data;
+ void *data;
/** Length of data */
size_t len;
};
-extern int asn1_enter_object ( struct asn1_cursor *cursor, unsigned int type );
-extern int asn1_skip_object ( struct asn1_cursor *cursor, unsigned int type );
+extern int asn1_enter ( struct asn1_cursor *cursor, unsigned int type );
+extern int asn1_skip ( struct asn1_cursor *cursor, unsigned int type );
#endif /* _GPXE_ASN1_H */
diff --git a/gpxe/src/include/gpxe/base64.h b/gpxe/src/include/gpxe/base64.h
new file mode 100644
index 00000000..3321971a
--- /dev/null
+++ b/gpxe/src/include/gpxe/base64.h
@@ -0,0 +1,24 @@
+#ifndef _GPXE_BASE64_H
+#define _GPXE_BASE64_H
+
+/** @file
+ *
+ * Base64 encoding
+ *
+ */
+
+#include <stdint.h>
+
+/**
+ * Calculate length of base64-encoded string
+ *
+ * @v raw_len Raw string length (excluding NUL)
+ * @ret encoded_len Encoded string length (excluding NUL)
+ */
+static inline size_t base64_encoded_len ( size_t raw_len ) {
+ return ( ( ( raw_len + 3 - 1 ) / 3 ) * 4 );
+}
+
+extern void base64_encode ( const char *raw, char *encoded );
+
+#endif /* _GPXE_BASE64_H */
diff --git a/gpxe/src/include/gpxe/bitops.h b/gpxe/src/include/gpxe/bitops.h
index f95af7d3..5405c854 100644
--- a/gpxe/src/include/gpxe/bitops.h
+++ b/gpxe/src/include/gpxe/bitops.h
@@ -1,27 +1,228 @@
#ifndef _GPXE_BITOPS_H
#define _GPXE_BITOPS_H
-/** @file
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/**
+ * @file
*
* Bit operations
+ *
*/
#include <stdint.h>
+#include <byteswap.h>
+
+/* Endianness selection.
+ *
+ * This is a property of the NIC, not a property of the host CPU.
+ */
+#ifdef BITOPS_LITTLE_ENDIAN
+#define cpu_to_BIT64 cpu_to_le64
+#define cpu_to_BIT32 cpu_to_le32
+#define BIT64_to_cpu le64_to_cpu
+#define BIT32_to_cpu le32_to_cpu
+#endif
+#ifdef BITOPS_BIG_ENDIAN
+#define cpu_to_BIT64 cpu_to_be64
+#define cpu_to_BIT32 cpu_to_be32
+#define BIT64_to_cpu be64_to_cpu
+#define BIT32_to_cpu be32_to_cpu
+#endif
+
+/** Datatype used to represent a bit in the pseudo-structures */
+typedef unsigned char pseudo_bit_t;
+
+/**
+ * Wrapper structure for pseudo_bit_t structures
+ *
+ * This structure provides a wrapper around pseudo_bit_t structures.
+ * It has the correct size, and also encapsulates type information
+ * about the underlying pseudo_bit_t-based structure, which allows the
+ * BIT_FILL() etc. macros to work without requiring explicit type
+ * information.
+ */
+#define PSEUDO_BIT_STRUCT( _structure ) \
+ union { \
+ uint8_t bytes[ sizeof ( _structure ) / 8 ]; \
+ uint32_t dwords[ sizeof ( _structure ) / 32 ]; \
+ uint64_t qwords[ sizeof ( _structure ) / 64 ]; \
+ _structure *dummy[0]; \
+ } u
+
+/** Get pseudo_bit_t structure type from wrapper structure pointer */
+#define PSEUDO_BIT_STRUCT_TYPE( _ptr ) \
+ typeof ( *((_ptr)->u.dummy[0]) )
+
+/** Bit offset of a field within a pseudo_bit_t structure */
+#define BIT_OFFSET( _ptr, _field ) \
+ offsetof ( PSEUDO_BIT_STRUCT_TYPE ( _ptr ), _field )
+
+/** Bit width of a field within a pseudo_bit_t structure */
+#define BIT_WIDTH( _ptr, _field ) \
+ sizeof ( ( ( PSEUDO_BIT_STRUCT_TYPE ( _ptr ) * ) NULL )->_field )
+
+/** Qword offset of a field within a pseudo_bit_t structure */
+#define QWORD_OFFSET( _ptr, _field ) \
+ ( BIT_OFFSET ( _ptr, _field ) / 64 )
+
+/** Qword bit offset of a field within a pseudo_bit_t structure */
+#define QWORD_BIT_OFFSET( _ptr, _index, _field ) \
+ ( BIT_OFFSET ( _ptr, _field ) - ( 64 * (_index) ) )
+
+/** Bit mask for a field within a pseudo_bit_t structure */
+#define BIT_MASK( _ptr, _field ) \
+ ( ( ~( ( uint64_t ) 0 ) ) >> \
+ ( 64 - BIT_WIDTH ( _ptr, _field ) ) )
+
+/*
+ * Assemble native-endian qword from named fields and values
+ *
+ */
+
+#define BIT_ASSEMBLE_1( _ptr, _index, _field, _value ) \
+ ( ( ( uint64_t) (_value) ) << \
+ QWORD_BIT_OFFSET ( _ptr, _index, _field ) )
+
+#define BIT_ASSEMBLE_2( _ptr, _index, _field, _value, ... ) \
+ ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \
+ BIT_ASSEMBLE_1 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define BIT_ASSEMBLE_3( _ptr, _index, _field, _value, ... ) \
+ ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \
+ BIT_ASSEMBLE_2 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define BIT_ASSEMBLE_4( _ptr, _index, _field, _value, ... ) \
+ ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \
+ BIT_ASSEMBLE_3 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define BIT_ASSEMBLE_5( _ptr, _index, _field, _value, ... ) \
+ ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \
+ BIT_ASSEMBLE_4 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define BIT_ASSEMBLE_6( _ptr, _index, _field, _value, ... ) \
+ ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \
+ BIT_ASSEMBLE_5 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define BIT_ASSEMBLE_7( _ptr, _index, _field, _value, ... ) \
+ ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \
+ BIT_ASSEMBLE_6 ( _ptr, _index, __VA_ARGS__ ) )
+
+/*
+ * Build native-endian (positive) qword bitmasks from named fields
+ *
+ */
+
+#define BIT_MASK_1( _ptr, _index, _field ) \
+ ( BIT_MASK ( _ptr, _field ) << \
+ QWORD_BIT_OFFSET ( _ptr, _index, _field ) )
+
+#define BIT_MASK_2( _ptr, _index, _field, ... ) \
+ ( BIT_MASK_1 ( _ptr, _index, _field ) | \
+ BIT_MASK_1 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define BIT_MASK_3( _ptr, _index, _field, ... ) \
+ ( BIT_MASK_1 ( _ptr, _index, _field ) | \
+ BIT_MASK_2 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define BIT_MASK_4( _ptr, _index, _field, ... ) \
+ ( BIT_MASK_1 ( _ptr, _index, _field ) | \
+ BIT_MASK_3 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define BIT_MASK_5( _ptr, _index, _field, ... ) \
+ ( BIT_MASK_1 ( _ptr, _index, _field ) | \
+ BIT_MASK_4 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define BIT_MASK_6( _ptr, _index, _field, ... ) \
+ ( BIT_MASK_1 ( _ptr, _index, _field ) | \
+ BIT_MASK_5 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define BIT_MASK_7( _ptr, _index, _field, ... ) \
+ ( BIT_MASK_1 ( _ptr, _index, _field ) | \
+ BIT_MASK_6 ( _ptr, _index, __VA_ARGS__ ) )
+
+/*
+ * Populate little-endian qwords from named fields and values
+ *
+ */
+
+#define BIT_FILL( _ptr, _index, _assembled ) do { \
+ uint64_t *__ptr = &(_ptr)->u.qwords[(_index)]; \
+ uint64_t __assembled = (_assembled); \
+ *__ptr = cpu_to_BIT64 ( __assembled ); \
+ } while ( 0 )
+
+#define BIT_FILL_1( _ptr, _field1, ... ) \
+ BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
+ BIT_ASSEMBLE_1 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
+ _field1, __VA_ARGS__ ) )
+
+#define BIT_FILL_2( _ptr, _field1, ... ) \
+ BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
+ BIT_ASSEMBLE_2 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
+ _field1, __VA_ARGS__ ) )
+
+#define BIT_FILL_3( _ptr, _field1, ... ) \
+ BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
+ BIT_ASSEMBLE_3 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
+ _field1, __VA_ARGS__ ) )
+
+#define BIT_FILL_4( _ptr, _field1, ... ) \
+ BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
+ BIT_ASSEMBLE_4 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
+ _field1, __VA_ARGS__ ) )
+
+#define BIT_FILL_5( _ptr, _field1, ... ) \
+ BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
+ BIT_ASSEMBLE_5 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
+ _field1, __VA_ARGS__ ) )
-static inline uint32_t rol32 ( uint32_t data, unsigned int rotation ) {
- return ( ( data << rotation ) | ( data >> ( 32 - rotation ) ) );
-}
+#define BIT_FILL_6( _ptr, _field1, ... ) \
+ BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
+ BIT_ASSEMBLE_6 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
+ _field1, __VA_ARGS__ ) )
-static inline uint32_t ror32 ( uint32_t data, unsigned int rotation ) {
- return ( ( data >> rotation ) | ( data << ( 32 - rotation ) ) );
-}
+/** Extract value of named field */
+#define BIT_GET64( _ptr, _field ) \
+ ( { \
+ unsigned int __index = QWORD_OFFSET ( _ptr, _field ); \
+ uint64_t *__ptr = &(_ptr)->u.qwords[__index]; \
+ uint64_t __value = BIT64_to_cpu ( *__ptr ); \
+ __value >>= \
+ QWORD_BIT_OFFSET ( _ptr, __index, _field ); \
+ __value &= BIT_MASK ( _ptr, _field ); \
+ __value; \
+ } )
-static inline uint64_t rol64 ( uint64_t data, unsigned int rotation ) {
- return ( ( data << rotation ) | ( data >> ( 64 - rotation ) ) );
-}
+/** Extract value of named field (for fields up to the size of a long) */
+#define BIT_GET( _ptr, _field ) \
+ ( ( unsigned long ) BIT_GET64 ( _ptr, _field ) )
-static inline uint64_t ror64 ( uint64_t data, unsigned int rotation ) {
- return ( ( data >> rotation ) | ( data << ( 64 - rotation ) ) );
-}
+#define BIT_SET( _ptr, _field, _value ) do { \
+ unsigned int __index = QWORD_OFFSET ( _ptr, _field ); \
+ uint64_t *__ptr = &(_ptr)->u.qwords[__index]; \
+ unsigned int __shift = \
+ QWORD_BIT_OFFSET ( _ptr, __index, _field ); \
+ uint64_t __value = (_value); \
+ *__ptr &= cpu_to_BIT64 ( ~( BIT_MASK ( _ptr, _field ) << \
+ __shift ) ); \
+ *__ptr |= cpu_to_BIT64 ( __value << __shift ); \
+ } while ( 0 )
#endif /* _GPXE_BITOPS_H */
diff --git a/gpxe/src/include/gpxe/blockdev.h b/gpxe/src/include/gpxe/blockdev.h
index 467ed1d9..8222984a 100644
--- a/gpxe/src/include/gpxe/blockdev.h
+++ b/gpxe/src/include/gpxe/blockdev.h
@@ -10,12 +10,10 @@
#include <gpxe/uaccess.h>
-/** A block device */
-struct block_device {
- /** Block size */
- size_t blksize;
- /** Total number of blocks */
- uint64_t blocks;
+struct block_device;
+
+/** Block device operations */
+struct block_device_operations {
/**
* Read block
*
@@ -40,4 +38,14 @@ struct block_device {
unsigned long count, userptr_t buffer );
};
+/** A block device */
+struct block_device {
+ /** Block device operations */
+ struct block_device_operations *op;
+ /** Block size */
+ size_t blksize;
+ /** Total number of blocks */
+ uint64_t blocks;
+};
+
#endif /* _GPXE_BLOCKDEV_H */
diff --git a/gpxe/src/include/gpxe/dhcp.h b/gpxe/src/include/gpxe/dhcp.h
index e89503d3..33e0c5d4 100644
--- a/gpxe/src/include/gpxe/dhcp.h
+++ b/gpxe/src/include/gpxe/dhcp.h
@@ -12,8 +12,9 @@
#include <gpxe/list.h>
#include <gpxe/refcnt.h>
#include <gpxe/tables.h>
+#include <gpxe/uuid.h>
+#include <gpxe/netdevice.h>
-struct net_device;
struct job_interface;
struct dhcp_options;
struct dhcp_packet;
@@ -24,8 +25,8 @@ struct dhcp_packet;
/** BOOTP/DHCP client port */
#define BOOTPC_PORT 68
-/** ProxyDHCP server port */
-#define PROXYDHCP_PORT 4011
+/** PXE server port */
+#define PXE_PORT 4011
/** Construct a tag value for an encapsulated option
*
@@ -81,6 +82,87 @@ struct dhcp_packet;
/** Vendor encapsulated options */
#define DHCP_VENDOR_ENCAP 43
+/** PXE boot server discovery control */
+#define DHCP_PXE_DISCOVERY_CONTROL DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 6 )
+
+/** PXE boot server discovery control bits */
+enum dhcp_pxe_discovery_control {
+ /** Inhibit broadcast discovery */
+ PXEBS_NO_BROADCAST = 1,
+ /** Inhibit multicast discovery */
+ PXEBS_NO_MULTICAST = 2,
+ /** Accept only servers in DHCP_PXE_BOOT_SERVERS list */
+ PXEBS_NO_UNKNOWN_SERVERS = 4,
+ /** Skip discovery if filename present */
+ PXEBS_SKIP = 8,
+};
+
+/** PXE boot server multicast address */
+#define DHCP_PXE_BOOT_SERVER_MCAST DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 7 )
+
+/** PXE boot servers */
+#define DHCP_PXE_BOOT_SERVERS DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 8 )
+
+/** PXE boot server */
+struct dhcp_pxe_boot_server {
+ /** "Type" */
+ uint16_t type;
+ /** Number of IPv4 addresses */
+ uint8_t num_ip;
+ /** IPv4 addresses */
+ struct in_addr ip[0];
+} __attribute__ (( packed ));
+
+/** PXE boot menu */
+#define DHCP_PXE_BOOT_MENU DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 9 )
+
+/** PXE boot menu */
+struct dhcp_pxe_boot_menu {
+ /** "Type" */
+ uint16_t type;
+ /** Description length */
+ uint8_t desc_len;
+ /** Description */
+ char desc[0];
+} __attribute__ (( packed ));
+
+/** PXE boot menu prompt */
+#define DHCP_PXE_BOOT_MENU_PROMPT DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 10 )
+
+/** PXE boot menu prompt */
+struct dhcp_pxe_boot_menu_prompt {
+ /** Timeout
+ *
+ * A value of 0 means "time out immediately and select first
+ * boot item, without displaying the prompt". A value of 255
+ * means "display menu immediately with no timeout". Any
+ * other value means "display prompt, wait this many seconds
+ * for keypress, if key is F8, display menu, otherwise select
+ * first boot item".
+ */
+ uint8_t timeout;
+ /** Prompt to press F8 */
+ char prompt[0];
+} __attribute__ (( packed ));
+
+/** PXE boot menu item */
+#define DHCP_PXE_BOOT_MENU_ITEM DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 71 )
+
+/** PXE boot menu item */
+struct dhcp_pxe_boot_menu_item {
+ /** "Type"
+ *
+ * This field actually identifies the specific boot server (or
+ * cluster of boot servers offering identical boot files).
+ */
+ uint16_t type;
+ /** "Layer"
+ *
+ * Just don't ask.
+ */
+ uint16_t layer;
+} __attribute__ (( packed ));
+
/** Requested IP address */
#define DHCP_REQUESTED_ADDRESS 50
@@ -127,6 +209,14 @@ struct dhcp_packet;
/** Client identifier */
#define DHCP_CLIENT_ID 61
+/** Client identifier */
+struct dhcp_client_id {
+ /** Link-layer protocol */
+ uint8_t ll_proto;
+ /** Link-layer address */
+ uint8_t ll_addr[MAX_LL_ADDR_LEN];
+} __attribute__ (( packed ));
+
/** TFTP server name
*
* This option replaces the fixed "sname" field, when that field is
@@ -141,6 +231,9 @@ struct dhcp_packet;
*/
#define DHCP_BOOTFILE_NAME 67
+/** User class identifier */
+#define DHCP_USER_CLASS_ID 77
+
/** Client system architecture */
#define DHCP_CLIENT_ARCHITECTURE 93
@@ -150,6 +243,16 @@ struct dhcp_packet;
/** UUID client identifier */
#define DHCP_CLIENT_UUID 97
+/** UUID client identifier */
+struct dhcp_client_uuid {
+ /** Identifier type */
+ uint8_t type;
+ /** UUID */
+ union uuid uuid;
+} __attribute__ (( packed ));
+
+#define DHCP_CLIENT_UUID_TYPE 0
+
/** Etherboot-specific encapsulated options
*
* This encapsulated options field is used to contain all options
@@ -197,12 +300,12 @@ struct dhcp_packet;
*
*/
-/** Ignore ProxyDHCP
+/** Skip PXE DHCP protocol extensions such as ProxyDHCP
*
* If set to a non-zero value, gPXE will not wait for ProxyDHCP offers
- * and will ignore any ProxyDHCP offers that it receives.
+ * and will ignore any PXE-specific DHCP options that it receives.
*/
-#define DHCP_EB_NO_PROXYDHCP DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xb0 )
+#define DHCP_EB_NO_PXEDHCP DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xb0 )
/** Network device descriptor
*
@@ -217,6 +320,16 @@ struct dhcp_packet;
*/
#define DHCP_EB_BUS_ID DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xb1 )
+/** Network device descriptor */
+struct dhcp_netdev_desc {
+ /** Bus type ID */
+ uint8_t type;
+ /** Vendor ID */
+ uint16_t vendor;
+ /** Device ID */
+ uint16_t device;
+} __attribute__ (( packed ));
+
/** BIOS drive number
*
* This is the drive number for a drive emulated via INT 13. 0x80 is
@@ -260,6 +373,9 @@ struct dhcp_packet;
*/
#define DHCP_EB_REVERSE_PASSWORD DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xc1 )
+/** gPXE version number */
+#define DHCP_EB_VERSION DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xeb )
+
/** iSCSI primary target IQN */
#define DHCP_ISCSI_PRIMARY_TARGET_IQN 201
@@ -464,28 +580,35 @@ struct dhcphdr {
*/
#define DHCP_MIN_LEN 552
-/** Maximum time that we will wait for ProxyDHCP responses */
-#define PROXYDHCP_WAIT_TIME ( TICKS_PER_SEC * 1 )
-
/** Timeouts for sending DHCP packets */
#define DHCP_MIN_TIMEOUT ( 1 * TICKS_PER_SEC )
#define DHCP_MAX_TIMEOUT ( 10 * TICKS_PER_SEC )
+/** Maximum time that we will wait for ProxyDHCP responses */
+#define PROXYDHCP_MAX_TIMEOUT ( 2 * TICKS_PER_SEC )
+
+/** Maximum time that we will wait for Boot Server responses */
+#define PXEBS_MAX_TIMEOUT ( 3 * TICKS_PER_SEC )
+
/** Settings block name used for DHCP responses */
#define DHCP_SETTINGS_NAME "dhcp"
/** Settings block name used for ProxyDHCP responses */
#define PROXYDHCP_SETTINGS_NAME "proxydhcp"
+/** Setting block name used for BootServerDHCP responses */
+#define PXEBS_SETTINGS_NAME "pxebs"
+
extern int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
struct net_device *netdev, uint8_t msgtype,
- struct dhcp_options *options,
+ const void *options, size_t options_len,
void *data, size_t max_len );
extern int dhcp_create_request ( struct dhcp_packet *dhcppkt,
struct net_device *netdev,
- struct in_addr ciaddr,
- struct dhcp_packet *dhcpoffer,
+ unsigned int msgtype, struct in_addr ciaddr,
void *data, size_t max_len );
extern int start_dhcp ( struct job_interface *job, struct net_device *netdev );
+extern int start_pxebs ( struct job_interface *job, struct net_device *netdev,
+ unsigned int pxe_type );
#endif /* _GPXE_DHCP_H */
diff --git a/gpxe/src/include/gpxe/dhcppkt.h b/gpxe/src/include/gpxe/dhcppkt.h
index 179be2f8..e8f8fafd 100644
--- a/gpxe/src/include/gpxe/dhcppkt.h
+++ b/gpxe/src/include/gpxe/dhcppkt.h
@@ -9,27 +9,54 @@
#include <gpxe/dhcp.h>
#include <gpxe/dhcpopts.h>
+#include <gpxe/refcnt.h>
/**
* A DHCP packet
*
*/
struct dhcp_packet {
+ /** Reference counter */
+ struct refcnt refcnt;
/** The DHCP packet contents */
struct dhcphdr *dhcphdr;
/** Maximum length of the DHCP packet buffer */
size_t max_len;
/** Used length of the DHCP packet buffer */
size_t len;
- /** DHCP option blocks */
+ /** DHCP options */
struct dhcp_options options;
+ /** Settings interface */
+ struct settings settings;
};
+/**
+ * Increment reference count on DHCP packet
+ *
+ * @v dhcppkt DHCP packet
+ * @ret dhcppkt DHCP packet
+ */
+static inline __attribute__ (( always_inline )) struct dhcp_packet *
+dhcppkt_get ( struct dhcp_packet *dhcppkt ) {
+ ref_get ( &dhcppkt->refcnt );
+ return dhcppkt;
+}
+
+/**
+ * Decrement reference count on DHCP packet
+ *
+ * @v dhcppkt DHCP packet
+ */
+static inline __attribute__ (( always_inline )) void
+dhcppkt_put ( struct dhcp_packet *dhcppkt ) {
+ ref_put ( &dhcppkt->refcnt );
+}
+
extern int dhcppkt_store ( struct dhcp_packet *dhcppkt, unsigned int tag,
const void *data, size_t len );
extern int dhcppkt_fetch ( struct dhcp_packet *dhcppkt, unsigned int tag,
void *data, size_t len );
extern void dhcppkt_init ( struct dhcp_packet *dhcppkt,
- void *data, size_t len );
+ struct dhcphdr *data, size_t len );
#endif /* _GPXE_DHCPPKT_H */
diff --git a/gpxe/src/include/gpxe/editbox.h b/gpxe/src/include/gpxe/editbox.h
index 47b07c25..007b042f 100644
--- a/gpxe/src/include/gpxe/editbox.h
+++ b/gpxe/src/include/gpxe/editbox.h
@@ -24,14 +24,22 @@ struct edit_box {
unsigned int width;
/** First displayed character */
unsigned int first;
+ /** Flags */
+ unsigned int flags;
+};
+
+/** Editable text box widget flags */
+enum edit_box_flags {
+ /** Show stars instead of contents (for password widgets) */
+ EDITBOX_STARS = 0x0001,
};
extern void init_editbox ( struct edit_box *box, char *buf, size_t len,
WINDOW *win, unsigned int row, unsigned int col,
- unsigned int width )
+ unsigned int width, unsigned int flags )
__attribute__ (( nonnull (1, 2) ));
extern void draw_editbox ( struct edit_box *box ) __nonnull;
-static inline int __pure edit_editbox ( struct edit_box *box, int key ) __nonnull;
+static inline int edit_editbox ( struct edit_box *box, int key ) __nonnull;
/**
* Edit text box widget
diff --git a/gpxe/src/include/gpxe/efi/Base.h b/gpxe/src/include/gpxe/efi/Base.h
new file mode 100644
index 00000000..b2552d80
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Base.h
@@ -0,0 +1,329 @@
+/** @file
+ Root include file for Mde Package Base type modules
+
+ This is the include file for any module of type base. Base modules only use
+ types defined via this include file and can be ported easily to any
+ environment. There are a set of base libraries in the Mde Package that can
+ be used to implement base modules.
+
+Copyright (c) 2006 - 2008, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#ifndef __BASE_H__
+#define __BASE_H__
+
+//
+// Include processor specific binding
+//
+#include <gpxe/efi/ProcessorBind.h>
+
+typedef struct {
+ UINT32 Data1;
+ UINT16 Data2;
+ UINT16 Data3;
+ UINT8 Data4[8];
+} GUID;
+
+typedef UINT64 PHYSICAL_ADDRESS;
+
+///
+/// LIST_ENTRY definition
+///
+typedef struct _LIST_ENTRY LIST_ENTRY;
+
+struct _LIST_ENTRY {
+ LIST_ENTRY *ForwardLink;
+ LIST_ENTRY *BackLink;
+};
+
+//
+// Modifiers to absract standard types to aid in debug of problems
+//
+#define CONST const
+#define STATIC static
+#define VOID void
+
+//
+// Modifiers for Data Types used to self document code.
+// This concept is borrowed for UEFI specification.
+//
+#define IN
+#define OUT
+#define OPTIONAL
+
+//
+// UEFI specification claims 1 and 0. We are concerned about the
+// complier portability so we did it this way.
+//
+#define TRUE ((BOOLEAN)(1==1))
+#define FALSE ((BOOLEAN)(0==1))
+
+#define NULL ((VOID *) 0)
+
+#define BIT0 0x00000001
+#define BIT1 0x00000002
+#define BIT2 0x00000004
+#define BIT3 0x00000008
+#define BIT4 0x00000010
+#define BIT5 0x00000020
+#define BIT6 0x00000040
+#define BIT7 0x00000080
+#define BIT8 0x00000100
+#define BIT9 0x00000200
+#define BIT10 0x00000400
+#define BIT11 0x00000800
+#define BIT12 0x00001000
+#define BIT13 0x00002000
+#define BIT14 0x00004000
+#define BIT15 0x00008000
+#define BIT16 0x00010000
+#define BIT17 0x00020000
+#define BIT18 0x00040000
+#define BIT19 0x00080000
+#define BIT20 0x00100000
+#define BIT21 0x00200000
+#define BIT22 0x00400000
+#define BIT23 0x00800000
+#define BIT24 0x01000000
+#define BIT25 0x02000000
+#define BIT26 0x04000000
+#define BIT27 0x08000000
+#define BIT28 0x10000000
+#define BIT29 0x20000000
+#define BIT30 0x40000000
+#define BIT31 0x80000000
+#define BIT32 0x0000000100000000UL
+#define BIT33 0x0000000200000000UL
+#define BIT34 0x0000000400000000UL
+#define BIT35 0x0000000800000000UL
+#define BIT36 0x0000001000000000UL
+#define BIT37 0x0000002000000000UL
+#define BIT38 0x0000004000000000UL
+#define BIT39 0x0000008000000000UL
+#define BIT40 0x0000010000000000UL
+#define BIT41 0x0000020000000000UL
+#define BIT42 0x0000040000000000UL
+#define BIT43 0x0000080000000000UL
+#define BIT44 0x0000100000000000UL
+#define BIT45 0x0000200000000000UL
+#define BIT46 0x0000400000000000UL
+#define BIT47 0x0000800000000000UL
+#define BIT48 0x0001000000000000UL
+#define BIT49 0x0002000000000000UL
+#define BIT50 0x0004000000000000UL
+#define BIT51 0x0008000000000000UL
+#define BIT52 0x0010000000000000UL
+#define BIT53 0x0020000000000000UL
+#define BIT54 0x0040000000000000UL
+#define BIT55 0x0080000000000000UL
+#define BIT56 0x0100000000000000UL
+#define BIT57 0x0200000000000000UL
+#define BIT58 0x0400000000000000UL
+#define BIT59 0x0800000000000000UL
+#define BIT60 0x1000000000000000UL
+#define BIT61 0x2000000000000000UL
+#define BIT62 0x4000000000000000UL
+#define BIT63 0x8000000000000000UL
+
+//
+// Support for variable length argument lists using the ANSI standard.
+//
+// Since we are using the ANSI standard we used the standard nameing and
+// did not folow the coding convention
+//
+// VA_LIST - typedef for argument list.
+// VA_START (VA_LIST Marker, argument before the ...) - Init Marker for use.
+// VA_END (VA_LIST Marker) - Clear Marker
+// VA_ARG (VA_LIST Marker, var arg size) - Use Marker to get an argumnet from
+// the ... list. You must know the size and pass it in this macro.
+//
+// example:
+//
+// UINTN
+// ExampleVarArg (
+// IN UINTN NumberOfArgs,
+// ...
+// )
+// {
+// VA_LIST Marker;
+// UINTN Index;
+// UINTN Result;
+//
+// //
+// // Initialize the Marker
+// //
+// VA_START (Marker, NumberOfArgs);
+// for (Index = 0, Result = 0; Index < NumberOfArgs; Index++) {
+// //
+// // The ... list is a series of UINTN values, so average them up.
+// //
+// Result += VA_ARG (Marker, UINTN);
+// }
+//
+// VA_END (Marker);
+// return Result
+// }
+//
+
+#define _INT_SIZE_OF(n) ((sizeof (n) + sizeof (UINTN) - 1) &~(sizeof (UINTN) - 1))
+
+//
+// Also support coding convention rules for var arg macros
+//
+typedef CHAR8 *VA_LIST;
+#define VA_START(ap, v) (ap = (VA_LIST) & (v) + _INT_SIZE_OF (v))
+#define VA_ARG(ap, t) (*(t *) ((ap += _INT_SIZE_OF (t)) - _INT_SIZE_OF (t)))
+#define VA_END(ap) (ap = (VA_LIST) 0)
+
+//
+// Macro that returns the byte offset of a field in a data structure.
+//
+#define OFFSET_OF(TYPE, Field) ((UINTN) &(((TYPE *)0)->Field))
+
+///
+/// CONTAINING_RECORD - returns a pointer to the structure
+/// from one of it's elements.
+///
+#define _CR(Record, TYPE, Field) ((TYPE *) ((CHAR8 *) (Record) - (CHAR8 *) &(((TYPE *) 0)->Field)))
+
+///
+/// ALIGN_VALUE - aligns a value up to the next boundary of the given alignment.
+///
+#define ALIGN_VALUE(Value, Alignment) ((Value) + (((Alignment) - (Value)) & ((Alignment) - 1)))
+
+///
+/// ALIGN_POINTER - aligns a pointer to the lowest boundry
+///
+#define ALIGN_POINTER(Pointer, Alignment) ((VOID *) (ALIGN_VALUE ((UINTN)(Pointer), (Alignment))))
+
+///
+/// ALIGN_VARIABLE - aligns a variable up to the next natural boundry for int size of a processor
+///
+#define ALIGN_VARIABLE(Value) ALIGN_VALUE ((Value), sizeof (UINTN))
+
+
+//
+// Return the maximum of two operands.
+// This macro returns the maximum of two operand specified by a and b.
+// Both a and b must be the same numerical types, signed or unsigned.
+//
+#define MAX(a, b) \
+ (((a) > (b)) ? (a) : (b))
+
+
+//
+// Return the minimum of two operands.
+// This macro returns the minimal of two operand specified by a and b.
+// Both a and b must be the same numerical types, signed or unsigned.
+//
+#define MIN(a, b) \
+ (((a) < (b)) ? (a) : (b))
+
+
+//
+// EFI Error Codes common to all execution phases
+//
+
+typedef INTN RETURN_STATUS;
+
+///
+/// Set the upper bit to indicate EFI Error.
+///
+#define ENCODE_ERROR(a) (MAX_BIT | (a))
+
+#define ENCODE_WARNING(a) (a)
+#define RETURN_ERROR(a) ((INTN) (a) < 0)
+
+#define RETURN_SUCCESS 0
+#define RETURN_LOAD_ERROR ENCODE_ERROR (1)
+#define RETURN_INVALID_PARAMETER ENCODE_ERROR (2)
+#define RETURN_UNSUPPORTED ENCODE_ERROR (3)
+#define RETURN_BAD_BUFFER_SIZE ENCODE_ERROR (4)
+#define RETURN_BUFFER_TOO_SMALL ENCODE_ERROR (5)
+#define RETURN_NOT_READY ENCODE_ERROR (6)
+#define RETURN_DEVICE_ERROR ENCODE_ERROR (7)
+#define RETURN_WRITE_PROTECTED ENCODE_ERROR (8)
+#define RETURN_OUT_OF_RESOURCES ENCODE_ERROR (9)
+#define RETURN_VOLUME_CORRUPTED ENCODE_ERROR (10)
+#define RETURN_VOLUME_FULL ENCODE_ERROR (11)
+#define RETURN_NO_MEDIA ENCODE_ERROR (12)
+#define RETURN_MEDIA_CHANGED ENCODE_ERROR (13)
+#define RETURN_NOT_FOUND ENCODE_ERROR (14)
+#define RETURN_ACCESS_DENIED ENCODE_ERROR (15)
+#define RETURN_NO_RESPONSE ENCODE_ERROR (16)
+#define RETURN_NO_MAPPING ENCODE_ERROR (17)
+#define RETURN_TIMEOUT ENCODE_ERROR (18)
+#define RETURN_NOT_STARTED ENCODE_ERROR (19)
+#define RETURN_ALREADY_STARTED ENCODE_ERROR (20)
+#define RETURN_ABORTED ENCODE_ERROR (21)
+#define RETURN_ICMP_ERROR ENCODE_ERROR (22)
+#define RETURN_TFTP_ERROR ENCODE_ERROR (23)
+#define RETURN_PROTOCOL_ERROR ENCODE_ERROR (24)
+#define RETURN_INCOMPATIBLE_VERSION ENCODE_ERROR (25)
+#define RETURN_SECURITY_VIOLATION ENCODE_ERROR (26)
+#define RETURN_CRC_ERROR ENCODE_ERROR (27)
+#define RETURN_END_OF_MEDIA ENCODE_ERROR (28)
+#define RETURN_END_OF_FILE ENCODE_ERROR (31)
+#define RETURN_INVALID_LANGUAGE ENCODE_ERROR (32)
+
+
+#define RETURN_WARN_UNKNOWN_GLYPH ENCODE_WARNING (1)
+#define RETURN_WARN_DELETE_FAILURE ENCODE_WARNING (2)
+#define RETURN_WARN_WRITE_FAILURE ENCODE_WARNING (3)
+#define RETURN_WARN_BUFFER_TOO_SMALL ENCODE_WARNING (4)
+
+/**
+ Returns a 16-bit signature built from 2 ASCII characters.
+
+ @param A The first ASCII character.
+ @param B The second ASCII character.
+
+ @return A 16-bit value built from the two ASCII characters specified by A and B.
+
+**/
+#define SIGNATURE_16(A, B) ((A) | (B << 8))
+
+/**
+ Returns a 32-bit signature built from 4 ASCII characters.
+
+ @param A The first ASCII character.
+ @param B The second ASCII character.
+ @param C The third ASCII character.
+ @param D The fourth ASCII character.
+
+ @return A 32-bit value built from the two ASCII characters specified by A, B,
+ C and D.
+
+**/
+#define SIGNATURE_32(A, B, C, D) (SIGNATURE_16 (A, B) | (SIGNATURE_16 (C, D) << 16))
+
+/**
+ Returns a 64-bit signature built from 8 ASCII characters.
+
+ @param A The first ASCII character.
+ @param B The second ASCII character.
+ @param C The third ASCII character.
+ @param D The fourth ASCII character.
+ @param E The fifth ASCII character.
+ @param F The sixth ASCII character.
+ @param G The seventh ASCII character.
+ @param H The eighth ASCII character.
+
+ @return A 64-bit value built from the two ASCII characters specified by A, B,
+ C, D, E, F, G and H.
+
+**/
+#define SIGNATURE_64(A, B, C, D, E, F, G, H) \
+ (SIGNATURE_32 (A, B, C, D) | ((UINT64) (SIGNATURE_32 (E, F, G, H)) << 32))
+
+#endif
+
diff --git a/gpxe/src/include/gpxe/efi/Guid/PcAnsi.h b/gpxe/src/include/gpxe/efi/Guid/PcAnsi.h
new file mode 100644
index 00000000..1dab3109
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Guid/PcAnsi.h
@@ -0,0 +1,58 @@
+/** @file
+ Terminal Device Path Vendor Guid.
+
+ Copyright (c) 2006, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+ @par Revision Reference:
+ GUIDs defined in UEFI 2.0 spec.
+
+**/
+
+#ifndef __PC_ANSI_H__
+#define __PC_ANSI_H__
+
+#define EFI_PC_ANSI_GUID \
+ { \
+ 0xe0c14753, 0xf9be, 0x11d2, {0x9a, 0x0c, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \
+ }
+
+#define EFI_VT_100_GUID \
+ { \
+ 0xdfa66065, 0xb419, 0x11d3, {0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \
+ }
+
+#define EFI_VT_100_PLUS_GUID \
+ { \
+ 0x7baec70b, 0x57e0, 0x4c76, {0x8e, 0x87, 0x2f, 0x9e, 0x28, 0x08, 0x83, 0x43 } \
+ }
+
+#define EFI_VT_UTF8_GUID \
+ { \
+ 0xad15a0d6, 0x8bec, 0x4acf, {0xa0, 0x73, 0xd0, 0x1d, 0xe7, 0x7e, 0x2d, 0x88 } \
+ }
+
+#define EFI_UART_DEVICE_PATH_GUID \
+ { \
+ 0x37499a9d, 0x542f, 0x4c89, {0xa0, 0x26, 0x35, 0xda, 0x14, 0x20, 0x94, 0xe4 } \
+ }
+
+#define EFI_SAS_DEVICE_PATH_GUID \
+ { \
+ 0xd487ddb4, 0x008b, 0x11d9, {0xaf, 0xdc, 0x00, 0x10, 0x83, 0xff, 0xca, 0x4d } \
+ }
+
+extern EFI_GUID gEfiPcAnsiGuid;
+extern EFI_GUID gEfiVT100Guid;
+extern EFI_GUID gEfiVT100PlusGuid;
+extern EFI_GUID gEfiVTUTF8Guid;
+extern EFI_GUID gEfiUartDevicePathGuid;
+extern EFI_GUID gEfiSasDevicePathGuid;
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Guid/SmBios.h b/gpxe/src/include/gpxe/efi/Guid/SmBios.h
new file mode 100644
index 00000000..c6c7f776
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Guid/SmBios.h
@@ -0,0 +1,34 @@
+/** @file
+ GUIDs used to locate the SMBIOS tables in the UEFI 2.0 system table.
+
+ This GUID in the system table is the only legal way to search for and
+ locate the SMBIOS tables. Do not search the 0xF0000 segment to find SMBIOS
+ tables.
+
+ Copyright (c) 2006, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+ @par Revision Reference:
+ GUIDs defined in UEFI 2.0 spec.
+
+**/
+
+#ifndef __SMBIOS_GUID_H__
+#define __SMBIOS_GUID_H__
+
+#define EFI_SMBIOS_TABLE_GUID \
+ { \
+ 0xeb9d2d31, 0x2d88, 0x11d3, {0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \
+ }
+
+#define SMBIOS_TABLE_GUID EFI_SMBIOS_TABLE_GUID
+
+extern EFI_GUID gEfiSmbiosTableGuid;
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Ia32/ProcessorBind.h b/gpxe/src/include/gpxe/efi/Ia32/ProcessorBind.h
new file mode 100644
index 00000000..5a3a9182
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Ia32/ProcessorBind.h
@@ -0,0 +1,215 @@
+/** @file
+ Processor or Compiler specific defines and types for Ia32 architecture.
+
+ Copyright (c) 2006, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __PROCESSOR_BIND_H__
+#define __PROCESSOR_BIND_H__
+
+///
+/// Define the processor type so other code can make processor based choices
+///
+#define MDE_CPU_IA32
+
+//
+// Make sure we are useing the correct packing rules per EFI specification
+//
+#ifndef __GNUC__
+#pragma pack()
+#endif
+
+#if __INTEL_COMPILER
+//
+// Disable ICC's remark #869: "Parameter" was never referenced warning.
+// This is legal ANSI C code so we disable the remark that is turned on with -Wall
+//
+#pragma warning ( disable : 869 )
+
+//
+// Disable ICC's remark #1418: external function definition with no prior declaration.
+// This is legal ANSI C code so we disable the remark that is turned on with /W4
+//
+#pragma warning ( disable : 1418 )
+
+//
+// Disable ICC's remark #1419: external declaration in primary source file
+// This is legal ANSI C code so we disable the remark that is turned on with /W4
+//
+#pragma warning ( disable : 1419 )
+
+#endif
+
+
+#if _MSC_EXTENSIONS
+
+//
+// Disable warning that make it impossible to compile at /W4
+// This only works for Microsoft* tools
+//
+
+//
+// Disabling bitfield type checking warnings.
+//
+#pragma warning ( disable : 4214 )
+
+//
+// Disabling the unreferenced formal parameter warnings.
+//
+#pragma warning ( disable : 4100 )
+
+//
+// Disable slightly different base types warning as CHAR8 * can not be set
+// to a constant string.
+//
+#pragma warning ( disable : 4057 )
+
+//
+// ASSERT(FALSE) or while (TRUE) are legal constructes so supress this warning
+//
+#pragma warning ( disable : 4127 )
+
+//
+// This warning is caused by functions defined but not used. For precompiled header only.
+//
+#pragma warning ( disable : 4505 )
+
+//
+// This warning is caused by empty (after preprocessing) souce file. For precompiled header only.
+//
+#pragma warning ( disable : 4206 )
+
+#endif
+
+
+#if !defined(__GNUC__) && (__STDC_VERSION__ < 199901L)
+ //
+ // No ANSI C 2000 stdint.h integer width declarations, so define equivalents
+ //
+
+ #if _MSC_EXTENSIONS
+
+ //
+ // use Microsoft* C complier dependent interger width types
+ //
+ typedef unsigned __int64 UINT64;
+ typedef __int64 INT64;
+ typedef unsigned __int32 UINT32;
+ typedef __int32 INT32;
+ typedef unsigned short UINT16;
+ typedef unsigned short CHAR16;
+ typedef short INT16;
+ typedef unsigned char BOOLEAN;
+ typedef unsigned char UINT8;
+ typedef char CHAR8;
+ typedef char INT8;
+ #else
+
+ //
+ // Assume standard IA-32 alignment.
+ // Need to check portability of long long
+ //
+ typedef unsigned long long UINT64;
+ typedef long long INT64;
+ typedef unsigned int UINT32;
+ typedef int INT32;
+ typedef unsigned short UINT16;
+ typedef unsigned short CHAR16;
+ typedef short INT16;
+ typedef unsigned char BOOLEAN;
+ typedef unsigned char UINT8;
+ typedef char CHAR8;
+ typedef char INT8;
+ #endif
+
+ #define UINT8_MAX 0xff
+
+#else
+ //
+ // Use ANSI C 2000 stdint.h integer width declarations
+ //
+ #include "stdint.h"
+ typedef uint8_t BOOLEAN;
+ typedef int8_t INT8;
+ typedef uint8_t UINT8;
+ typedef int16_t INT16;
+ typedef uint16_t UINT16;
+ typedef int32_t INT32;
+ typedef uint32_t UINT32;
+ typedef int64_t INT64;
+ typedef uint64_t UINT64;
+ typedef char CHAR8;
+ typedef uint16_t CHAR16;
+
+#endif
+
+typedef UINT32 UINTN;
+typedef INT32 INTN;
+
+
+///
+/// Processor specific defines
+///
+#define MAX_BIT 0x80000000
+#define MAX_2_BITS 0xC0000000
+
+///
+/// Maximum legal IA-32 address
+///
+#define MAX_ADDRESS 0xFFFFFFFF
+
+///
+/// The stack alignment required for IA-32
+///
+#define CPU_STACK_ALIGNMENT sizeof(UINTN)
+
+//
+// Modifier to ensure that all protocol member functions and EFI intrinsics
+// use the correct C calling convention. All protocol member functions and
+// EFI intrinsics are required to modify thier member functions with EFIAPI.
+//
+#if _MSC_EXTENSIONS
+ ///
+ /// Microsoft* compiler requires _EFIAPI useage, __cdecl is Microsoft* specific C.
+ ///
+ #define EFIAPI __cdecl
+#else
+ #if __GNUC__
+ #define EFIAPI __attribute__((cdecl,regparm(0)))
+ #endif
+#endif
+
+//
+// The Microsoft* C compiler can removed references to unreferenced data items
+// if the /OPT:REF linker option is used. We defined a macro as this is a
+// a non standard extension
+//
+#if _MSC_EXTENSIONS
+ #define GLOBAL_REMOVE_IF_UNREFERENCED __declspec(selectany)
+#else
+ #define GLOBAL_REMOVE_IF_UNREFERENCED
+#endif
+
+//
+// For symbol name in GNU assembly code, an extra "_" is necessary
+//
+#if __GNUC__
+ #if defined(linux)
+ #define ASM_PFX(name) name
+ #else
+ #define ASM_PFX(name) _##name
+ #endif
+#endif
+
+#define FUNCTION_ENTRY_POINT(p) (p)
+
+#endif
+
diff --git a/gpxe/src/include/gpxe/efi/IndustryStandard/Pci22.h b/gpxe/src/include/gpxe/efi/IndustryStandard/Pci22.h
new file mode 100644
index 00000000..5b96a56d
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/IndustryStandard/Pci22.h
@@ -0,0 +1,601 @@
+/** @file
+ Support for PCI 2.2 standard.
+
+ This file includes the definitions in the following specifications,
+ PCI Local Bus Specification, 2.0
+ PCI-to-PCI Bridge Architecture Specification,
+ PC Card Standard, 8.0
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _PCI22_H_
+#define _PCI22_H_
+
+#define PCI_MAX_SEGMENT 0
+#define PCI_MAX_BUS 255
+#define PCI_MAX_DEVICE 31
+#define PCI_MAX_FUNC 7
+
+
+#pragma pack(1)
+typedef struct {
+ UINT16 VendorId;
+ UINT16 DeviceId;
+ UINT16 Command;
+ UINT16 Status;
+ UINT8 RevisionID;
+ UINT8 ClassCode[3];
+ UINT8 CacheLineSize;
+ UINT8 LatencyTimer;
+ UINT8 HeaderType;
+ UINT8 BIST;
+} PCI_DEVICE_INDEPENDENT_REGION;
+
+typedef struct {
+ UINT32 Bar[6];
+ UINT32 CISPtr;
+ UINT16 SubsystemVendorID;
+ UINT16 SubsystemID;
+ UINT32 ExpansionRomBar;
+ UINT8 CapabilityPtr;
+ UINT8 Reserved1[3];
+ UINT32 Reserved2;
+ UINT8 InterruptLine;
+ UINT8 InterruptPin;
+ UINT8 MinGnt;
+ UINT8 MaxLat;
+} PCI_DEVICE_HEADER_TYPE_REGION;
+
+typedef struct {
+ PCI_DEVICE_INDEPENDENT_REGION Hdr;
+ PCI_DEVICE_HEADER_TYPE_REGION Device;
+} PCI_TYPE00;
+
+///
+/// defined in PCI-to-PCI Bridge Architecture Specification
+///
+typedef struct {
+ UINT32 Bar[2];
+ UINT8 PrimaryBus;
+ UINT8 SecondaryBus;
+ UINT8 SubordinateBus;
+ UINT8 SecondaryLatencyTimer;
+ UINT8 IoBase;
+ UINT8 IoLimit;
+ UINT16 SecondaryStatus;
+ UINT16 MemoryBase;
+ UINT16 MemoryLimit;
+ UINT16 PrefetchableMemoryBase;
+ UINT16 PrefetchableMemoryLimit;
+ UINT32 PrefetchableBaseUpper32;
+ UINT32 PrefetchableLimitUpper32;
+ UINT16 IoBaseUpper16;
+ UINT16 IoLimitUpper16;
+ UINT8 CapabilityPtr;
+ UINT8 Reserved[3];
+ UINT32 ExpansionRomBAR;
+ UINT8 InterruptLine;
+ UINT8 InterruptPin;
+ UINT16 BridgeControl;
+} PCI_BRIDGE_CONTROL_REGISTER;
+
+typedef struct {
+ PCI_DEVICE_INDEPENDENT_REGION Hdr;
+ PCI_BRIDGE_CONTROL_REGISTER Bridge;
+} PCI_TYPE01;
+
+typedef union {
+ PCI_TYPE00 Device;
+ PCI_TYPE01 Bridge;
+} PCI_TYPE_GENERIC;
+
+///
+/// CardBus Conroller Configuration Space, defined in PC Card Standard. 8.0
+///
+typedef struct {
+ UINT32 CardBusSocketReg; ///< Cardus Socket/ExCA Base
+ UINT8 Cap_Ptr;
+ UINT8 Reserved;
+ UINT16 SecondaryStatus; ///< Secondary Status
+ UINT8 PciBusNumber; ///< PCI Bus Number
+ UINT8 CardBusBusNumber; ///< CardBus Bus Number
+ UINT8 SubordinateBusNumber; ///< Subordinate Bus Number
+ UINT8 CardBusLatencyTimer; ///< CardBus Latency Timer
+ UINT32 MemoryBase0; ///< Memory Base Register 0
+ UINT32 MemoryLimit0; ///< Memory Limit Register 0
+ UINT32 MemoryBase1;
+ UINT32 MemoryLimit1;
+ UINT32 IoBase0;
+ UINT32 IoLimit0; ///< I/O Base Register 0
+ UINT32 IoBase1; ///< I/O Limit Register 0
+ UINT32 IoLimit1;
+ UINT8 InterruptLine; ///< Interrupt Line
+ UINT8 InterruptPin; ///< Interrupt Pin
+ UINT16 BridgeControl; ///< Bridge Control
+} PCI_CARDBUS_CONTROL_REGISTER;
+
+///
+/// Definitions of PCI class bytes and manipulation macros.
+///
+#define PCI_CLASS_OLD 0x00
+#define PCI_CLASS_OLD_OTHER 0x00
+#define PCI_CLASS_OLD_VGA 0x01
+
+#define PCI_CLASS_MASS_STORAGE 0x01
+#define PCI_CLASS_MASS_STORAGE_SCSI 0x00
+#define PCI_CLASS_MASS_STORAGE_IDE 0x01
+#define PCI_CLASS_MASS_STORAGE_FLOPPY 0x02
+#define PCI_CLASS_MASS_STORAGE_IPI 0x03
+#define PCI_CLASS_MASS_STORAGE_RAID 0x04
+#define PCI_CLASS_MASS_STORAGE_OTHER 0x80
+
+#define PCI_CLASS_NETWORK 0x02
+#define PCI_CLASS_NETWORK_ETHERNET 0x00
+#define PCI_CLASS_NETWORK_TOKENRING 0x01
+#define PCI_CLASS_NETWORK_FDDI 0x02
+#define PCI_CLASS_NETWORK_ATM 0x03
+#define PCI_CLASS_NETWORK_ISDN 0x04
+#define PCI_CLASS_NETWORK_OTHER 0x80
+
+#define PCI_CLASS_DISPLAY 0x03
+#define PCI_CLASS_DISPLAY_VGA 0x00
+#define PCI_IF_VGA_VGA 0x00
+#define PCI_IF_VGA_8514 0x01
+#define PCI_CLASS_DISPLAY_XGA 0x01
+#define PCI_CLASS_DISPLAY_3D 0x02
+#define PCI_CLASS_DISPLAY_OTHER 0x80
+#define PCI_CLASS_DISPLAY_GFX 0x80
+
+#define PCI_CLASS_MEDIA 0x04
+#define PCI_CLASS_MEDIA_VIDEO 0x00
+#define PCI_CLASS_MEDIA_AUDIO 0x01
+#define PCI_CLASS_MEDIA_TELEPHONE 0x02
+#define PCI_CLASS_MEDIA_OTHER 0x80
+
+#define PCI_CLASS_MEMORY_CONTROLLER 0x05
+#define PCI_CLASS_MEMORY_RAM 0x00
+#define PCI_CLASS_MEMORY_FLASH 0x01
+#define PCI_CLASS_MEMORY_OTHER 0x80
+
+#define PCI_CLASS_BRIDGE 0x06
+#define PCI_CLASS_BRIDGE_HOST 0x00
+#define PCI_CLASS_BRIDGE_ISA 0x01
+#define PCI_CLASS_BRIDGE_EISA 0x02
+#define PCI_CLASS_BRIDGE_MCA 0x03
+#define PCI_CLASS_BRIDGE_P2P 0x04
+#define PCI_IF_BRIDGE_P2P 0x00
+#define PCI_IF_BRIDGE_P2P_SUBTRACTIVE 0x01
+#define PCI_CLASS_BRIDGE_PCMCIA 0x05
+#define PCI_CLASS_BRIDGE_NUBUS 0x06
+#define PCI_CLASS_BRIDGE_CARDBUS 0x07
+#define PCI_CLASS_BRIDGE_RACEWAY 0x08
+#define PCI_CLASS_BRIDGE_OTHER 0x80
+#define PCI_CLASS_BRIDGE_ISA_PDECODE 0x80
+
+#define PCI_CLASS_SCC 0x07 ///< Simple communications controllers
+#define PCI_SUBCLASS_SERIAL 0x00
+#define PCI_IF_GENERIC_XT 0x00
+#define PCI_IF_16450 0x01
+#define PCI_IF_16550 0x02
+#define PCI_IF_16650 0x03
+#define PCI_IF_16750 0x04
+#define PCI_IF_16850 0x05
+#define PCI_IF_16950 0x06
+#define PCI_SUBCLASS_PARALLEL 0x01
+#define PCI_IF_PARALLEL_PORT 0x00
+#define PCI_IF_BI_DIR_PARALLEL_PORT 0x01
+#define PCI_IF_ECP_PARALLEL_PORT 0x02
+#define PCI_IF_1284_CONTROLLER 0x03
+#define PCI_IF_1284_DEVICE 0xFE
+#define PCI_SUBCLASS_MULTIPORT_SERIAL 0x02
+#define PCI_SUBCLASS_MODEM 0x03
+#define PCI_IF_GENERIC_MODEM 0x00
+#define PCI_IF_16450_MODEM 0x01
+#define PCI_IF_16550_MODEM 0x02
+#define PCI_IF_16650_MODEM 0x03
+#define PCI_IF_16750_MODEM 0x04
+#define PCI_SUBCLASS_SCC_OTHER 0x80
+
+#define PCI_CLASS_SYSTEM_PERIPHERAL 0x08
+#define PCI_SUBCLASS_PIC 0x00
+#define PCI_IF_8259_PIC 0x00
+#define PCI_IF_ISA_PIC 0x01
+#define PCI_IF_EISA_PIC 0x02
+#define PCI_IF_APIC_CONTROLLER 0x10 ///< I/O APIC interrupt controller , 32 bye none-prefectable memory.
+#define PCI_IF_APIC_CONTROLLER2 0x20
+#define PCI_SUBCLASS_DMA 0x01
+#define PCI_IF_8237_DMA 0x00
+#define PCI_IF_ISA_DMA 0x01
+#define PCI_IF_EISA_DMA 0x02
+#define PCI_SUBCLASS_TIMER 0x02
+#define PCI_IF_8254_TIMER 0x00
+#define PCI_IF_ISA_TIMER 0x01
+#define PCI_IF_EISA_TIMER 0x02
+#define PCI_SUBCLASS_RTC 0x03
+#define PCI_IF_GENERIC_RTC 0x00
+#define PCI_IF_ISA_RTC 0x00
+#define PCI_SUBCLASS_PNP_CONTROLLER 0x04 ///< HotPlug Controller
+#define PCI_SUBCLASS_PERIPHERAL_OTHER 0x80
+
+#define PCI_CLASS_INPUT_DEVICE 0x09
+#define PCI_SUBCLASS_KEYBOARD 0x00
+#define PCI_SUBCLASS_PEN 0x01
+#define PCI_SUBCLASS_MOUSE_CONTROLLER 0x02
+#define PCI_SUBCLASS_SCAN_CONTROLLER 0x03
+#define PCI_SUBCLASS_GAMEPORT 0x04
+#define PCI_IF_GAMEPORT 0x00
+#define PCI_IF_GAMEPORT1 0x01
+#define PCI_SUBCLASS_INPUT_OTHER 0x80
+
+#define PCI_CLASS_DOCKING_STATION 0x0A
+
+#define PCI_CLASS_PROCESSOR 0x0B
+#define PCI_SUBCLASS_PROC_386 0x00
+#define PCI_SUBCLASS_PROC_486 0x01
+#define PCI_SUBCLASS_PROC_PENTIUM 0x02
+#define PCI_SUBCLASS_PROC_ALPHA 0x10
+#define PCI_SUBCLASS_PROC_POWERPC 0x20
+#define PCI_SUBCLASS_PROC_MIPS 0x30
+#define PCI_SUBCLASS_PROC_CO_PORC 0x40 ///< Co-Processor
+
+#define PCI_CLASS_SERIAL 0x0C
+#define PCI_CLASS_SERIAL_FIREWIRE 0x00
+#define PCI_IF_1394 0x00
+#define PCI_IF_1394_OPEN_HCI 0x10
+#define PCI_CLASS_SERIAL_ACCESS_BUS 0x01
+#define PCI_CLASS_SERIAL_SSA 0x02
+#define PCI_CLASS_SERIAL_USB 0x03
+#define PCI_IF_UHCI 0x00
+#define PCI_IF_OHCI 0x10
+#define PCI_IF_USB_OTHER 0x80
+#define PCI_IF_USB_DEVICE 0xFE
+#define PCI_CLASS_SERIAL_FIBRECHANNEL 0x04
+#define PCI_CLASS_SERIAL_SMB 0x05
+
+#define PCI_CLASS_WIRELESS 0x0D
+#define PCI_SUBCLASS_IRDA 0x00
+#define PCI_SUBCLASS_IR 0x01
+#define PCI_SUBCLASS_RF 0x02
+#define PCI_SUBCLASS_WIRELESS_OTHER 0x80
+
+#define PCI_CLASS_INTELLIGENT_IO 0x0E
+
+#define PCI_CLASS_SATELLITE 0x0F
+#define PCI_SUBCLASS_TV 0x01
+#define PCI_SUBCLASS_AUDIO 0x02
+#define PCI_SUBCLASS_VOICE 0x03
+#define PCI_SUBCLASS_DATA 0x04
+
+#define PCI_SECURITY_CONTROLLER 0x10 ///< Encryption and decryption controller
+#define PCI_SUBCLASS_NET_COMPUT 0x00
+#define PCI_SUBCLASS_ENTERTAINMENT 0x10
+#define PCI_SUBCLASS_SECURITY_OTHER 0x80
+
+#define PCI_CLASS_DPIO 0x11
+#define PCI_SUBCLASS_DPIO 0x00
+#define PCI_SUBCLASS_DPIO_OTHER 0x80
+
+#define IS_CLASS1(_p, c) ((_p)->Hdr.ClassCode[2] == (c))
+#define IS_CLASS2(_p, c, s) (IS_CLASS1 (_p, c) && ((_p)->Hdr.ClassCode[1] == (s)))
+#define IS_CLASS3(_p, c, s, p) (IS_CLASS2 (_p, c, s) && ((_p)->Hdr.ClassCode[0] == (p)))
+
+#define IS_PCI_DISPLAY(_p) IS_CLASS1 (_p, PCI_CLASS_DISPLAY)
+#define IS_PCI_VGA(_p) IS_CLASS3 (_p, PCI_CLASS_DISPLAY, PCI_CLASS_DISPLAY_VGA, 0)
+#define IS_PCI_8514(_p) IS_CLASS3 (_p, PCI_CLASS_DISPLAY, PCI_CLASS_DISPLAY_VGA, 1)
+#define IS_PCI_GFX(_p) IS_CLASS3 (_p, PCI_CLASS_DISPLAY, PCI_CLASS_DISPLAY_GFX, 0)
+#define IS_PCI_OLD(_p) IS_CLASS1 (_p, PCI_CLASS_OLD)
+#define IS_PCI_OLD_VGA(_p) IS_CLASS2 (_p, PCI_CLASS_OLD, PCI_CLASS_OLD_VGA)
+#define IS_PCI_IDE(_p) IS_CLASS2 (_p, PCI_CLASS_MASS_STORAGE, PCI_CLASS_MASS_STORAGE_IDE)
+#define IS_PCI_SCSI(_p) IS_CLASS3 (_p, PCI_CLASS_MASS_STORAGE, PCI_CLASS_MASS_STORAGE_SCSI, 0)
+#define IS_PCI_RAID(_p) IS_CLASS3 (_p, PCI_CLASS_MASS_STORAGE, PCI_CLASS_MASS_STORAGE_RAID, 0)
+#define IS_PCI_LPC(_p) IS_CLASS3 (_p, PCI_CLASS_BRIDGE, PCI_CLASS_BRIDGE_ISA, 0)
+#define IS_PCI_P2P(_p) IS_CLASS3 (_p, PCI_CLASS_BRIDGE, PCI_CLASS_BRIDGE_P2P, 0)
+#define IS_PCI_P2P_SUB(_p) IS_CLASS3 (_p, PCI_CLASS_BRIDGE, PCI_CLASS_BRIDGE_P2P, 1)
+#define IS_PCI_16550_SERIAL(_p) IS_CLASS3 (_p, PCI_CLASS_SCC, PCI_SUBCLASS_SERIAL, PCI_IF_16550)
+#define IS_PCI_USB(_p) IS_CLASS2 (_p, PCI_CLASS_SERIAL, PCI_CLASS_SERIAL_USB)
+
+//
+// the definition of Header Type
+//
+#define HEADER_TYPE_DEVICE 0x00
+#define HEADER_TYPE_PCI_TO_PCI_BRIDGE 0x01
+#define HEADER_TYPE_CARDBUS_BRIDGE 0x02
+#define HEADER_TYPE_MULTI_FUNCTION 0x80
+//
+// Mask of Header type
+//
+#define HEADER_LAYOUT_CODE 0x7f
+
+#define IS_PCI_BRIDGE(_p) (((_p)->Hdr.HeaderType & HEADER_LAYOUT_CODE) == (HEADER_TYPE_PCI_TO_PCI_BRIDGE))
+#define IS_CARDBUS_BRIDGE(_p) (((_p)->Hdr.HeaderType & HEADER_LAYOUT_CODE) == (HEADER_TYPE_CARDBUS_BRIDGE))
+#define IS_PCI_MULTI_FUNC(_p) ((_p)->Hdr.HeaderType & HEADER_TYPE_MULTI_FUNCTION)
+
+///
+/// Rom Base Address in Bridge, defined in PCI-to-PCI Bridge Architecure Specification,
+///
+#define PCI_BRIDGE_ROMBAR 0x38
+
+#define PCI_MAX_BAR 0x0006
+#define PCI_MAX_CONFIG_OFFSET 0x0100
+
+#define PCI_VENDOR_ID_OFFSET 0x00
+#define PCI_DEVICE_ID_OFFSET 0x02
+#define PCI_COMMAND_OFFSET 0x04
+#define PCI_PRIMARY_STATUS_OFFSET 0x06
+#define PCI_REVISION_ID_OFFSET 0x08
+#define PCI_CLASSCODE_OFFSET 0x09
+#define PCI_CACHELINE_SIZE_OFFSET 0x0C
+#define PCI_LATENCY_TIMER_OFFSET 0x0D
+#define PCI_HEADER_TYPE_OFFSET 0x0E
+#define PCI_BIST_OFFSET 0x0F
+#define PCI_BASE_ADDRESSREG_OFFSET 0x10
+#define PCI_CARDBUS_CIS_OFFSET 0x28
+#define PCI_SVID_OFFSET 0x2C ///< SubSystem Vendor id
+#define PCI_SUBSYSTEM_VENDOR_ID_OFFSET 0x2C
+#define PCI_SID_OFFSET 0x2E ///< SubSystem ID
+#define PCI_SUBSYSTEM_ID_OFFSET 0x2E
+#define PCI_EXPANSION_ROM_BASE 0x30
+#define PCI_CAPBILITY_POINTER_OFFSET 0x34
+#define PCI_INT_LINE_OFFSET 0x3C ///< Interrupt Line Register
+#define PCI_INT_PIN_OFFSET 0x3D ///< Interrupt Pin Register
+#define PCI_MAXGNT_OFFSET 0x3E ///< Max Grant Register
+#define PCI_MAXLAT_OFFSET 0x3F ///< Max Latency Register
+
+///
+/// defined in PCI-to-PCI Bridge Architecture Specification
+///
+#define PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET 0x18
+#define PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET 0x19
+#define PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET 0x1a
+#define PCI_BRIDGE_STATUS_REGISTER_OFFSET 0x1E
+#define PCI_BRIDGE_CONTROL_REGISTER_OFFSET 0x3E
+
+///
+/// Interrupt Line "Unknown" or "No connection" value defined for x86 based system
+///
+#define PCI_INT_LINE_UNKNOWN 0xFF
+
+typedef union {
+ struct {
+ UINT32 Reg : 8;
+ UINT32 Func : 3;
+ UINT32 Dev : 5;
+ UINT32 Bus : 8;
+ UINT32 Reserved : 7;
+ UINT32 Enable : 1;
+ } Bits;
+ UINT32 Uint32;
+} PCI_CONFIG_ACCESS_CF8;
+
+#pragma pack()
+
+#define EFI_PCI_COMMAND_IO_SPACE BIT0 ///< 0x0001
+#define EFI_PCI_COMMAND_MEMORY_SPACE BIT1 ///< 0x0002
+#define EFI_PCI_COMMAND_BUS_MASTER BIT2 ///< 0x0004
+#define EFI_PCI_COMMAND_SPECIAL_CYCLE BIT3 ///< 0x0008
+#define EFI_PCI_COMMAND_MEMORY_WRITE_AND_INVALIDATE BIT4 ///< 0x0010
+#define EFI_PCI_COMMAND_VGA_PALETTE_SNOOP BIT5 ///< 0x0020
+#define EFI_PCI_COMMAND_PARITY_ERROR_RESPOND BIT6 ///< 0x0040
+#define EFI_PCI_COMMAND_STEPPING_CONTROL BIT7 ///< 0x0080
+#define EFI_PCI_COMMAND_SERR BIT8 ///< 0x0100
+#define EFI_PCI_COMMAND_FAST_BACK_TO_BACK BIT9 ///< 0x0200
+
+///
+/// defined in PCI-to-PCI Bridge Architecture Specification
+///
+#define EFI_PCI_BRIDGE_CONTROL_PARITY_ERROR_RESPONSE BIT0 ///< 0x0001
+#define EFI_PCI_BRIDGE_CONTROL_SERR BIT1 ///< 0x0002
+#define EFI_PCI_BRIDGE_CONTROL_ISA BIT2 ///< 0x0004
+#define EFI_PCI_BRIDGE_CONTROL_VGA BIT3 ///< 0x0008
+#define EFI_PCI_BRIDGE_CONTROL_VGA_16 BIT4 ///< 0x0010
+#define EFI_PCI_BRIDGE_CONTROL_MASTER_ABORT BIT5 ///< 0x0020
+#define EFI_PCI_BRIDGE_CONTROL_RESET_SECONDARY_BUS BIT6 ///< 0x0040
+#define EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK BIT7 ///< 0x0080
+#define EFI_PCI_BRIDGE_CONTROL_PRIMARY_DISCARD_TIMER BIT8 ///< 0x0100
+#define EFI_PCI_BRIDGE_CONTROL_SECONDARY_DISCARD_TIMER BIT9 ///< 0x0200
+#define EFI_PCI_BRIDGE_CONTROL_TIMER_STATUS BIT10 ///< 0x0400
+#define EFI_PCI_BRIDGE_CONTROL_DISCARD_TIMER_SERR BIT11 ///< 0x0800
+
+///
+/// Following are the PCI-CARDBUS bridge control bit, defined in PC Card Standard
+///
+#define EFI_PCI_BRIDGE_CONTROL_IREQINT_ENABLE BIT7 ///< 0x0080
+#define EFI_PCI_BRIDGE_CONTROL_RANGE0_MEMORY_TYPE BIT8 ///< 0x0100
+#define EFI_PCI_BRIDGE_CONTROL_RANGE1_MEMORY_TYPE BIT9 ///< 0x0200
+#define EFI_PCI_BRIDGE_CONTROL_WRITE_POSTING_ENABLE BIT10 ///< 0x0400
+
+//
+// Following are the PCI status control bit
+//
+#define EFI_PCI_STATUS_CAPABILITY BIT4 ///< 0x0010
+#define EFI_PCI_STATUS_66MZ_CAPABLE BIT5 ///< 0x0020
+#define EFI_PCI_FAST_BACK_TO_BACK_CAPABLE BIT7 ///< 0x0080
+#define EFI_PCI_MASTER_DATA_PARITY_ERROR BIT8 ///< 0x0100
+
+///
+/// defined in PC Card Standard
+///
+#define EFI_PCI_CARDBUS_BRIDGE_CAPABILITY_PTR 0x14
+
+#pragma pack(1)
+//
+// PCI Capability List IDs and records
+//
+#define EFI_PCI_CAPABILITY_ID_PMI 0x01
+#define EFI_PCI_CAPABILITY_ID_AGP 0x02
+#define EFI_PCI_CAPABILITY_ID_VPD 0x03
+#define EFI_PCI_CAPABILITY_ID_SLOTID 0x04
+#define EFI_PCI_CAPABILITY_ID_MSI 0x05
+#define EFI_PCI_CAPABILITY_ID_HOTPLUG 0x06
+typedef struct {
+ UINT8 CapabilityID;
+ UINT8 NextItemPtr;
+} EFI_PCI_CAPABILITY_HDR;
+
+///
+/// Capability EFI_PCI_CAPABILITY_ID_PMI, defined in PCI Power Management Interface Specifiction
+///
+typedef struct {
+ EFI_PCI_CAPABILITY_HDR Hdr;
+ UINT16 PMC;
+ UINT16 PMCSR;
+ UINT8 BridgeExtention;
+ UINT8 Data;
+} EFI_PCI_CAPABILITY_PMI;
+
+///
+/// Capability EFI_PCI_CAPABILITY_ID_AGP, defined in Accelerated Graphics Port Interface Specification
+///
+typedef struct {
+ EFI_PCI_CAPABILITY_HDR Hdr;
+ UINT8 Rev;
+ UINT8 Reserved;
+ UINT32 Status;
+ UINT32 Command;
+} EFI_PCI_CAPABILITY_AGP;
+
+///
+/// Capability EFI_PCI_CAPABILITY_ID_VPD, in PCI2.2 Spec.
+///
+typedef struct {
+ EFI_PCI_CAPABILITY_HDR Hdr;
+ UINT16 AddrReg;
+ UINT32 DataReg;
+} EFI_PCI_CAPABILITY_VPD;
+
+///
+/// Capability EFI_PCI_CAPABILITY_ID_SLOTID, defined in PCI-to-PCI Bridge Architeture Specification
+///
+typedef struct {
+ EFI_PCI_CAPABILITY_HDR Hdr;
+ UINT8 ExpnsSlotReg;
+ UINT8 ChassisNo;
+} EFI_PCI_CAPABILITY_SLOTID;
+
+///
+/// Capability EFI_PCI_CAPABILITY_ID_MSI, defined in PCI2.2
+///
+typedef struct {
+ EFI_PCI_CAPABILITY_HDR Hdr;
+ UINT16 MsgCtrlReg;
+ UINT32 MsgAddrReg;
+ UINT16 MsgDataReg;
+} EFI_PCI_CAPABILITY_MSI32;
+
+typedef struct {
+ EFI_PCI_CAPABILITY_HDR Hdr;
+ UINT16 MsgCtrlReg;
+ UINT32 MsgAddrRegLsdw;
+ UINT32 MsgAddrRegMsdw;
+ UINT16 MsgDataReg;
+} EFI_PCI_CAPABILITY_MSI64;
+
+///
+/// Capability EFI_PCI_CAPABILITY_ID_HOTPLUG, defined in CompactPCI Hot Swap Specification PICMG 2.1, R1.0
+///
+typedef struct {
+ EFI_PCI_CAPABILITY_HDR Hdr;
+ ///
+ /// not finished - fields need to go here
+ ///
+} EFI_PCI_CAPABILITY_HOTPLUG;
+
+#define DEVICE_ID_NOCARE 0xFFFF
+
+#define PCI_ACPI_UNUSED 0
+#define PCI_BAR_NOCHANGE 0
+#define PCI_BAR_OLD_ALIGN 0xFFFFFFFFFFFFFFFFULL
+#define PCI_BAR_EVEN_ALIGN 0xFFFFFFFFFFFFFFFEULL
+#define PCI_BAR_SQUAD_ALIGN 0xFFFFFFFFFFFFFFFDULL
+#define PCI_BAR_DQUAD_ALIGN 0xFFFFFFFFFFFFFFFCULL
+
+#define PCI_BAR_IDX0 0x00
+#define PCI_BAR_IDX1 0x01
+#define PCI_BAR_IDX2 0x02
+#define PCI_BAR_IDX3 0x03
+#define PCI_BAR_IDX4 0x04
+#define PCI_BAR_IDX5 0x05
+#define PCI_BAR_ALL 0xFF
+
+///
+/// EFI PCI Option ROM definitions
+///
+#define EFI_ROOT_BRIDGE_LIST 'eprb'
+#define EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE 0x0EF1 ///< defined in UEFI Spec.
+
+typedef struct {
+ UINT8 Register;
+ UINT8 Function;
+ UINT8 Device;
+ UINT8 Bus;
+ UINT8 Reserved[4];
+} DEFIO_PCI_ADDR;
+
+#define PCI_EXPANSION_ROM_HEADER_SIGNATURE 0xaa55
+#define PCI_DATA_STRUCTURE_SIGNATURE SIGNATURE_32 ('P', 'C', 'I', 'R')
+#define PCI_CODE_TYPE_PCAT_IMAGE 0x00
+#define EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED 0x0001 ///<defined in UEFI spec.
+
+typedef struct {
+ UINT16 Signature; ///< 0xaa55
+ UINT8 Reserved[0x16];
+ UINT16 PcirOffset;
+} PCI_EXPANSION_ROM_HEADER;
+
+typedef struct {
+ UINT16 Signature; ///< 0xaa55
+ UINT8 Size512;
+ UINT8 InitEntryPoint[3];
+ UINT8 Reserved[0x12];
+ UINT16 PcirOffset;
+} EFI_LEGACY_EXPANSION_ROM_HEADER;
+
+typedef struct {
+ UINT32 Signature; ///< "PCIR"
+ UINT16 VendorId;
+ UINT16 DeviceId;
+ UINT16 Reserved0;
+ UINT16 Length;
+ UINT8 Revision;
+ UINT8 ClassCode[3];
+ UINT16 ImageLength;
+ UINT16 CodeRevision;
+ UINT8 CodeType;
+ UINT8 Indicator;
+ UINT16 Reserved1;
+} PCI_DATA_STRUCTURE;
+
+///
+/// defined in EFI/UEFI Spec
+///
+typedef struct {
+ UINT16 Signature; ///< 0xaa55
+ UINT16 InitializationSize;
+ UINT32 EfiSignature; ///< 0x0EF1
+ UINT16 EfiSubsystem;
+ UINT16 EfiMachineType;
+ UINT16 CompressionType;
+ UINT8 Reserved[8];
+ UINT16 EfiImageHeaderOffset;
+ UINT16 PcirOffset;
+} EFI_PCI_EXPANSION_ROM_HEADER;
+
+typedef union {
+ UINT8 *Raw;
+ PCI_EXPANSION_ROM_HEADER *Generic;
+ EFI_PCI_EXPANSION_ROM_HEADER *Efi;
+ EFI_LEGACY_EXPANSION_ROM_HEADER *PcAt;
+} EFI_PCI_ROM_HEADER;
+
+#pragma pack()
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/IndustryStandard/PeImage.h b/gpxe/src/include/gpxe/efi/IndustryStandard/PeImage.h
new file mode 100644
index 00000000..73b3a5ad
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/IndustryStandard/PeImage.h
@@ -0,0 +1,752 @@
+/** @file
+ EFI image format for PE32, PE32+ and TE. Please note some data structures are
+ different for PE32 and PE32+. EFI_IMAGE_NT_HEADERS32 is for PE32 and
+ EFI_IMAGE_NT_HEADERS64 is for PE32+.
+
+ This file is coded to the Visual Studio, Microsoft Portable Executable and
+ Common Object File Format Specification, Revision 8.0 - May 16, 2006.
+ This file also includes some definitions in PI Specification, Revision 1.0.
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __PE_IMAGE_H__
+#define __PE_IMAGE_H__
+
+///
+/// PE32+ Subsystem type for EFI images
+///
+#define EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION 10
+#define EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11
+#define EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12
+#define EFI_IMAGE_SUBSYSTEM_EFI_EFI_ROM 13
+
+#define EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER 13 ///< defined PI Specification, 1.0
+
+
+///
+/// PE32+ Machine type for EFI images
+///
+#define IMAGE_FILE_MACHINE_I386 0x014c
+#define IMAGE_FILE_MACHINE_IA64 0x0200
+#define IMAGE_FILE_MACHINE_EBC 0x0EBC
+#define IMAGE_FILE_MACHINE_X64 0x8664
+//
+// Support old names for backward compatible
+//
+#define EFI_IMAGE_MACHINE_IA32 IMAGE_FILE_MACHINE_I386
+#define EFI_IMAGE_MACHINE_IA64 IMAGE_FILE_MACHINE_IA64
+#define EFI_IMAGE_MACHINE_IPF IMAGE_FILE_MACHINE_IA64
+#define EFI_IMAGE_MACHINE_EBC IMAGE_FILE_MACHINE_EBC
+#define EFI_IMAGE_MACHINE_X64 IMAGE_FILE_MACHINE_X64
+
+///
+/// EXE file formats
+///
+#define EFI_IMAGE_DOS_SIGNATURE SIGNATURE_16('M', 'Z')
+#define EFI_IMAGE_OS2_SIGNATURE SIGNATURE_16('N', 'E')
+#define EFI_IMAGE_OS2_SIGNATURE_LE SIGNATURE_16('L', 'E')
+#define EFI_IMAGE_NT_SIGNATURE SIGNATURE_32('P', 'E', '\0', '\0')
+
+///
+/// PE images can start with an optional DOS header, so if an image is run
+/// under DOS it can print an error message.
+///
+typedef struct {
+ UINT16 e_magic; ///< Magic number
+ UINT16 e_cblp; ///< Bytes on last page of file
+ UINT16 e_cp; ///< Pages in file
+ UINT16 e_crlc; ///< Relocations
+ UINT16 e_cparhdr; ///< Size of header in paragraphs
+ UINT16 e_minalloc; ///< Minimum extra paragraphs needed
+ UINT16 e_maxalloc; ///< Maximum extra paragraphs needed
+ UINT16 e_ss; ///< Initial (relative) SS value
+ UINT16 e_sp; ///< Initial SP value
+ UINT16 e_csum; ///< Checksum
+ UINT16 e_ip; ///< Initial IP value
+ UINT16 e_cs; ///< Initial (relative) CS value
+ UINT16 e_lfarlc; ///< File address of relocation table
+ UINT16 e_ovno; ///< Overlay number
+ UINT16 e_res[4]; ///< Reserved words
+ UINT16 e_oemid; ///< OEM identifier (for e_oeminfo)
+ UINT16 e_oeminfo; ///< OEM information; e_oemid specific
+ UINT16 e_res2[10]; ///< Reserved words
+ UINT32 e_lfanew; ///< File address of new exe header
+} EFI_IMAGE_DOS_HEADER;
+
+///
+/// COFF File Header (Object and Image)
+///
+typedef struct {
+ UINT16 Machine;
+ UINT16 NumberOfSections;
+ UINT32 TimeDateStamp;
+ UINT32 PointerToSymbolTable;
+ UINT32 NumberOfSymbols;
+ UINT16 SizeOfOptionalHeader;
+ UINT16 Characteristics;
+} EFI_IMAGE_FILE_HEADER;
+
+///
+/// Size of EFI_IMAGE_FILE_HEADER
+///
+#define EFI_IMAGE_SIZEOF_FILE_HEADER 20
+
+///
+/// Characteristics
+///
+#define EFI_IMAGE_FILE_RELOCS_STRIPPED BIT0 ///< 0x0001 Relocation info stripped from file.
+#define EFI_IMAGE_FILE_EXECUTABLE_IMAGE BIT1 ///< 0x0002 File is executable (i.e. no unresolved externel references).
+#define EFI_IMAGE_FILE_LINE_NUMS_STRIPPED BIT2 ///< 0x0004 Line nunbers stripped from file.
+#define EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED BIT3 ///< 0x0008 Local symbols stripped from file.
+#define EFI_IMAGE_FILE_BYTES_REVERSED_LO BIT7 ///< 0x0080 Bytes of machine word are reversed.
+#define EFI_IMAGE_FILE_32BIT_MACHINE BIT8 ///< 0x0100 32 bit word machine.
+#define EFI_IMAGE_FILE_DEBUG_STRIPPED BIT9 ///< 0x0200 Debugging info stripped from file in .DBG file
+#define EFI_IMAGE_FILE_SYSTEM BIT12 ///< 0x1000 System File.
+#define EFI_IMAGE_FILE_DLL BIT13 ///< 0x2000 File is a DLL.
+#define EFI_IMAGE_FILE_BYTES_REVERSED_HI BIT15 ///< 0x8000 Bytes of machine word are reversed.
+
+///
+/// Other Machine Types
+///
+#define EFI_IMAGE_FILE_MACHINE_UNKNOWN 0 ///< Any machine type
+#define EFI_IMAGE_FILE_MACHINE_I386 0x14c ///< Intel 386.
+#define EFI_IMAGE_FILE_MACHINE_R3000 0x162 ///< MIPS* little-endian, 0540 big-endian
+#define EFI_IMAGE_FILE_MACHINE_R4000 0x166 ///< MIPS* little-endian
+#define EFI_IMAGE_FILE_MACHINE_POWERPC 0x1F0 ///< IBM* PowerPC Little-Endian
+//
+// * Other names and brands may be claimed as the property of others.
+//
+
+///
+/// Header Data Directories
+///
+typedef struct {
+ UINT32 VirtualAddress;
+ UINT32 Size;
+} EFI_IMAGE_DATA_DIRECTORY;
+
+#define EFI_IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107
+
+///
+/// Directory Entries
+///
+#define EFI_IMAGE_DIRECTORY_ENTRY_EXPORT 0
+#define EFI_IMAGE_DIRECTORY_ENTRY_IMPORT 1
+#define EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE 2
+#define EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION 3
+#define EFI_IMAGE_DIRECTORY_ENTRY_SECURITY 4
+#define EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC 5
+#define EFI_IMAGE_DIRECTORY_ENTRY_DEBUG 6
+#define EFI_IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7
+#define EFI_IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8
+#define EFI_IMAGE_DIRECTORY_ENTRY_TLS 9
+#define EFI_IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10
+
+#define EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES 16
+
+///
+/// @attention
+/// EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC means PE32 and
+/// EFI_IMAGE_OPTIONAL_HEADER32 must be used. The data structures only vary
+/// after NT additional fields.
+///
+#define EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b
+
+typedef struct {
+ ///
+ /// Standard fields.
+ ///
+ UINT16 Magic;
+ UINT8 MajorLinkerVersion;
+ UINT8 MinorLinkerVersion;
+ UINT32 SizeOfCode;
+ UINT32 SizeOfInitializedData;
+ UINT32 SizeOfUninitializedData;
+ UINT32 AddressOfEntryPoint;
+ UINT32 BaseOfCode;
+ UINT32 BaseOfData; ///< PE32 contains this additional field, which is absent in PE32+
+ ///
+ /// NT additional fields.
+ ///
+ UINT32 ImageBase;
+ UINT32 SectionAlignment;
+ UINT32 FileAlignment;
+ UINT16 MajorOperatingSystemVersion;
+ UINT16 MinorOperatingSystemVersion;
+ UINT16 MajorImageVersion;
+ UINT16 MinorImageVersion;
+ UINT16 MajorSubsystemVersion;
+ UINT16 MinorSubsystemVersion;
+ UINT32 Win32VersionValue;
+ UINT32 SizeOfImage;
+ UINT32 SizeOfHeaders;
+ UINT32 CheckSum;
+ UINT16 Subsystem;
+ UINT16 DllCharacteristics;
+ UINT32 SizeOfStackReserve;
+ UINT32 SizeOfStackCommit;
+ UINT32 SizeOfHeapReserve;
+ UINT32 SizeOfHeapCommit;
+ UINT32 LoaderFlags;
+ UINT32 NumberOfRvaAndSizes;
+ EFI_IMAGE_DATA_DIRECTORY DataDirectory[EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES];
+} EFI_IMAGE_OPTIONAL_HEADER32;
+
+///
+/// @attention
+/// EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC means PE32+ and
+/// EFI_IMAGE_OPTIONAL_HEADER64 must be used. The data structures only vary
+/// after NT additional fields.
+///
+#define EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b
+
+typedef struct {
+ //
+ // Standard fields.
+ //
+ UINT16 Magic;
+ UINT8 MajorLinkerVersion;
+ UINT8 MinorLinkerVersion;
+ UINT32 SizeOfCode;
+ UINT32 SizeOfInitializedData;
+ UINT32 SizeOfUninitializedData;
+ UINT32 AddressOfEntryPoint;
+ UINT32 BaseOfCode;
+ //
+ // NT additional fields.
+ //
+ UINT64 ImageBase;
+ UINT32 SectionAlignment;
+ UINT32 FileAlignment;
+ UINT16 MajorOperatingSystemVersion;
+ UINT16 MinorOperatingSystemVersion;
+ UINT16 MajorImageVersion;
+ UINT16 MinorImageVersion;
+ UINT16 MajorSubsystemVersion;
+ UINT16 MinorSubsystemVersion;
+ UINT32 Win32VersionValue;
+ UINT32 SizeOfImage;
+ UINT32 SizeOfHeaders;
+ UINT32 CheckSum;
+ UINT16 Subsystem;
+ UINT16 DllCharacteristics;
+ UINT64 SizeOfStackReserve;
+ UINT64 SizeOfStackCommit;
+ UINT64 SizeOfHeapReserve;
+ UINT64 SizeOfHeapCommit;
+ UINT32 LoaderFlags;
+ UINT32 NumberOfRvaAndSizes;
+ EFI_IMAGE_DATA_DIRECTORY DataDirectory[EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES];
+} EFI_IMAGE_OPTIONAL_HEADER64;
+
+
+///
+/// @attention
+/// EFI_IMAGE_NT_HEADERS32 and EFI_IMAGE_HEADERS64 are for use ONLY
+/// by tools. All proper EFI code MUST use EFI_IMAGE_NT_HEADERS ONLY!!!
+///
+typedef struct {
+ UINT32 Signature;
+ EFI_IMAGE_FILE_HEADER FileHeader;
+ EFI_IMAGE_OPTIONAL_HEADER32 OptionalHeader;
+} EFI_IMAGE_NT_HEADERS32;
+
+#define EFI_IMAGE_SIZEOF_NT_OPTIONAL32_HEADER sizeof (EFI_IMAGE_NT_HEADERS32)
+
+typedef struct {
+ UINT32 Signature;
+ EFI_IMAGE_FILE_HEADER FileHeader;
+ EFI_IMAGE_OPTIONAL_HEADER64 OptionalHeader;
+} EFI_IMAGE_NT_HEADERS64;
+
+#define EFI_IMAGE_SIZEOF_NT_OPTIONAL64_HEADER sizeof (EFI_IMAGE_NT_HEADERS64)
+
+
+///
+/// Processor specific definition of EFI_IMAGE_OPTIONAL_HEADER so the
+/// type name EFI_IMAGE_OPTIONAL_HEADER is appropriate to the build. Same for
+/// EFI_IMAGE_NT_HEADERS. These definitions MUST be used by ALL EFI code.
+///
+#if defined (MDE_CPU_IA32)
+
+#define EFI_IMAGE_MACHINE_TYPE_SUPPORTED(Machine) \
+ (((Machine) == EFI_IMAGE_MACHINE_IA32) || ((Machine) == EFI_IMAGE_MACHINE_EBC))
+
+#define EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED(Machine) ((Machine) == EFI_IMAGE_MACHINE_X64)
+
+typedef EFI_IMAGE_NT_HEADERS32 EFI_IMAGE_NT_HEADERS;
+
+#elif defined (MDE_CPU_IPF)
+
+#define EFI_IMAGE_MACHINE_TYPE_SUPPORTED(Machine) \
+ (((Machine) == EFI_IMAGE_MACHINE_IPF) || ((Machine) == EFI_IMAGE_MACHINE_EBC))
+
+#define EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED(Machine) (FALSE)
+
+typedef EFI_IMAGE_NT_HEADERS64 EFI_IMAGE_NT_HEADERS;
+
+#elif defined (MDE_CPU_X64)
+
+#define EFI_IMAGE_MACHINE_TYPE_SUPPORTED(Machine) \
+ (((Machine) == EFI_IMAGE_MACHINE_X64) || ((Machine) == EFI_IMAGE_MACHINE_EBC))
+
+#define EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED(Machine) ((Machine) == EFI_IMAGE_MACHINE_IA32)
+
+typedef EFI_IMAGE_NT_HEADERS64 EFI_IMAGE_NT_HEADERS;
+
+#elif defined (MDE_CPU_EBC)
+
+///
+/// This is just to make sure you can cross compile with the EBC compiiler.
+/// It does not make sense to have a PE loader coded in EBC. You need to
+/// understand the basic
+///
+#define EFI_IMAGE_MACHINE_TYPE_SUPPORTED(Machine) ((Machine) == EFI_IMAGE_MACHINE_EBC)
+
+#define EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED(Machine) (FALSE)
+
+typedef EFI_IMAGE_NT_HEADERS64 EFI_IMAGE_NT_HEADERS;
+
+#else
+#error Unknown Processor Type
+#endif
+
+
+#define EFI_IMAGE_FIRST_SECTION(ntheader) \
+ ( \
+ (EFI_IMAGE_SECTION_HEADER *) \
+ ( \
+ (UINT32) ntheader + \
+ FIELD_OFFSET (EFI_IMAGE_NT_HEADERS, OptionalHeader) + \
+ ((EFI_IMAGE_NT_HEADERS *) (ntheader))->FileHeader.SizeOfOptionalHeader \
+ ) \
+ )
+
+///
+/// Other Windows Subsystem Values
+///
+#define EFI_IMAGE_SUBSYSTEM_UNKNOWN 0
+#define EFI_IMAGE_SUBSYSTEM_NATIVE 1
+#define EFI_IMAGE_SUBSYSTEM_WINDOWS_GUI 2
+#define EFI_IMAGE_SUBSYSTEM_WINDOWS_CUI 3
+#define EFI_IMAGE_SUBSYSTEM_OS2_CUI 5
+#define EFI_IMAGE_SUBSYSTEM_POSIX_CUI 7
+
+///
+/// Section header format.
+///
+#define EFI_IMAGE_SIZEOF_SHORT_NAME 8
+
+typedef struct {
+ UINT8 Name[EFI_IMAGE_SIZEOF_SHORT_NAME];
+ union {
+ UINT32 PhysicalAddress;
+ UINT32 VirtualSize;
+ } Misc;
+ UINT32 VirtualAddress;
+ UINT32 SizeOfRawData;
+ UINT32 PointerToRawData;
+ UINT32 PointerToRelocations;
+ UINT32 PointerToLinenumbers;
+ UINT16 NumberOfRelocations;
+ UINT16 NumberOfLinenumbers;
+ UINT32 Characteristics;
+} EFI_IMAGE_SECTION_HEADER;
+
+///
+/// Size of EFI_IMAGE_SECTION_HEADER
+///
+#define EFI_IMAGE_SIZEOF_SECTION_HEADER 40
+
+///
+/// Section Flags Values
+///
+#define EFI_IMAGE_SCN_TYPE_NO_PAD BIT3 ///< 0x00000008 ///< Reserved.
+#define EFI_IMAGE_SCN_CNT_CODE BIT5 ///< 0x00000020
+#define EFI_IMAGE_SCN_CNT_INITIALIZED_DATA BIT6 ///< 0x00000040
+#define EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA BIT7 ///< 0x00000080
+
+#define EFI_IMAGE_SCN_LNK_OTHER BIT8 ///< 0x00000100 ///< Reserved.
+#define EFI_IMAGE_SCN_LNK_INFO BIT9 ///< 0x00000200 ///< Section contains comments or some other type of information.
+#define EFI_IMAGE_SCN_LNK_REMOVE BIT10 ///< 0x00000800 ///< Section contents will not become part of image.
+#define EFI_IMAGE_SCN_LNK_COMDAT BIT12 ///< 0x00001000
+
+#define EFI_IMAGE_SCN_ALIGN_1BYTES BIT20 ///< 0x00100000
+#define EFI_IMAGE_SCN_ALIGN_2BYTES BIT21 ///< 0x00200000
+#define EFI_IMAGE_SCN_ALIGN_4BYTES (BIT20|BIT21) ///< 0x00300000
+#define EFI_IMAGE_SCN_ALIGN_8BYTES BIT22 ///< 0x00400000
+#define EFI_IMAGE_SCN_ALIGN_16BYTES (BIT20|BIT22) ///< 0x00500000
+#define EFI_IMAGE_SCN_ALIGN_32BYTES (BIT21|BIT22) ///< 0x00600000
+#define EFI_IMAGE_SCN_ALIGN_64BYTES (BIT20|BIT21|BIT22) ///< 0x00700000
+
+#define EFI_IMAGE_SCN_MEM_DISCARDABLE BIT25 ///< 0x02000000
+#define EFI_IMAGE_SCN_MEM_NOT_CACHED BIT26 ///< 0x04000000
+#define EFI_IMAGE_SCN_MEM_NOT_PAGED BIT27 ///< 0x08000000
+#define EFI_IMAGE_SCN_MEM_SHARED BIT28 ///< 0x10000000
+#define EFI_IMAGE_SCN_MEM_EXECUTE BIT29 ///< 0x20000000
+#define EFI_IMAGE_SCN_MEM_READ BIT30 ///< 0x40000000
+#define EFI_IMAGE_SCN_MEM_WRITE BIT31 ///< 0x80000000
+
+///
+/// Size of a Symbol Table Record
+///
+#define EFI_IMAGE_SIZEOF_SYMBOL 18
+
+///
+/// Symbols have a section number of the section in which they are
+/// defined. Otherwise, section numbers have the following meanings:
+///
+#define EFI_IMAGE_SYM_UNDEFINED (UINT16) 0 ///< Symbol is undefined or is common.
+#define EFI_IMAGE_SYM_ABSOLUTE (UINT16) -1 ///< Symbol is an absolute value.
+#define EFI_IMAGE_SYM_DEBUG (UINT16) -2 ///< Symbol is a special debug item.
+
+///
+/// Symbol Type (fundamental) values.
+///
+#define EFI_IMAGE_SYM_TYPE_NULL 0 ///< no type.
+#define EFI_IMAGE_SYM_TYPE_VOID 1 ///< no valid type.
+#define EFI_IMAGE_SYM_TYPE_CHAR 2 ///< type character.
+#define EFI_IMAGE_SYM_TYPE_SHORT 3 ///< type short integer.
+#define EFI_IMAGE_SYM_TYPE_INT 4
+#define EFI_IMAGE_SYM_TYPE_LONG 5
+#define EFI_IMAGE_SYM_TYPE_FLOAT 6
+#define EFI_IMAGE_SYM_TYPE_DOUBLE 7
+#define EFI_IMAGE_SYM_TYPE_STRUCT 8
+#define EFI_IMAGE_SYM_TYPE_UNION 9
+#define EFI_IMAGE_SYM_TYPE_ENUM 10 ///< enumeration.
+#define EFI_IMAGE_SYM_TYPE_MOE 11 ///< member of enumeration.
+#define EFI_IMAGE_SYM_TYPE_BYTE 12
+#define EFI_IMAGE_SYM_TYPE_WORD 13
+#define EFI_IMAGE_SYM_TYPE_UINT 14
+#define EFI_IMAGE_SYM_TYPE_DWORD 15
+
+///
+/// Symbol Type (derived) values.
+///
+#define EFI_IMAGE_SYM_DTYPE_NULL 0 ///< no derived type.
+#define EFI_IMAGE_SYM_DTYPE_POINTER 1
+#define EFI_IMAGE_SYM_DTYPE_FUNCTION 2
+#define EFI_IMAGE_SYM_DTYPE_ARRAY 3
+
+///
+/// Storage classes.
+///
+#define EFI_IMAGE_SYM_CLASS_END_OF_FUNCTION ((UINT8) -1)
+#define EFI_IMAGE_SYM_CLASS_NULL 0
+#define EFI_IMAGE_SYM_CLASS_AUTOMATIC 1
+#define EFI_IMAGE_SYM_CLASS_EXTERNAL 2
+#define EFI_IMAGE_SYM_CLASS_STATIC 3
+#define EFI_IMAGE_SYM_CLASS_REGISTER 4
+#define EFI_IMAGE_SYM_CLASS_EXTERNAL_DEF 5
+#define EFI_IMAGE_SYM_CLASS_LABEL 6
+#define EFI_IMAGE_SYM_CLASS_UNDEFINED_LABEL 7
+#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 8
+#define EFI_IMAGE_SYM_CLASS_ARGUMENT 9
+#define EFI_IMAGE_SYM_CLASS_STRUCT_TAG 10
+#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_UNION 11
+#define EFI_IMAGE_SYM_CLASS_UNION_TAG 12
+#define EFI_IMAGE_SYM_CLASS_TYPE_DEFINITION 13
+#define EFI_IMAGE_SYM_CLASS_UNDEFINED_STATIC 14
+#define EFI_IMAGE_SYM_CLASS_ENUM_TAG 15
+#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_ENUM 16
+#define EFI_IMAGE_SYM_CLASS_REGISTER_PARAM 17
+#define EFI_IMAGE_SYM_CLASS_BIT_FIELD 18
+#define EFI_IMAGE_SYM_CLASS_BLOCK 100
+#define EFI_IMAGE_SYM_CLASS_FUNCTION 101
+#define EFI_IMAGE_SYM_CLASS_END_OF_STRUCT 102
+#define EFI_IMAGE_SYM_CLASS_FILE 103
+#define EFI_IMAGE_SYM_CLASS_SECTION 104
+#define EFI_IMAGE_SYM_CLASS_WEAK_EXTERNAL 105
+
+//
+// type packing constants
+//
+#define EFI_IMAGE_N_BTMASK 017
+#define EFI_IMAGE_N_TMASK 060
+#define EFI_IMAGE_N_TMASK1 0300
+#define EFI_IMAGE_N_TMASK2 0360
+#define EFI_IMAGE_N_BTSHFT 4
+#define EFI_IMAGE_N_TSHIFT 2
+
+///
+/// Communal selection types.
+///
+#define EFI_IMAGE_COMDAT_SELECT_NODUPLICATES 1
+#define EFI_IMAGE_COMDAT_SELECT_ANY 2
+#define EFI_IMAGE_COMDAT_SELECT_SAME_SIZE 3
+#define EFI_IMAGE_COMDAT_SELECT_EXACT_MATCH 4
+#define EFI_IMAGE_COMDAT_SELECT_ASSOCIATIVE 5
+
+///
+/// the following values only be referred in PeCoff, not defined in PECOFF.
+///
+#define EFI_IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1
+#define EFI_IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2
+#define EFI_IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3
+
+///
+/// Relocation format.
+///
+typedef struct {
+ UINT32 VirtualAddress;
+ UINT32 SymbolTableIndex;
+ UINT16 Type;
+} EFI_IMAGE_RELOCATION;
+
+///
+/// Size of EFI_IMAGE_RELOCATION
+///
+#define EFI_IMAGE_SIZEOF_RELOCATION 10
+
+///
+/// I386 relocation types.
+///
+#define EFI_IMAGE_REL_I386_ABSOLUTE 0x0000 ///< Reference is absolute, no relocation is necessary
+#define EFI_IMAGE_REL_I386_DIR16 0x0001 ///< Direct 16-bit reference to the symbols virtual address
+#define EFI_IMAGE_REL_I386_REL16 0x0002 ///< PC-relative 16-bit reference to the symbols virtual address
+#define EFI_IMAGE_REL_I386_DIR32 0x0006 ///< Direct 32-bit reference to the symbols virtual address
+#define EFI_IMAGE_REL_I386_DIR32NB 0x0007 ///< Direct 32-bit reference to the symbols virtual address, base not included
+#define EFI_IMAGE_REL_I386_SEG12 0x0009 ///< Direct 16-bit reference to the segment-selector bits of a 32-bit virtual address
+#define EFI_IMAGE_REL_I386_SECTION 0x000A
+#define EFI_IMAGE_REL_I386_SECREL 0x000B
+#define EFI_IMAGE_REL_I386_REL32 0x0014 ///< PC-relative 32-bit reference to the symbols virtual address
+
+///
+/// x64 processor relocation types.
+///
+#define IMAGE_REL_AMD64_ABSOLUTE 0x0000
+#define IMAGE_REL_AMD64_ADDR64 0x0001
+#define IMAGE_REL_AMD64_ADDR32 0x0002
+#define IMAGE_REL_AMD64_ADDR32NB 0x0003
+#define IMAGE_REL_AMD64_REL32 0x0004
+#define IMAGE_REL_AMD64_REL32_1 0x0005
+#define IMAGE_REL_AMD64_REL32_2 0x0006
+#define IMAGE_REL_AMD64_REL32_3 0x0007
+#define IMAGE_REL_AMD64_REL32_4 0x0008
+#define IMAGE_REL_AMD64_REL32_5 0x0009
+#define IMAGE_REL_AMD64_SECTION 0x000A
+#define IMAGE_REL_AMD64_SECREL 0x000B
+#define IMAGE_REL_AMD64_SECREL7 0x000C
+#define IMAGE_REL_AMD64_TOKEN 0x000D
+#define IMAGE_REL_AMD64_SREL32 0x000E
+#define IMAGE_REL_AMD64_PAIR 0x000F
+#define IMAGE_REL_AMD64_SSPAN32 0x0010
+
+///
+/// Based relocation format.
+///
+typedef struct {
+ UINT32 VirtualAddress;
+ UINT32 SizeOfBlock;
+} EFI_IMAGE_BASE_RELOCATION;
+
+///
+/// Size of EFI_IMAGE_BASE_RELOCATION
+///
+#define EFI_IMAGE_SIZEOF_BASE_RELOCATION 8
+
+///
+/// Based relocation types.
+///
+#define EFI_IMAGE_REL_BASED_ABSOLUTE 0
+#define EFI_IMAGE_REL_BASED_HIGH 1
+#define EFI_IMAGE_REL_BASED_LOW 2
+#define EFI_IMAGE_REL_BASED_HIGHLOW 3
+#define EFI_IMAGE_REL_BASED_HIGHADJ 4
+#define EFI_IMAGE_REL_BASED_MIPS_JMPADDR 5
+#define EFI_IMAGE_REL_BASED_IA64_IMM64 9
+#define IMAGE_REL_BASED_MIPS_JMPADDR16 9
+#define EFI_IMAGE_REL_BASED_DIR64 10
+
+///
+/// Line number format.
+///
+typedef struct {
+ union {
+ UINT32 SymbolTableIndex; // Symbol table index of function name if Linenumber is 0.
+ UINT32 VirtualAddress; // Virtual address of line number.
+ } Type;
+ UINT16 Linenumber; // Line number.
+} EFI_IMAGE_LINENUMBER;
+
+///
+/// Size of EFI_IMAGE_LINENUMBER
+///
+#define EFI_IMAGE_SIZEOF_LINENUMBER 6
+
+///
+/// Archive format.
+///
+#define EFI_IMAGE_ARCHIVE_START_SIZE 8
+#define EFI_IMAGE_ARCHIVE_START "!<arch>\n"
+#define EFI_IMAGE_ARCHIVE_END "`\n"
+#define EFI_IMAGE_ARCHIVE_PAD "\n"
+#define EFI_IMAGE_ARCHIVE_LINKER_MEMBER "/ "
+#define EFI_IMAGE_ARCHIVE_LONGNAMES_MEMBER "// "
+
+typedef struct {
+ UINT8 Name[16]; ///< File member name - `/' terminated.
+ UINT8 Date[12]; ///< File member date - decimal.
+ UINT8 UserID[6]; ///< File member user id - decimal.
+ UINT8 GroupID[6]; ///< File member group id - decimal.
+ UINT8 Mode[8]; ///< File member mode - octal.
+ UINT8 Size[10]; ///< File member size - decimal.
+ UINT8 EndHeader[2]; ///< String to end header. (0x60 0x0A)
+} EFI_IMAGE_ARCHIVE_MEMBER_HEADER;
+
+///
+/// Size of EFI_IMAGE_ARCHIVE_MEMBER_HEADER
+///
+#define EFI_IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60
+
+
+///
+/// DLL Support
+///
+
+///
+/// Export Directory Table
+///
+typedef struct {
+ UINT32 Characteristics;
+ UINT32 TimeDateStamp;
+ UINT16 MajorVersion;
+ UINT16 MinorVersion;
+ UINT32 Name;
+ UINT32 Base;
+ UINT32 NumberOfFunctions;
+ UINT32 NumberOfNames;
+ UINT32 AddressOfFunctions;
+ UINT32 AddressOfNames;
+ UINT32 AddressOfNameOrdinals;
+} EFI_IMAGE_EXPORT_DIRECTORY;
+
+///
+/// Hint/Name Table
+///
+typedef struct {
+ UINT16 Hint;
+ UINT8 Name[1];
+} EFI_IMAGE_IMPORT_BY_NAME;
+
+typedef struct {
+ union {
+ UINT32 Function;
+ UINT32 Ordinal;
+ EFI_IMAGE_IMPORT_BY_NAME *AddressOfData;
+ } u1;
+} EFI_IMAGE_THUNK_DATA;
+
+#define EFI_IMAGE_ORDINAL_FLAG BIT31 ///< Flag for PE32
+#define EFI_IMAGE_SNAP_BY_ORDINAL(Ordinal) ((Ordinal & EFI_IMAGE_ORDINAL_FLAG) != 0)
+#define EFI_IMAGE_ORDINAL(Ordinal) (Ordinal & 0xffff)
+
+///
+/// Import Directory Table
+///
+typedef struct {
+ UINT32 Characteristics;
+ UINT32 TimeDateStamp;
+ UINT32 ForwarderChain;
+ UINT32 Name;
+ EFI_IMAGE_THUNK_DATA *FirstThunk;
+} EFI_IMAGE_IMPORT_DESCRIPTOR;
+
+
+///
+/// Debug Direcotry Format
+///
+typedef struct {
+ UINT32 Characteristics;
+ UINT32 TimeDateStamp;
+ UINT16 MajorVersion;
+ UINT16 MinorVersion;
+ UINT32 Type;
+ UINT32 SizeOfData;
+ UINT32 RVA; ///< The address of the debug data when loaded, relative to the image base
+ UINT32 FileOffset; ///< The file pointer to the debug data
+} EFI_IMAGE_DEBUG_DIRECTORY_ENTRY;
+
+#define EFI_IMAGE_DEBUG_TYPE_CODEVIEW 2 ///< The Visual C++ debug information
+
+///
+/// Debug Data Structure defined in Microsoft C++
+///
+#define CODEVIEW_SIGNATURE_NB10 SIGNATURE_32('N', 'B', '1', '0')
+typedef struct {
+ UINT32 Signature; ///< "NB10"
+ UINT32 Unknown;
+ UINT32 Unknown2;
+ UINT32 Unknown3;
+ //
+ // Filename of .PDB goes here
+ //
+} EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY;
+
+///
+/// Debug Data Structure defined in Microsoft C++
+///
+#define CODEVIEW_SIGNATURE_RSDS SIGNATURE_32('R', 'S', 'D', 'S')
+typedef struct {
+ UINT32 Signature; ///< "RSDS"
+ UINT32 Unknown;
+ UINT32 Unknown2;
+ UINT32 Unknown3;
+ UINT32 Unknown4;
+ UINT32 Unknown5;
+ //
+ // Filename of .PDB goes here
+ //
+} EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY;
+
+///
+/// Header format for TE images, defined in PI Specification, 1.0
+///
+typedef struct {
+ UINT16 Signature; ///< signature for TE format = "VZ"
+ UINT16 Machine; ///< from the original file header
+ UINT8 NumberOfSections; ///< from the original file header
+ UINT8 Subsystem; ///< from original optional header
+ UINT16 StrippedSize; ///< how many bytes we removed from the header
+ UINT32 AddressOfEntryPoint; ///< offset to entry point -- from original optional header
+ UINT32 BaseOfCode; ///< from original image -- required for ITP debug
+ UINT64 ImageBase; ///< from original file header
+ EFI_IMAGE_DATA_DIRECTORY DataDirectory[2]; ///< only base relocation and debug directory
+} EFI_TE_IMAGE_HEADER;
+
+
+#define EFI_TE_IMAGE_HEADER_SIGNATURE SIGNATURE_16('V', 'Z')
+
+//
+// Data directory indexes in our TE image header
+//
+#define EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC 0
+#define EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG 1
+
+
+///
+/// Union of PE32, PE32+, and TE headers
+///
+typedef union {
+ EFI_IMAGE_NT_HEADERS32 Pe32;
+ EFI_IMAGE_NT_HEADERS64 Pe32Plus;
+ EFI_TE_IMAGE_HEADER Te;
+} EFI_IMAGE_OPTIONAL_HEADER_UNION;
+
+typedef union {
+ EFI_IMAGE_NT_HEADERS32 *Pe32;
+ EFI_IMAGE_NT_HEADERS64 *Pe32Plus;
+ EFI_TE_IMAGE_HEADER *Te;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *Union;
+} EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION;
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/LICENCE b/gpxe/src/include/gpxe/efi/LICENCE
new file mode 100644
index 00000000..6aa2b2ff
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/LICENCE
@@ -0,0 +1,40 @@
+The EFI headers contained herein are copied from the EFI Development
+Kit, available from http://www.tianocore.org and published under the
+following licence:
+
+ BSD License from Intel
+ Copyright (c) 2004, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+
+This licence applies only to files that are part of the EFI
+Development Kit. Other files may contain their own licence terms, or
+may fall under the standard gPXE GPL licence.
diff --git a/gpxe/src/include/gpxe/efi/Pi/PiBootMode.h b/gpxe/src/include/gpxe/efi/Pi/PiBootMode.h
new file mode 100644
index 00000000..bebca227
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Pi/PiBootMode.h
@@ -0,0 +1,43 @@
+/** @file
+ Present the boot mode values in PI.
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+ @par Revision Reference:
+ PI Version 1.0
+
+**/
+
+#ifndef __PI_BOOT_MODE_H__
+#define __PI_BOOT_MODE_H__
+
+#include <gpxe/efi/ProcessorBind.h>
+
+///
+/// EFI boot mode
+///
+typedef UINT32 EFI_BOOT_MODE;
+
+//
+// 0x21 - 0xf..f are reserved.
+//
+#define BOOT_WITH_FULL_CONFIGURATION 0x00
+#define BOOT_WITH_MINIMAL_CONFIGURATION 0x01
+#define BOOT_ASSUMING_NO_CONFIGURATION_CHANGES 0x02
+#define BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS 0x03
+#define BOOT_WITH_DEFAULT_SETTINGS 0x04
+#define BOOT_ON_S4_RESUME 0x05
+#define BOOT_ON_S5_RESUME 0x06
+#define BOOT_ON_S2_RESUME 0x10
+#define BOOT_ON_S3_RESUME 0x11
+#define BOOT_ON_FLASH_UPDATE 0x12
+#define BOOT_IN_RECOVERY_MODE 0x20
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Pi/PiDependency.h b/gpxe/src/include/gpxe/efi/Pi/PiDependency.h
new file mode 100644
index 00000000..73f6027e
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Pi/PiDependency.h
@@ -0,0 +1,47 @@
+/** @file
+ Present the dependency expression values in PI.
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+ @par Revision Reference:
+ PI Version 1.0
+
+**/
+#ifndef __PI_DEPENDENCY_H__
+#define __PI_DEPENDENCY_H__
+
+///
+/// If present, this must be the first and only opcode,
+/// EFI_DEP_BEFORE is only used by DXE driver.
+///
+#define EFI_DEP_BEFORE 0x00
+
+///
+/// If present, this must be the first and only opcode,
+/// EFI_DEP_AFTER is only used by DXE driver.
+///
+#define EFI_DEP_AFTER 0x01
+
+#define EFI_DEP_PUSH 0x02
+#define EFI_DEP_AND 0x03
+#define EFI_DEP_OR 0x04
+#define EFI_DEP_NOT 0x05
+#define EFI_DEP_TRUE 0x06
+#define EFI_DEP_FALSE 0x07
+#define EFI_DEP_END 0x08
+
+
+///
+/// If present, this must be the first opcode,
+/// EFI_DEP_SOR is only used by DXE driver.
+///
+#define EFI_DEP_SOR 0x09
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Pi/PiDxeCis.h b/gpxe/src/include/gpxe/efi/Pi/PiDxeCis.h
new file mode 100644
index 00000000..a9248883
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Pi/PiDxeCis.h
@@ -0,0 +1,642 @@
+/** @file
+ Include file matches things in PI.
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+ @par Revision Reference:
+ PI Version 1.0
+
+**/
+
+#ifndef __PI_DXECIS_H__
+#define __PI_DXECIS_H__
+
+#include <gpxe/efi/Pi/PiMultiPhase.h>
+
+///
+/// Global Coherencey Domain types - Memory type
+///
+typedef enum {
+ EfiGcdMemoryTypeNonExistent,
+ EfiGcdMemoryTypeReserved,
+ EfiGcdMemoryTypeSystemMemory,
+ EfiGcdMemoryTypeMemoryMappedIo,
+ EfiGcdMemoryTypeMaximum
+} EFI_GCD_MEMORY_TYPE;
+
+///
+/// Global Coherencey Domain types - IO type
+///
+typedef enum {
+ EfiGcdIoTypeNonExistent,
+ EfiGcdIoTypeReserved,
+ EfiGcdIoTypeIo,
+ EfiGcdIoTypeMaximum
+} EFI_GCD_IO_TYPE;
+
+///
+/// The type of allocation to perform.
+///
+typedef enum {
+ EfiGcdAllocateAnySearchBottomUp,
+ EfiGcdAllocateMaxAddressSearchBottomUp,
+ EfiGcdAllocateAddress,
+ EfiGcdAllocateAnySearchTopDown,
+ EfiGcdAllocateMaxAddressSearchTopDown,
+ EfiGcdMaxAllocateType
+} EFI_GCD_ALLOCATE_TYPE;
+
+///
+/// EFI_GCD_MEMORY_SPACE_DESCRIPTOR
+///
+typedef struct {
+ ///
+ /// The physical address of the first byte in the memory region. Type
+ /// EFI_PHYSICAL_ADDRESS is defined in the AllocatePages() function
+ /// description in the UEFI 2.0 specification
+ ///
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+
+ ///
+ /// The number of bytes in the memory region.
+ ///
+ UINT64 Length;
+
+ ///
+ /// The bit mask of attributes that the memory region is capable of supporting. The bit
+ /// mask of available attributes is defined in the GetMemoryMap() function description
+ /// in the UEFI 2.0 specification.
+ ///
+ UINT64 Capabilities;
+ ///
+ /// The bit mask of attributes that the memory region is currently using. The bit mask of
+ /// available attributes is defined in GetMemoryMap().
+ ///
+ UINT64 Attributes;
+ ///
+ /// Type of the memory region. Type EFI_GCD_MEMORY_TYPE is defined in the
+ /// AddMemorySpace() function description
+ ///
+ EFI_GCD_MEMORY_TYPE GcdMemoryType;
+
+ ///
+ /// The image handle of the agent that allocated the memory resource described by
+ /// PhysicalStart and NumberOfBytes. If this field is NULL, then the memory
+ /// resource is not currently allocated. Type EFI_HANDLE is defined in
+ /// InstallProtocolInterface() in the UEFI 2.0 specification.
+ ///
+ EFI_HANDLE ImageHandle;
+
+ ///
+ /// The device handle for which the memory resource has been allocated. If
+ /// ImageHandle is NULL, then the memory resource is not currently allocated. If this
+ /// field is NULL, then the memory resource is not associated with a device that is
+ /// described by a device handle. Type EFI_HANDLE is defined in
+ /// InstallProtocolInterface() in the UEFI 2.0 specification.
+ ///
+ EFI_HANDLE DeviceHandle;
+} EFI_GCD_MEMORY_SPACE_DESCRIPTOR;
+
+///
+/// EFI_GCD_IO_SPACE_DESCRIPTOR
+///
+typedef struct {
+ ///
+ /// Physical address of the first byte in the I/O region. Type
+ /// EFI_PHYSICAL_ADDRESS is defined in the AllocatePages() function
+ /// description in the UEFI 2.0 specification.
+ ///
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+
+ ///
+ /// Number of bytes in the I/O region.
+ ///
+ UINT64 Length;
+
+ ///
+ /// Type of the I/O region. Type EFI_GCD_IO_TYPE is defined in the
+ /// AddIoSpace() function description.
+ ///
+ EFI_GCD_IO_TYPE GcdIoType;
+
+ ///
+ /// The image handle of the agent that allocated the I/O resource described by
+ /// PhysicalStart and NumberOfBytes. If this field is NULL, then the I/O
+ /// resource is not currently allocated. Type EFI_HANDLE is defined in
+ /// InstallProtocolInterface() in the UEFI 2.0 specification.
+ ///
+ EFI_HANDLE ImageHandle;
+
+ ///
+ /// The device handle for which the I/O resource has been allocated. If ImageHandle
+ /// is NULL, then the I/O resource is not currently allocated. If this field is NULL, then
+ /// the I/O resource is not associated with a device that is described by a device handle.
+ /// Type EFI_HANDLE is defined in InstallProtocolInterface() in the UEFI
+ /// 2.0 specification.
+ ///
+ EFI_HANDLE DeviceHandle;
+} EFI_GCD_IO_SPACE_DESCRIPTOR;
+
+
+/**
+ Adds reserved memory, system memory, or memory-mapped I/O resources to the
+ global coherency domain of the processor.
+
+ @param GcdMemoryType The type of memory resource being added.
+ @param BaseAddress The physical address that is the start address
+ of the memory resource being added.
+ @param Length The size, in bytes, of the memory resource that
+ is being added.
+ @param Capabilities The bit mask of attributes that the memory
+ resource region supports.
+
+ @retval EFI_SUCCESS The memory resource was added to the global
+ coherency domain of the processor.
+ @retval EFI_INVALID_PARAMETER GcdMemoryType is invalid.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to add
+ the memory resource to the global coherency
+ domain of the processor.
+ @retval EFI_UNSUPPORTED The processor does not support one or more bytes
+ of the memory resource range specified by
+ BaseAddress and Length.
+ @retval EFI_ACCESS_DENIED One or more bytes of the memory resource range
+ specified by BaseAddress and Length conflicts
+ with a memory resource range that was previously
+ added to the global coherency domain of the processor.
+ @retval EFI_ACCESS_DENIED One or more bytes of the memory resource range
+ specified by BaseAddress and Length was allocated
+ in a prior call to AllocateMemorySpace()..
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ADD_MEMORY_SPACE)(
+ IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Capabilities
+ );
+
+/**
+ Allocates nonexistent memory, reserved memory, system memory, or memorymapped
+ I/O resources from the global coherency domain of the processor.
+
+ @param GcdAllocateType The type of allocation to perform.
+ @param GcdMemoryType The type of memory resource being allocated.
+ @param Alignment The log base 2 of the boundary that BaseAddress must
+ be aligned on output. Align with 2^Alignment.
+ @param Length The size in bytes of the memory resource range that
+ is being allocated.
+ @param BaseAddress A pointer to a physical address to allocate.
+ @param Imagehandle The image handle of the agent that is allocating
+ the memory resource.
+ @param DeviceHandle The device handle for which the memory resource
+ is being allocated.
+
+ @retval EFI_INVALID_PARAMETER GcdAllocateType is invalid.
+ @retval EFI_INVALID_PARAMETER GcdMemoryType is invalid.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_INVALID_PARAMETER BaseAddress is NULL.
+ @retval EFI_INVALID_PARAMETER ImageHandle is NULL.
+ @retval EFI_NOT_FOUND The memory resource request could not be satisfied.
+ No descriptor contains the desired space.
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to allocate the memory
+ resource from the global coherency domain of the processor.
+ @retval EFI_SUCCESS The memory resource was allocated from the global coherency
+ domain of the processor.
+
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ALLOCATE_MEMORY_SPACE)(
+ IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType,
+ IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
+ IN UINTN Alignment,
+ IN UINT64 Length,
+ IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_HANDLE DeviceHandle OPTIONAL
+ );
+
+/**
+ Frees nonexistent memory, reserved memory, system memory, or memory-mapped
+ I/O resources from the global coherency domain of the processor.
+
+ @param BaseAddress The physical address that is the start address of the memory resource being freed.
+ @param Length The size in bytes of the memory resource range that is being freed.
+
+ @retval EFI_SUCCESS The memory resource was freed from the global coherency domain of
+ the processor.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
+ resource range specified by BaseAddress and Length.
+ @retval EFI_NOT_FOUND The memory resource range specified by BaseAddress and
+ Length was not allocated with previous calls to AllocateMemorySpace().
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to free the memory resource
+ from the global coherency domain of the processor.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FREE_MEMORY_SPACE)(
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+/**
+ Removes reserved memory, system memory, or memory-mapped I/O resources from
+ the global coherency domain of the processor.
+
+ @param BaseAddress The physical address that is the start address of the memory resource being removed.
+ @param Length The size in bytes of the memory resource that is being removed.
+
+ @retval EFI_SUCCESS The memory resource was removed from the global coherency
+ domain of the processor.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
+ resource range specified by BaseAddress and Length.
+ @retval EFI_NOT_FOUND One or more bytes of the memory resource range specified by
+ BaseAddress and Length was not added with previous calls to
+ AddMemorySpace().
+ @retval EFI_ACCESS_DEFINED One or more bytes of the memory resource range specified by
+ BaseAddress and Length has been allocated with AllocateMemorySpace().
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to remove the memory
+ resource from the global coherency domain of the processor.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_REMOVE_MEMORY_SPACE)(
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+/**
+ Retrieves the descriptor for a memory region containing a specified address.
+
+ @param BaseAddress The physical address that is the start address of a memory region.
+ @param Descriptor A pointer to a caller allocated descriptor.
+
+ @retval EFI_SUCCESS The descriptor for the memory resource region containing
+ BaseAddress was returned in Descriptor.
+ @retval EFI_INVALID_PARAMETER Descriptor is NULL.
+ @retval EFI_NOT_FOUND A memory resource range containing BaseAddress was not found.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_MEMORY_SPACE_DESCRIPTOR)(
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor
+ );
+
+/**
+ Modifies the attributes for a memory region in the global coherency domain of the
+ processor.
+
+ @param BaseAddress The physical address that is the start address of a memory region.
+ @param Length The size in bytes of the memory region.
+ @param Attributes The bit mask of attributes to set for the memory region.
+
+ @retval EFI_SUCCESS The attributes were set for the memory region.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
+ resource range specified by BaseAddress and Length.
+ @retval EFI_UNSUPPORTED The bit mask of attributes is not support for the memory resource
+ range specified by BaseAddress and Length.
+ @retval EFI_ACCESS_DEFINED The attributes for the memory resource range specified by
+ BaseAddress and Length cannot be modified.
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
+ the memory resource range.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SET_MEMORY_SPACE_ATTRIBUTES)(
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Attributes
+ );
+
+/**
+ Returns a map of the memory resources in the global coherency domain of the
+ processor.
+
+ @param NumberOfDescriptors A pointer to number of descriptors returned in the MemorySpaceMap buffer.
+ @param MemorySpaceMap A pointer to the array of EFI_GCD_MEMORY_SPACE_DESCRIPTORs.
+
+ @retval EFI_SUCCESS The memory space map was returned in the MemorySpaceMap
+ buffer, and the number of descriptors in MemorySpaceMap was
+ returned in NumberOfDescriptors.
+ @retval EFI_INVALID_PARAMETER NumberOfDescriptors is NULL.
+ @retval EFI_INVALID_PARAMETER MemorySpaceMap is NULL.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate MemorySpaceMap.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_MEMORY_SPACE_MAP)(
+ OUT UINTN *NumberOfDescriptors,
+ OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR **MemorySpaceMap
+ );
+
+/**
+ Adds reserved I/O or I/O resources to the global coherency domain of the processor.
+
+ @param GcdIoType The type of I/O resource being added.
+ @param BaseAddress The physical address that is the start address of the I/O resource being added.
+ @param Length The size in bytes of the I/O resource that is being added.
+
+ @retval EFI_SUCCESS The I/O resource was added to the global coherency domain of
+ the processor.
+ @retval EFI_INVALID_PARAMETER GcdIoType is invalid.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to add the I/O resource to
+ the global coherency domain of the processor.
+ @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the I/O
+ resource range specified by BaseAddress and Length.
+ @retval EFI_ACCESS_DENIED One or more bytes of the I/O resource range specified by
+ BaseAddress and Length conflicts with an I/O resource
+ range that was previously added to the global coherency domain
+ of the processor.
+ @retval EFI_ACCESS_DENIED One or more bytes of the I/O resource range specified by
+ BaseAddress and Length was allocated in a prior call to
+ AllocateIoSpace().
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ADD_IO_SPACE)(
+ IN EFI_GCD_IO_TYPE GcdIoType,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+/**
+ Allocates nonexistent I/O, reserved I/O, or I/O resources from the global coherency
+ domain of the processor.
+
+ @param GcdAllocateType The type of allocation to perform.
+ @param GcdIoType The type of I/O resource being allocated.
+ @param Alignment The log base 2 of the boundary that BaseAddress must be aligned on output.
+ @param Length The size in bytes of the I/O resource range that is being allocated.
+ @param BaseAddress A pointer to a physical address.
+ @param Imagehandle The image handle of the agent that is allocating the I/O resource.
+ @param DeviceHandle The device handle for which the I/O resource is being allocated.
+
+ @retval EFI_SUCCESS The I/O resource was allocated from the global coherency domain
+ of the processor.
+ @retval EFI_INVALID_PARAMETER GcdAllocateType is invalid.
+ @retval EFI_INVALID_PARAMETER GcdIoType is invalid.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_INVALID_PARAMETER BaseAddress is NULL.
+ @retval EFI_INVALID_PARAMETER ImageHandle is NULL.
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to allocate the I/O
+ resource from the global coherency domain of the processor.
+ @retval EFI_NOT_FOUND The I/O resource request could not be satisfied.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ALLOCATE_IO_SPACE)(
+ IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType,
+ IN EFI_GCD_IO_TYPE GcdIoType,
+ IN UINTN Alignment,
+ IN UINT64 Length,
+ IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_HANDLE DeviceHandle OPTIONAL
+ );
+
+/**
+ Frees nonexistent I/O, reserved I/O, or I/O resources from the global coherency
+ domain of the processor.
+
+ @param BaseAddress The physical address that is the start address of the I/O resource being freed.
+ @param Length The size in bytes of the I/O resource range that is being freed.
+
+ @retval EFI_SUCCESS The I/O resource was freed from the global coherency domain of the
+ processor.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the I/O resource
+ range specified by BaseAddress and Length.
+ @retval EFI_NOT_FOUND The I/O resource range specified by BaseAddress and Length
+ was not allocated with previous calls to AllocateIoSpace().
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to free the I/O resource from
+ the global coherency domain of the processor.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FREE_IO_SPACE)(
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+/**
+ Removes reserved I/O or I/O resources from the global coherency domain of the
+ processor.
+
+ @param BaseAddress A pointer to a physical address that is the start address of the I/O resource being
+ removed.
+ @param Length The size in bytes of the I/O resource that is being removed.
+
+ @retval EFI_SUCCESS The I/O resource was removed from the global coherency domain
+ of the processor.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the I/O
+ resource range specified by BaseAddress and Length.
+ @retval EFI_NOT_FOUND One or more bytes of the I/O resource range specified by
+ BaseAddress and Length was not added with previous
+ calls to AddIoSpace().
+ @retval EFI_ACCESS_DENIED One or more bytes of the I/O resource range specified by
+ BaseAddress and Length has been allocated with
+ AllocateIoSpace().
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to remove the I/O
+ resource from the global coherency domain of the processor.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_REMOVE_IO_SPACE)(
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+/**
+ Retrieves the descriptor for an I/O region containing a specified address.
+
+ @param BaseAddress The physical address that is the start address of an I/O region.
+ @param Descriptor A pointer to a caller allocated descriptor.
+
+ @retval EFI_SUCCESS The descriptor for the I/O resource region containing
+ BaseAddress was returned in Descriptor.
+ @retval EFI_INVALID_PARAMETER Descriptor is NULL.
+ @retval EFI_NOT_FOUND An I/O resource range containing BaseAddress was not found.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_IO_SPACE_DESCRIPTOR)(
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ OUT EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor
+ );
+
+/**
+ Returns a map of the I/O resources in the global coherency domain of the processor.
+
+ @param NumberOfDescriptors A pointer to number of descriptors returned in the IoSpaceMap buffer.
+ @param MemorySpaceMap A pointer to the array of EFI_GCD_IO_SPACE_DESCRIPTORs.
+
+ @retval EFI_SUCCESS The I/O space map was returned in the IoSpaceMap buffer, and
+ the number of descriptors in IoSpaceMap was returned in
+ NumberOfDescriptors.
+ @retval EFI_INVALID_PARAMETER NumberOfDescriptors is NULL.
+ @retval EFI_INVALID_PARAMETER IoSpaceMap is NULL.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate IoSpaceMap.
+
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_IO_SPACE_MAP)(
+ OUT UINTN *NumberOfDescriptors,
+ OUT EFI_GCD_IO_SPACE_DESCRIPTOR **IoSpaceMap
+ );
+
+
+
+/**
+ Loads and executed DXE drivers from firmware volumes.
+
+ The Dispatch() function searches for DXE drivers in firmware volumes that have been
+ installed since the last time the Dispatch() service was called. It then evaluates
+ the dependency expressions of all the DXE drivers and loads and executes those DXE
+ drivers whose dependency expression evaluate to TRUE. This service must interact with
+ the Security Architectural Protocol to authenticate DXE drivers before they are executed.
+ This process is continued until no more DXE drivers can be executed.
+
+ @retval EFI_SUCCESS One or more DXE driver were dispatched.
+ @retval EFI_NOT_FOUND No DXE drivers were dispatched.
+ @retval EFI_ALREADY_STARTED An attempt is being made to start the DXE Dispatcher recursively.
+ Thus no action was taken.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_DISPATCH)(
+ VOID
+ );
+
+/**
+ Clears the Schedule on Request (SOR) flag for a component that is stored in a firmware volume.
+
+ @param FirmwareVolumeHandle The handle of the firmware volume that contains the file specified by FileName.
+ @param FileName A pointer to the name of the file in a firmware volume.
+
+ @retval EFI_SUCCESS The DXE driver was found and its SOR bit was cleared.
+ @retval EFI_NOT_FOUND The DXE driver does not exist, or the DXE driver exists and its SOR
+ bit is not set.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SCHEDULE)(
+ IN EFI_HANDLE FirmwareVolumeHandle,
+ IN CONST EFI_GUID *FileName
+ );
+
+/**
+ Promotes a file stored in a firmware volume from the untrusted to the trusted state.
+
+ @param FirmwareVolumeHandle The handle of the firmware volume that contains the file specified by FileName.
+ @param DriverName A pointer to the name of the file in a firmware volume.
+
+ @return Status of promoting FFS from untrusted to trusted
+ state.
+ @retval EFI_NOT_FOUND The file was not found in the untrusted state.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_TRUST)(
+ IN EFI_HANDLE FirmwareVolumeHandle,
+ IN CONST EFI_GUID *FileName
+ );
+
+/**
+ Creates a firmware volume handle for a firmware volume that is present in system memory.
+
+ @param FirmwareVolumeHeader A pointer to the header of the firmware volume.
+ @param Size The size, in bytes, of the firmware volume.
+ @param FirmwareVolumeHandle On output, a pointer to the created handle.
+
+ @retval EFI_SUCCESS The EFI_FIRMWARE_VOLUME_PROTOCOL and
+ EFI_DEVICE_PATH_PROTOCOL were installed onto
+ FirmwareVolumeHandle for the firmware volume described
+ by FirmwareVolumeHeader and Size.
+ @retval EFI_VOLUME_CORRUPTED The firmware volume described by FirmwareVolumeHeader
+ and Size is corrupted.
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources available to produce the
+ EFI_FIRMWARE_VOLUME_PROTOCOL and EFI_DEVICE_PATH_PROTOCOL
+ for the firmware volume described by FirmwareVolumeHeader and Size.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PROCESS_FIRMWARE_VOLUME)(
+ IN CONST VOID *FirmwareVolumeHeader,
+ IN UINTN Size,
+ OUT EFI_HANDLE *FirmwareVolumeHandle
+ );
+
+//
+// DXE Services Table
+//
+#define DXE_SERVICES_SIGNATURE 0x565245535f455844ULL
+#define DXE_SERVICES_REVISION ((1<<16) | (00))
+
+typedef struct {
+ EFI_TABLE_HEADER Hdr;
+
+ //
+ // Global Coherency Domain Services
+ //
+ EFI_ADD_MEMORY_SPACE AddMemorySpace;
+ EFI_ALLOCATE_MEMORY_SPACE AllocateMemorySpace;
+ EFI_FREE_MEMORY_SPACE FreeMemorySpace;
+ EFI_REMOVE_MEMORY_SPACE RemoveMemorySpace;
+ EFI_GET_MEMORY_SPACE_DESCRIPTOR GetMemorySpaceDescriptor;
+ EFI_SET_MEMORY_SPACE_ATTRIBUTES SetMemorySpaceAttributes;
+ EFI_GET_MEMORY_SPACE_MAP GetMemorySpaceMap;
+ EFI_ADD_IO_SPACE AddIoSpace;
+ EFI_ALLOCATE_IO_SPACE AllocateIoSpace;
+ EFI_FREE_IO_SPACE FreeIoSpace;
+ EFI_REMOVE_IO_SPACE RemoveIoSpace;
+ EFI_GET_IO_SPACE_DESCRIPTOR GetIoSpaceDescriptor;
+ EFI_GET_IO_SPACE_MAP GetIoSpaceMap;
+
+ //
+ // Dispatcher Services
+ //
+ EFI_DISPATCH Dispatch;
+ EFI_SCHEDULE Schedule;
+ EFI_TRUST Trust;
+ //
+ // Service to process a single firmware volume found in a capsule
+ //
+ EFI_PROCESS_FIRMWARE_VOLUME ProcessFirmwareVolume;
+} DXE_SERVICES;
+
+typedef DXE_SERVICES EFI_DXE_SERVICES;
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Pi/PiFirmwareFile.h b/gpxe/src/include/gpxe/efi/Pi/PiFirmwareFile.h
new file mode 100644
index 00000000..be6f8bd2
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Pi/PiFirmwareFile.h
@@ -0,0 +1,242 @@
+/** @file
+ The firmware file related definitions in PI.
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+ @par Revision Reference:
+ PI Version 1.0
+
+**/
+
+
+#ifndef __PI_FIRMWARE_FILE_H__
+#define __PI_FIRMWARE_FILE_H__
+
+#include <gpxe/efi/ProcessorBind.h>
+
+#pragma pack(1)
+///
+/// Used to verify the integrity of the file.
+///
+typedef union {
+ struct {
+ UINT8 Header;
+ UINT8 File;
+ } Checksum;
+ UINT16 Checksum16;
+} EFI_FFS_INTEGRITY_CHECK;
+
+typedef UINT8 EFI_FV_FILETYPE;
+typedef UINT8 EFI_FFS_FILE_ATTRIBUTES;
+typedef UINT8 EFI_FFS_FILE_STATE;
+
+///
+/// File Types Definitions
+///
+#define EFI_FV_FILETYPE_ALL 0x00
+#define EFI_FV_FILETYPE_RAW 0x01
+#define EFI_FV_FILETYPE_FREEFORM 0x02
+#define EFI_FV_FILETYPE_SECURITY_CORE 0x03
+#define EFI_FV_FILETYPE_PEI_CORE 0x04
+#define EFI_FV_FILETYPE_DXE_CORE 0x05
+#define EFI_FV_FILETYPE_PEIM 0x06
+#define EFI_FV_FILETYPE_DRIVER 0x07
+#define EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER 0x08
+#define EFI_FV_FILETYPE_APPLICATION 0x09
+#define EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE 0x0B
+#define EFI_FV_FILETYPE_OEM_MIN 0xc0
+#define EFI_FV_FILETYPE_OEM_MAX 0xdf
+#define EFI_FV_FILETYPE_DEBUG_MIN 0xe0
+#define EFI_FV_FILETYPE_DEBUG_MAX 0xef
+#define EFI_FV_FILETYPE_FFS_MIN 0xf0
+#define EFI_FV_FILETYPE_FFS_MAX 0xff
+#define EFI_FV_FILETYPE_FFS_PAD 0xf0
+///
+/// FFS File Attributes.
+///
+#define FFS_ATTRIB_FIXED 0x04
+#define FFS_ATTRIB_DATA_ALIGNMENT 0x38
+#define FFS_ATTRIB_CHECKSUM 0x40
+
+///
+/// FFS File State Bits.
+///
+#define EFI_FILE_HEADER_CONSTRUCTION 0x01
+#define EFI_FILE_HEADER_VALID 0x02
+#define EFI_FILE_DATA_VALID 0x04
+#define EFI_FILE_MARKED_FOR_UPDATE 0x08
+#define EFI_FILE_DELETED 0x10
+#define EFI_FILE_HEADER_INVALID 0x20
+
+
+///
+/// Each file begins with the header that describe the
+/// contents and state of the files.
+///
+typedef struct {
+ EFI_GUID Name;
+ EFI_FFS_INTEGRITY_CHECK IntegrityCheck;
+ EFI_FV_FILETYPE Type;
+ EFI_FFS_FILE_ATTRIBUTES Attributes;
+ UINT8 Size[3];
+ EFI_FFS_FILE_STATE State;
+} EFI_FFS_FILE_HEADER;
+
+
+typedef UINT8 EFI_SECTION_TYPE;
+
+///
+/// Pseudo type. It is
+/// used as a wild card when retrieving sections. The section
+/// type EFI_SECTION_ALL matches all section types.
+///
+#define EFI_SECTION_ALL 0x00
+
+///
+/// Encapsulation section Type values
+///
+#define EFI_SECTION_COMPRESSION 0x01
+
+#define EFI_SECTION_GUID_DEFINED 0x02
+
+///
+/// Leaf section Type values
+///
+#define EFI_SECTION_PE32 0x10
+#define EFI_SECTION_PIC 0x11
+#define EFI_SECTION_TE 0x12
+#define EFI_SECTION_DXE_DEPEX 0x13
+#define EFI_SECTION_VERSION 0x14
+#define EFI_SECTION_USER_INTERFACE 0x15
+#define EFI_SECTION_COMPATIBILITY16 0x16
+#define EFI_SECTION_FIRMWARE_VOLUME_IMAGE 0x17
+#define EFI_SECTION_FREEFORM_SUBTYPE_GUID 0x18
+#define EFI_SECTION_RAW 0x19
+#define EFI_SECTION_PEI_DEPEX 0x1B
+
+///
+/// Common section header
+///
+typedef struct {
+ UINT8 Size[3];
+ EFI_SECTION_TYPE Type;
+} EFI_COMMON_SECTION_HEADER;
+
+///
+/// Leaf section type that contains an
+/// IA-32 16-bit executable image.
+///
+typedef EFI_COMMON_SECTION_HEADER EFI_COMPATIBILITY16_SECTION;
+
+///
+/// CompressionType of EFI_COMPRESSION_SECTION.
+///
+#define EFI_NOT_COMPRESSED 0x00
+#define EFI_STANDARD_COMPRESSION 0x01
+///
+/// An encapsulation section type in which the
+/// section data is compressed.
+///
+typedef struct {
+ EFI_COMMON_SECTION_HEADER CommonHeader;
+ UINT32 UncompressedLength;
+ UINT8 CompressionType;
+} EFI_COMPRESSION_SECTION;
+
+///
+/// Leaf section which could be used to determine the dispatch order of DXEs.
+///
+typedef EFI_COMMON_SECTION_HEADER EFI_DXE_DEPEX_SECTION;
+
+///
+/// Leaf section which contains a PI FV.
+///
+typedef EFI_COMMON_SECTION_HEADER EFI_FIRMWARE_VOLUME_IMAGE_SECTION;
+
+///
+/// Leaf section which contains a single GUID.
+///
+typedef struct {
+ EFI_COMMON_SECTION_HEADER CommonHeader;
+ EFI_GUID SubTypeGuid;
+} EFI_FREEFORM_SUBTYPE_GUID_SECTION;
+
+///
+/// Attributes of EFI_GUID_DEFINED_SECTION
+///
+#define EFI_GUIDED_SECTION_PROCESSING_REQUIRED 0x01
+#define EFI_GUIDED_SECTION_AUTH_STATUS_VALID 0x02
+///
+/// Leaf section which is encapsulation defined by specific GUID
+///
+typedef struct {
+ EFI_COMMON_SECTION_HEADER CommonHeader;
+ EFI_GUID SectionDefinitionGuid;
+ UINT16 DataOffset;
+ UINT16 Attributes;
+} EFI_GUID_DEFINED_SECTION;
+
+///
+/// Leaf section which contains PE32+ image.
+///
+typedef EFI_COMMON_SECTION_HEADER EFI_PE32_SECTION;
+
+
+///
+/// Leaf section which used to determine the dispatch order of PEIMs.
+///
+typedef EFI_COMMON_SECTION_HEADER EFI_PEI_DEPEX_SECTION;
+
+///
+/// Leaf section which constains the position-independent-code image.
+///
+typedef EFI_COMMON_SECTION_HEADER EFI_TE_SECTION;
+
+///
+/// Leaf section which contains an array of zero or more bytes.
+///
+typedef EFI_COMMON_SECTION_HEADER EFI_RAW_SECTION;
+
+///
+/// Leaf section which contains a unicode string that
+/// is human readable file name.
+///
+typedef struct {
+ EFI_COMMON_SECTION_HEADER CommonHeader;
+
+ ///
+ /// Array of unicode string.
+ ///
+ CHAR16 FileNameString[1];
+} EFI_USER_INTERFACE_SECTION;
+
+
+///
+/// Leaf section which contains a numeric build number and
+/// an optional unicode string that represents the file revision.
+///
+typedef struct {
+ EFI_COMMON_SECTION_HEADER CommonHeader;
+ UINT16 BuildNumber;
+
+ ///
+ /// Array of unicode string.
+ ///
+ CHAR16 VersionString[1];
+} EFI_VERSION_SECTION;
+
+
+#define SECTION_SIZE(SectionHeaderPtr) \
+ ((UINT32) (*((UINT32 *) ((EFI_COMMON_SECTION_HEADER *) SectionHeaderPtr)->Size) & 0x00ffffff))
+
+#pragma pack()
+
+#endif
+
diff --git a/gpxe/src/include/gpxe/efi/Pi/PiFirmwareVolume.h b/gpxe/src/include/gpxe/efi/Pi/PiFirmwareVolume.h
new file mode 100644
index 00000000..277b7045
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Pi/PiFirmwareVolume.h
@@ -0,0 +1,154 @@
+/** @file
+ The firmware volume related definitions in PI.
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+ @par Revision Reference:
+ PI Version 1.0
+
+**/
+
+#ifndef __PI_FIRMWAREVOLUME_H__
+#define __PI_FIRMWAREVOLUME_H__
+
+#include <gpxe/efi/ProcessorBind.h>
+
+///
+/// EFI_FV_FILE_ATTRIBUTES
+///
+typedef UINT32 EFI_FV_FILE_ATTRIBUTES;
+
+//
+// Value of EFI_FV_FILE_ATTRIBUTES.
+//
+#define EFI_FV_FILE_ATTRIB_ALIGNMENT 0x0000001F
+#define EFI_FV_FILE_ATTRIB_FIXED 0x00000100
+#define EFI_FV_FILE_ATTRIB_MEMORY_MAPPED 0x00000200
+
+///
+/// type of EFI FVB attribute
+///
+typedef UINT32 EFI_FVB_ATTRIBUTES_2;
+
+//
+// Attributes bit definitions
+//
+#define EFI_FVB2_READ_DISABLED_CAP 0x00000001
+#define EFI_FVB2_READ_ENABLED_CAP 0x00000002
+#define EFI_FVB2_READ_STATUS 0x00000004
+#define EFI_FVB2_WRITE_DISABLED_CAP 0x00000008
+#define EFI_FVB2_WRITE_ENABLED_CAP 0x00000010
+#define EFI_FVB2_WRITE_STATUS 0x00000020
+#define EFI_FVB2_LOCK_CAP 0x00000040
+#define EFI_FVB2_LOCK_STATUS 0x00000080
+#define EFI_FVB2_STICKY_WRITE 0x00000200
+#define EFI_FVB2_MEMORY_MAPPED 0x00000400
+#define EFI_FVB2_ERASE_POLARITY 0x00000800
+#define EFI_FVB2_READ_LOCK_CAP 0x00001000
+#define EFI_FVB2_READ_LOCK_STATUS 0x00002000
+#define EFI_FVB2_WRITE_LOCK_CAP 0x00004000
+#define EFI_FVB2_WRITE_LOCK_STATUS 0x00008000
+#define EFI_FVB2_ALIGNMENT 0x001F0000
+#define EFI_FVB2_ALIGNMENT_1 0x00000000
+#define EFI_FVB2_ALIGNMENT_2 0x00010000
+#define EFI_FVB2_ALIGNMENT_4 0x00020000
+#define EFI_FVB2_ALIGNMENT_8 0x00030000
+#define EFI_FVB2_ALIGNMENT_16 0x00040000
+#define EFI_FVB2_ALIGNMENT_32 0x00050000
+#define EFI_FVB2_ALIGNMENT_64 0x00060000
+#define EFI_FVB2_ALIGNMENT_128 0x00070000
+#define EFI_FVB2_ALIGNMENT_256 0x00080000
+#define EFI_FVB2_ALIGNMENT_512 0x00090000
+#define EFI_FVB2_ALIGNMENT_1K 0x000A0000
+#define EFI_FVB2_ALIGNMENT_2K 0x000B0000
+#define EFI_FVB2_ALIGNMENT_4K 0x000C0000
+#define EFI_FVB2_ALIGNMENT_8K 0x000D0000
+#define EFI_FVB2_ALIGNMENT_16K 0x000E0000
+#define EFI_FVB2_ALIGNMENT_32K 0x000F0000
+#define EFI_FVB2_ALIGNMENT_64K 0x00100000
+#define EFI_FVB2_ALIGNMENT_128K 0x00110000
+#define EFI_FVB2_ALIGNMENT_256K 0x00120000
+#define EFI_FVB2_ALIGNMNET_512K 0x00130000
+#define EFI_FVB2_ALIGNMENT_1M 0x00140000
+#define EFI_FVB2_ALIGNMENT_2M 0x00150000
+#define EFI_FVB2_ALIGNMENT_4M 0x00160000
+#define EFI_FVB2_ALIGNMENT_8M 0x00170000
+#define EFI_FVB2_ALIGNMENT_16M 0x00180000
+#define EFI_FVB2_ALIGNMENT_32M 0x00190000
+#define EFI_FVB2_ALIGNMENT_64M 0x001A0000
+#define EFI_FVB2_ALIGNMENT_128M 0x001B0000
+#define EFI_FVB2_ALIGNMENT_256M 0x001C0000
+#define EFI_FVB2_ALIGNMENT_512M 0x001D0000
+#define EFI_FVB2_ALIGNMENT_1G 0x001E0000
+#define EFI_FVB2_ALIGNMENT_2G 0x001F0000
+
+
+typedef struct {
+ UINT32 NumBlocks;
+ UINT32 Length;
+} EFI_FV_BLOCK_MAP_ENTRY;
+
+///
+/// Describes the features and layout of the firmware volume.
+///
+typedef struct {
+ UINT8 ZeroVector[16];
+ EFI_GUID FileSystemGuid;
+ UINT64 FvLength;
+ UINT32 Signature;
+ EFI_FVB_ATTRIBUTES_2 Attributes;
+ UINT16 HeaderLength;
+ UINT16 Checksum;
+ UINT16 ExtHeaderOffset;
+ UINT8 Reserved[1];
+ UINT8 Revision;
+ EFI_FV_BLOCK_MAP_ENTRY BlockMap[1];
+} EFI_FIRMWARE_VOLUME_HEADER;
+
+#define EFI_FVH_SIGNATURE EFI_SIGNATURE_32 ('_', 'F', 'V', 'H')
+
+///
+/// Firmware Volume Header Revision definition
+///
+#define EFI_FVH_REVISION 0x02
+
+///
+/// Extension header pointed by ExtHeaderOffset of volume header.
+///
+typedef struct {
+ EFI_GUID FvName;
+ UINT32 ExtHeaderSize;
+} EFI_FIRMWARE_VOLUME_EXT_HEADER;
+
+///
+/// Entry struture for describing FV extension header
+///
+typedef struct {
+ UINT16 ExtEntrySize;
+ UINT16 ExtEntryType;
+} EFI_FIRMWARE_VOLUME_EXT_ENTRY;
+
+#define EFI_FV_EXT_TYPE_OEM_TYPE 0x01
+///
+/// This extension header provides a mapping between a GUID and an OEM file type.
+///
+typedef struct {
+ EFI_FIRMWARE_VOLUME_EXT_ENTRY Hdr;
+ UINT32 TypeMask;
+
+ //
+ // Array of GUIDs.
+ // Each GUID represents an OEM file type.
+ //
+ EFI_GUID Types[1];
+} EFI_FIRMWARE_VOLUME_EXT_ENTRY_OEM_TYPE;
+
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Pi/PiHob.h b/gpxe/src/include/gpxe/efi/Pi/PiHob.h
new file mode 100644
index 00000000..0c8df1f2
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Pi/PiHob.h
@@ -0,0 +1,295 @@
+/** @file
+ HOB related definitions in PI.
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+ @par Revision Reference:
+ PI Version 1.0
+
+**/
+
+#ifndef __PI_HOB_H__
+#define __PI_HOB_H__
+
+#include <gpxe/efi/ProcessorBind.h>
+#include <gpxe/efi/Pi/PiBootMode.h>
+#include <gpxe/efi/Uefi/UefiBaseType.h>
+#include <gpxe/efi/Uefi/UefiMultiPhase.h>
+
+//
+// HobType of EFI_HOB_GENERIC_HEADER.
+//
+#define EFI_HOB_TYPE_HANDOFF 0x0001
+#define EFI_HOB_TYPE_MEMORY_ALLOCATION 0x0002
+#define EFI_HOB_TYPE_RESOURCE_DESCRIPTOR 0x0003
+#define EFI_HOB_TYPE_GUID_EXTENSION 0x0004
+#define EFI_HOB_TYPE_FV 0x0005
+#define EFI_HOB_TYPE_CPU 0x0006
+#define EFI_HOB_TYPE_MEMORY_POOL 0x0007
+#define EFI_HOB_TYPE_FV2 0x0009
+#define EFI_HOB_TYPE_LOAD_PEIM 0x000A
+#define EFI_HOB_TYPE_UNUSED 0xFFFE
+#define EFI_HOB_TYPE_END_OF_HOB_LIST 0xFFFF
+
+///
+/// Describes the format and size of the data inside the HOB.
+/// All HOBs must contain this generic HOB header.
+///
+typedef struct {
+ UINT16 HobType;
+ UINT16 HobLength;
+ UINT32 Reserved;
+} EFI_HOB_GENERIC_HEADER;
+
+
+///
+/// Value of version ofinEFI_HOB_HANDOFF_INFO_TABLE.
+///
+#define EFI_HOB_HANDOFF_TABLE_VERSION 0x0009
+
+///
+/// Contains general state information used by the HOB producer phase.
+/// This HOB must be the first one in the HOB list.
+///
+typedef struct {
+ EFI_HOB_GENERIC_HEADER Header;
+ UINT32 Version;
+ EFI_BOOT_MODE BootMode;
+ EFI_PHYSICAL_ADDRESS EfiMemoryTop;
+ EFI_PHYSICAL_ADDRESS EfiMemoryBottom;
+ EFI_PHYSICAL_ADDRESS EfiFreeMemoryTop;
+ EFI_PHYSICAL_ADDRESS EfiFreeMemoryBottom;
+ EFI_PHYSICAL_ADDRESS EfiEndOfHobList;
+} EFI_HOB_HANDOFF_INFO_TABLE;
+
+///
+/// EFI_HOB_MEMORY_ALLOCATION_HEADER describes the
+/// various attributes of the logical memory allocation. The type field will be used for
+/// subsequent inclusion in the UEFI memory map.
+///
+typedef struct {
+ ///
+ /// A GUID that defines the memory allocation region's type and purpose, as well as
+ /// other fields within the memory allocation HOB. This GUID is used to define the
+ /// additional data within the HOB that may be present for the memory allocation HOB.
+ /// Type EFI_GUID is defined in InstallProtocolInterface() in the UEFI 2.0
+ /// specification.
+ ///
+ EFI_GUID Name;
+
+ ///
+ /// The base address of memory allocated by this HOB. Type
+ /// EFI_PHYSICAL_ADDRESS is defined in AllocatePages() in the UEFI 2.0
+ /// specification.
+ ///
+ EFI_PHYSICAL_ADDRESS MemoryBaseAddress;
+
+ ///
+ /// The length in bytes of memory allocated by this HOB.
+ ///
+ UINT64 MemoryLength;
+
+ ///
+ /// Defines the type of memory allocated by this HOB. The memory type definition
+ /// follows the EFI_MEMORY_TYPE definition. Type EFI_MEMORY_TYPE is defined
+ /// in AllocatePages() in the UEFI 2.0 specification.
+ ///
+ EFI_MEMORY_TYPE MemoryType;
+
+ ///
+ /// Padding for Itanium processor family
+ ///
+ UINT8 Reserved[4];
+} EFI_HOB_MEMORY_ALLOCATION_HEADER;
+
+///
+/// Describes all memory ranges used during the HOB producer
+/// phase that exist outside the HOB list. This HOB type
+/// describes how memory is used,
+/// not the physical attributes of memory.
+///
+typedef struct {
+ EFI_HOB_GENERIC_HEADER Header;
+ EFI_HOB_MEMORY_ALLOCATION_HEADER AllocDescriptor;
+ //
+ // Additional data pertaining to the "Name" Guid memory
+ // may go here.
+ //
+} EFI_HOB_MEMORY_ALLOCATION;
+
+
+///
+/// Describes the memory stack that is produced by the HOB producer
+/// phase and upon which all postmemory-installed executable
+/// content in the HOB producer phase is executing.
+///
+typedef struct {
+ EFI_HOB_GENERIC_HEADER Header;
+ EFI_HOB_MEMORY_ALLOCATION_HEADER AllocDescriptor;
+} EFI_HOB_MEMORY_ALLOCATION_STACK;
+
+///
+/// Defines the location of the boot-strap
+/// processor (BSP) BSPStore ("Backing Store Pointer Store").
+/// This HOB is valid for the Itanium processor family only
+/// register overflow store.
+///
+typedef struct {
+ EFI_HOB_GENERIC_HEADER Header;
+ EFI_HOB_MEMORY_ALLOCATION_HEADER AllocDescriptor;
+} EFI_HOB_MEMORY_ALLOCATION_BSP_STORE;
+
+///
+/// Defines the location and entry point of the HOB consumer phase.
+///
+typedef struct {
+ EFI_HOB_GENERIC_HEADER Header;
+ EFI_HOB_MEMORY_ALLOCATION_HEADER MemoryAllocationHeader;
+ EFI_GUID ModuleName;
+ EFI_PHYSICAL_ADDRESS EntryPoint;
+} EFI_HOB_MEMORY_ALLOCATION_MODULE;
+
+///
+/// Resource type
+///
+typedef UINT32 EFI_RESOURCE_TYPE;
+
+//
+// Value of ResourceType in EFI_HOB_RESOURCE_DESCRIPTOR.
+//
+#define EFI_RESOURCE_SYSTEM_MEMORY 0x00000000
+#define EFI_RESOURCE_MEMORY_MAPPED_IO 0x00000001
+#define EFI_RESOURCE_IO 0x00000002
+#define EFI_RESOURCE_FIRMWARE_DEVICE 0x00000003
+#define EFI_RESOURCE_MEMORY_MAPPED_IO_PORT 0x00000004
+#define EFI_RESOURCE_MEMORY_RESERVED 0x00000005
+#define EFI_RESOURCE_IO_RESERVED 0x00000006
+#define EFI_RESOURCE_MAX_MEMORY_TYPE 0x00000007
+
+///
+/// type of recount attribute type
+///
+typedef UINT32 EFI_RESOURCE_ATTRIBUTE_TYPE;
+
+//
+// These types can be ORed together as needed.
+//
+// The first three enumerations describe settings
+//
+#define EFI_RESOURCE_ATTRIBUTE_PRESENT 0x00000001
+#define EFI_RESOURCE_ATTRIBUTE_INITIALIZED 0x00000002
+#define EFI_RESOURCE_ATTRIBUTE_TESTED 0x00000004
+//
+// The rest of the settings describe capabilities
+//
+#define EFI_RESOURCE_ATTRIBUTE_SINGLE_BIT_ECC 0x00000008
+#define EFI_RESOURCE_ATTRIBUTE_MULTIPLE_BIT_ECC 0x00000010
+#define EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_1 0x00000020
+#define EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_2 0x00000040
+#define EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED 0x00000080
+#define EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED 0x00000100
+#define EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED 0x00000200
+#define EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE 0x00000400
+#define EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE 0x00000800
+#define EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE 0x00001000
+#define EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE 0x00002000
+#define EFI_RESOURCE_ATTRIBUTE_16_BIT_IO 0x00004000
+#define EFI_RESOURCE_ATTRIBUTE_32_BIT_IO 0x00008000
+#define EFI_RESOURCE_ATTRIBUTE_64_BIT_IO 0x00010000
+#define EFI_RESOURCE_ATTRIBUTE_UNCACHED_EXPORTED 0x00020000
+
+///
+/// Describes the resource properties of all fixed,
+/// nonrelocatable resource ranges found on the processor
+/// host bus during the HOB producer phase.
+///
+typedef struct {
+ EFI_HOB_GENERIC_HEADER Header;
+ EFI_GUID Owner;
+ EFI_RESOURCE_TYPE ResourceType;
+ EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute;
+ EFI_PHYSICAL_ADDRESS PhysicalStart;
+ UINT64 ResourceLength;
+} EFI_HOB_RESOURCE_DESCRIPTOR;
+
+///
+/// Allows writers of executable content in the HOB producer phase to
+/// maintain and manage HOBs with specific GUID.
+///
+typedef struct {
+ EFI_HOB_GENERIC_HEADER Header;
+ EFI_GUID Name;
+
+ ///
+ /// Guid specific data goes here
+ ///
+} EFI_HOB_GUID_TYPE;
+
+///
+/// Details the location of firmware volumes that contain firmware files.
+///
+typedef struct {
+ EFI_HOB_GENERIC_HEADER Header;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINT64 Length;
+} EFI_HOB_FIRMWARE_VOLUME;
+
+///
+/// Details the location of a firmware volume which was extracted
+/// from a file within another firmware volume.
+///
+typedef struct {
+ EFI_HOB_GENERIC_HEADER Header;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINT64 Length;
+ EFI_GUID FvName;
+ EFI_GUID FileName;
+} EFI_HOB_FIRMWARE_VOLUME2;
+
+
+///
+/// Describes processor information, such as address space and I/O space capabilities.
+///
+typedef struct {
+ EFI_HOB_GENERIC_HEADER Header;
+ UINT8 SizeOfMemorySpace;
+ UINT8 SizeOfIoSpace;
+ UINT8 Reserved[6];
+} EFI_HOB_CPU;
+
+
+///
+/// Describes pool memory allocations.
+///
+typedef struct {
+ EFI_HOB_GENERIC_HEADER Header;
+} EFI_HOB_MEMORY_POOL;
+
+///
+/// Union of all the possible HOB Types
+///
+typedef union {
+ EFI_HOB_GENERIC_HEADER *Header;
+ EFI_HOB_HANDOFF_INFO_TABLE *HandoffInformationTable;
+ EFI_HOB_MEMORY_ALLOCATION *MemoryAllocation;
+ EFI_HOB_MEMORY_ALLOCATION_BSP_STORE *MemoryAllocationBspStore;
+ EFI_HOB_MEMORY_ALLOCATION_STACK *MemoryAllocationStack;
+ EFI_HOB_MEMORY_ALLOCATION_MODULE *MemoryAllocationModule;
+ EFI_HOB_RESOURCE_DESCRIPTOR *ResourceDescriptor;
+ EFI_HOB_GUID_TYPE *Guid;
+ EFI_HOB_FIRMWARE_VOLUME *FirmwareVolume;
+ EFI_HOB_FIRMWARE_VOLUME2 *FirmwareVolume2;
+ EFI_HOB_CPU *Cpu;
+ EFI_HOB_MEMORY_POOL *Pool;
+ UINT8 *Raw;
+} EFI_PEI_HOB_POINTERS;
+
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Pi/PiMultiPhase.h b/gpxe/src/include/gpxe/efi/Pi/PiMultiPhase.h
new file mode 100644
index 00000000..3ab6421f
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Pi/PiMultiPhase.h
@@ -0,0 +1,104 @@
+/** @file
+ Include file matches things in PI for multiple module types.
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+ @par Revision Reference:
+ PI Version 1.0
+
+**/
+
+#ifndef __PI_MULTIPHASE_H__
+#define __PI_MULTIPHASE_H__
+
+#include <gpxe/efi/Uefi/UefiMultiPhase.h>
+
+#include <gpxe/efi/Pi/PiFirmwareVolume.h>
+#include <gpxe/efi/Pi/PiFirmwareFile.h>
+#include <gpxe/efi/Pi/PiBootMode.h>
+
+#include <gpxe/efi/Pi/PiHob.h>
+#include <gpxe/efi/Pi/PiDependency.h>
+
+
+#define EFI_NOT_AVAILABLE_YET EFIERR (32)
+
+///
+/// Status Code Type Definition
+///
+typedef UINT32 EFI_STATUS_CODE_TYPE;
+
+//
+// A Status Code Type is made up of the code type and severity
+// All values masked by EFI_STATUS_CODE_RESERVED_MASK are
+// reserved for use by this specification.
+//
+#define EFI_STATUS_CODE_TYPE_MASK 0x000000FF
+#define EFI_STATUS_CODE_SEVERITY_MASK 0xFF000000
+#define EFI_STATUS_CODE_RESERVED_MASK 0x00FFFF00
+
+//
+// Definition of code types, all other values masked by
+// EFI_STATUS_CODE_TYPE_MASK are reserved for use by
+// this specification.
+//
+#define EFI_PROGRESS_CODE 0x00000001
+#define EFI_ERROR_CODE 0x00000002
+#define EFI_DEBUG_CODE 0x00000003
+
+//
+// Definitions of severities, all other values masked by
+// EFI_STATUS_CODE_SEVERITY_MASK are reserved for use by
+// this specification.
+// Uncontained errors are major errors that could not contained
+// to the specific component that is reporting the error
+// For example, if a memory error was not detected early enough,
+// the bad data could be consumed by other drivers.
+//
+#define EFI_ERROR_MINOR 0x40000000
+#define EFI_ERROR_MAJOR 0x80000000
+#define EFI_ERROR_UNRECOVERED 0x90000000
+#define EFI_ERROR_UNCONTAINED 0xa0000000
+
+///
+/// Status Code Value Definition
+///
+typedef UINT32 EFI_STATUS_CODE_VALUE;
+
+//
+// A Status Code Value is made up of the class, subclass, and
+// an operation.
+//
+#define EFI_STATUS_CODE_CLASS_MASK 0xFF000000
+#define EFI_STATUS_CODE_SUBCLASS_MASK 0x00FF0000
+#define EFI_STATUS_CODE_OPERATION_MASK 0x0000FFFF
+
+///
+/// Definition of Status Code extended data header.
+/// The data will follow HeaderSize bytes from the beginning of
+/// the structure and is Size bytes long.
+///
+typedef struct {
+ UINT16 HeaderSize;
+ UINT16 Size;
+ EFI_GUID Type;
+} EFI_STATUS_CODE_DATA;
+
+
+//
+// Bit values for Authentication Status
+//
+#define EFI_AUTH_STATUS_PLATFORM_OVERRIDE 0x01
+#define EFI_AUTH_STATUS_IMAGE_SIGNED 0x02
+#define EFI_AUTH_STATUS_NOT_TESTED 0x04
+#define EFI_AUTH_STATUS_TEST_FAILED 0x08
+#define EFI_AUTH_STATUS_ALL 0x0f
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/PiDxe.h b/gpxe/src/include/gpxe/efi/PiDxe.h
new file mode 100644
index 00000000..c3263029
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/PiDxe.h
@@ -0,0 +1,25 @@
+/** @file
+
+ Root include file for Mde Package DXE_CORE, DXE, SMM, SAL type modules.
+
+Copyright (c) 2006 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __PI_DXE_H__
+#define __PI_DXE_H__
+
+#include <gpxe/efi/Uefi/UefiBaseType.h>
+#include <gpxe/efi/Uefi/UefiSpec.h>
+
+#include <gpxe/efi/Pi/PiDxeCis.h>
+
+#endif
+
diff --git a/gpxe/src/include/gpxe/efi/ProcessorBind.h b/gpxe/src/include/gpxe/efi/ProcessorBind.h
new file mode 100644
index 00000000..3dbaf1b8
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/ProcessorBind.h
@@ -0,0 +1,14 @@
+/*
+ * EFI header files rely on having the CPU architecture directory
+ * present in the search path in order to pick up ProcessorBind.h. We
+ * use this header file as a quick indirection layer.
+ * - mcb30
+ */
+
+#if __i386__
+#include <gpxe/efi/Ia32/ProcessorBind.h>
+#endif
+
+#if __x86_64__
+#include <gpxe/efi/X64/ProcessorBind.h>
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Protocol/ComponentName2.h b/gpxe/src/include/gpxe/efi/Protocol/ComponentName2.h
new file mode 100644
index 00000000..0f010142
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Protocol/ComponentName2.h
@@ -0,0 +1,174 @@
+/** @file
+ UEFI Component Name 2 Protocol as defined in the UEFI 2.1 specification.
+ This protocol is used to retrieve user readable names of drivers
+ and controllers managed by UEFI Drivers.
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __EFI_COMPONENT_NAME2_H__
+#define __EFI_COMPONENT_NAME2_H__
+
+///
+/// Global ID for the Component Name Protocol
+///
+#define EFI_COMPONENT_NAME2_PROTOCOL_GUID \
+ {0x6a7a5cff, 0xe8d9, 0x4f70, { 0xba, 0xda, 0x75, 0xab, 0x30, 0x25, 0xce, 0x14 } }
+
+typedef struct _EFI_COMPONENT_NAME2_PROTOCOL EFI_COMPONENT_NAME2_PROTOCOL;
+
+
+/**
+ Retrieves a Unicode string that is the user readable name of
+ the EFI Driver.
+
+ @param This A pointer to the
+ EFI_COMPONENT_NAME2_PROTOCOL instance.
+
+ @param Language A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller
+ is requesting, and it must match one of the
+ languages specified in SupportedLanguages.
+ The number of languages supported by a
+ driver is up to the driver writer. Language
+ is specified in RFC 3066 language code
+ format.
+
+ @param DriverName A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the
+ Driver specified by This and the
+ language specified by Language
+ was returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This
+ does not support the language
+ specified by Language.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_COMPONENT_NAME2_GET_DRIVER_NAME)(
+ IN EFI_COMPONENT_NAME2_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+
+/**
+ Retrieves a Unicode string that is the user readable name of
+ the controller that is being managed by an EFI Driver.
+
+ @param This A pointer to the
+ EFI_COMPONENT_NAME2_PROTOCOL instance.
+
+ @param ControllerHandle The handle of a controller that the
+ driver specified by This is managing.
+ This handle specifies the controller
+ whose name is to be returned.
+
+ @param ChildHandle The handle of the child controller to
+ retrieve the name of. This is an
+ optional parameter that may be NULL.
+ It will be NULL for device drivers.
+ It will also be NULL for a bus
+ drivers that wish to retrieve the
+ name of the bus controller. It will
+ not be NULL for a bus driver that
+ wishes to retrieve the name of a
+ child controller.
+
+ @param Language A pointer to a Null-terminated ASCII
+ string array indicating the language.
+ This is the language of the driver
+ name that the caller is requesting,
+ and it must match one of the
+ languages specified in
+ SupportedLanguages. The number of
+ languages supported by a driver is up
+ to the driver writer. Language is
+ specified in RFC 3066 language code
+ format.
+
+ @param ControllerName A pointer to the Unicode string to
+ return. This Unicode string is the
+ name of the controller specified by
+ ControllerHandle and ChildHandle in
+ the language specified by Language
+ from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user
+ readable name in the language
+ specified by Language for the
+ driver specified by This was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it
+ is not a valid EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is
+ not currently managing the
+ controller specified by
+ ControllerHandle and
+ ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This
+ does not support the language
+ specified by Language.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)(
+ IN EFI_COMPONENT_NAME2_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+///
+/// This protocol is used to retrieve user readable names of drivers
+/// and controllers managed by UEFI Drivers.
+///
+struct _EFI_COMPONENT_NAME2_PROTOCOL {
+ EFI_COMPONENT_NAME2_GET_DRIVER_NAME GetDriverName;
+ EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME GetControllerName;
+
+ ///
+ /// A Null-terminated ASCII string array that contains one or more
+ /// supported language codes. This is the list of language codes that
+ /// this protocol supports. The number of languages supported by a
+ /// driver is up to the driver writer. SupportedLanguages is
+ /// specified in RFC 3066 format.
+ ///
+ CHAR8 *SupportedLanguages;
+};
+
+extern EFI_GUID gEfiComponentName2ProtocolGuid;
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Protocol/Cpu.h b/gpxe/src/include/gpxe/efi/Protocol/Cpu.h
new file mode 100644
index 00000000..da3d0fda
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Protocol/Cpu.h
@@ -0,0 +1,291 @@
+/** @file
+ CPU Architectural Protocol as defined in PI spec Volume 2 DXE
+
+ This code abstracts the DXE core from processor implementation details.
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __ARCH_PROTOCOL_CPU_H__
+#define __ARCH_PROTOCOL_CPU_H__
+
+#include <gpxe/efi/Protocol/DebugSupport.h>
+
+#define EFI_CPU_ARCH_PROTOCOL_GUID \
+ { 0x26baccb1, 0x6f42, 0x11d4, {0xbc, 0xe7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } }
+
+typedef struct _EFI_CPU_ARCH_PROTOCOL EFI_CPU_ARCH_PROTOCOL;
+
+typedef enum {
+ EfiCpuFlushTypeWriteBackInvalidate,
+ EfiCpuFlushTypeWriteBack,
+ EfiCpuFlushTypeInvalidate,
+ EfiCpuMaxFlushType
+} EFI_CPU_FLUSH_TYPE;
+
+typedef enum {
+ EfiCpuInit,
+ EfiCpuMaxInitType
+} EFI_CPU_INIT_TYPE;
+
+/**
+ EFI_CPU_INTERRUPT_HANDLER that is called when a processor interrupt occurs.
+
+ @param InterruptType Defines the type of interrupt or exception that
+ occurred on the processor.This parameter is processor architecture specific.
+ @param SystemContext A pointer to the processor context when
+ the interrupt occurred on the processor.
+
+ @return None
+
+**/
+typedef
+VOID
+(EFIAPI *EFI_CPU_INTERRUPT_HANDLER)(
+ IN CONST EFI_EXCEPTION_TYPE InterruptType,
+ IN CONST EFI_SYSTEM_CONTEXT SystemContext
+ );
+
+/**
+ This function flushes the range of addresses from Start to Start+Length
+ from the processor's data cache. If Start is not aligned to a cache line
+ boundary, then the bytes before Start to the preceding cache line boundary
+ are also flushed. If Start+Length is not aligned to a cache line boundary,
+ then the bytes past Start+Length to the end of the next cache line boundary
+ are also flushed. The FlushType of EfiCpuFlushTypeWriteBackInvalidate must be
+ supported. If the data cache is fully coherent with all DMA operations, then
+ this function can just return EFI_SUCCESS. If the processor does not support
+ flushing a range of the data cache, then the entire data cache can be flushed.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+ @param Start The beginning physical address to flush from the processor's data
+ cache.
+ @param Length The number of bytes to flush from the processor's data cache. This
+ function may flush more bytes than Length specifies depending upon
+ the granularity of the flush operation that the processor supports.
+ @param FlushType Specifies the type of flush operation to perform.
+
+ @retval EFI_SUCCESS The address range from Start to Start+Length was flushed from
+ the processor's data cache.
+ @retval EFI_UNSUPPORTEDT The processor does not support the cache flush type specified
+ by FlushType.
+ @retval EFI_DEVICE_ERROR The address range from Start to Start+Length could not be flushed
+ from the processor's data cache.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_FLUSH_DATA_CACHE)(
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS Start,
+ IN UINT64 Length,
+ IN EFI_CPU_FLUSH_TYPE FlushType
+ );
+
+
+/**
+ This function enables interrupt processing by the processor.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+
+ @retval EFI_SUCCESS Interrupts are enabled on the processor.
+ @retval EFI_DEVICE_ERROR Interrupts could not be enabled on the processor.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_ENABLE_INTERRUPT)(
+ IN EFI_CPU_ARCH_PROTOCOL *This
+ );
+
+
+/**
+ This function disables interrupt processing by the processor.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+
+ @retval EFI_SUCCESS Interrupts are disabled on the processor.
+ @retval EFI_DEVICE_ERROR Interrupts could not be disabled on the processor.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_DISABLE_INTERRUPT)(
+ IN EFI_CPU_ARCH_PROTOCOL *This
+ );
+
+
+/**
+ This function retrieves the processor's current interrupt state a returns it in
+ State. If interrupts are currently enabled, then TRUE is returned. If interrupts
+ are currently disabled, then FALSE is returned.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+ @param State A pointer to the processor's current interrupt state. Set to TRUE if
+ interrupts are enabled and FALSE if interrupts are disabled.
+
+ @retval EFI_SUCCESS The processor's current interrupt state was returned in State.
+ @retval EFI_INVALID_PARAMETER State is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_GET_INTERRUPT_STATE)(
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ OUT BOOLEAN *State
+ );
+
+
+/**
+ This function generates an INIT on the processor. If this function succeeds, then the
+ processor will be reset, and control will not be returned to the caller. If InitType is
+ not supported by this processor, or the processor cannot programmatically generate an
+ INIT without help from external hardware, then EFI_UNSUPPORTED is returned. If an error
+ occurs attempting to generate an INIT, then EFI_DEVICE_ERROR is returned.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+ @param InitType The type of processor INIT to perform.
+
+ @retval EFI_SUCCESS The processor INIT was performed. This return code should never be seen.
+ @retval EFI_UNSUPPORTED The processor INIT operation specified by InitType is not supported
+ by this processor.
+ @retval EFI_DEVICE_ERROR The processor INIT failed.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_INIT)(
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_CPU_INIT_TYPE InitType
+ );
+
+
+/**
+ This function registers and enables the handler specified by InterruptHandler for a processor
+ interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
+ handler for the processor interrupt or exception type specified by InterruptType is uninstalled.
+ The installed handler is called once for each processor interrupt or exception.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+ @param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts
+ are enabled and FALSE if interrupts are disabled.
+ @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
+ when a processor interrupt occurs. If this parameter is NULL, then the handler
+ will be uninstalled.
+
+ @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
+ previously installed.
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
+ previously installed.
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_REGISTER_INTERRUPT_HANDLER)(
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ );
+
+
+/**
+ This function reads the processor timer specified by TimerIndex and returns it in TimerValue.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+ @param TimerIndex Specifies which processor timer is to be returned in TimerValue. This parameter
+ must be between 0 and NumberOfTimers-1.
+ @param TimerValue Pointer to the returned timer value.
+ @param TimerPeriod A pointer to the amount of time that passes in femtoseconds for each increment
+ of TimerValue.
+
+ @retval EFI_SUCCESS The processor timer value specified by TimerIndex was returned in TimerValue.
+ @retval EFI_DEVICE_ERROR An error occurred attempting to read one of the processor's timers.
+ @retval EFI_INVALID_PARAMETER TimerValue is NULL or TimerIndex is not valid.
+ @retval EFI_UNSUPPORTED The processor does not have any readable timers.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_GET_TIMER_VALUE)(
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN UINT32 TimerIndex,
+ OUT UINT64 *TimerValue,
+ OUT UINT64 *TimerPeriod OPTIONAL
+ );
+
+
+/**
+ This function modifies the attributes for the memory region specified by BaseAddress and
+ Length from their current attributes to the attributes specified by Attributes.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+ @param BaseAddress The physical address that is the start address of a memory region.
+ @param Length The size in bytes of the memory region.
+ @param Attributes The bit mask of attributes to set for the memory region.
+
+ @retval EFI_SUCCESS The attributes were set for the memory region.
+ @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
+ BaseAddress and Length cannot be modified.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
+ the memory resource range.
+ @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
+ resource range specified by BaseAddress and Length.
+ The bit mask of attributes is not support for the memory resource
+ range specified by BaseAddress and Length.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_SET_MEMORY_ATTRIBUTES)(
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Attributes
+ );
+
+
+///
+/// The EFI_CPU_ARCH_PROTOCOL is used to abstract processor-specific functions from the DXE
+/// Foundation. This includes flushing caches, enabling and disabling interrupts, hooking interrupt
+/// vectors and exception vectors, reading internal processor timers, resetting the processor, and
+/// determining the processor frequency.
+///
+struct _EFI_CPU_ARCH_PROTOCOL {
+ EFI_CPU_FLUSH_DATA_CACHE FlushDataCache;
+ EFI_CPU_ENABLE_INTERRUPT EnableInterrupt;
+ EFI_CPU_DISABLE_INTERRUPT DisableInterrupt;
+ EFI_CPU_GET_INTERRUPT_STATE GetInterruptState;
+ EFI_CPU_INIT Init;
+ EFI_CPU_REGISTER_INTERRUPT_HANDLER RegisterInterruptHandler;
+ EFI_CPU_GET_TIMER_VALUE GetTimerValue;
+ EFI_CPU_SET_MEMORY_ATTRIBUTES SetMemoryAttributes;
+ ///
+ /// The number of timers that are available in a processor. The value in this
+ /// field is a constant that must not be modified after the CPU Architectural
+ /// Protocol is installed. All consumers must treat this as a read-only field.
+ ///
+ UINT32 NumberOfTimers;
+ ///
+ /// The size, in bytes, of the alignment required for DMA buffer allocations.
+ /// This is typically the size of the largest data cache line in the platform.
+ /// The value in this field is a constant that must not be modified after the
+ /// CPU Architectural Protocol is installed. All consumers must treat this as
+ /// a read-only field.
+ ///
+ UINT32 DmaBufferAlignment;
+};
+
+extern EFI_GUID gEfiCpuArchProtocolGuid;
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Protocol/CpuIo.h b/gpxe/src/include/gpxe/efi/Protocol/CpuIo.h
new file mode 100644
index 00000000..8d35c6cd
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Protocol/CpuIo.h
@@ -0,0 +1,128 @@
+/** @file
+ This code abstracts the CPU IO Protocol which installed by some platform or chipset-specific
+ PEIM that abstracts the processor-visible I/O operations.
+
+ Copyright (c) 2007, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+ Module Name: CpuIO.h
+
+ @par Revision Reference:
+ CPU IO Protocol is defined in Framework of EFI CPU IO Protocol Spec
+ Version 0.9
+
+**/
+
+#ifndef _CPUIO_H_
+#define _CPUIO_H_
+
+#include <gpxe/efi/PiDxe.h>
+
+#define EFI_CPU_IO_PROTOCOL_GUID \
+ { \
+ 0xB0732526, 0x38C8, 0x4b40, {0x88, 0x77, 0x61, 0xC7, 0xB0, 0x6A, 0xAC, 0x45 } \
+ }
+
+typedef struct _EFI_CPU_IO_PROTOCOL EFI_CPU_IO_PROTOCOL;
+
+//
+// *******************************************************
+// EFI_CPU_IO_PROTOCOL_WIDTH
+// *******************************************************
+//
+typedef enum {
+ EfiCpuIoWidthUint8,
+ EfiCpuIoWidthUint16,
+ EfiCpuIoWidthUint32,
+ EfiCpuIoWidthUint64,
+ EfiCpuIoWidthFifoUint8,
+ EfiCpuIoWidthFifoUint16,
+ EfiCpuIoWidthFifoUint32,
+ EfiCpuIoWidthFifoUint64,
+ EfiCpuIoWidthFillUint8,
+ EfiCpuIoWidthFillUint16,
+ EfiCpuIoWidthFillUint32,
+ EfiCpuIoWidthFillUint64,
+ EfiCpuIoWidthMaximum
+} EFI_CPU_IO_PROTOCOL_WIDTH;
+
+//
+// *******************************************************
+// EFI_CPU_IO_PROTOCOL_IO_MEM
+// *******************************************************
+//
+/**
+ Enables a driver to access memory-mapped registers in the EFI system memory space.
+ Or, Enables a driver to access registers in the EFI CPU I/O space.
+
+ @param This A pointer to the EFI_CPU_IO_PROTOCOL instance.
+ @param Width Signifies the width of the I/O or Memory operation.
+ @param Address The base address of the I/O or Memoryoperation.
+ @param Count The number of I/O or Memory operations to perform.
+ The number of bytes moved is Width size * Count, starting at Address.
+ @param Buffer For read operations, the destination buffer to store the results.
+ For write operations, the source buffer from which to write data.
+
+ @retval EFI_SUCCESS The data was read from or written to the EFI system.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this EFI system.Or Buffer is NULL.
+ @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
+ Or,The address range specified by Address, Width, and Count is not valid for this EFI system.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_IO_PROTOCOL_IO_MEM)(
+ IN EFI_CPU_IO_PROTOCOL *This,
+ IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+//
+// *******************************************************
+// EFI_CPU_IO_PROTOCOL_ACCESS
+// *******************************************************
+//
+typedef struct {
+ EFI_CPU_IO_PROTOCOL_IO_MEM Read;
+ EFI_CPU_IO_PROTOCOL_IO_MEM Write;
+} EFI_CPU_IO_PROTOCOL_ACCESS;
+
+//
+// *******************************************************
+// EFI_CPU_IO_PROTOCOL
+// *******************************************************
+//
+/**
+ @par Protocol Description:
+ Provides the basic memory and I/O interfaces that are used to abstract
+ accesses to devices in a system.
+
+ @param Mem.Read
+ Allows reads from memory-mapped I/O space.
+
+ @param Mem.Write
+ Allows writes to memory-mapped I/O space.
+
+ @param Io.Read
+ Allows reads from I/O space.
+
+ @param Io.Write
+ Allows writes to I/O space.
+
+**/
+struct _EFI_CPU_IO_PROTOCOL {
+ EFI_CPU_IO_PROTOCOL_ACCESS Mem;
+ EFI_CPU_IO_PROTOCOL_ACCESS Io;
+};
+
+extern EFI_GUID gEfiCpuIoProtocolGuid;
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Protocol/DebugSupport.h b/gpxe/src/include/gpxe/efi/Protocol/DebugSupport.h
new file mode 100644
index 00000000..c8db2498
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Protocol/DebugSupport.h
@@ -0,0 +1,634 @@
+/** @file
+ DebugSupport protocol and supporting definitions as defined in the UEFI2.0
+ specification.
+
+ The DebugSupport protocol is used by source level debuggers to abstract the
+ processor and handle context save and restore operations.
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __DEBUG_SUPPORT_H__
+#define __DEBUG_SUPPORT_H__
+
+#include <gpxe/efi/ProcessorBind.h>
+#include <gpxe/efi/IndustryStandard/PeImage.h>
+
+typedef struct _EFI_DEBUG_SUPPORT_PROTOCOL EFI_DEBUG_SUPPORT_PROTOCOL;
+
+///
+/// Debug Support protocol {2755590C-6F3C-42FA-9EA4-A3BA543CDA25}
+///
+#define EFI_DEBUG_SUPPORT_PROTOCOL_GUID \
+ { \
+ 0x2755590C, 0x6F3C, 0x42FA, {0x9E, 0xA4, 0xA3, 0xBA, 0x54, 0x3C, 0xDA, 0x25 } \
+ }
+
+///
+/// Debug Support definitions
+///
+typedef INTN EFI_EXCEPTION_TYPE;
+
+//
+// IA-32 processor exception types
+//
+#define EXCEPT_IA32_DIVIDE_ERROR 0
+#define EXCEPT_IA32_DEBUG 1
+#define EXCEPT_IA32_NMI 2
+#define EXCEPT_IA32_BREAKPOINT 3
+#define EXCEPT_IA32_OVERFLOW 4
+#define EXCEPT_IA32_BOUND 5
+#define EXCEPT_IA32_INVALID_OPCODE 6
+#define EXCEPT_IA32_DOUBLE_FAULT 8
+#define EXCEPT_IA32_INVALID_TSS 10
+#define EXCEPT_IA32_SEG_NOT_PRESENT 11
+#define EXCEPT_IA32_STACK_FAULT 12
+#define EXCEPT_IA32_GP_FAULT 13
+#define EXCEPT_IA32_PAGE_FAULT 14
+#define EXCEPT_IA32_FP_ERROR 16
+#define EXCEPT_IA32_ALIGNMENT_CHECK 17
+#define EXCEPT_IA32_MACHINE_CHECK 18
+#define EXCEPT_IA32_SIMD 19
+
+///
+/// IA-32 processor context definition
+///
+///
+/// FXSAVE_STATE
+/// FP / MMX / XMM registers (see fxrstor instruction definition)
+///
+typedef struct {
+ UINT16 Fcw;
+ UINT16 Fsw;
+ UINT16 Ftw;
+ UINT16 Opcode;
+ UINT32 Eip;
+ UINT16 Cs;
+ UINT16 Reserved1;
+ UINT32 DataOffset;
+ UINT16 Ds;
+ UINT8 Reserved2[10];
+ UINT8 St0Mm0[10], Reserved3[6];
+ UINT8 St1Mm1[10], Reserved4[6];
+ UINT8 St2Mm2[10], Reserved5[6];
+ UINT8 St3Mm3[10], Reserved6[6];
+ UINT8 St4Mm4[10], Reserved7[6];
+ UINT8 St5Mm5[10], Reserved8[6];
+ UINT8 St6Mm6[10], Reserved9[6];
+ UINT8 St7Mm7[10], Reserved10[6];
+ UINT8 Xmm0[16];
+ UINT8 Xmm1[16];
+ UINT8 Xmm2[16];
+ UINT8 Xmm3[16];
+ UINT8 Xmm4[16];
+ UINT8 Xmm5[16];
+ UINT8 Xmm6[16];
+ UINT8 Xmm7[16];
+ UINT8 Reserved11[14 * 16];
+} EFI_FX_SAVE_STATE_IA32;
+
+typedef struct {
+ UINT32 ExceptionData;
+ EFI_FX_SAVE_STATE_IA32 FxSaveState;
+ UINT32 Dr0;
+ UINT32 Dr1;
+ UINT32 Dr2;
+ UINT32 Dr3;
+ UINT32 Dr6;
+ UINT32 Dr7;
+ UINT32 Cr0;
+ UINT32 Cr1; /* Reserved */
+ UINT32 Cr2;
+ UINT32 Cr3;
+ UINT32 Cr4;
+ UINT32 Eflags;
+ UINT32 Ldtr;
+ UINT32 Tr;
+ UINT32 Gdtr[2];
+ UINT32 Idtr[2];
+ UINT32 Eip;
+ UINT32 Gs;
+ UINT32 Fs;
+ UINT32 Es;
+ UINT32 Ds;
+ UINT32 Cs;
+ UINT32 Ss;
+ UINT32 Edi;
+ UINT32 Esi;
+ UINT32 Ebp;
+ UINT32 Esp;
+ UINT32 Ebx;
+ UINT32 Edx;
+ UINT32 Ecx;
+ UINT32 Eax;
+} EFI_SYSTEM_CONTEXT_IA32;
+
+//
+// X64 processor exception types
+//
+#define EXCEPT_X64_DIVIDE_ERROR 0
+#define EXCEPT_X64_DEBUG 1
+#define EXCEPT_X64_NMI 2
+#define EXCEPT_X64_BREAKPOINT 3
+#define EXCEPT_X64_OVERFLOW 4
+#define EXCEPT_X64_BOUND 5
+#define EXCEPT_X64_INVALID_OPCODE 6
+#define EXCEPT_X64_DOUBLE_FAULT 8
+#define EXCEPT_X64_INVALID_TSS 10
+#define EXCEPT_X64_SEG_NOT_PRESENT 11
+#define EXCEPT_X64_STACK_FAULT 12
+#define EXCEPT_X64_GP_FAULT 13
+#define EXCEPT_X64_PAGE_FAULT 14
+#define EXCEPT_X64_FP_ERROR 16
+#define EXCEPT_X64_ALIGNMENT_CHECK 17
+#define EXCEPT_X64_MACHINE_CHECK 18
+#define EXCEPT_X64_SIMD 19
+
+///
+/// X64 processor context definition
+///
+/// FXSAVE_STATE
+/// FP / MMX / XMM registers (see fxrstor instruction definition)
+///
+typedef struct {
+ UINT16 Fcw;
+ UINT16 Fsw;
+ UINT16 Ftw;
+ UINT16 Opcode;
+ UINT64 Rip;
+ UINT64 DataOffset;
+ UINT8 Reserved1[8];
+ UINT8 St0Mm0[10], Reserved2[6];
+ UINT8 St1Mm1[10], Reserved3[6];
+ UINT8 St2Mm2[10], Reserved4[6];
+ UINT8 St3Mm3[10], Reserved5[6];
+ UINT8 St4Mm4[10], Reserved6[6];
+ UINT8 St5Mm5[10], Reserved7[6];
+ UINT8 St6Mm6[10], Reserved8[6];
+ UINT8 St7Mm7[10], Reserved9[6];
+ UINT8 Xmm0[16];
+ UINT8 Xmm1[16];
+ UINT8 Xmm2[16];
+ UINT8 Xmm3[16];
+ UINT8 Xmm4[16];
+ UINT8 Xmm5[16];
+ UINT8 Xmm6[16];
+ UINT8 Xmm7[16];
+ //
+ // NOTE: UEFI 2.0 spec definition as follows.
+ //
+ UINT8 Reserved11[14 * 16];
+} EFI_FX_SAVE_STATE_X64;
+
+typedef struct {
+ UINT64 ExceptionData;
+ EFI_FX_SAVE_STATE_X64 FxSaveState;
+ UINT64 Dr0;
+ UINT64 Dr1;
+ UINT64 Dr2;
+ UINT64 Dr3;
+ UINT64 Dr6;
+ UINT64 Dr7;
+ UINT64 Cr0;
+ UINT64 Cr1; /* Reserved */
+ UINT64 Cr2;
+ UINT64 Cr3;
+ UINT64 Cr4;
+ UINT64 Cr8;
+ UINT64 Rflags;
+ UINT64 Ldtr;
+ UINT64 Tr;
+ UINT64 Gdtr[2];
+ UINT64 Idtr[2];
+ UINT64 Rip;
+ UINT64 Gs;
+ UINT64 Fs;
+ UINT64 Es;
+ UINT64 Ds;
+ UINT64 Cs;
+ UINT64 Ss;
+ UINT64 Rdi;
+ UINT64 Rsi;
+ UINT64 Rbp;
+ UINT64 Rsp;
+ UINT64 Rbx;
+ UINT64 Rdx;
+ UINT64 Rcx;
+ UINT64 Rax;
+ UINT64 R8;
+ UINT64 R9;
+ UINT64 R10;
+ UINT64 R11;
+ UINT64 R12;
+ UINT64 R13;
+ UINT64 R14;
+ UINT64 R15;
+} EFI_SYSTEM_CONTEXT_X64;
+
+//
+// IPF processor exception types
+//
+#define EXCEPT_IPF_VHTP_TRANSLATION 0
+#define EXCEPT_IPF_INSTRUCTION_TLB 1
+#define EXCEPT_IPF_DATA_TLB 2
+#define EXCEPT_IPF_ALT_INSTRUCTION_TLB 3
+#define EXCEPT_IPF_ALT_DATA_TLB 4
+#define EXCEPT_IPF_DATA_NESTED_TLB 5
+#define EXCEPT_IPF_INSTRUCTION_KEY_MISSED 6
+#define EXCEPT_IPF_DATA_KEY_MISSED 7
+#define EXCEPT_IPF_DIRTY_BIT 8
+#define EXCEPT_IPF_INSTRUCTION_ACCESS_BIT 9
+#define EXCEPT_IPF_DATA_ACCESS_BIT 10
+#define EXCEPT_IPF_BREAKPOINT 11
+#define EXCEPT_IPF_EXTERNAL_INTERRUPT 12
+//
+// 13 - 19 reserved
+//
+#define EXCEPT_IPF_PAGE_NOT_PRESENT 20
+#define EXCEPT_IPF_KEY_PERMISSION 21
+#define EXCEPT_IPF_INSTRUCTION_ACCESS_RIGHTS 22
+#define EXCEPT_IPF_DATA_ACCESS_RIGHTS 23
+#define EXCEPT_IPF_GENERAL_EXCEPTION 24
+#define EXCEPT_IPF_DISABLED_FP_REGISTER 25
+#define EXCEPT_IPF_NAT_CONSUMPTION 26
+#define EXCEPT_IPF_SPECULATION 27
+//
+// 28 reserved
+//
+#define EXCEPT_IPF_DEBUG 29
+#define EXCEPT_IPF_UNALIGNED_REFERENCE 30
+#define EXCEPT_IPF_UNSUPPORTED_DATA_REFERENCE 31
+#define EXCEPT_IPF_FP_FAULT 32
+#define EXCEPT_IPF_FP_TRAP 33
+#define EXCEPT_IPF_LOWER_PRIVILEGE_TRANSFER_TRAP 34
+#define EXCEPT_IPF_TAKEN_BRANCH 35
+#define EXCEPT_IPF_SINGLE_STEP 36
+//
+// 37 - 44 reserved
+//
+#define EXCEPT_IPF_IA32_EXCEPTION 45
+#define EXCEPT_IPF_IA32_INTERCEPT 46
+#define EXCEPT_IPF_IA32_INTERRUPT 47
+
+///
+/// IPF processor context definition
+///
+typedef struct {
+ //
+ // The first reserved field is necessary to preserve alignment for the correct
+ // bits in UNAT and to insure F2 is 16 byte aligned..
+ //
+ UINT64 Reserved;
+ UINT64 R1;
+ UINT64 R2;
+ UINT64 R3;
+ UINT64 R4;
+ UINT64 R5;
+ UINT64 R6;
+ UINT64 R7;
+ UINT64 R8;
+ UINT64 R9;
+ UINT64 R10;
+ UINT64 R11;
+ UINT64 R12;
+ UINT64 R13;
+ UINT64 R14;
+ UINT64 R15;
+ UINT64 R16;
+ UINT64 R17;
+ UINT64 R18;
+ UINT64 R19;
+ UINT64 R20;
+ UINT64 R21;
+ UINT64 R22;
+ UINT64 R23;
+ UINT64 R24;
+ UINT64 R25;
+ UINT64 R26;
+ UINT64 R27;
+ UINT64 R28;
+ UINT64 R29;
+ UINT64 R30;
+ UINT64 R31;
+
+ UINT64 F2[2];
+ UINT64 F3[2];
+ UINT64 F4[2];
+ UINT64 F5[2];
+ UINT64 F6[2];
+ UINT64 F7[2];
+ UINT64 F8[2];
+ UINT64 F9[2];
+ UINT64 F10[2];
+ UINT64 F11[2];
+ UINT64 F12[2];
+ UINT64 F13[2];
+ UINT64 F14[2];
+ UINT64 F15[2];
+ UINT64 F16[2];
+ UINT64 F17[2];
+ UINT64 F18[2];
+ UINT64 F19[2];
+ UINT64 F20[2];
+ UINT64 F21[2];
+ UINT64 F22[2];
+ UINT64 F23[2];
+ UINT64 F24[2];
+ UINT64 F25[2];
+ UINT64 F26[2];
+ UINT64 F27[2];
+ UINT64 F28[2];
+ UINT64 F29[2];
+ UINT64 F30[2];
+ UINT64 F31[2];
+
+ UINT64 Pr;
+
+ UINT64 B0;
+ UINT64 B1;
+ UINT64 B2;
+ UINT64 B3;
+ UINT64 B4;
+ UINT64 B5;
+ UINT64 B6;
+ UINT64 B7;
+
+ //
+ // application registers
+ //
+ UINT64 ArRsc;
+ UINT64 ArBsp;
+ UINT64 ArBspstore;
+ UINT64 ArRnat;
+
+ UINT64 ArFcr;
+
+ UINT64 ArEflag;
+ UINT64 ArCsd;
+ UINT64 ArSsd;
+ UINT64 ArCflg;
+ UINT64 ArFsr;
+ UINT64 ArFir;
+ UINT64 ArFdr;
+
+ UINT64 ArCcv;
+
+ UINT64 ArUnat;
+
+ UINT64 ArFpsr;
+
+ UINT64 ArPfs;
+ UINT64 ArLc;
+ UINT64 ArEc;
+
+ //
+ // control registers
+ //
+ UINT64 CrDcr;
+ UINT64 CrItm;
+ UINT64 CrIva;
+ UINT64 CrPta;
+ UINT64 CrIpsr;
+ UINT64 CrIsr;
+ UINT64 CrIip;
+ UINT64 CrIfa;
+ UINT64 CrItir;
+ UINT64 CrIipa;
+ UINT64 CrIfs;
+ UINT64 CrIim;
+ UINT64 CrIha;
+
+ //
+ // debug registers
+ //
+ UINT64 Dbr0;
+ UINT64 Dbr1;
+ UINT64 Dbr2;
+ UINT64 Dbr3;
+ UINT64 Dbr4;
+ UINT64 Dbr5;
+ UINT64 Dbr6;
+ UINT64 Dbr7;
+
+ UINT64 Ibr0;
+ UINT64 Ibr1;
+ UINT64 Ibr2;
+ UINT64 Ibr3;
+ UINT64 Ibr4;
+ UINT64 Ibr5;
+ UINT64 Ibr6;
+ UINT64 Ibr7;
+
+ //
+ // virtual registers - nat bits for R1-R31
+ //
+ UINT64 IntNat;
+
+} EFI_SYSTEM_CONTEXT_IPF;
+
+//
+// EBC processor exception types
+//
+#define EXCEPT_EBC_UNDEFINED 0
+#define EXCEPT_EBC_DIVIDE_ERROR 1
+#define EXCEPT_EBC_DEBUG 2
+#define EXCEPT_EBC_BREAKPOINT 3
+#define EXCEPT_EBC_OVERFLOW 4
+#define EXCEPT_EBC_INVALID_OPCODE 5 // opcode out of range
+#define EXCEPT_EBC_STACK_FAULT 6
+#define EXCEPT_EBC_ALIGNMENT_CHECK 7
+#define EXCEPT_EBC_INSTRUCTION_ENCODING 8 // malformed instruction
+#define EXCEPT_EBC_BAD_BREAK 9 // BREAK 0 or undefined BREAK
+#define EXCEPT_EBC_STEP 10 // to support debug stepping
+///
+/// For coding convenience, define the maximum valid EBC exception.
+///
+#define MAX_EBC_EXCEPTION EXCEPT_EBC_STEP
+
+///
+/// EBC processor context definition
+///
+typedef struct {
+ UINT64 R0;
+ UINT64 R1;
+ UINT64 R2;
+ UINT64 R3;
+ UINT64 R4;
+ UINT64 R5;
+ UINT64 R6;
+ UINT64 R7;
+ UINT64 Flags;
+ UINT64 ControlFlags;
+ UINT64 Ip;
+} EFI_SYSTEM_CONTEXT_EBC;
+
+///
+/// Universal EFI_SYSTEM_CONTEXT definition
+///
+typedef union {
+ EFI_SYSTEM_CONTEXT_EBC *SystemContextEbc;
+ EFI_SYSTEM_CONTEXT_IA32 *SystemContextIa32;
+ EFI_SYSTEM_CONTEXT_X64 *SystemContextX64;
+ EFI_SYSTEM_CONTEXT_IPF *SystemContextIpf;
+} EFI_SYSTEM_CONTEXT;
+
+//
+// DebugSupport callback function prototypes
+//
+
+/**
+ Registers and enables an exception callback function for the specified exception.
+
+ @param ExceptionType Exception types in EBC, IA-32, X64, or IPF
+ @param SystemContext Exception content.
+
+**/
+typedef
+VOID
+(*EFI_EXCEPTION_CALLBACK)(
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ );
+
+/**
+ Registers and enables the on-target debug agent's periodic entry point.
+
+ @param SystemContext Exception content.
+
+**/
+typedef
+VOID
+(*EFI_PERIODIC_CALLBACK)(
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ );
+
+///
+/// Machine type definition
+///
+typedef enum {
+ IsaIa32 = IMAGE_FILE_MACHINE_I386, ///< 0x014C
+ IsaX64 = IMAGE_FILE_MACHINE_X64, ///< 0x8664
+ IsaIpf = IMAGE_FILE_MACHINE_IA64, ///< 0x0200
+ IsaEbc = IMAGE_FILE_MACHINE_EBC ///< 0x0EBC
+} EFI_INSTRUCTION_SET_ARCHITECTURE;
+
+
+//
+// DebugSupport member function definitions
+//
+
+/**
+ Returns the maximum value that may be used for the ProcessorIndex parameter in
+ RegisterPeriodicCallback() and RegisterExceptionCallback().
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.
+ @param MaxProcessorIndex Pointer to a caller-allocated UINTN in which the maximum supported
+ processor index is returned.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_MAXIMUM_PROCESSOR_INDEX)(
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ OUT UINTN *MaxProcessorIndex
+ );
+
+/**
+ Registers a function to be called back periodically in interrupt context.
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.
+ @param ProcessorIndex Specifies which processor the callback function applies to.
+ @param PeriodicCallback A pointer to a function of type PERIODIC_CALLBACK that is the main
+ periodic entry point of the debug agent.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a callback
+ function was previously registered.
+ @retval EFI_OUT_OF_RESOURCES System has insufficient memory resources to register new callback
+ function.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_REGISTER_PERIODIC_CALLBACK)(
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ IN UINTN ProcessorIndex,
+ IN EFI_PERIODIC_CALLBACK PeriodicCallback
+ );
+
+/**
+ Registers a function to be called when a given processor exception occurs.
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.
+ @param ProcessorIndex Specifies which processor the callback function applies to.
+ @param PeriodicCallback A pointer to a function of type EXCEPTION_CALLBACK that is called
+ when the processor exception specified by ExceptionType occurs.
+ @param ExceptionType Specifies which processor exception to hook.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a callback
+ function was previously registered.
+ @retval EFI_OUT_OF_RESOURCES System has insufficient memory resources to register new callback
+ function.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_REGISTER_EXCEPTION_CALLBACK)(
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ IN UINTN ProcessorIndex,
+ IN EFI_EXCEPTION_CALLBACK ExceptionCallback,
+ IN EFI_EXCEPTION_TYPE ExceptionType
+ );
+
+/**
+ Invalidates processor instruction cache for a memory range. Subsequent execution in this range
+ causes a fresh memory fetch to retrieve code to be executed.
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.
+ @param ProcessorIndex Specifies which processor's instruction cache is to be invalidated.
+ @param Start Specifies the physical base of the memory range to be invalidated.
+ @param Length Specifies the minimum number of bytes in the processor's instruction
+ cache to invalidate.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_INVALIDATE_INSTRUCTION_CACHE)(
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ IN UINTN ProcessorIndex,
+ IN VOID *Start,
+ IN UINT64 Length
+ );
+
+///
+/// This protocol provides the services to allow the debug agent to register
+/// callback functions that are called either periodically or when specific
+/// processor exceptions occur.
+///
+struct _EFI_DEBUG_SUPPORT_PROTOCOL {
+ ///
+ /// Declares the processor architecture for this instance of the EFI Debug Support protocol.
+ ///
+ EFI_INSTRUCTION_SET_ARCHITECTURE Isa;
+ EFI_GET_MAXIMUM_PROCESSOR_INDEX GetMaximumProcessorIndex;
+ EFI_REGISTER_PERIODIC_CALLBACK RegisterPeriodicCallback;
+ EFI_REGISTER_EXCEPTION_CALLBACK RegisterExceptionCallback;
+ EFI_INVALIDATE_INSTRUCTION_CACHE InvalidateInstructionCache;
+};
+
+extern EFI_GUID gEfiDebugSupportProtocolGuid;
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Protocol/DevicePath.h b/gpxe/src/include/gpxe/efi/Protocol/DevicePath.h
new file mode 100644
index 00000000..e847668f
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Protocol/DevicePath.h
@@ -0,0 +1,535 @@
+/** @file
+ The device path protocol as defined in UEFI 2.0.
+
+ The device path represents a programatic path to a device. It's the view
+ from a software point of view. It also must persist from boot to boot, so
+ it can not contain things like PCI bus numbers that change from boot to boot.
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __EFI_DEVICE_PATH_PROTOCOL_H__
+#define __EFI_DEVICE_PATH_PROTOCOL_H__
+
+#include <gpxe/efi/Guid/PcAnsi.h>
+
+///
+/// Device Path protocol
+///
+#define EFI_DEVICE_PATH_PROTOCOL_GUID \
+ { \
+ 0x9576e91, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
+ }
+
+//
+// Protocol GUID defined in EFI1.1.
+//
+
+///
+/// Device Path information
+///
+#define DEVICE_PATH_PROTOCOL EFI_DEVICE_PATH_PROTOCOL_GUID
+
+#pragma pack(1)
+
+/**
+ This protocol can be used on any device handle to obtain generic path/location
+ information concerning the physical device or logical device. If the handle does
+ not logically map to a physical device, the handle may not necessarily support
+ the device path protocol. The device path describes the location of the device
+ the handle is for. The size of the Device Path can be determined from the structures
+ that make up the Device Path.
+**/
+typedef struct {
+ UINT8 Type; ///< 0x01 Hardware Device Path
+ ///< 0x02 ACPI Device Path
+ ///< 0x03 Messaging Device Path
+ ///< 0x04 Media Device Path
+ ///< 0x05 BIOS Boot Specification Device Path
+ ///< 0x7F End of Hardware Device Path
+
+ UINT8 SubType; ///< Varies by Type
+ ///< 0xFF End Entire Device Path, or
+ ///< 0x01 End This Instance of a Device Path and start a new
+ ///< Device Path
+
+ UINT8 Length[2]; ///< Specific Device Path data. Type and Sub-Type define
+ ///< type of data. Size of data is included in Length.
+
+} EFI_DEVICE_PATH_PROTOCOL;
+
+///
+/// For backward-compatible with EFI1.1.
+///
+typedef EFI_DEVICE_PATH_PROTOCOL EFI_DEVICE_PATH;
+
+///
+/// Hardware Device Paths
+///
+#define HARDWARE_DEVICE_PATH 0x01
+
+#define HW_PCI_DP 0x01
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT8 Function;
+ UINT8 Device;
+} PCI_DEVICE_PATH;
+
+#define HW_PCCARD_DP 0x02
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT8 FunctionNumber;
+} PCCARD_DEVICE_PATH;
+
+#define HW_MEMMAP_DP 0x03
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT32 MemoryType;
+ EFI_PHYSICAL_ADDRESS StartingAddress;
+ EFI_PHYSICAL_ADDRESS EndingAddress;
+} MEMMAP_DEVICE_PATH;
+
+#define HW_VENDOR_DP 0x04
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ EFI_GUID Guid;
+} VENDOR_DEVICE_PATH;
+
+#define HW_CONTROLLER_DP 0x05
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT32 ControllerNumber;
+} CONTROLLER_DEVICE_PATH;
+
+///
+/// ACPI Device Paths
+///
+#define ACPI_DEVICE_PATH 0x02
+
+#define ACPI_DP 0x01
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT32 HID;
+ UINT32 UID;
+} ACPI_HID_DEVICE_PATH;
+
+#define ACPI_EXTENDED_DP 0x02
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT32 HID;
+ UINT32 UID;
+ UINT32 CID;
+ ///
+ /// Optional variable length _HIDSTR
+ /// Optional variable length _UIDSTR
+ /// Optional variable length _CIDSTR
+ ///
+} ACPI_EXTENDED_HID_DEVICE_PATH;
+
+//
+// EISA ID Macro
+// EISA ID Definition 32-bits
+// bits[15:0] - three character compressed ASCII EISA ID.
+// bits[31:16] - binary number
+// Compressed ASCII is 5 bits per character 0b00001 = 'A' 0b11010 = 'Z'
+//
+#define PNP_EISA_ID_CONST 0x41d0
+#define EISA_ID(_Name, _Num) ((UINT32)((_Name) | (_Num) << 16))
+#define EISA_PNP_ID(_PNPId) (EISA_ID(PNP_EISA_ID_CONST, (_PNPId)))
+#define EFI_PNP_ID(_PNPId) (EISA_ID(PNP_EISA_ID_CONST, (_PNPId)))
+
+#define PNP_EISA_ID_MASK 0xffff
+#define EISA_ID_TO_NUM(_Id) ((_Id) >> 16)
+
+
+#define ACPI_ADR_DP 0x03
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT32 ADR;
+} ACPI_ADR_DEVICE_PATH;
+
+#define ACPI_ADR_DISPLAY_TYPE_OTHER 0
+#define ACPI_ADR_DISPLAY_TYPE_VGA 1
+#define ACPI_ADR_DISPLAY_TYPE_TV 2
+#define ACPI_ADR_DISPLAY_TYPE_EXTERNAL_DIGITAL 3
+#define ACPI_ADR_DISPLAY_TYPE_INTERNAL_DIGITAL 4
+
+#define ACPI_DISPLAY_ADR(_DeviceIdScheme, _HeadId, _NonVgaOutput, _BiosCanDetect, _VendorInfo, _Type, _Port, _Index) \
+ ((UINT32)( (((_DeviceIdScheme) & 0x1) << 31) | \
+ (((_HeadId) & 0x7) << 18) | \
+ (((_NonVgaOutput) & 0x1) << 17) | \
+ (((_BiosCanDetect) & 0x1) << 16) | \
+ (((_VendorInfo) & 0xf) << 12) | \
+ (((_Type) & 0xf) << 8) | \
+ (((_Port) & 0xf) << 4) | \
+ ((_Index) & 0xf) ))
+
+///
+/// Messaging Device Paths
+///
+#define MESSAGING_DEVICE_PATH 0x03
+
+#define MSG_ATAPI_DP 0x01
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT8 PrimarySecondary;
+ UINT8 SlaveMaster;
+ UINT16 Lun;
+} ATAPI_DEVICE_PATH;
+
+#define MSG_SCSI_DP 0x02
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT16 Pun;
+ UINT16 Lun;
+} SCSI_DEVICE_PATH;
+
+#define MSG_FIBRECHANNEL_DP 0x03
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT32 Reserved;
+ UINT64 WWN;
+ UINT64 Lun;
+} FIBRECHANNEL_DEVICE_PATH;
+
+#define MSG_1394_DP 0x04
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT32 Reserved;
+ UINT64 Guid;
+} F1394_DEVICE_PATH;
+
+#define MSG_USB_DP 0x05
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT8 ParentPortNumber;
+ UINT8 InterfaceNumber;
+} USB_DEVICE_PATH;
+
+#define MSG_USB_CLASS_DP 0x0f
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT16 VendorId;
+ UINT16 ProductId;
+ UINT8 DeviceClass;
+ UINT8 DeviceSubClass;
+ UINT8 DeviceProtocol;
+} USB_CLASS_DEVICE_PATH;
+
+#define MSG_USB_WWID_DP 0x10
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT16 InterfaceNumber;
+ UINT16 VendorId;
+ UINT16 ProductId;
+ // CHAR16 SerialNumber[...];
+} USB_WWID_DEVICE_PATH;
+
+
+#define MSG_DEVICE_LOGICAL_UNIT_DP 0x11
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT8 Lun;
+} DEVICE_LOGICAL_UNIT_DEVICE_PATH;
+
+#define MSG_SATA_DP 0x12
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT16 HBAPortNumber;
+ UINT16 PortMultiplierPortNumber;
+ UINT16 Lun;
+} SATA_DEVICE_PATH;
+
+#define MSG_I2O_DP 0x06
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT32 Tid;
+} I2O_DEVICE_PATH;
+
+#define MSG_MAC_ADDR_DP 0x0b
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ EFI_MAC_ADDRESS MacAddress;
+ UINT8 IfType;
+} MAC_ADDR_DEVICE_PATH;
+
+#define MSG_IPv4_DP 0x0c
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ EFI_IPv4_ADDRESS LocalIpAddress;
+ EFI_IPv4_ADDRESS RemoteIpAddress;
+ UINT16 LocalPort;
+ UINT16 RemotePort;
+ UINT16 Protocol;
+ BOOLEAN StaticIpAddress;
+} IPv4_DEVICE_PATH;
+
+#define MSG_IPv6_DP 0x0d
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ EFI_IPv6_ADDRESS LocalIpAddress;
+ EFI_IPv6_ADDRESS RemoteIpAddress;
+ UINT16 LocalPort;
+ UINT16 RemotePort;
+ UINT16 Protocol;
+ BOOLEAN StaticIpAddress;
+} IPv6_DEVICE_PATH;
+
+#define MSG_INFINIBAND_DP 0x09
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT32 ResourceFlags;
+ UINT8 PortGid[16];
+ UINT64 ServiceId;
+ UINT64 TargetPortId;
+ UINT64 DeviceId;
+} INFINIBAND_DEVICE_PATH;
+
+#define INFINIBAND_RESOURCE_FLAG_IOC_SERVICE 0x01
+#define INFINIBAND_RESOURCE_FLAG_EXTENDED_BOOT_ENVIRONMENT 0x02
+#define INFINIBAND_RESOURCE_FLAG_CONSOLE_PROTOCOL 0x04
+#define INFINIBAND_RESOURCE_FLAG_STORAGE_PROTOCOL 0x08
+#define INFINIBAND_RESOURCE_FLAG_NETWORK_PROTOCOL 0x10
+
+#define MSG_UART_DP 0x0e
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT32 Reserved;
+ UINT64 BaudRate;
+ UINT8 DataBits;
+ UINT8 Parity;
+ UINT8 StopBits;
+} UART_DEVICE_PATH;
+
+//
+// Use VENDOR_DEVICE_PATH struct
+//
+#define MSG_VENDOR_DP 0x0a
+typedef VENDOR_DEVICE_PATH VENDOR_DEFINED_DEVICE_PATH;
+
+#define DEVICE_PATH_MESSAGING_PC_ANSI EFI_PC_ANSI_GUID
+#define DEVICE_PATH_MESSAGING_VT_100 EFI_VT_100_GUID
+#define DEVICE_PATH_MESSAGING_VT_100_PLUS EFI_VT_100_PLUS_GUID
+#define DEVICE_PATH_MESSAGING_VT_UTF8 EFI_VT_UTF8_GUID
+
+#define DEVICE_PATH_MESSAGING_UART_FLOW_CONTROL EFI_UART_DEVICE_PATH_GUID
+
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ EFI_GUID Guid;
+ UINT32 FlowControlMap;
+} UART_FLOW_CONTROL_DEVICE_PATH;
+
+#define DEVICE_PATH_MESSAGING_SAS EFI_SAS_DEVICE_PATH_GUID
+
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ EFI_GUID Guid;
+ UINT32 Reserved;
+ UINT64 SasAddress;
+ UINT64 Lun;
+ UINT16 DeviceTopology;
+ UINT16 RelativeTargetPort;
+} SAS_DEVICE_PATH;
+
+#define MSG_ISCSI_DP 0x13
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT16 NetworkProtocol;
+ UINT16 LoginOption;
+ UINT64 Lun;
+ UINT16 TargetPortalGroupTag;
+ // CHAR8 iSCSI Target Name
+} ISCSI_DEVICE_PATH;
+
+#define ISCSI_LOGIN_OPTION_NO_HEADER_DIGEST 0x0000
+#define ISCSI_LOGIN_OPTION_HEADER_DIGEST_USING_CRC32C 0x0002
+#define ISCSI_LOGIN_OPTION_NO_DATA_DIGEST 0x0000
+#define ISCSI_LOGIN_OPTION_DATA_DIGEST_USING_CRC32C 0x0008
+#define ISCSI_LOGIN_OPTION_AUTHMETHOD_CHAP 0x0000
+#define ISCSI_LOGIN_OPTION_AUTHMETHOD_NON 0x1000
+#define ISCSI_LOGIN_OPTION_CHAP_BI 0x0000
+#define ISCSI_LOGIN_OPTION_CHAP_UNI 0x2000
+
+//
+// Media Device Path
+//
+#define MEDIA_DEVICE_PATH 0x04
+
+#define MEDIA_HARDDRIVE_DP 0x01
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT32 PartitionNumber;
+ UINT64 PartitionStart;
+ UINT64 PartitionSize;
+ UINT8 Signature[16];
+ UINT8 MBRType;
+ UINT8 SignatureType;
+} HARDDRIVE_DEVICE_PATH;
+
+#define MBR_TYPE_PCAT 0x01
+#define MBR_TYPE_EFI_PARTITION_TABLE_HEADER 0x02
+
+#define SIGNATURE_TYPE_MBR 0x01
+#define SIGNATURE_TYPE_GUID 0x02
+
+#define MEDIA_CDROM_DP 0x02
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT32 BootEntry;
+ UINT64 PartitionStart;
+ UINT64 PartitionSize;
+} CDROM_DEVICE_PATH;
+
+//
+// Use VENDOR_DEVICE_PATH struct
+//
+#define MEDIA_VENDOR_DP 0x03
+
+#define MEDIA_FILEPATH_DP 0x04
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ CHAR16 PathName[1];
+} FILEPATH_DEVICE_PATH;
+
+#define SIZE_OF_FILEPATH_DEVICE_PATH EFI_FIELD_OFFSET(FILEPATH_DEVICE_PATH,PathName)
+
+#define MEDIA_PROTOCOL_DP 0x05
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ EFI_GUID Protocol;
+} MEDIA_PROTOCOL_DEVICE_PATH;
+
+
+#define MEDIA_PIWG_FW_VOL_DP 0x7
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ EFI_GUID FvName;
+} MEDIA_FW_VOL_DEVICE_PATH;
+
+
+#define MEDIA_PIWG_FW_FILE_DP 0x6
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ EFI_GUID FvFileName;
+} MEDIA_FW_VOL_FILEPATH_DEVICE_PATH;
+
+//
+// BBS Device Path
+//
+#define BBS_DEVICE_PATH 0x05
+#define BBS_BBS_DP 0x01
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT16 DeviceType;
+ UINT16 StatusFlag;
+ CHAR8 String[1];
+} BBS_BBS_DEVICE_PATH;
+
+//
+// DeviceType definitions - from BBS specification
+//
+#define BBS_TYPE_FLOPPY 0x01
+#define BBS_TYPE_HARDDRIVE 0x02
+#define BBS_TYPE_CDROM 0x03
+#define BBS_TYPE_PCMCIA 0x04
+#define BBS_TYPE_USB 0x05
+#define BBS_TYPE_EMBEDDED_NETWORK 0x06
+#define BBS_TYPE_BEV 0x80
+#define BBS_TYPE_UNKNOWN 0xFF
+
+
+///
+/// Union of all possible Device Paths and pointers to Device Paths
+///
+
+typedef union {
+ EFI_DEVICE_PATH_PROTOCOL DevPath;
+ PCI_DEVICE_PATH Pci;
+ PCCARD_DEVICE_PATH PcCard;
+ MEMMAP_DEVICE_PATH MemMap;
+ VENDOR_DEVICE_PATH Vendor;
+
+ CONTROLLER_DEVICE_PATH Controller;
+ ACPI_HID_DEVICE_PATH Acpi;
+
+ ATAPI_DEVICE_PATH Atapi;
+ SCSI_DEVICE_PATH Scsi;
+ ISCSI_DEVICE_PATH Iscsi;
+ FIBRECHANNEL_DEVICE_PATH FibreChannel;
+
+ F1394_DEVICE_PATH F1394;
+ USB_DEVICE_PATH Usb;
+ SATA_DEVICE_PATH Sata;
+ USB_CLASS_DEVICE_PATH UsbClass;
+ I2O_DEVICE_PATH I2O;
+ MAC_ADDR_DEVICE_PATH MacAddr;
+ IPv4_DEVICE_PATH Ipv4;
+ IPv6_DEVICE_PATH Ipv6;
+ INFINIBAND_DEVICE_PATH InfiniBand;
+ UART_DEVICE_PATH Uart;
+
+ HARDDRIVE_DEVICE_PATH HardDrive;
+ CDROM_DEVICE_PATH CD;
+
+ FILEPATH_DEVICE_PATH FilePath;
+ MEDIA_PROTOCOL_DEVICE_PATH MediaProtocol;
+
+ BBS_BBS_DEVICE_PATH Bbs;
+} EFI_DEV_PATH;
+
+
+
+typedef union {
+ EFI_DEVICE_PATH_PROTOCOL *DevPath;
+ PCI_DEVICE_PATH *Pci;
+ PCCARD_DEVICE_PATH *PcCard;
+ MEMMAP_DEVICE_PATH *MemMap;
+ VENDOR_DEVICE_PATH *Vendor;
+
+ CONTROLLER_DEVICE_PATH *Controller;
+ ACPI_HID_DEVICE_PATH *Acpi;
+ ACPI_EXTENDED_HID_DEVICE_PATH *ExtendedAcpi;
+
+ ATAPI_DEVICE_PATH *Atapi;
+ SCSI_DEVICE_PATH *Scsi;
+ FIBRECHANNEL_DEVICE_PATH *FibreChannel;
+
+ F1394_DEVICE_PATH *F1394;
+ USB_DEVICE_PATH *Usb;
+ SATA_DEVICE_PATH *Sata;
+ USB_CLASS_DEVICE_PATH *UsbClass;
+ I2O_DEVICE_PATH *I2O;
+ MAC_ADDR_DEVICE_PATH *MacAddr;
+ IPv4_DEVICE_PATH *Ipv4;
+ IPv6_DEVICE_PATH *Ipv6;
+ INFINIBAND_DEVICE_PATH *InfiniBand;
+ UART_DEVICE_PATH *Uart;
+
+ HARDDRIVE_DEVICE_PATH *HardDrive;
+ CDROM_DEVICE_PATH *CD;
+
+ FILEPATH_DEVICE_PATH *FilePath;
+ MEDIA_PROTOCOL_DEVICE_PATH *MediaProtocol;
+
+ BBS_BBS_DEVICE_PATH *Bbs;
+ UINT8 *Raw;
+} EFI_DEV_PATH_PTR;
+
+#pragma pack()
+
+#define END_DEVICE_PATH_TYPE 0x7f
+#define END_ENTIRE_DEVICE_PATH_SUBTYPE 0xFF
+#define END_INSTANCE_DEVICE_PATH_SUBTYPE 0x01
+
+extern EFI_GUID gEfiDevicePathProtocolGuid;
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Protocol/DriverBinding.h b/gpxe/src/include/gpxe/efi/Protocol/DriverBinding.h
new file mode 100644
index 00000000..510cb7ce
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Protocol/DriverBinding.h
@@ -0,0 +1,153 @@
+/** @file
+ UEFI DriverBinding Protocol is defined in UEFI specification.
+
+ This protocol is produced by every driver that follows the UEFI Driver Model,
+ and it is the central component that allows drivers and controllers to be managed.
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __EFI_DRIVER_BINDING_H__
+#define __EFI_DRIVER_BINDING_H__
+
+#include <gpxe/efi/Protocol/DevicePath.h>
+///
+/// Global ID for the ControllerHandle Driver Protocol
+///
+#define EFI_DRIVER_BINDING_PROTOCOL_GUID \
+ { \
+ 0x18a031ab, 0xb443, 0x4d1a, {0xa5, 0xc0, 0xc, 0x9, 0x26, 0x1e, 0x9f, 0x71 } \
+ }
+
+typedef struct _EFI_DRIVER_BINDING_PROTOCOL EFI_DRIVER_BINDING_PROTOCOL;
+
+/**
+ Test to see if this driver supports ControllerHandle. This service
+ is called by the EFI boot service ConnectController(). In
+ order to make drivers as small as possible, there are a few calling
+ restrictions for this service. ConnectController() must
+ follow these calling restrictions. If any other agent wishes to call
+ Supported() it must also follow these calling restrictions.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to test
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver supports this device
+ @retval EFI_ALREADY_STARTED This driver is already running on this device
+ @retval other This driver does not support this device
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_DRIVER_BINDING_SUPPORTED)(
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+/**
+ Start this driver on ControllerHandle. This service is called by the
+ EFI boot service ConnectController(). In order to make
+ drivers as small as possible, there are a few calling restrictions for
+ this service. ConnectController() must follow these
+ calling restrictions. If any other agent wishes to call Start() it
+ must also follow these calling restrictions.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to bind driver to
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver is added to ControllerHandle
+ @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
+ @retval other This driver does not support this device
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_DRIVER_BINDING_START)(
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+/**
+ Stop this driver on ControllerHandle. This service is called by the
+ EFI boot service DisconnectController(). In order to
+ make drivers as small as possible, there are a few calling
+ restrictions for this service. DisconnectController()
+ must follow these calling restrictions. If any other agent wishes
+ to call Stop() it must also follow these calling restrictions.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to stop driver on
+ @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
+ children is zero stop the entire bus driver.
+ @param ChildHandleBuffer List of Child Handles to Stop.
+
+ @retval EFI_SUCCESS This driver is removed ControllerHandle
+ @retval other This driver was not removed from this device
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_DRIVER_BINDING_STOP)(
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
+ );
+
+///
+/// This protocol provides the services required to determine if a driver supports a given controller.
+/// If a controller is supported, then it also provides routines to start and stop the controller.
+///
+struct _EFI_DRIVER_BINDING_PROTOCOL {
+ EFI_DRIVER_BINDING_SUPPORTED Supported;
+ EFI_DRIVER_BINDING_START Start;
+ EFI_DRIVER_BINDING_STOP Stop;
+
+ ///
+ /// The version number of the UEFI driver that produced the
+ /// EFI_DRIVER_BINDING_PROTOCOL. This field is used by
+ /// the EFI boot service ConnectController() to determine
+ /// the order that driver's Supported() service will be used when
+ /// a controller needs to be started. EFI Driver Binding Protocol
+ /// instances with higher Version values will be used before ones
+ /// with lower Version values. The Version values of 0x0-
+ /// 0x0f and 0xfffffff0-0xffffffff are reserved for
+ /// platform/OEM specific drivers. The Version values of 0x10-
+ /// 0xffffffef are reserved for IHV-developed drivers.
+ ///
+ UINT32 Version;
+
+ ///
+ /// The image handle of the UEFI driver that produced this instance
+ /// of the EFI_DRIVER_BINDING_PROTOCOL.
+ ///
+ EFI_HANDLE ImageHandle;
+
+ ///
+ /// The handle on which this instance of the
+ /// EFI_DRIVER_BINDING_PROTOCOL is installed. In most
+ /// cases, this is the same handle as ImageHandle. However, for
+ /// UEFI drivers that produce more than one instance of the
+ /// EFI_DRIVER_BINDING_PROTOCOL, this value may not be
+ /// the same as ImageHandle.
+ ///
+ EFI_HANDLE DriverBindingHandle;
+};
+
+extern EFI_GUID gEfiDriverBindingProtocolGuid;
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Protocol/NetworkInterfaceIdentifier.h b/gpxe/src/include/gpxe/efi/Protocol/NetworkInterfaceIdentifier.h
new file mode 100644
index 00000000..e99ec38e
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Protocol/NetworkInterfaceIdentifier.h
@@ -0,0 +1,74 @@
+/** @file
+ EFI Network Interface Identifier Protocol
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+**/
+
+#ifndef __EFI_NETWORK_INTERFACE_IDENTIFER_H__
+#define __EFI_NETWORK_INTERFACE_IDENTIFER_H__
+
+
+#define EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_GUID \
+ { \
+ 0xE18541CD, 0xF755, 0x4f73, {0x92, 0x8D, 0x64, 0x3C, 0x8A, 0x79, 0xB2, 0x29 } \
+ }
+
+#define EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION 0x00010000
+
+///
+/// Revision defined in EFI1.1.
+///
+#define EFI_NETWORK_INTERFACE_IDENTIFIER_INTERFACE_REVISION EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION
+
+///
+/// Forward reference for pure ANSI compatability
+///
+typedef struct _EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL;
+
+///
+/// Protocol defined in EFI1.1.
+///
+typedef EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL EFI_NETWORK_INTERFACE_IDENTIFIER_INTERFACE;
+
+typedef enum {
+ EfiNetworkInterfaceUndi = 1
+} EFI_NETWORK_PROTOCOL_TYPE;
+
+///
+/// An optional protocol that is used to describe details about the software
+/// layer that is used to produce the Simple Network Protocol.
+///
+struct _EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL {
+ UINT64 Revision; ///< The revision of the EFI_NETWORK_INTERFACE_IDENTIFIER protocol.
+ UINT64 ID; ///< Address of the first byte of the identifying structure for this network
+ ///< interface. This is only valid when the network interface is started
+ ///< (see Start()). When the network interface is not started, this field is set to zero.
+ UINT64 ImageAddr; ///< Address of the first byte of the identifying structure for this
+ ///< network interface. This is set to zero if there is no structure.
+ UINT32 ImageSize; ///< Size of unrelocated network interface image.
+ CHAR8 StringId[4];///< A four-character ASCII string that is sent in the class identifier field of
+ ///< option 60 in DHCP. For a Type of EfiNetworkInterfaceUndi, this field is UNDI.
+ UINT8 Type; ///< Network interface type. This will be set to one of the values
+ ///< in EFI_NETWORK_INTERFACE_TYPE.
+ UINT8 MajorVer; ///< Major version number.
+ UINT8 MinorVer; ///< Minor version number.
+ BOOLEAN Ipv6Supported; ///< TRUE if the network interface supports IPv6; otherwise FALSE.
+ UINT8 IfNum; ///< The network interface number that is being identified by this Network
+ ///< Interface Identifier Protocol. This field must be less than or equal
+ ///< to the IFcnt field in the !PXE structure.
+
+};
+
+extern EFI_GUID gEfiNetworkInterfaceIdentifierProtocolGuid;
+extern EFI_GUID gEfiNetworkInterfaceIdentifierProtocolGuid_31;
+
+#endif // _EFI_NII_H
diff --git a/gpxe/src/include/gpxe/efi/Protocol/PciIo.h b/gpxe/src/include/gpxe/efi/Protocol/PciIo.h
new file mode 100644
index 00000000..5aea5b4a
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Protocol/PciIo.h
@@ -0,0 +1,519 @@
+/** @file
+ EFI PCI I/O Protocol provides the basic Memory, I/O, PCI configuration,
+ and DMA interfaces that a driver uses to access its PCI controller.
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __PCI_IO_H__
+#define __PCI_IO_H__
+
+///
+/// Global ID for the PCI I/O Protocol
+///
+#define EFI_PCI_IO_PROTOCOL_GUID \
+ { \
+ 0x4cf5b200, 0x68b8, 0x4ca5, {0x9e, 0xec, 0xb2, 0x3e, 0x3f, 0x50, 0x2, 0x9a } \
+ }
+
+typedef struct _EFI_PCI_IO_PROTOCOL EFI_PCI_IO_PROTOCOL;
+
+///
+/// Prototypes for the PCI I/O Protocol
+///
+typedef enum {
+ EfiPciIoWidthUint8 = 0,
+ EfiPciIoWidthUint16,
+ EfiPciIoWidthUint32,
+ EfiPciIoWidthUint64,
+ EfiPciIoWidthFifoUint8,
+ EfiPciIoWidthFifoUint16,
+ EfiPciIoWidthFifoUint32,
+ EfiPciIoWidthFifoUint64,
+ EfiPciIoWidthFillUint8,
+ EfiPciIoWidthFillUint16,
+ EfiPciIoWidthFillUint32,
+ EfiPciIoWidthFillUint64,
+ EfiPciIoWidthMaximum
+} EFI_PCI_IO_PROTOCOL_WIDTH;
+
+//
+// Complete PCI address generater
+//
+#define EFI_PCI_IO_PASS_THROUGH_BAR 0xff ///< Special BAR that passes a memory or I/O cycle through unchanged
+#define EFI_PCI_IO_ATTRIBUTE_MASK 0x077f ///< All the following I/O and Memory cycles
+#define EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO 0x0001 ///< I/O cycles 0x0000-0x00FF (10 bit decode)
+#define EFI_PCI_IO_ATTRIBUTE_ISA_IO 0x0002 ///< I/O cycles 0x0100-0x03FF or greater (10 bit decode)
+#define EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO 0x0004 ///< I/O cycles 0x3C6, 0x3C8, 0x3C9 (10 bit decode)
+#define EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY 0x0008 ///< MEM cycles 0xA0000-0xBFFFF (24 bit decode)
+#define EFI_PCI_IO_ATTRIBUTE_VGA_IO 0x0010 ///< I/O cycles 0x3B0-0x3BB and 0x3C0-0x3DF (10 bit decode)
+#define EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO 0x0020 ///< I/O cycles 0x1F0-0x1F7, 0x3F6, 0x3F7 (10 bit decode)
+#define EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO 0x0040 ///< I/O cycles 0x170-0x177, 0x376, 0x377 (10 bit decode)
+#define EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE 0x0080 ///< Map a memory range so write are combined
+#define EFI_PCI_IO_ATTRIBUTE_IO 0x0100 ///< Enable the I/O decode bit in the PCI Config Header
+#define EFI_PCI_IO_ATTRIBUTE_MEMORY 0x0200 ///< Enable the Memory decode bit in the PCI Config Header
+#define EFI_PCI_IO_ATTRIBUTE_BUS_MASTER 0x0400 ///< Enable the DMA bit in the PCI Config Header
+#define EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED 0x0800 ///< Map a memory range so all r/w accesses are cached
+#define EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE 0x1000 ///< Disable a memory range
+#define EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE 0x2000 ///< Clear for an add-in PCI Device
+#define EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM 0x4000 ///< Clear for a physical PCI Option ROM accessed through ROM BAR
+#define EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE 0x8000 ///< Clear for PCI controllers that can not genrate a DAC
+#define EFI_PCI_IO_ATTRIBUTE_ISA_IO_16 0x10000 ///< I/O cycles 0x0100-0x03FF or greater (16 bit decode)
+#define EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16 0x20000 ///< I/O cycles 0x3C6, 0x3C8, 0x3C9 (16 bit decode)
+#define EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 0x30000 ///< I/O cycles 0x3B0-0x3BB and 0x3C0-0x3DF (16 bit decode)
+
+#define EFI_PCI_DEVICE_ENABLE (EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER)
+#define EFI_VGA_DEVICE_ENABLE (EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_IO)
+
+///
+/// *******************************************************
+/// EFI_PCI_IO_PROTOCOL_OPERATION
+/// *******************************************************
+///
+typedef enum {
+ EfiPciIoOperationBusMasterRead,
+ EfiPciIoOperationBusMasterWrite,
+ EfiPciIoOperationBusMasterCommonBuffer,
+ EfiPciIoOperationMaximum
+} EFI_PCI_IO_PROTOCOL_OPERATION;
+
+///
+/// *******************************************************
+/// EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION
+/// *******************************************************
+///
+typedef enum {
+ EfiPciIoAttributeOperationGet,
+ EfiPciIoAttributeOperationSet,
+ EfiPciIoAttributeOperationEnable,
+ EfiPciIoAttributeOperationDisable,
+ EfiPciIoAttributeOperationSupported,
+ EfiPciIoAttributeOperationMaximum
+} EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION;
+
+/**
+ Reads from the memory space of a PCI controller. Returns when either the polling exit criteria is
+ satisfied or after a defined duration.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory operation to perform.
+ @param Offset The offset within the selected BAR to start the memory operation.
+ @param Mask Mask used for the polling criteria.
+ @param Value The comparison value used for the polling exit criteria.
+ @param Delay The number of 100 ns units to poll.
+ @param Result Pointer to the last value read from the memory location.
+
+ @retval EFI_SUCCESS The last data returned from the access matched the poll exit criteria.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED Offset is not valid for the BarIndex of this PCI controller.
+ @retval EFI_TIMEOUT Delay expired before a match occurred.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_POLL_IO_MEM)(
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINT64 Mask,
+ IN UINT64 Value,
+ IN UINT64 Delay,
+ OUT UINT64 *Result
+ );
+
+/**
+ Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory or I/O operation to perform.
+ @param Offset The offset within the selected BAR to start the memory or I/O operation.
+ @param Count The number of memory or I/O operations to perform.
+ @param Buffer For read operations, the destination buffer to store the results. For write
+ operations, the source buffer to write data from.
+
+ @retval EFI_SUCCESS The data was read from or written to the PCI controller.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
+ valid for the PCI BAR specified by BarIndex.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_IO_MEM)(
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+typedef struct {
+ EFI_PCI_IO_PROTOCOL_IO_MEM Read;
+ EFI_PCI_IO_PROTOCOL_IO_MEM Write;
+} EFI_PCI_IO_PROTOCOL_ACCESS;
+
+/**
+ Enable a PCI driver to access PCI controller registers in PCI configuration space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory operations.
+ @param Offset The offset within the PCI configuration space for the PCI controller.
+ @param Count The number of PCI configuration operations to perform.
+ @param Buffer For read operations, the destination buffer to store the results. For write
+ operations, the source buffer to write data from.
+
+
+ @retval EFI_SUCCESS The data was read from or written to the PCI controller.
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
+ valid for the PCI configuration header of the PCI controller.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL or Width is invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_CONFIG)(
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT32 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+typedef struct {
+ EFI_PCI_IO_PROTOCOL_CONFIG Read;
+ EFI_PCI_IO_PROTOCOL_CONFIG Write;
+} EFI_PCI_IO_PROTOCOL_CONFIG_ACCESS;
+
+/**
+ Enables a PCI driver to copy one region of PCI memory space to another region of PCI
+ memory space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory operations.
+ @param DestBarIndex The BAR index in the standard PCI Configuration header to use as the
+ base address for the memory operation to perform.
+ @param DestOffset The destination offset within the BAR specified by DestBarIndex to
+ start the memory writes for the copy operation.
+ @param SrcBarIndex The BAR index in the standard PCI Configuration header to use as the
+ base address for the memory operation to perform.
+ @param SrcOffset The source offset within the BAR specified by SrcBarIndex to start
+ the memory reads for the copy operation.
+ @param Count The number of memory operations to perform. Bytes moved is Width
+ size * Count, starting at DestOffset and SrcOffset.
+
+ @retval EFI_SUCCESS The data was copied from one memory region to another memory region.
+ @retval EFI_UNSUPPORTED DestBarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED SrcBarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED The address range specified by DestOffset, Width, and Count
+ is not valid for the PCI BAR specified by DestBarIndex.
+ @retval EFI_UNSUPPORTED The address range specified by SrcOffset, Width, and Count is
+ not valid for the PCI BAR specified by SrcBarIndex.
+ @retval EFI_INVALID_PARAMETER Width is invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_COPY_MEM)(
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 DestBarIndex,
+ IN UINT64 DestOffset,
+ IN UINT8 SrcBarIndex,
+ IN UINT64 SrcOffset,
+ IN UINTN Count
+ );
+
+/**
+ Provides the PCI controller-Cspecific addresses needed to access system memory.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Operation Indicates if the bus master is going to read or write to system memory.
+ @param HostAddress The system memory address to map to the PCI controller.
+ @param NumberOfBytes On input the number of bytes to map. On output the number of bytes
+ that were mapped.
+ @param DeviceAddress The resulting map address for the bus master PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_MAP)(
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ );
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The range was unmapped.
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_UNMAP)(
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN VOID *Mapping
+ );
+
+/**
+ Allocates pages that are suitable for an EfiPciIoOperationBusMasterCommonBuffer
+ mapping.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Type This parameter is not used and must be ignored.
+ @param MemoryType The type of memory to allocate, EfiBootServicesData or
+ EfiRuntimeServicesData.
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param Attributes The requested bit mask of attributes for the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_ALLOCATE_BUFFER)(
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ OUT VOID **HostAddress,
+ IN UINT64 Attributes
+ );
+
+/**
+ Frees memory that was allocated with AllocateBuffer().
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Pages The number of pages to free.
+ @param HostAddress The base system memory address of the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were freed.
+ @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
+ was not allocated with AllocateBuffer().
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_FREE_BUFFER)(
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN UINTN Pages,
+ IN VOID *HostAddress
+ );
+
+/**
+ Flushes all PCI posted write transactions from a PCI host bridge to system memory.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+
+ @retval EFI_SUCCESS The PCI posted write transactions were flushed from the PCI host
+ bridge to system memory.
+ @retval EFI_DEVICE_ERROR The PCI posted write transactions were not flushed from the PCI
+ host bridge due to a hardware error.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_FLUSH)(
+ IN EFI_PCI_IO_PROTOCOL *This
+ );
+
+/**
+ Retrieves this PCI controller's current PCI bus number, device number, and function number.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param SegmentNumber The PCI controller's current PCI segment number.
+ @param BusNumber The PCI controller's current PCI bus number.
+ @param DeviceNumber The PCI controller's current PCI device number.
+ @param FunctionNumber The PCI controller's current PCI function number.
+
+ @retval EFI_SUCCESS The PCI controller location was returned.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_GET_LOCATION)(
+ IN EFI_PCI_IO_PROTOCOL *This,
+ OUT UINTN *SegmentNumber,
+ OUT UINTN *BusNumber,
+ OUT UINTN *DeviceNumber,
+ OUT UINTN *FunctionNumber
+ );
+
+/**
+ Performs an operation on the attributes that this PCI controller supports. The operations include
+ getting the set of supported attributes, retrieving the current attributes, setting the current
+ attributes, enabling attributes, and disabling attributes.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Operation The operation to perform on the attributes for this PCI controller.
+ @param Attributes The mask of attributes that are used for Set, Enable, and Disable
+ operations.
+ @param Result A pointer to the result mask of attributes that are returned for the Get
+ and Supported operations.
+
+ @retval EFI_SUCCESS The operation on the PCI controller's attributes was completed.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_UNSUPPORTED one or more of the bits set in
+ Attributes are not supported by this PCI controller or one of
+ its parent bridges when Operation is Set, Enable or Disable.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_ATTRIBUTES)(
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation,
+ IN UINT64 Attributes,
+ OUT UINT64 *Result OPTIONAL
+ );
+
+/**
+ Gets the attributes that this PCI controller supports setting on a BAR using
+ SetBarAttributes(), and retrieves the list of resource descriptors for a BAR.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for resource range. The legal range for this field is 0..5.
+ @param Supports A pointer to the mask of attributes that this PCI controller supports
+ setting for this BAR with SetBarAttributes().
+ @param Resources A pointer to the ACPI 2.0 resource descriptors that describe the current
+ configuration of this BAR of the PCI controller.
+
+ @retval EFI_SUCCESS If Supports is not NULL, then the attributes that the PCI
+ controller supports are returned in Supports. If Resources
+ is not NULL, then the ACPI 2.0 resource descriptors that the PCI
+ controller is currently using are returned in Resources.
+ @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to allocate
+ Resources.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_GET_BAR_ATTRIBUTES)(
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN UINT8 BarIndex,
+ OUT UINT64 *Supports, OPTIONAL
+ OUT VOID **Resources OPTIONAL
+ );
+
+/**
+ Sets the attributes for a range of a BAR on a PCI controller.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Attributes The mask of attributes to set for the resource range specified by
+ BarIndex, Offset, and Length.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for resource range. The legal range for this field is 0..5.
+ @param Offset A pointer to the BAR relative base address of the resource range to be
+ modified by the attributes specified by Attributes.
+ @param Length A pointer to the length of the resource range to be modified by the
+ attributes specified by Attributes.
+
+ @retval EFI_SUCCESS The set of attributes specified by Attributes for the resource
+ range specified by BarIndex, Offset, and Length were
+ set on the PCI controller, and the actual resource range is returned
+ in Offset and Length.
+ @retval EFI_INVALID_PARAMETER Offset or Length is NULL.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to set the attributes on the
+ resource range specified by BarIndex, Offset, and
+ Length.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_SET_BAR_ATTRIBUTES)(
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN UINT64 Attributes,
+ IN UINT8 BarIndex,
+ IN OUT UINT64 *Offset,
+ IN OUT UINT64 *Length
+ );
+
+///
+/// The EFI_PCI_IO_PROTOCOL provides the basic Memory, I/O, PCI configuration,
+/// and DMA interfaces that are used to abstract accesses to PCI controllers.
+/// There is one EFI_PCI_IO_PROTOCOL instance for each PCI controller on a PCI bus.
+/// A device driver that wishes to manage a PCI controller in a system will have to
+/// retrieve the EFI_PCI_IO_PROTOCOL instance that is associated with the PCI controller.
+///
+struct _EFI_PCI_IO_PROTOCOL {
+ EFI_PCI_IO_PROTOCOL_POLL_IO_MEM PollMem;
+ EFI_PCI_IO_PROTOCOL_POLL_IO_MEM PollIo;
+ EFI_PCI_IO_PROTOCOL_ACCESS Mem;
+ EFI_PCI_IO_PROTOCOL_ACCESS Io;
+ EFI_PCI_IO_PROTOCOL_CONFIG_ACCESS Pci;
+ EFI_PCI_IO_PROTOCOL_COPY_MEM CopyMem;
+ EFI_PCI_IO_PROTOCOL_MAP Map;
+ EFI_PCI_IO_PROTOCOL_UNMAP Unmap;
+ EFI_PCI_IO_PROTOCOL_ALLOCATE_BUFFER AllocateBuffer;
+ EFI_PCI_IO_PROTOCOL_FREE_BUFFER FreeBuffer;
+ EFI_PCI_IO_PROTOCOL_FLUSH Flush;
+ EFI_PCI_IO_PROTOCOL_GET_LOCATION GetLocation;
+ EFI_PCI_IO_PROTOCOL_ATTRIBUTES Attributes;
+ EFI_PCI_IO_PROTOCOL_GET_BAR_ATTRIBUTES GetBarAttributes;
+ EFI_PCI_IO_PROTOCOL_SET_BAR_ATTRIBUTES SetBarAttributes;
+
+ ///
+ /// The size, in bytes, of the ROM image.
+ ///
+ UINT64 RomSize;
+
+ ///
+ /// A pointer to the in memory copy of the ROM image. The PCI Bus Driver is responsible
+ /// for allocating memory for the ROM image, and copying the contents of the ROM to memory.
+ /// The contents of this buffer are either from the PCI option ROM that can be accessed
+ /// through the ROM BAR of the PCI controller, or it is from a platform-specific location.
+ /// The Attributes() function can be used to determine from which of these two sources
+ /// the RomImage buffer was initialized.
+ ///
+ VOID *RomImage;
+};
+
+extern EFI_GUID gEfiPciIoProtocolGuid;
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Protocol/PciRootBridgeIo.h b/gpxe/src/include/gpxe/efi/Protocol/PciRootBridgeIo.h
new file mode 100644
index 00000000..a1150f08
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Protocol/PciRootBridgeIo.h
@@ -0,0 +1,393 @@
+/** @file
+ PCI Root Bridge I/O protocol as defined in the UEFI 2.0 specification.
+
+ PCI Root Bridge I/O protocol is used by PCI Bus Driver to perform PCI Memory, PCI I/O,
+ and PCI Configuration cycles on a PCI Root Bridge. It also provides services to perform
+ defferent types of bus mastering DMA
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __PCI_ROOT_BRIDGE_IO_H__
+#define __PCI_ROOT_BRIDGE_IO_H__
+
+#define EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GUID \
+ { \
+ 0x2f707ebb, 0x4a1a, 0x11d4, {0x9a, 0x38, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \
+ }
+
+typedef struct _EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL;
+
+typedef enum {
+ EfiPciWidthUint8,
+ EfiPciWidthUint16,
+ EfiPciWidthUint32,
+ EfiPciWidthUint64,
+ EfiPciWidthFifoUint8,
+ EfiPciWidthFifoUint16,
+ EfiPciWidthFifoUint32,
+ EfiPciWidthFifoUint64,
+ EfiPciWidthFillUint8,
+ EfiPciWidthFillUint16,
+ EfiPciWidthFillUint32,
+ EfiPciWidthFillUint64,
+ EfiPciWidthMaximum
+} EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH;
+
+typedef enum {
+ EfiPciOperationBusMasterRead,
+ EfiPciOperationBusMasterWrite,
+ EfiPciOperationBusMasterCommonBuffer,
+ EfiPciOperationBusMasterRead64,
+ EfiPciOperationBusMasterWrite64,
+ EfiPciOperationBusMasterCommonBuffer64,
+ EfiPciOperationMaximum
+} EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION;
+
+#define EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO 0x0001
+#define EFI_PCI_ATTRIBUTE_ISA_IO 0x0002
+#define EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO 0x0004
+#define EFI_PCI_ATTRIBUTE_VGA_MEMORY 0x0008
+#define EFI_PCI_ATTRIBUTE_VGA_IO 0x0010
+#define EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO 0x0020
+#define EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO 0x0040
+#define EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE 0x0080
+#define EFI_PCI_ATTRIBUTE_MEMORY_CACHED 0x0800
+#define EFI_PCI_ATTRIBUTE_MEMORY_DISABLE 0x1000
+#define EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE 0x8000
+
+#define EFI_PCI_ATTRIBUTE_VALID_FOR_ALLOCATE_BUFFER (EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE | EFI_PCI_ATTRIBUTE_MEMORY_CACHED | EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE)
+
+#define EFI_PCI_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER (~EFI_PCI_ATTRIBUTE_VALID_FOR_ALLOCATE_BUFFER)
+
+#define EFI_PCI_ADDRESS(bus, dev, func, reg) \
+ ((UINT64) ((((UINTN) bus) << 24) + (((UINTN) dev) << 16) + (((UINTN) func) << 8) + ((UINTN) reg)))
+
+typedef struct {
+ UINT8 Register;
+ UINT8 Function;
+ UINT8 Device;
+ UINT8 Bus;
+ UINT32 ExtendedRegister;
+} EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS;
+
+/**
+ Reads from the I/O space of a PCI Root Bridge. Returns when either the polling exit criteria is
+ satisfied or after a defined duration.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param Address The base address of the memory or I/O operations.
+ @param Mask Mask used for the polling criteria.
+ @param Value The comparison value used for the polling exit criteria.
+ @param Delay The number of 100 ns units to poll.
+ @param Result Pointer to the last value read from the memory location.
+
+ @retval EFI_SUCCESS The last data returned from the access matched the poll exit criteria.
+ @retval EFI_TIMEOUT Delay expired before a match occurred.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_POLL_IO_MEM)(
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINT64 Mask,
+ IN UINT64 Value,
+ IN UINT64 Delay,
+ OUT UINT64 *Result
+ );
+
+/**
+ Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Width Signifies the width of the memory operations.
+ @param Address The base address of the memory operations.
+ @param Count The number of memory operations to perform.
+ @param Buffer For read operations, the destination buffer to store the results. For write
+ operations, the source buffer to write data from.
+
+ @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_IO_MEM)(
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+typedef struct {
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_IO_MEM Read;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_IO_MEM Write;
+} EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS;
+
+/**
+ Enables a PCI driver to copy one region of PCI root bridge memory space to another region of PCI
+ root bridge memory space.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory operations.
+ @param DestAddress The destination address of the memory operation.
+ @param SrcAddress The source address of the memory operation.
+ @param Count The number of memory operations to perform.
+
+ @retval EFI_SUCCESS The data was copied from one memory region to another memory region.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_COPY_MEM)(
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 DestAddress,
+ IN UINT64 SrcAddress,
+ IN UINTN Count
+ );
+
+/**
+ Provides the PCI controller-Cspecific addresses required to access system memory from a
+ DMA bus master.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Operation Indicates if the bus master is going to read or write to system memory.
+ @param HostAddress The system memory address to map to the PCI controller.
+ @param NumberOfBytes On input the number of bytes to map. On output the number of bytes
+ that were mapped.
+ @param DeviceAddress The resulting map address for the bus master PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_MAP)(
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ );
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The range was unmapped.
+ @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_UNMAP)(
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN VOID *Mapping
+ );
+
+/**
+ Allocates pages that are suitable for an EfiPciOperationBusMasterCommonBuffer or
+ EfiPciOperationBusMasterCommonBuffer64 mapping.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Type This parameter is not used and must be ignored.
+ @param MemoryType The type of memory to allocate, EfiBootServicesData or
+ EfiRuntimeServicesData.
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param Attributes The requested bit mask of attributes for the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ALLOCATE_BUFFER)(
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ IN OUT VOID **HostAddress,
+ IN UINT64 Attributes
+ );
+
+/**
+ Frees memory that was allocated with AllocateBuffer().
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Pages The number of pages to free.
+ @param HostAddress The base system memory address of the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were freed.
+ @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
+ was not allocated with AllocateBuffer().
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_FREE_BUFFER)(
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN UINTN Pages,
+ IN VOID *HostAddress
+ );
+
+/**
+ Flushes all PCI posted write transactions from a PCI host bridge to system memory.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+
+ @retval EFI_SUCCESS The PCI posted write transactions were flushed from the PCI host
+ bridge to system memory.
+ @retval EFI_DEVICE_ERROR The PCI posted write transactions were not flushed from the PCI
+ host bridge due to a hardware error.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_FLUSH)(
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This
+ );
+
+/**
+ Gets the attributes that a PCI root bridge supports setting with SetAttributes(), and the
+ attributes that a PCI root bridge is currently using.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Supports A pointer to the mask of attributes that this PCI root bridge supports
+ setting with SetAttributes().
+ @param Attributes A pointer to the mask of attributes that this PCI root bridge is currently
+ using.
+
+ @retval EFI_SUCCESS If Supports is not NULL, then the attributes that the PCI root
+ bridge supports is returned in Supports. If Attributes is
+ not NULL, then the attributes that the PCI root bridge is currently
+ using is returned in Attributes.
+ @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL.
+
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GET_ATTRIBUTES)(
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ OUT UINT64 *Supports,
+ OUT UINT64 *Attributes
+ );
+
+/**
+ Sets attributes for a resource range on a PCI root bridge.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Attributes The mask of attributes to set.
+ @param ResourceBase A pointer to the base address of the resource range to be modified by the
+ attributes specified by Attributes.
+ @param ResourceLength A pointer to the length of the resource range to be modified by the
+ attributes specified by Attributes.
+
+ @retval EFI_SUCCESS The set of attributes specified by Attributes for the resource
+ range specified by ResourceBase and ResourceLength
+ were set on the PCI root bridge, and the actual resource range is
+ returned in ResuourceBase and ResourceLength.
+ @retval EFI_UNSUPPORTED A bit is set in Attributes that is not supported by the PCI Root
+ Bridge.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to set the attributes on the
+ resource range specified by BaseAddress and Length.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_SET_ATTRIBUTES)(
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN UINT64 Attributes,
+ IN OUT UINT64 *ResourceBase,
+ IN OUT UINT64 *ResourceLength
+ );
+
+/**
+ Retrieves the current resource settings of this PCI root bridge in the form of a set of ACPI 2.0
+ resource descriptors.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Resources A pointer to the ACPI 2.0 resource descriptors that describe the current
+ configuration of this PCI root bridge.
+
+ @retval EFI_SUCCESS The current configuration of this PCI root bridge was returned in
+ Resources.
+ @retval EFI_UNSUPPORTED The current configuration of this PCI root bridge could not be
+ retrieved.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_CONFIGURATION)(
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ OUT VOID **Resources
+ );
+
+///
+/// Provides the basic Memory, I/O, PCI configuration, and DMA interfaces that are
+/// used to abstract accesses to PCI controllers behind a PCI Root Bridge Controller.
+///
+struct _EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL {
+ ///
+ /// The EFI_HANDLE of the PCI Host Bridge of which this PCI Root Bridge is a member.
+ ///
+ EFI_HANDLE ParentHandle;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_POLL_IO_MEM PollMem;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_POLL_IO_MEM PollIo;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS Mem;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS Io;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS Pci;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_COPY_MEM CopyMem;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_MAP Map;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_UNMAP Unmap;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ALLOCATE_BUFFER AllocateBuffer;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_FREE_BUFFER FreeBuffer;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_FLUSH Flush;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GET_ATTRIBUTES GetAttributes;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_SET_ATTRIBUTES SetAttributes;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_CONFIGURATION Configuration;
+
+ ///
+ /// The segment number that this PCI root bridge resides.
+ ///
+ UINT32 SegmentNumber;
+};
+
+extern EFI_GUID gEfiPciRootBridgeIoProtocolGuid;
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Protocol/SimpleNetwork.h b/gpxe/src/include/gpxe/efi/Protocol/SimpleNetwork.h
new file mode 100644
index 00000000..d3d2afc7
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Protocol/SimpleNetwork.h
@@ -0,0 +1,593 @@
+/** @file
+ Simple Network protocol as defined in the UEFI 2.0 specification.
+
+ Basic network device abstraction.
+
+ Rx - Received
+ Tx - Transmit
+ MCast - MultiCast
+ ...
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __SIMPLE_NETWORK_H__
+#define __SIMPLE_NETWORK_H__
+
+#define EFI_SIMPLE_NETWORK_PROTOCOL_GUID \
+ { \
+ 0xA19832B9, 0xAC25, 0x11D3, {0x9A, 0x2D, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D } \
+ }
+
+typedef struct _EFI_SIMPLE_NETWORK_PROTOCOL EFI_SIMPLE_NETWORK_PROTOCOL;
+
+
+///
+/// Protocol defined in EFI1.1.
+///
+typedef EFI_SIMPLE_NETWORK_PROTOCOL EFI_SIMPLE_NETWORK;
+
+///
+/// Simple Network Protocol data structures
+///
+typedef struct {
+ ///
+ /// Total number of frames received. Includes frames with errors and
+ /// dropped frames.
+ ///
+ UINT64 RxTotalFrames;
+
+ ///
+ /// Number of valid frames received and copied into receive buffers.
+ ///
+ UINT64 RxGoodFrames;
+
+ ///
+ /// Number of frames below the minimum length for the media.
+ /// This would be <64 for ethernet.
+ ///
+ UINT64 RxUndersizeFrames;
+
+ ///
+ /// Number of frames longer than the maxminum length for the
+ /// media. This would be >1500 for ethernet.
+ ///
+ UINT64 RxOversizeFrames;
+
+ ///
+ /// Valid frames that were dropped because receive buffers were full.
+ ///
+ UINT64 RxDroppedFrames;
+
+ ///
+ /// Number of valid unicast frames received and not dropped.
+ ///
+ UINT64 RxUnicastFrames;
+
+ ///
+ /// Number of valid broadcast frames received and not dropped.
+ ///
+ UINT64 RxBroadcastFrames;
+
+ ///
+ /// Number of valid mutlicast frames received and not dropped.
+ ///
+ UINT64 RxMulticastFrames;
+
+ ///
+ /// Number of frames w/ CRC or alignment errors.
+ ///
+ UINT64 RxCrcErrorFrames;
+
+ ///
+ /// Total number of bytes received. Includes frames with errors
+ /// and dropped frames.
+ //
+ UINT64 RxTotalBytes;
+
+ ///
+ /// Transmit statistics.
+ ///
+ UINT64 TxTotalFrames;
+ UINT64 TxGoodFrames;
+ UINT64 TxUndersizeFrames;
+ UINT64 TxOversizeFrames;
+ UINT64 TxDroppedFrames;
+ UINT64 TxUnicastFrames;
+ UINT64 TxBroadcastFrames;
+ UINT64 TxMulticastFrames;
+ UINT64 TxCrcErrorFrames;
+ UINT64 TxTotalBytes;
+
+ ///
+ /// Number of collisions detection on this subnet.
+ ///
+ UINT64 Collisions;
+
+ ///
+ /// Number of frames destined for unsupported protocol.
+ ///
+ UINT64 UnsupportedProtocol;
+
+} EFI_NETWORK_STATISTICS;
+
+typedef enum {
+ EfiSimpleNetworkStopped,
+ EfiSimpleNetworkStarted,
+ EfiSimpleNetworkInitialized,
+ EfiSimpleNetworkMaxState
+} EFI_SIMPLE_NETWORK_STATE;
+
+#define EFI_SIMPLE_NETWORK_RECEIVE_UNICAST 0x01
+#define EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST 0x02
+#define EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST 0x04
+#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS 0x08
+#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST 0x10
+
+#define EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT 0x01
+#define EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT 0x02
+#define EFI_SIMPLE_NETWORK_COMMAND_INTERRUPT 0x04
+#define EFI_SIMPLE_NETWORK_SOFTWARE_INTERRUPT 0x08
+
+#define MAX_MCAST_FILTER_CNT 16
+typedef struct {
+ UINT32 State;
+ UINT32 HwAddressSize;
+ UINT32 MediaHeaderSize;
+ UINT32 MaxPacketSize;
+ UINT32 NvRamSize;
+ UINT32 NvRamAccessSize;
+ UINT32 ReceiveFilterMask;
+ UINT32 ReceiveFilterSetting;
+ UINT32 MaxMCastFilterCount;
+ UINT32 MCastFilterCount;
+ EFI_MAC_ADDRESS MCastFilter[MAX_MCAST_FILTER_CNT];
+ EFI_MAC_ADDRESS CurrentAddress;
+ EFI_MAC_ADDRESS BroadcastAddress;
+ EFI_MAC_ADDRESS PermanentAddress;
+ UINT8 IfType;
+ BOOLEAN MacAddressChangeable;
+ BOOLEAN MultipleTxSupported;
+ BOOLEAN MediaPresentSupported;
+ BOOLEAN MediaPresent;
+} EFI_SIMPLE_NETWORK_MODE;
+
+//
+// Protocol Member Functions
+//
+/**
+ Changes the state of a network interface from "stopped" to "started".
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The network interface was started.
+ @retval EFI_ALREADY_STARTED The network interface is already in the started state.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_START)(
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ );
+
+/**
+ Changes the state of a network interface from "started" to "stopped".
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The network interface was stopped.
+ @retval EFI_ALREADY_STARTED The network interface is already in the stopped state.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_STOP)(
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ );
+
+/**
+ Resets a network adapter and allocates the transmit and receive buffers
+ required by the network interface; optionally, also requests allocation
+ of additional transmit and receive buffers.
+
+ @param This Protocol instance pointer.
+ @param ExtraRxBufferSize The size, in bytes, of the extra receive buffer space
+ that the driver should allocate for the network interface.
+ Some network interfaces will not be able to use the extra
+ buffer, and the caller will not know if it is actually
+ being used.
+ @param ExtraTxBufferSize The size, in bytes, of the extra transmit buffer space
+ that the driver should allocate for the network interface.
+ Some network interfaces will not be able to use the extra
+ buffer, and the caller will not know if it is actually
+ being used.
+
+ @retval EFI_SUCCESS The network interface was initialized.
+ @retval EFI_NOT_STARTED The network interface has not been started
+ @retval EFI_OUT_OF_RESOURCES There was not enough memory for the transmit and
+ receive buffers. .
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_INITIALIZE)(
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN UINTN ExtraRxBufferSize OPTIONAL,
+ IN UINTN ExtraTxBufferSize OPTIONAL
+ );
+
+/**
+ Resets a network adapter and re-initializes it with the parameters that were
+ provided in the previous call to Initialize().
+
+ @param This Protocol instance pointer.
+ @param ExtendedVerification Indicates that the driver may perform a more
+ exhaustive verification operation of the device
+ during reset.
+
+ @retval EFI_SUCCESS The network interface was reset.
+ @retval EFI_NOT_STARTED The network interface has not been started
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_RESET)(
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Resets a network adapter and leaves it in a state that is safe for
+ another driver to initialize.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The network interface was shutdown.
+ @retval EFI_NOT_STARTED The network interface has not been started
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_SHUTDOWN)(
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ );
+
+/**
+ Manages the multicast receive filters of a network interface.
+
+ @param This Protocol instance pointer.
+ @param Enable A bit mask of receive filters to enable on the network interface.
+ @param Disable A bit mask of receive filters to disable on the network interface.
+ @param ResetMCastFilter Set to TRUE to reset the contents of the multicast receive
+ filters on the network interface to their default values.
+ @param McastFilterCnt Number of multicast HW MAC addresses in the new
+ MCastFilter list. This value must be less than or equal to
+ the MCastFilterCnt field of EFI_SIMPLE_NETWORK_MODE. This
+ field is optional if ResetMCastFilter is TRUE.
+ @param MCastFilter A pointer to a list of new multicast receive filter HW MAC
+ addresses. This list will replace any existing multicast
+ HW MAC address list. This field is optional if
+ ResetMCastFilter is TRUE.
+
+ @retval EFI_SUCCESS The multicast receive filter list was updated.
+ @retval EFI_NOT_STARTED The network interface has not been started
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_RECEIVE_FILTERS)(
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN UINT32 Enable,
+ IN UINT32 Disable,
+ IN BOOLEAN ResetMCastFilter,
+ IN UINTN MCastFilterCnt OPTIONAL,
+ IN EFI_MAC_ADDRESS *MCastFilter OPTIONAL
+ );
+
+/**
+ Modifies or resets the current station address, if supported.
+
+ @param This Protocol instance pointer.
+ @param Reset Flag used to reset the station address to the network interfaces
+ permanent address.
+ @param New New station address to be used for the network interface.
+
+ @retval EFI_SUCCESS The network interfaces station address was updated.
+ @retval EFI_NOT_STARTED The network interface has not been started
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_STATION_ADDRESS)(
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN Reset,
+ IN EFI_MAC_ADDRESS *New OPTIONAL
+ );
+
+/**
+ Resets or collects the statistics on a network interface.
+
+ @param This Protocol instance pointer.
+ @param Reset Set to TRUE to reset the statistics for the network interface.
+ @param StatisticsSize On input the size, in bytes, of StatisticsTable. On
+ output the size, in bytes, of the resulting table of
+ statistics.
+ @param StatisticsTable A pointer to the EFI_NETWORK_STATISTICS structure that
+ contains the statistics.
+
+ @retval EFI_SUCCESS The statistics were collected from the network interface.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_BUFFER_TOO_SMALL The Statistics buffer was too small. The current buffer
+ size needed to hold the statistics is returned in
+ StatisticsSize.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_STATISTICS)(
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN Reset,
+ IN OUT UINTN *StatisticsSize OPTIONAL,
+ OUT EFI_NETWORK_STATISTICS *StatisticsTable OPTIONAL
+ );
+
+/**
+ Converts a multicast IP address to a multicast HW MAC address.
+
+ @param This Protocol instance pointer.
+ @param IPv6 Set to TRUE if the multicast IP address is IPv6 [RFC 2460]. Set
+ to FALSE if the multicast IP address is IPv4 [RFC 791].
+ @param IP The multicast IP address that is to be converted to a multicast
+ HW MAC address.
+ @param MAC The multicast HW MAC address that is to be generated from IP.
+
+ @retval EFI_SUCCESS The multicast IP address was mapped to the multicast
+ HW MAC address.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_BUFFER_TOO_SMALL The Statistics buffer was too small. The current buffer
+ size needed to hold the statistics is returned in
+ StatisticsSize.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_MCAST_IP_TO_MAC)(
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN IPv6,
+ IN EFI_IP_ADDRESS *IP,
+ OUT EFI_MAC_ADDRESS *MAC
+ );
+
+/**
+ Performs read and write operations on the NVRAM device attached to a
+ network interface.
+
+ @param This Protocol instance pointer.
+ @param ReadWrite TRUE for read operations, FALSE for write operations.
+ @param Offset Byte offset in the NVRAM device at which to start the read or
+ write operation. This must be a multiple of NvRamAccessSize and
+ less than NvRamSize.
+ @param BufferSize The number of bytes to read or write from the NVRAM device.
+ This must also be a multiple of NvramAccessSize.
+ @param Buffer A pointer to the data buffer.
+
+ @retval EFI_SUCCESS The NVRAM access was performed.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_NVDATA)(
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN ReadWrite,
+ IN UINTN Offset,
+ IN UINTN BufferSize,
+ IN OUT VOID *Buffer
+ );
+
+/**
+ Reads the current interrupt status and recycled transmit buffer status from
+ a network interface.
+
+ @param This Protocol instance pointer.
+ @param InterruptStatus A pointer to the bit mask of the currently active interrupts
+ If this is NULL, the interrupt status will not be read from
+ the device. If this is not NULL, the interrupt status will
+ be read from the device. When the interrupt status is read,
+ it will also be cleared. Clearing the transmit interrupt
+ does not empty the recycled transmit buffer array.
+ @param TxBuf Recycled transmit buffer address. The network interface will
+ not transmit if its internal recycled transmit buffer array
+ is full. Reading the transmit buffer does not clear the
+ transmit interrupt. If this is NULL, then the transmit buffer
+ status will not be read. If there are no transmit buffers to
+ recycle and TxBuf is not NULL, * TxBuf will be set to NULL.
+
+ @retval EFI_SUCCESS The status of the network interface was retrieved.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_GET_STATUS)(
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ OUT UINT32 *InterruptStatus OPTIONAL,
+ OUT VOID **TxBuf OPTIONAL
+ );
+
+/**
+ Places a packet in the transmit queue of a network interface.
+
+ @param This Protocol instance pointer.
+ @param HeaderSize The size, in bytes, of the media header to be filled in by
+ the Transmit() function. If HeaderSize is non-zero, then it
+ must be equal to This->Mode->MediaHeaderSize and the DestAddr
+ and Protocol parameters must not be NULL.
+ @param BufferSize The size, in bytes, of the entire packet (media header and
+ data) to be transmitted through the network interface.
+ @param Buffer A pointer to the packet (media header followed by data) to be
+ transmitted. This parameter cannot be NULL. If HeaderSize is zero,
+ then the media header in Buffer must already be filled in by the
+ caller. If HeaderSize is non-zero, then the media header will be
+ filled in by the Transmit() function.
+ @param SrcAddr The source HW MAC address. If HeaderSize is zero, then this parameter
+ is ignored. If HeaderSize is non-zero and SrcAddr is NULL, then
+ This->Mode->CurrentAddress is used for the source HW MAC address.
+ @param DsetAddr The destination HW MAC address. If HeaderSize is zero, then this
+ parameter is ignored.
+ @param Protocol The type of header to build. If HeaderSize is zero, then this
+ parameter is ignored. See RFC 1700, section "Ether Types", for
+ examples.
+
+ @retval EFI_SUCCESS The packet was placed on the transmit queue.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_NOT_READY The network interface is too busy to accept this transmit request.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_TRANSMIT)(
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN UINTN HeaderSize,
+ IN UINTN BufferSize,
+ IN VOID *Buffer,
+ IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
+ IN EFI_MAC_ADDRESS *DestAddr OPTIONAL,
+ IN UINT16 *Protocol OPTIONAL
+ );
+
+/**
+ Receives a packet from a network interface.
+
+ @param This Protocol instance pointer.
+ @param HeaderSize The size, in bytes, of the media header received on the network
+ interface. If this parameter is NULL, then the media header size
+ will not be returned.
+ @param BufferSize On entry, the size, in bytes, of Buffer. On exit, the size, in
+ bytes, of the packet that was received on the network interface.
+ @param Buffer A pointer to the data buffer to receive both the media header and
+ the data.
+ @param SrcAddr The source HW MAC address. If this parameter is NULL, the
+ HW MAC source address will not be extracted from the media
+ header.
+ @param DsetAddr The destination HW MAC address. If this parameter is NULL,
+ the HW MAC destination address will not be extracted from the
+ media header.
+ @param Protocol The media header type. If this parameter is NULL, then the
+ protocol will not be extracted from the media header. See
+ RFC 1700 section "Ether Types" for examples.
+
+ @retval EFI_SUCCESS The received data was stored in Buffer, and BufferSize has
+ been updated to the number of bytes received.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_NOT_READY The network interface is too busy to accept this transmit
+ request.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_RECEIVE)(
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ OUT UINTN *HeaderSize OPTIONAL,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer,
+ OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
+ OUT EFI_MAC_ADDRESS *DestAddr OPTIONAL,
+ OUT UINT16 *Protocol OPTIONAL
+ );
+
+#define EFI_SIMPLE_NETWORK_PROTOCOL_REVISION 0x00010000
+
+//
+// Revision defined in EFI1.1
+//
+#define EFI_SIMPLE_NETWORK_INTERFACE_REVISION EFI_SIMPLE_NETWORK_PROTOCOL_REVISION
+
+///
+/// The EFI_SIMPLE_NETWORK_PROTOCOL protocol is used to initialize access
+/// to a network adapter. Once the network adapter initializes,
+/// the EFI_SIMPLE_NETWORK_PROTOCOL protocol provides services that
+/// allow packets to be transmitted and received.
+///
+struct _EFI_SIMPLE_NETWORK_PROTOCOL {
+ ///
+ /// Revision of the EFI_SIMPLE_NETWORK_PROTOCOL. All future revisions must
+ /// be backwards compatible. If a future version is not backwards compatible
+ /// it is not the same GUID.
+ ///
+ UINT64 Revision;
+ EFI_SIMPLE_NETWORK_START Start;
+ EFI_SIMPLE_NETWORK_STOP Stop;
+ EFI_SIMPLE_NETWORK_INITIALIZE Initialize;
+ EFI_SIMPLE_NETWORK_RESET Reset;
+ EFI_SIMPLE_NETWORK_SHUTDOWN Shutdown;
+ EFI_SIMPLE_NETWORK_RECEIVE_FILTERS ReceiveFilters;
+ EFI_SIMPLE_NETWORK_STATION_ADDRESS StationAddress;
+ EFI_SIMPLE_NETWORK_STATISTICS Statistics;
+ EFI_SIMPLE_NETWORK_MCAST_IP_TO_MAC MCastIpToMac;
+ EFI_SIMPLE_NETWORK_NVDATA NvData;
+ EFI_SIMPLE_NETWORK_GET_STATUS GetStatus;
+ EFI_SIMPLE_NETWORK_TRANSMIT Transmit;
+ EFI_SIMPLE_NETWORK_RECEIVE Receive;
+ ///
+ /// Event used with WaitForEvent() to wait for a packet to be received.
+ ///
+ EFI_EVENT WaitForPacket;
+ ///
+ /// Pointer to the EFI_SIMPLE_NETWORK_MODE data for the device.
+ ///
+ EFI_SIMPLE_NETWORK_MODE *Mode;
+};
+
+extern EFI_GUID gEfiSimpleNetworkProtocolGuid;
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Protocol/SimpleTextIn.h b/gpxe/src/include/gpxe/efi/Protocol/SimpleTextIn.h
new file mode 100644
index 00000000..f14f62d5
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Protocol/SimpleTextIn.h
@@ -0,0 +1,136 @@
+/** @file
+ Simple Text In protocol from the UEFI 2.0 specification.
+
+ Abstraction of a very simple input device like a keyboard or serial
+ terminal.
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __SIMPLE_TEXT_IN_PROTOCOL_H__
+#define __SIMPLE_TEXT_IN_PROTOCOL_H__
+
+#include <gpxe/efi/ProcessorBind.h>
+
+#define EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID \
+ { \
+ 0x387477c1, 0x69c7, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
+ }
+
+///
+/// Protocol GUID defined in EFI1.1.
+///
+#define SIMPLE_INPUT_PROTOCOL EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID
+
+typedef struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL EFI_SIMPLE_TEXT_INPUT_PROTOCOL;
+
+///
+/// Backward-compatible with EFI1.1.
+///
+typedef struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL SIMPLE_INPUT_INTERFACE;
+//
+// Data structures
+//
+typedef struct {
+ UINT16 ScanCode;
+ CHAR16 UnicodeChar;
+} EFI_INPUT_KEY;
+
+//
+// Required unicode control chars
+//
+#define CHAR_NULL 0x0000
+#define CHAR_BACKSPACE 0x0008
+#define CHAR_TAB 0x0009
+#define CHAR_LINEFEED 0x000A
+#define CHAR_CARRIAGE_RETURN 0x000D
+
+//
+// EFI Scan codes
+//
+#define SCAN_NULL 0x0000
+#define SCAN_UP 0x0001
+#define SCAN_DOWN 0x0002
+#define SCAN_RIGHT 0x0003
+#define SCAN_LEFT 0x0004
+#define SCAN_HOME 0x0005
+#define SCAN_END 0x0006
+#define SCAN_INSERT 0x0007
+#define SCAN_DELETE 0x0008
+#define SCAN_PAGE_UP 0x0009
+#define SCAN_PAGE_DOWN 0x000A
+#define SCAN_F1 0x000B
+#define SCAN_F2 0x000C
+#define SCAN_F3 0x000D
+#define SCAN_F4 0x000E
+#define SCAN_F5 0x000F
+#define SCAN_F6 0x0010
+#define SCAN_F7 0x0011
+#define SCAN_F8 0x0012
+#define SCAN_F9 0x0013
+#define SCAN_F10 0x0014
+#define SCAN_F11 0x0015
+#define SCAN_F12 0x0016
+#define SCAN_ESC 0x0017
+
+/**
+ Reset the input device and optionaly run diagnostics
+
+ @param This Protocol instance pointer.
+ @param ExtendedVerification Driver may perform diagnostics on reset.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could not be reset.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_INPUT_RESET)(
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Reads the next keystroke from the input device. The WaitForKey Event can
+ be used to test for existance of a keystroke via WaitForEvent () call.
+
+ @param This Protocol instance pointer.
+ @param Key Driver may perform diagnostics on reset.
+
+ @retval EFI_SUCCESS The keystroke information was returned.
+ @retval EFI_NOT_READY There was no keystroke data availiable.
+ @retval EFI_DEVICE_ERROR The keydtroke information was not returned due to
+ hardware errors.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_INPUT_READ_KEY)(
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ OUT EFI_INPUT_KEY *Key
+ );
+
+///
+/// The EFI_SIMPLE_TEXT_INPUT_PROTOCOL is used on the ConsoleIn device.
+/// It is the minimum required protocol for ConsoleIn.
+///
+struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL {
+ EFI_INPUT_RESET Reset;
+ EFI_INPUT_READ_KEY ReadKeyStroke;
+ ///
+ /// Event to use with WaitForEvent() to wait for a key to be available
+ ///
+ EFI_EVENT WaitForKey;
+};
+
+extern EFI_GUID gEfiSimpleTextInProtocolGuid;
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Protocol/SimpleTextOut.h b/gpxe/src/include/gpxe/efi/Protocol/SimpleTextOut.h
new file mode 100644
index 00000000..426ce819
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Protocol/SimpleTextOut.h
@@ -0,0 +1,404 @@
+/** @file
+ Simple Text Out protocol from the UEFI 2.0 specification.
+
+ Abstraction of a very simple text based output device like VGA text mode or
+ a serial terminal. The Simple Text Out protocol instance can represent
+ a single hardware device or a virtual device that is an agregation
+ of multiple physical devices.
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __SIMPLE_TEXT_OUT_H__
+#define __SIMPLE_TEXT_OUT_H__
+
+#define EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID \
+ { \
+ 0x387477c2, 0x69c7, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
+ }
+
+///
+/// Protocol GUID defined in EFI1.1.
+///
+#define SIMPLE_TEXT_OUTPUT_PROTOCOL EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID
+
+typedef struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL;
+
+///
+/// Backward-compatible with EFI1.1.
+///
+typedef EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL SIMPLE_TEXT_OUTPUT_INTERFACE;
+
+//
+// Define's for required EFI Unicode Box Draw characters
+//
+#define BOXDRAW_HORIZONTAL 0x2500
+#define BOXDRAW_VERTICAL 0x2502
+#define BOXDRAW_DOWN_RIGHT 0x250c
+#define BOXDRAW_DOWN_LEFT 0x2510
+#define BOXDRAW_UP_RIGHT 0x2514
+#define BOXDRAW_UP_LEFT 0x2518
+#define BOXDRAW_VERTICAL_RIGHT 0x251c
+#define BOXDRAW_VERTICAL_LEFT 0x2524
+#define BOXDRAW_DOWN_HORIZONTAL 0x252c
+#define BOXDRAW_UP_HORIZONTAL 0x2534
+#define BOXDRAW_VERTICAL_HORIZONTAL 0x253c
+#define BOXDRAW_DOUBLE_HORIZONTAL 0x2550
+#define BOXDRAW_DOUBLE_VERTICAL 0x2551
+#define BOXDRAW_DOWN_RIGHT_DOUBLE 0x2552
+#define BOXDRAW_DOWN_DOUBLE_RIGHT 0x2553
+#define BOXDRAW_DOUBLE_DOWN_RIGHT 0x2554
+#define BOXDRAW_DOWN_LEFT_DOUBLE 0x2555
+#define BOXDRAW_DOWN_DOUBLE_LEFT 0x2556
+#define BOXDRAW_DOUBLE_DOWN_LEFT 0x2557
+#define BOXDRAW_UP_RIGHT_DOUBLE 0x2558
+#define BOXDRAW_UP_DOUBLE_RIGHT 0x2559
+#define BOXDRAW_DOUBLE_UP_RIGHT 0x255a
+#define BOXDRAW_UP_LEFT_DOUBLE 0x255b
+#define BOXDRAW_UP_DOUBLE_LEFT 0x255c
+#define BOXDRAW_DOUBLE_UP_LEFT 0x255d
+#define BOXDRAW_VERTICAL_RIGHT_DOUBLE 0x255e
+#define BOXDRAW_VERTICAL_DOUBLE_RIGHT 0x255f
+#define BOXDRAW_DOUBLE_VERTICAL_RIGHT 0x2560
+#define BOXDRAW_VERTICAL_LEFT_DOUBLE 0x2561
+#define BOXDRAW_VERTICAL_DOUBLE_LEFT 0x2562
+#define BOXDRAW_DOUBLE_VERTICAL_LEFT 0x2563
+#define BOXDRAW_DOWN_HORIZONTAL_DOUBLE 0x2564
+#define BOXDRAW_DOWN_DOUBLE_HORIZONTAL 0x2565
+#define BOXDRAW_DOUBLE_DOWN_HORIZONTAL 0x2566
+#define BOXDRAW_UP_HORIZONTAL_DOUBLE 0x2567
+#define BOXDRAW_UP_DOUBLE_HORIZONTAL 0x2568
+#define BOXDRAW_DOUBLE_UP_HORIZONTAL 0x2569
+#define BOXDRAW_VERTICAL_HORIZONTAL_DOUBLE 0x256a
+#define BOXDRAW_VERTICAL_DOUBLE_HORIZONTAL 0x256b
+#define BOXDRAW_DOUBLE_VERTICAL_HORIZONTAL 0x256c
+
+//
+// EFI Required Block Elements Code Chart
+//
+#define BLOCKELEMENT_FULL_BLOCK 0x2588
+#define BLOCKELEMENT_LIGHT_SHADE 0x2591
+
+//
+// EFI Required Geometric Shapes Code Chart
+//
+#define GEOMETRICSHAPE_UP_TRIANGLE 0x25b2
+#define GEOMETRICSHAPE_RIGHT_TRIANGLE 0x25ba
+#define GEOMETRICSHAPE_DOWN_TRIANGLE 0x25bc
+#define GEOMETRICSHAPE_LEFT_TRIANGLE 0x25c4
+
+//
+// EFI Required Arrow shapes
+//
+#define ARROW_LEFT 0x2190
+#define ARROW_UP 0x2191
+#define ARROW_RIGHT 0x2192
+#define ARROW_DOWN 0x2193
+
+//
+// EFI Console Colours
+//
+#define EFI_BLACK 0x00
+#define EFI_BLUE 0x01
+#define EFI_GREEN 0x02
+#define EFI_CYAN (EFI_BLUE | EFI_GREEN)
+#define EFI_RED 0x04
+#define EFI_MAGENTA (EFI_BLUE | EFI_RED)
+#define EFI_BROWN (EFI_GREEN | EFI_RED)
+#define EFI_LIGHTGRAY (EFI_BLUE | EFI_GREEN | EFI_RED)
+#define EFI_BRIGHT 0x08
+#define EFI_DARKGRAY (EFI_BRIGHT)
+#define EFI_LIGHTBLUE (EFI_BLUE | EFI_BRIGHT)
+#define EFI_LIGHTGREEN (EFI_GREEN | EFI_BRIGHT)
+#define EFI_LIGHTCYAN (EFI_CYAN | EFI_BRIGHT)
+#define EFI_LIGHTRED (EFI_RED | EFI_BRIGHT)
+#define EFI_LIGHTMAGENTA (EFI_MAGENTA | EFI_BRIGHT)
+#define EFI_YELLOW (EFI_BROWN | EFI_BRIGHT)
+#define EFI_WHITE (EFI_BLUE | EFI_GREEN | EFI_RED | EFI_BRIGHT)
+
+#define EFI_TEXT_ATTR(f, b) ((f) | ((b) << 4))
+
+#define EFI_BACKGROUND_BLACK 0x00
+#define EFI_BACKGROUND_BLUE 0x10
+#define EFI_BACKGROUND_GREEN 0x20
+#define EFI_BACKGROUND_CYAN (EFI_BACKGROUND_BLUE | EFI_BACKGROUND_GREEN)
+#define EFI_BACKGROUND_RED 0x40
+#define EFI_BACKGROUND_MAGENTA (EFI_BACKGROUND_BLUE | EFI_BACKGROUND_RED)
+#define EFI_BACKGROUND_BROWN (EFI_BACKGROUND_GREEN | EFI_BACKGROUND_RED)
+#define EFI_BACKGROUND_LIGHTGRAY (EFI_BACKGROUND_BLUE | EFI_BACKGROUND_GREEN | EFI_BACKGROUND_RED)
+
+//
+// We currently define attributes from 0 - 7F for color manipulations
+// To internally handle the local display characteristics for a particular character, we are defining
+// Bit 7 to signify the local glyph representation for a character. If turned on, glyphs will be
+// pulled from the wide glyph database and will display locally as a wide character (16 X 19 versus 8 X 19)
+// If bit 7 is off, the narrow glyph database will be used. This does NOT affect information that is sent to
+// non-local displays (e.g. serial or LAN consoles).
+//
+#define EFI_WIDE_ATTRIBUTE 0x80
+
+/**
+ Reset the text output device hardware and optionaly run diagnostics
+
+ @param This Protocol instance pointer.
+ @param ExtendedVerification Driver may perform more exhaustive verfication
+ operation of the device during reset.
+
+ @retval EFI_SUCCESS The text output device was reset.
+ @retval EFI_DEVICE_ERROR The text output device is not functioning correctly and
+ could not be reset.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_TEXT_RESET)(
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Write a Unicode string to the output device.
+
+ @param This Protocol instance pointer.
+ @param String The NULL-terminated Unicode string to be displayed on the output
+ device(s). All output devices must also support the Unicode
+ drawing defined in this file.
+
+ @retval EFI_SUCCESS The string was output to the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting to output
+ the text.
+ @retval EFI_UNSUPPORTED The output device's mode is not currently in a
+ defined text mode.
+ @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the
+ characters in the Unicode string could not be
+ rendered and were skipped.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_TEXT_STRING)(
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN CHAR16 *String
+ );
+
+/**
+ Verifies that all characters in a Unicode string can be output to the
+ target device.
+
+ @param This Protocol instance pointer.
+ @param String The NULL-terminated Unicode string to be examined for the output
+ device(s).
+
+ @retval EFI_SUCCESS The device(s) are capable of rendering the output string.
+ @retval EFI_UNSUPPORTED Some of the characters in the Unicode string cannot be
+ rendered by one or more of the output devices mapped
+ by the EFI handle.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_TEXT_TEST_STRING)(
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN CHAR16 *String
+ );
+
+/**
+ Returns information for an available text mode that the output device(s)
+ supports.
+
+ @param This Protocol instance pointer.
+ @param ModeNumber The mode number to return information on.
+ @param Columns Returns the geometry of the text output device for the
+ requested ModeNumber.
+ @param Rows Returns the geometry of the text output device for the
+ requested ModeNumber.
+
+ @retval EFI_SUCCESS The requested mode information was returned.
+ @retval EFI_DEVICE_ERROR The device had an error and could not complete the request.
+ @retval EFI_UNSUPPORTED The mode number was not valid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_TEXT_QUERY_MODE)(
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN ModeNumber,
+ OUT UINTN *Columns,
+ OUT UINTN *Rows
+ );
+
+/**
+ Sets the output device(s) to a specified mode.
+
+ @param This Protocol instance pointer.
+ @param ModeNumber The mode number to set.
+
+ @retval EFI_SUCCESS The requested text mode was set.
+ @retval EFI_DEVICE_ERROR The device had an error and could not complete the request.
+ @retval EFI_UNSUPPORTED The mode number was not valid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_TEXT_SET_MODE)(
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN ModeNumber
+ );
+
+/**
+ Sets the background and foreground colors for the OutputString () and
+ ClearScreen () functions.
+
+ @param This Protocol instance pointer.
+ @param Attribute The attribute to set. Bits 0..3 are the foreground color, and
+ bits 4..6 are the background color. All other bits are undefined
+ and must be zero. The valid Attributes are defined in this file.
+
+ @retval EFI_SUCCESS The attribute was set.
+ @retval EFI_DEVICE_ ERROR The device had an error and could not complete the request.
+ @retval EFI_UNSUPPORTED The attribute requested is not defined.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_TEXT_SET_ATTRIBUTE)(
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN Attribute
+ );
+
+/**
+ Clears the output device(s) display to the currently selected background
+ color.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_DEVICE_ERROR The device had an error and could not complete the request.
+ @retval EFI_UNSUPPORTED The output device is not in a valid text mode.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_TEXT_CLEAR_SCREEN)(
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
+ );
+
+/**
+ Sets the current coordinates of the cursor position
+
+ @param This Protocol instance pointer.
+ @param Column The position to set the cursor to. Must be greater than or
+ equal to zero and less than the number of columns and rows
+ by QueryMode ().
+ @param Row The position to set the cursor to. Must be greater than or
+ equal to zero and less than the number of columns and rows
+ by QueryMode ().
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_DEVICE_ERROR The device had an error and could not complete the request.
+ @retval EFI_UNSUPPORTED The output device is not in a valid text mode, or the
+ cursor position is invalid for the current mode.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_TEXT_SET_CURSOR_POSITION)(
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN Column,
+ IN UINTN Row
+ );
+
+/**
+ Makes the cursor visible or invisible
+
+ @param This Protocol instance pointer.
+ @param Visible If TRUE, the cursor is set to be visible. If FALSE, the cursor is
+ set to be invisible.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_DEVICE_ERROR The device had an error and could not complete the
+ request, or the device does not support changing
+ the cursor mode.
+ @retval EFI_UNSUPPORTED The output device is not in a valid text mode.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_TEXT_ENABLE_CURSOR)(
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN BOOLEAN Visible
+ );
+
+/**
+ @par Data Structure Description:
+ Mode Structure pointed to by Simple Text Out protocol.
+
+ @param MaxMode
+ The number of modes supported by QueryMode () and SetMode ().
+
+ @param Mode
+ The text mode of the output device(s).
+
+ @param Attribute
+ The current character output attribute
+
+ @param CursorColumn
+ The cursor's column.
+
+ @param CursorRow
+ The cursor's row.
+
+ @param CursorVisible
+ The cursor is currently visbile or not.
+
+**/
+typedef struct {
+ INT32 MaxMode;
+
+ //
+ // current settings
+ //
+ INT32 Mode;
+ INT32 Attribute;
+ INT32 CursorColumn;
+ INT32 CursorRow;
+ BOOLEAN CursorVisible;
+} EFI_SIMPLE_TEXT_OUTPUT_MODE;
+
+///
+/// The SIMPLE_TEXT_OUTPUT protocol is used to control text-based output devices.
+/// It is the minimum required protocol for any handle supplied as the ConsoleOut
+/// or StandardError device. In addition, the minimum supported text mode of such
+/// devices is at least 80 x 25 characters.
+///
+struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL {
+ EFI_TEXT_RESET Reset;
+
+ EFI_TEXT_STRING OutputString;
+ EFI_TEXT_TEST_STRING TestString;
+
+ EFI_TEXT_QUERY_MODE QueryMode;
+ EFI_TEXT_SET_MODE SetMode;
+ EFI_TEXT_SET_ATTRIBUTE SetAttribute;
+
+ EFI_TEXT_CLEAR_SCREEN ClearScreen;
+ EFI_TEXT_SET_CURSOR_POSITION SetCursorPosition;
+ EFI_TEXT_ENABLE_CURSOR EnableCursor;
+
+ ///
+ /// Pointer to SIMPLE_TEXT_OUTPUT_MODE data.
+ ///
+ EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
+};
+
+extern EFI_GUID gEfiSimpleTextOutProtocolGuid;
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Uefi.h b/gpxe/src/include/gpxe/efi/Uefi.h
new file mode 100644
index 00000000..58ddb11f
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Uefi.h
@@ -0,0 +1,27 @@
+/** @file
+
+ Root include file for Mde Package UEFI, UEFI_APPLICATION type modules.
+
+ This is the include file for any module of type UEFI and UEFI_APPLICATION. Uefi modules only use
+ types defined via this include file and can be ported easily to any
+ environment.
+
+Copyright (c) 2006 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __PI_UEFI_H__
+#define __PI_UEFI_H__
+
+#include <gpxe/efi/Uefi/UefiBaseType.h>
+#include <gpxe/efi/Uefi/UefiSpec.h>
+
+#endif
+
diff --git a/gpxe/src/include/gpxe/efi/Uefi/UefiBaseType.h b/gpxe/src/include/gpxe/efi/Uefi/UefiBaseType.h
new file mode 100644
index 00000000..475ac01e
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Uefi/UefiBaseType.h
@@ -0,0 +1,200 @@
+/** @file
+ Defines data types and constants introduced in UEFI.
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __UEFI_BASETYPE_H__
+#define __UEFI_BASETYPE_H__
+
+#include <gpxe/efi/Base.h>
+
+//
+// Basical data type definitions introduced in UEFI.
+//
+
+///
+/// 128-bit buffer containing a unique identifier value.
+///
+typedef GUID EFI_GUID;
+///
+/// Function return status for EFI API
+///
+typedef RETURN_STATUS EFI_STATUS;
+///
+/// A collection of related interfaces.
+///
+typedef VOID *EFI_HANDLE;
+///
+/// Handle to an event structure.
+///
+typedef VOID *EFI_EVENT;
+///
+/// Task priority level.
+///
+typedef UINTN EFI_TPL;
+///
+/// Logical block address.
+///
+typedef UINT64 EFI_LBA;
+typedef UINT64 EFI_PHYSICAL_ADDRESS;
+typedef UINT64 EFI_VIRTUAL_ADDRESS;
+
+///
+/// EFI Time Abstraction:
+/// Year: 1998 - 20XX
+/// Month: 1 - 12
+/// Day: 1 - 31
+/// Hour: 0 - 23
+/// Minute: 0 - 59
+/// Second: 0 - 59
+/// Nanosecond: 0 - 999,999,999
+/// TimeZone: -1440 to 1440 or 2047
+///
+typedef struct {
+ UINT16 Year;
+ UINT8 Month;
+ UINT8 Day;
+ UINT8 Hour;
+ UINT8 Minute;
+ UINT8 Second;
+ UINT8 Pad1;
+ UINT32 Nanosecond;
+ INT16 TimeZone;
+ UINT8 Daylight;
+ UINT8 Pad2;
+} EFI_TIME;
+
+
+///
+/// 4-byte buffer. An IPv4 internet protocol address.
+///
+typedef struct {
+ UINT8 Addr[4];
+} EFI_IPv4_ADDRESS;
+
+///
+/// 16-byte buffer. An IPv6 internet protocol address
+///
+typedef struct {
+ UINT8 Addr[16];
+} EFI_IPv6_ADDRESS;
+
+///
+/// 32-byte buffer containing a network Media Access Control address.
+///
+typedef struct {
+ UINT8 Addr[32];
+} EFI_MAC_ADDRESS;
+
+///
+/// 16-byte buffer aligned on a 4-byte boundary.
+/// An IPv4 or IPv6 internet protocol address.
+///
+typedef union {
+ UINT32 Addr[4];
+ EFI_IPv4_ADDRESS v4;
+ EFI_IPv6_ADDRESS v6;
+} EFI_IP_ADDRESS;
+
+
+//
+// Enumeration of EFI_STATUS.
+//
+#define EFI_SUCCESS RETURN_SUCCESS
+#define EFI_LOAD_ERROR RETURN_LOAD_ERROR
+#define EFI_INVALID_PARAMETER RETURN_INVALID_PARAMETER
+#define EFI_UNSUPPORTED RETURN_UNSUPPORTED
+#define EFI_BAD_BUFFER_SIZE RETURN_BAD_BUFFER_SIZE
+#define EFI_BUFFER_TOO_SMALL RETURN_BUFFER_TOO_SMALL
+#define EFI_NOT_READY RETURN_NOT_READY
+#define EFI_DEVICE_ERROR RETURN_DEVICE_ERROR
+#define EFI_WRITE_PROTECTED RETURN_WRITE_PROTECTED
+#define EFI_OUT_OF_RESOURCES RETURN_OUT_OF_RESOURCES
+#define EFI_VOLUME_CORRUPTED RETURN_VOLUME_CORRUPTED
+#define EFI_VOLUME_FULL RETURN_VOLUME_FULL
+#define EFI_NO_MEDIA RETURN_NO_MEDIA
+#define EFI_MEDIA_CHANGED RETURN_MEDIA_CHANGED
+#define EFI_NOT_FOUND RETURN_NOT_FOUND
+#define EFI_ACCESS_DENIED RETURN_ACCESS_DENIED
+#define EFI_NO_RESPONSE RETURN_NO_RESPONSE
+#define EFI_NO_MAPPING RETURN_NO_MAPPING
+#define EFI_TIMEOUT RETURN_TIMEOUT
+#define EFI_NOT_STARTED RETURN_NOT_STARTED
+#define EFI_ALREADY_STARTED RETURN_ALREADY_STARTED
+#define EFI_ABORTED RETURN_ABORTED
+#define EFI_ICMP_ERROR RETURN_ICMP_ERROR
+#define EFI_TFTP_ERROR RETURN_TFTP_ERROR
+#define EFI_PROTOCOL_ERROR RETURN_PROTOCOL_ERROR
+#define EFI_INCOMPATIBLE_VERSION RETURN_INCOMPATIBLE_VERSION
+#define EFI_SECURITY_VIOLATION RETURN_SECURITY_VIOLATION
+#define EFI_CRC_ERROR RETURN_CRC_ERROR
+#define EFI_END_OF_MEDIA RETURN_END_OF_MEDIA
+#define EFI_END_OF_FILE RETURN_END_OF_FILE
+#define EFI_INVALID_LANGUAGE RETURN_INVALID_LANGUAGE
+
+#define EFI_WARN_UNKNOWN_GLYPH RETURN_WARN_UNKNOWN_GLYPH
+#define EFI_WARN_DELETE_FAILURE RETURN_WARN_DELETE_FAILURE
+#define EFI_WARN_WRITE_FAILURE RETURN_WARN_WRITE_FAILURE
+#define EFI_WARN_BUFFER_TOO_SMALL RETURN_WARN_BUFFER_TOO_SMALL
+
+
+//
+// Define macro to encode the status code.
+//
+#define EFIERR(_a) ENCODE_ERROR(_a)
+
+#define EFI_ERROR(A) RETURN_ERROR(A)
+
+//
+// Define macros to build data structure signatures from characters.
+//
+#define EFI_SIGNATURE_16(A, B) SIGNATURE_16 (A, B)
+#define EFI_SIGNATURE_32(A, B, C, D) SIGNATURE_32 (A, B, C, D)
+#define EFI_SIGNATURE_64(A, B, C, D, E, F, G, H) SIGNATURE_64 (A, B, C, D, E, F, G, H)
+
+
+///
+/// Returns the byte offset to a field within a structure
+///
+#define EFI_FIELD_OFFSET(TYPE,Field) ((UINTN)(&(((TYPE *) 0)->Field)))
+
+//
+// The EFI memory allocation functions work in units of EFI_PAGEs that are
+// 4K. This should in no way be confused with the page size of the processor.
+// An EFI_PAGE is just the quanta of memory in EFI.
+//
+#define EFI_PAGE_SIZE 0x1000
+#define EFI_PAGE_MASK 0xFFF
+#define EFI_PAGE_SHIFT 12
+
+#define EFI_SIZE_TO_PAGES(a) (((a) >> EFI_PAGE_SHIFT) + (((a) & EFI_PAGE_MASK) ? 1 : 0))
+
+#define EFI_PAGES_TO_SIZE(a) ( (a) << EFI_PAGE_SHIFT)
+
+
+#define EFI_MAX_BIT MAX_BIT
+#define EFI_MAX_ADDRESS MAX_ADDRESS
+
+
+///
+/// Limited buffer size for a language code recommended by RFC3066
+/// (42 characters plus a NULL terminator)
+///
+#define RFC_3066_ENTRY_SIZE (42 + 1)
+
+///
+/// The size of a 3 character ISO639 language code.
+///
+#define ISO_639_2_ENTRY_SIZE 3
+
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Uefi/UefiGpt.h b/gpxe/src/include/gpxe/efi/Uefi/UefiGpt.h
new file mode 100644
index 00000000..92c3035e
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Uefi/UefiGpt.h
@@ -0,0 +1,62 @@
+/** @file
+ EFI Guid Partition Table Format Definition.
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __UEFI_GPT_H__
+#define __UEFI_GPT_H__
+
+///
+/// The primary GUID Partition Table Header must be
+/// located in LBA 1 (i.e., the second logical block).
+///
+#define PRIMARY_PART_HEADER_LBA 1
+
+///
+/// EFI Partition Table Signature: "EFI PART"
+///
+#define EFI_PTAB_HEADER_ID 0x5452415020494645ULL
+
+#pragma pack(1)
+
+///
+/// GPT Partition Table Header
+///
+typedef struct {
+ EFI_TABLE_HEADER Header;
+ EFI_LBA MyLBA;
+ EFI_LBA AlternateLBA;
+ EFI_LBA FirstUsableLBA;
+ EFI_LBA LastUsableLBA;
+ EFI_GUID DiskGUID;
+ EFI_LBA PartitionEntryLBA;
+ UINT32 NumberOfPartitionEntries;
+ UINT32 SizeOfPartitionEntry;
+ UINT32 PartitionEntryArrayCRC32;
+} EFI_PARTITION_TABLE_HEADER;
+
+///
+/// GPT Partition Entry
+///
+typedef struct {
+ EFI_GUID PartitionTypeGUID;
+ EFI_GUID UniquePartitionGUID;
+ EFI_LBA StartingLBA;
+ EFI_LBA EndingLBA;
+ UINT64 Attributes;
+ CHAR16 PartitionName[36];
+} EFI_PARTITION_ENTRY;
+
+#pragma pack()
+#endif
+
+
diff --git a/gpxe/src/include/gpxe/efi/Uefi/UefiInternalFormRepresentation.h b/gpxe/src/include/gpxe/efi/Uefi/UefiInternalFormRepresentation.h
new file mode 100644
index 00000000..c6755173
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Uefi/UefiInternalFormRepresentation.h
@@ -0,0 +1,1590 @@
+/** @file
+ This file defines the encoding for the VFR (Visual Form Representation) language.
+ IFR is primarily consumed by the EFI presentation engine, and produced by EFI
+ internal application and drivers as well as all add-in card option-ROM drivers
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+ @par Revision Reference:
+ These definitions are from UEFI2.1.
+
+**/
+
+#ifndef __UEFI_INTERNAL_FORMREPRESENTATION_H__
+#define __UEFI_INTERNAL_FORMREPRESENTATION_H__
+
+///
+/// The following types are currently defined:
+///
+typedef VOID* EFI_HII_HANDLE;
+typedef CHAR16* EFI_STRING;
+typedef UINT16 EFI_IMAGE_ID;
+typedef UINT16 EFI_QUESTION_ID;
+typedef UINT16 EFI_STRING_ID;
+typedef UINT16 EFI_FORM_ID;
+typedef UINT16 EFI_VARSTORE_ID;
+
+typedef UINT16 EFI_DEFAULT_ID;
+
+typedef UINT32 EFI_HII_FONT_STYLE;
+
+
+
+#pragma pack(1)
+
+//
+// Definitions for Package Lists and Package Headers
+// Section 27.3.1
+//
+
+///
+/// The header found at the start of each package list.
+///
+typedef struct {
+ EFI_GUID PackageListGuid;
+ UINT32 PackageLength;
+} EFI_HII_PACKAGE_LIST_HEADER;
+
+///
+/// The header found at the start of each package.
+///
+typedef struct {
+ UINT32 Length:24;
+ UINT32 Type:8;
+ // UINT8 Data[...];
+} EFI_HII_PACKAGE_HEADER;
+
+//
+// Value of HII package type
+//
+#define EFI_HII_PACKAGE_TYPE_ALL 0x00
+#define EFI_HII_PACKAGE_TYPE_GUID 0x01
+#define EFI_HII_PACKAGE_FORMS 0x02
+#define EFI_HII_PACKAGE_STRINGS 0x04
+#define EFI_HII_PACKAGE_FONTS 0x05
+#define EFI_HII_PACKAGE_IMAGES 0x06
+#define EFI_HII_PACKAGE_SIMPLE_FONTS 0x07
+#define EFI_HII_PACKAGE_DEVICE_PATH 0x08
+#define EFI_HII_PACKAGE_KEYBOARD_LAYOUT 0x09
+#define EFI_HII_PACKAGE_END 0xDF
+#define EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN 0xE0
+#define EFI_HII_PACKAGE_TYPE_SYSTEM_END 0xFF
+
+//
+// Definitions for Simplified Font Package
+// Section 27.3.2
+//
+
+//
+// Contents of EFI_NARROW_GLYPH.Attributes
+//
+#define EFI_GLYPH_NON_SPACING 0x01
+#define EFI_GLYPH_WIDE 0x02
+#define EFI_GLYPH_HEIGHT 19
+#define EFI_GLYPH_WIDTH 8
+
+typedef struct {
+ CHAR16 UnicodeWeight;
+ UINT8 Attributes;
+ UINT8 GlyphCol1[EFI_GLYPH_HEIGHT];
+} EFI_NARROW_GLYPH;
+
+typedef struct {
+ CHAR16 UnicodeWeight;
+ UINT8 Attributes;
+ UINT8 GlyphCol1[EFI_GLYPH_HEIGHT];
+ UINT8 GlyphCol2[EFI_GLYPH_HEIGHT];
+ UINT8 Pad[3];
+} EFI_WIDE_GLYPH;
+
+///
+/// A simplified font package consists of a font header
+/// followed by a series of glyph structures.
+///
+typedef struct _EFI_HII_SIMPLE_FONT_PACKAGE_HDR {
+ EFI_HII_PACKAGE_HEADER Header;
+ UINT16 NumberOfNarrowGlyphs;
+ UINT16 NumberOfWideGlyphs;
+ // EFI_NARROW_GLYPH NarrowGlyphs[];
+ // EFI_WIDE_GLYPH WideGlyphs[];
+} EFI_HII_SIMPLE_FONT_PACKAGE_HDR;
+
+//
+// Definitions for Font Package
+// Section 27.3.3
+//
+
+//
+// Value for font style
+//
+#define EFI_HII_FONT_STYLE_NORMAL 0x00000000
+#define EFI_HII_FONT_STYLE_BOLD 0x00000001
+#define EFI_HII_FONT_STYLE_ITALIC 0x00000002
+#define EFI_HII_FONT_STYLE_EMBOSS 0x00010000
+#define EFI_HII_FONT_STYLE_OUTLINE 0x00020000
+#define EFI_HII_FONT_STYLE_SHADOW 0x00040000
+#define EFI_HII_FONT_STYLE_UNDERLINE 0x00080000
+#define EFI_HII_FONT_STYLE_DBL_UNDER 0x00100000
+
+typedef struct _EFI_HII_GLYPH_INFO {
+ UINT16 Width;
+ UINT16 Height;
+ INT16 OffsetX;
+ INT16 OffsetY;
+ INT16 AdvanceX;
+} EFI_HII_GLYPH_INFO;
+
+///
+/// The fixed header consists of a standard record header and
+/// then the character values in this section, the flags
+/// (including the encoding method) and the offsets of the glyph
+/// information, the glyph bitmaps and the character map.
+///
+typedef struct _EFI_HII_FONT_PACKAGE_HDR {
+ EFI_HII_PACKAGE_HEADER Header;
+ UINT32 HdrSize;
+ UINT32 GlyphBlockOffset;
+ EFI_HII_GLYPH_INFO Cell;
+ EFI_HII_FONT_STYLE FontStyle;
+ CHAR16 FontFamily[1];
+} EFI_HII_FONT_PACKAGE_HDR;
+
+//
+// Value of different glyph info block types
+//
+#define EFI_HII_GIBT_END 0x00
+#define EFI_HII_GIBT_GLYPH 0x10
+#define EFI_HII_GIBT_GLYPHS 0x11
+#define EFI_HII_GIBT_GLYPH_DEFAULT 0x12
+#define EFI_HII_GIBT_GLYPHS_DEFAULT 0x13
+#define EFI_HII_GIBT_DUPLICATE 0x20
+#define EFI_HII_GIBT_SKIP2 0x21
+#define EFI_HII_GIBT_SKIP1 0x22
+#define EFI_HII_GIBT_DEFAULTS 0x23
+#define EFI_HII_GIBT_EXT1 0x30
+#define EFI_HII_GIBT_EXT2 0x31
+#define EFI_HII_GIBT_EXT4 0x32
+
+typedef struct _EFI_HII_GLYPH_BLOCK {
+ UINT8 BlockType;
+} EFI_HII_GLYPH_BLOCK;
+
+//
+// Definition of different glyph info block types
+//
+
+typedef struct _EFI_HII_GIBT_DEFAULTS_BLOCK {
+ EFI_HII_GLYPH_BLOCK Header;
+ EFI_HII_GLYPH_INFO Cell;
+} EFI_HII_GIBT_DEFAULTS_BLOCK;
+
+typedef struct _EFI_HII_GIBT_DUPLICATE_BLOCK {
+ EFI_HII_GLYPH_BLOCK Header;
+ CHAR16 CharValue;
+} EFI_HII_GIBT_DUPLICATE_BLOCK;
+
+typedef struct _EFI_GLYPH_GIBT_END_BLOCK {
+ EFI_HII_GLYPH_BLOCK Header;
+} EFI_GLYPH_GIBT_END_BLOCK;
+
+typedef struct _EFI_HII_GIBT_EXT1_BLOCK {
+ EFI_HII_GLYPH_BLOCK Header;
+ UINT8 BlockType2;
+ UINT8 Length;
+} EFI_HII_GIBT_EXT1_BLOCK;
+
+typedef struct _EFI_HII_GIBT_EXT2_BLOCK {
+ EFI_HII_GLYPH_BLOCK Header;
+ UINT8 BlockType2;
+ UINT16 Length;
+} EFI_HII_GIBT_EXT2_BLOCK;
+
+typedef struct _EFI_HII_GIBT_EXT4_BLOCK {
+ EFI_HII_GLYPH_BLOCK Header;
+ UINT8 BlockType2;
+ UINT32 Length;
+} EFI_HII_GIBT_EXT4_BLOCK;
+
+typedef struct _EFI_HII_GIBT_GLYPH_BLOCK {
+ EFI_HII_GLYPH_BLOCK Header;
+ EFI_HII_GLYPH_INFO Cell;
+ UINT8 BitmapData[1];
+} EFI_HII_GIBT_GLYPH_BLOCK;
+
+typedef struct _EFI_HII_GIBT_GLYPHS_BLOCK {
+ EFI_HII_GLYPH_BLOCK Header;
+ EFI_HII_GLYPH_INFO Cell;
+ UINT16 Count;
+ UINT8 BitmapData[1];
+} EFI_HII_GIBT_GLYPHS_BLOCK;
+
+typedef struct _EFI_HII_GIBT_GLYPH_DEFAULT_BLOCK {
+ EFI_HII_GLYPH_BLOCK Header;
+ UINT8 BitmapData[1];
+} EFI_HII_GIBT_GLYPH_DEFAULT_BLOCK;
+
+typedef struct _EFI_HII_GIBT_GLYPHS_DEFAULT_BLOCK {
+ EFI_HII_GLYPH_BLOCK Header;
+ UINT16 Count;
+ UINT8 BitmapData[1];
+} EFI_HII_GIBT_GLYPHS_DEFAULT_BLOCK;
+
+typedef struct _EFI_HII_GIBT_SKIP1_BLOCK {
+ EFI_HII_GLYPH_BLOCK Header;
+ UINT8 SkipCount;
+} EFI_HII_GIBT_SKIP1_BLOCK;
+
+typedef struct _EFI_HII_GIBT_SKIP2_BLOCK {
+ EFI_HII_GLYPH_BLOCK Header;
+ UINT16 SkipCount;
+} EFI_HII_GIBT_SKIP2_BLOCK;
+
+//
+// Definitions for Device Path Package
+// Section 27.3.4
+//
+
+///
+/// The device path package is used to carry a device path
+/// associated with the package list.
+///
+typedef struct _EFI_HII_DEVICE_PATH_PACKAGE {
+ EFI_HII_PACKAGE_HEADER Header;
+ // EFI_DEVICE_PATH_PROTOCOL DevicePath[];
+} EFI_HII_DEVICE_PATH_PACKAGE;
+
+//
+// Definitions for GUID Package
+// Section 27.3.5
+//
+
+///
+/// The GUID package is used to carry data where the format is defined by a GUID.
+///
+typedef struct _EFI_HII_GUID_PACKAGE_HDR {
+ EFI_HII_PACKAGE_HEADER Header;
+ EFI_GUID Guid;
+ // Data per GUID definition may follow
+} EFI_HII_GUID_PACKAGE_HDR;
+
+//
+// Definitions for String Package
+// Section 27.3.6
+//
+
+#define UEFI_CONFIG_LANG L"x-UEFI"
+#define UEFI_CONFIG_LANG2 L"x-i-UEFI"
+
+///
+/// The fixed header consists of a standard record header and then the string identifiers
+/// contained in this section and the offsets of the string and language information.
+///
+typedef struct _EFI_HII_STRING_PACKAGE_HDR {
+ EFI_HII_PACKAGE_HEADER Header;
+ UINT32 HdrSize;
+ UINT32 StringInfoOffset;
+ CHAR16 LanguageWindow[16];
+ EFI_STRING_ID LanguageName;
+ CHAR8 Language[1];
+} EFI_HII_STRING_PACKAGE_HDR;
+
+typedef struct {
+ UINT8 BlockType;
+} EFI_HII_STRING_BLOCK;
+
+//
+// Value of different string information block types
+//
+#define EFI_HII_SIBT_END 0x00
+#define EFI_HII_SIBT_STRING_SCSU 0x10
+#define EFI_HII_SIBT_STRING_SCSU_FONT 0x11
+#define EFI_HII_SIBT_STRINGS_SCSU 0x12
+#define EFI_HII_SIBT_STRINGS_SCSU_FONT 0x13
+#define EFI_HII_SIBT_STRING_UCS2 0x14
+#define EFI_HII_SIBT_STRING_UCS2_FONT 0x15
+#define EFI_HII_SIBT_STRINGS_UCS2 0x16
+#define EFI_HII_SIBT_STRINGS_UCS2_FONT 0x17
+#define EFI_HII_SIBT_DUPLICATE 0x20
+#define EFI_HII_SIBT_SKIP2 0x21
+#define EFI_HII_SIBT_SKIP1 0x22
+#define EFI_HII_SIBT_EXT1 0x30
+#define EFI_HII_SIBT_EXT2 0x31
+#define EFI_HII_SIBT_EXT4 0x32
+#define EFI_HII_SIBT_FONT 0x40
+
+//
+// Definition of different string information block types
+//
+
+typedef struct _EFI_HII_SIBT_DUPLICATE_BLOCK {
+ EFI_HII_STRING_BLOCK Header;
+ EFI_STRING_ID StringId;
+} EFI_HII_SIBT_DUPLICATE_BLOCK;
+
+typedef struct _EFI_HII_SIBT_END_BLOCK {
+ EFI_HII_STRING_BLOCK Header;
+} EFI_HII_SIBT_END_BLOCK;
+
+typedef struct _EFI_HII_SIBT_EXT1_BLOCK {
+ EFI_HII_STRING_BLOCK Header;
+ UINT8 BlockType2;
+ UINT8 Length;
+} EFI_HII_SIBT_EXT1_BLOCK;
+
+typedef struct _EFI_HII_SIBT_EXT2_BLOCK {
+ EFI_HII_STRING_BLOCK Header;
+ UINT8 BlockType2;
+ UINT16 Length;
+} EFI_HII_SIBT_EXT2_BLOCK;
+
+typedef struct _EFI_HII_SIBT_EXT4_BLOCK {
+ EFI_HII_STRING_BLOCK Header;
+ UINT8 BlockType2;
+ UINT32 Length;
+} EFI_HII_SIBT_EXT4_BLOCK;
+
+typedef struct _EFI_HII_SIBT_FONT_BLOCK {
+ EFI_HII_SIBT_EXT2_BLOCK Header;
+ UINT8 FontId;
+ UINT16 FontSize;
+ EFI_HII_FONT_STYLE FontStyle;
+ CHAR16 FontName[1];
+} EFI_HII_SIBT_FONT_BLOCK;
+
+typedef struct _EFI_HII_SIBT_SKIP1_BLOCK {
+ EFI_HII_STRING_BLOCK Header;
+ UINT8 SkipCount;
+} EFI_HII_SIBT_SKIP1_BLOCK;
+
+typedef struct _EFI_HII_SIBT_SKIP2_BLOCK {
+ EFI_HII_STRING_BLOCK Header;
+ UINT16 SkipCount;
+} EFI_HII_SIBT_SKIP2_BLOCK;
+
+typedef struct _EFI_HII_SIBT_STRING_SCSU_BLOCK {
+ EFI_HII_STRING_BLOCK Header;
+ UINT8 StringText[1];
+} EFI_HII_SIBT_STRING_SCSU_BLOCK;
+
+typedef struct _EFI_HII_SIBT_STRING_SCSU_FONT_BLOCK {
+ EFI_HII_STRING_BLOCK Header;
+ UINT8 FontIdentifier;
+ UINT8 StringText[1];
+} EFI_HII_SIBT_STRING_SCSU_FONT_BLOCK;
+
+typedef struct _EFI_HII_SIBT_STRINGS_SCSU_BLOCK {
+ EFI_HII_STRING_BLOCK Header;
+ UINT16 StringCount;
+ UINT8 StringText[1];
+} EFI_HII_SIBT_STRINGS_SCSU_BLOCK;
+
+typedef struct _EFI_HII_SIBT_STRINGS_SCSU_FONT_BLOCK {
+ EFI_HII_STRING_BLOCK Header;
+ UINT8 FontIdentifier;
+ UINT16 StringCount;
+ UINT8 StringText[1];
+} EFI_HII_SIBT_STRINGS_SCSU_FONT_BLOCK;
+
+typedef struct _EFI_HII_SIBT_STRING_UCS2_BLOCK {
+ EFI_HII_STRING_BLOCK Header;
+ CHAR16 StringText[1];
+} EFI_HII_SIBT_STRING_UCS2_BLOCK;
+
+typedef struct _EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK {
+ EFI_HII_STRING_BLOCK Header;
+ UINT8 FontIdentifier;
+ CHAR16 StringText[1];
+} EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK;
+
+typedef struct _EFI_HII_SIBT_STRINGS_UCS2_BLOCK {
+ EFI_HII_STRING_BLOCK Header;
+ UINT16 StringCount;
+ CHAR16 StringText[1];
+} EFI_HII_SIBT_STRINGS_UCS2_BLOCK;
+
+typedef struct _EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK {
+ EFI_HII_STRING_BLOCK Header;
+ UINT8 FontIdentifier;
+ UINT16 StringCount;
+ CHAR16 StringText[1];
+} EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK;
+
+//
+// Definitions for Image Package
+// Section 27.3.7
+//
+
+typedef struct _EFI_HII_IMAGE_PACKAGE_HDR {
+ EFI_HII_PACKAGE_HEADER Header;
+ UINT32 ImageInfoOffset;
+ UINT32 PaletteInfoOffset;
+} EFI_HII_IMAGE_PACKAGE_HDR;
+
+typedef struct _EFI_HII_IMAGE_BLOCK {
+ UINT8 BlockType;
+} EFI_HII_IMAGE_BLOCK;
+
+//
+// Value of different image information block types
+//
+#define EFI_HII_IIBT_END 0x00
+#define EFI_HII_IIBT_IMAGE_1BIT 0x10
+#define EFI_HII_IIBT_IMAGE_1BIT_TRANS 0x11
+#define EFI_HII_IIBT_IMAGE_4BIT 0x12
+#define EFI_HII_IIBT_IMAGE_4BIT_TRANS 0x13
+#define EFI_HII_IIBT_IMAGE_8BIT 0x14
+#define EFI_HII_IIBT_IMAGE_8BIT_TRANS 0x15
+#define EFI_HII_IIBT_IMAGE_24BIT 0x16
+#define EFI_HII_IIBT_IMAGE_24BIT_TRANS 0x17
+#define EFI_HII_IIBT_IMAGE_JPEG 0x18
+#define EFI_HII_IIBT_DUPLICATE 0x20
+#define EFI_HII_IIBT_SKIP2 0x21
+#define EFI_HII_IIBT_SKIP1 0x22
+#define EFI_HII_IIBT_EXT1 0x30
+#define EFI_HII_IIBT_EXT2 0x31
+#define EFI_HII_IIBT_EXT4 0x32
+
+//
+// Definition of different image information block types
+//
+
+typedef struct _EFI_HII_IIBT_END_BLOCK {
+ EFI_HII_IMAGE_BLOCK Header;
+} EFI_HII_IIBT_END_BLOCK;
+
+typedef struct _EFI_HII_IIBT_EXT1_BLOCK {
+ EFI_HII_IMAGE_BLOCK Header;
+ UINT8 BlockType2;
+ UINT8 Length;
+} EFI_HII_IIBT_EXT1_BLOCK;
+
+typedef struct _EFI_HII_IIBT_EXT2_BLOCK {
+ EFI_HII_IMAGE_BLOCK Header;
+ UINT8 BlockType2;
+ UINT16 Length;
+} EFI_HII_IIBT_EXT2_BLOCK;
+
+typedef struct _EFI_HII_IIBT_EXT4_BLOCK {
+ EFI_HII_IMAGE_BLOCK Header;
+ UINT8 BlockType2;
+ UINT32 Length;
+} EFI_HII_IIBT_EXT4_BLOCK;
+
+typedef struct _EFI_HII_IIBT_IMAGE_1BIT_BASE {
+ UINT16 Width;
+ UINT16 Height;
+ UINT8 Data[1];
+} EFI_HII_IIBT_IMAGE_1BIT_BASE;
+
+typedef struct _EFI_HII_IIBT_IMAGE_1BIT_BLOCK {
+ EFI_HII_IMAGE_BLOCK Header;
+ UINT8 PaletteIndex;
+ EFI_HII_IIBT_IMAGE_1BIT_BASE Bitmap;
+} EFI_HII_IIBT_IMAGE_1BIT_BLOCK;
+
+typedef struct _EFI_HII_IIBT_IMAGE_1BIT_TRANS_BLOCK {
+ EFI_HII_IMAGE_BLOCK Header;
+ UINT8 PaletteIndex;
+ EFI_HII_IIBT_IMAGE_1BIT_BASE Bitmap;
+} EFI_HII_IIBT_IMAGE_1BIT_TRANS_BLOCK;
+
+typedef struct _EFI_HII_RGB_PIXEL {
+ UINT8 b;
+ UINT8 g;
+ UINT8 r;
+} EFI_HII_RGB_PIXEL;
+
+typedef struct _EFI_HII_IIBT_IMAGE_24BIT_BASE {
+ UINT16 Width;
+ UINT16 Height;
+ EFI_HII_RGB_PIXEL Bitmap[1];
+} EFI_HII_IIBT_IMAGE_24BIT_BASE;
+
+typedef struct _EFI_HII_IIBT_IMAGE_24BIT_BLOCK {
+ EFI_HII_IMAGE_BLOCK Header;
+ EFI_HII_IIBT_IMAGE_24BIT_BASE Bitmap;
+} EFI_HII_IIBT_IMAGE_24BIT_BLOCK;
+
+typedef struct _EFI_HII_IIBT_IMAGE_24BIT_TRANS_BLOCK {
+ EFI_HII_IMAGE_BLOCK Header;
+ EFI_HII_IIBT_IMAGE_24BIT_BASE Bitmap;
+} EFI_HII_IIBT_IMAGE_24BIT_TRANS_BLOCK;
+
+typedef struct _EFI_HII_IIBT_IMAGE_4BIT_BASE {
+ UINT16 Width;
+ UINT16 Height;
+ UINT8 Data[1];
+} EFI_HII_IIBT_IMAGE_4BIT_BASE;
+
+typedef struct _EFI_HII_IIBT_IMAGE_4BIT_BLOCK {
+ EFI_HII_IMAGE_BLOCK Header;
+ UINT8 PaletteIndex;
+ EFI_HII_IIBT_IMAGE_4BIT_BASE Bitmap;
+} EFI_HII_IIBT_IMAGE_4BIT_BLOCK;
+
+typedef struct _EFI_HII_IIBT_IMAGE_4BIT_TRANS_BLOCK {
+ EFI_HII_IMAGE_BLOCK Header;
+ UINT8 PaletteIndex;
+ EFI_HII_IIBT_IMAGE_4BIT_BASE Bitmap;
+} EFI_HII_IIBT_IMAGE_4BIT_TRANS_BLOCK;
+
+typedef struct _EFI_HII_IIBT_IMAGE_8BIT_BASE {
+ UINT16 Width;
+ UINT16 Height;
+ UINT8 Data[1];
+} EFI_HII_IIBT_IMAGE_8BIT_BASE;
+
+typedef struct _EFI_HII_IIBT_IMAGE_8BIT_PALETTE_BLOCK {
+ EFI_HII_IMAGE_BLOCK Header;
+ UINT8 PaletteIndex;
+ EFI_HII_IIBT_IMAGE_8BIT_BASE Bitmap;
+} EFI_HII_IIBT_IMAGE_8BIT_BLOCK;
+
+typedef struct _EFI_HII_IIBT_IMAGE_8BIT_TRANS_BLOCK {
+ EFI_HII_IMAGE_BLOCK Header;
+ UINT8 PaletteIndex;
+ EFI_HII_IIBT_IMAGE_8BIT_BASE Bitmap;
+} EFI_HII_IIBT_IMAGE_8BIT_TRAN_BLOCK;
+
+typedef struct _EFI_HII_IIBT_DUPLICATE_BLOCK {
+ EFI_HII_IMAGE_BLOCK Header;
+ EFI_IMAGE_ID ImageId;
+} EFI_HII_IIBT_DUPLICATE_BLOCK;
+
+typedef struct _EFI_HII_IIBT_JPEG_BLOCK {
+ EFI_HII_IMAGE_BLOCK Header;
+ UINT32 Size;
+ UINT8 Data[1];
+} EFI_HII_IIBT_JPEG_BLOCK;
+
+typedef struct _EFI_HII_IIBT_SKIP1_BLOCK {
+ EFI_HII_IMAGE_BLOCK Header;
+ UINT8 SkipCount;
+} EFI_HII_IIBT_SKIP1_BLOCK;
+
+typedef struct _EFI_HII_IIBT_SKIP2_BLOCK {
+ EFI_HII_IMAGE_BLOCK Header;
+ UINT16 SkipCount;
+} EFI_HII_IIBT_SKIP2_BLOCK;
+
+//
+// Definitions for Palette Information
+//
+
+typedef struct _EFI_HII_IMAGE_PALETTE_INFO_HEADER {
+ UINT16 PaletteCount;
+} EFI_HII_IMAGE_PALETTE_INFO_HEADER;
+
+typedef struct _EFI_HII_IMAGE_PALETTE_INFO {
+ UINT16 PaletteSize;
+ EFI_HII_RGB_PIXEL PaletteValue[1];
+} EFI_HII_IMAGE_PALETTE_INFO;
+
+//
+// Definitions for Forms Package
+// Section 27.3.8
+//
+
+///
+/// The Forms package is used to carry forms-based encoding data.
+///
+typedef struct _EFI_HII_FORM_PACKAGE {
+ EFI_HII_PACKAGE_HEADER Header;
+ // EFI_IFR_OP_HEADER OpCodeHeader;
+ // More op-codes follow
+} EFI_HII_FORM_PACKAGE;
+
+typedef struct {
+ UINT8 Hour;
+ UINT8 Minute;
+ UINT8 Second;
+} EFI_HII_TIME;
+
+typedef struct {
+ UINT16 Year;
+ UINT8 Month;
+ UINT8 Day;
+} EFI_HII_DATE;
+
+typedef union {
+ UINT8 u8;
+ UINT16 u16;
+ UINT32 u32;
+ UINT64 u64;
+ BOOLEAN b;
+ EFI_HII_TIME time;
+ EFI_HII_DATE date;
+ EFI_STRING_ID string;
+} EFI_IFR_TYPE_VALUE;
+
+//
+// IFR Opcodes
+//
+#define EFI_IFR_FORM_OP 0x01
+#define EFI_IFR_SUBTITLE_OP 0x02
+#define EFI_IFR_TEXT_OP 0x03
+#define EFI_IFR_IMAGE_OP 0x04
+#define EFI_IFR_ONE_OF_OP 0x05
+#define EFI_IFR_CHECKBOX_OP 0x06
+#define EFI_IFR_NUMERIC_OP 0x07
+#define EFI_IFR_PASSWORD_OP 0x08
+#define EFI_IFR_ONE_OF_OPTION_OP 0x09
+#define EFI_IFR_SUPPRESS_IF_OP 0x0A
+#define EFI_IFR_LOCKED_OP 0x0B
+#define EFI_IFR_ACTION_OP 0x0C
+#define EFI_IFR_RESET_BUTTON_OP 0x0D
+#define EFI_IFR_FORM_SET_OP 0x0E
+#define EFI_IFR_REF_OP 0x0F
+#define EFI_IFR_NO_SUBMIT_IF_OP 0x10
+#define EFI_IFR_INCONSISTENT_IF_OP 0x11
+#define EFI_IFR_EQ_ID_VAL_OP 0x12
+#define EFI_IFR_EQ_ID_ID_OP 0x13
+#define EFI_IFR_EQ_ID_LIST_OP 0x14
+#define EFI_IFR_AND_OP 0x15
+#define EFI_IFR_OR_OP 0x16
+#define EFI_IFR_NOT_OP 0x17
+#define EFI_IFR_RULE_OP 0x18
+#define EFI_IFR_GRAY_OUT_IF_OP 0x19
+#define EFI_IFR_DATE_OP 0x1A
+#define EFI_IFR_TIME_OP 0x1B
+#define EFI_IFR_STRING_OP 0x1C
+#define EFI_IFR_REFRESH_OP 0x1D
+#define EFI_IFR_DISABLE_IF_OP 0x1E
+#define EFI_IFR_TO_LOWER_OP 0x20
+#define EFI_IFR_TO_UPPER_OP 0x21
+#define EFI_IFR_ORDERED_LIST_OP 0x23
+#define EFI_IFR_VARSTORE_OP 0x24
+#define EFI_IFR_VARSTORE_NAME_VALUE_OP 0x25
+#define EFI_IFR_VARSTORE_EFI_OP 0x26
+#define EFI_IFR_VARSTORE_DEVICE_OP 0x27
+#define EFI_IFR_VERSION_OP 0x28
+#define EFI_IFR_END_OP 0x29
+#define EFI_IFR_MATCH_OP 0x2A
+#define EFI_IFR_EQUAL_OP 0x2F
+#define EFI_IFR_NOT_EQUAL_OP 0x30
+#define EFI_IFR_GREATER_THAN_OP 0x31
+#define EFI_IFR_GREATER_EQUAL_OP 0x32
+#define EFI_IFR_LESS_THAN_OP 0x33
+#define EFI_IFR_LESS_EQUAL_OP 0x34
+#define EFI_IFR_BITWISE_AND_OP 0x35
+#define EFI_IFR_BITWISE_OR_OP 0x36
+#define EFI_IFR_BITWISE_NOT_OP 0x37
+#define EFI_IFR_SHIFT_LEFT_OP 0x38
+#define EFI_IFR_SHIFT_RIGHT_OP 0x39
+#define EFI_IFR_ADD_OP 0x3A
+#define EFI_IFR_SUBTRACT_OP 0x3B
+#define EFI_IFR_MULTIPLY_OP 0x3C
+#define EFI_IFR_DIVIDE_OP 0x3D
+#define EFI_IFR_MODULO_OP 0x3E
+#define EFI_IFR_RULE_REF_OP 0x3F
+#define EFI_IFR_QUESTION_REF1_OP 0x40
+#define EFI_IFR_QUESTION_REF2_OP 0x41
+#define EFI_IFR_UINT8_OP 0x42
+#define EFI_IFR_UINT16_OP 0x43
+#define EFI_IFR_UINT32_OP 0x44
+#define EFI_IFR_UINT64_OP 0x45
+#define EFI_IFR_TRUE_OP 0x46
+#define EFI_IFR_FALSE_OP 0x47
+#define EFI_IFR_TO_UINT_OP 0x48
+#define EFI_IFR_TO_STRING_OP 0x49
+#define EFI_IFR_TO_BOOLEAN_OP 0x4A
+#define EFI_IFR_MID_OP 0x4B
+#define EFI_IFR_FIND_OP 0x4C
+#define EFI_IFR_TOKEN_OP 0x4D
+#define EFI_IFR_STRING_REF1_OP 0x4E
+#define EFI_IFR_STRING_REF2_OP 0x4F
+#define EFI_IFR_CONDITIONAL_OP 0x50
+#define EFI_IFR_QUESTION_REF3_OP 0x51
+#define EFI_IFR_ZERO_OP 0x52
+#define EFI_IFR_ONE_OP 0x53
+#define EFI_IFR_ONES_OP 0x54
+#define EFI_IFR_UNDEFINED_OP 0x55
+#define EFI_IFR_LENGTH_OP 0x56
+#define EFI_IFR_DUP_OP 0x57
+#define EFI_IFR_THIS_OP 0x58
+#define EFI_IFR_SPAN_OP 0x59
+#define EFI_IFR_VALUE_OP 0x5A
+#define EFI_IFR_DEFAULT_OP 0x5B
+#define EFI_IFR_DEFAULTSTORE_OP 0x5C
+#define EFI_IFR_CATENATE_OP 0x5E
+#define EFI_IFR_GUID_OP 0x5F
+
+//
+// Definitions of IFR Standard Headers
+// Section 27.3.8.2
+//
+
+typedef struct _EFI_IFR_OP_HEADER {
+ UINT8 OpCode;
+ UINT8 Length:7;
+ UINT8 Scope:1;
+} EFI_IFR_OP_HEADER;
+
+typedef struct _EFI_IFR_STATEMENT_HEADER {
+ EFI_STRING_ID Prompt;
+ EFI_STRING_ID Help;
+} EFI_IFR_STATEMENT_HEADER;
+
+typedef struct _EFI_IFR_QUESTION_HEADER {
+ EFI_IFR_STATEMENT_HEADER Header;
+ EFI_QUESTION_ID QuestionId;
+ EFI_VARSTORE_ID VarStoreId;
+ union {
+ EFI_STRING_ID VarName;
+ UINT16 VarOffset;
+ } VarStoreInfo;
+ UINT8 Flags;
+} EFI_IFR_QUESTION_HEADER;
+
+//
+// Flag values of EFI_IFR_QUESTION_HEADER
+//
+#define EFI_IFR_FLAG_READ_ONLY 0x01
+#define EFI_IFR_FLAG_CALLBACK 0x04
+#define EFI_IFR_FLAG_RESET_REQUIRED 0x10
+#define EFI_IFR_FLAG_OPTIONS_ONLY 0x80
+
+//
+// Definition for Opcode Reference
+// Section 27.3.8.3
+//
+typedef struct _EFI_IFR_DEFAULTSTORE {
+ EFI_IFR_OP_HEADER Header;
+ EFI_STRING_ID DefaultName;
+ UINT16 DefaultId;
+} EFI_IFR_DEFAULTSTORE;
+
+//
+// Default Identifier of default store
+//
+#define EFI_HII_DEFAULT_CLASS_STANDARD 0x0000
+#define EFI_HII_DEFAULT_CLASS_MANUFACTURING 0x0001
+#define EFI_HII_DEFAULT_CLASS_SAFE 0x0002
+#define EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN 0x4000
+#define EFI_HII_DEFAULT_CLASS_PLATFORM_END 0x7fff
+#define EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN 0x8000
+#define EFI_HII_DEFAULT_CLASS_HARDWARE_END 0xbfff
+#define EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN 0xc000
+#define EFI_HII_DEFAULT_CLASS_FIRMWARE_END 0xffff
+
+typedef struct _EFI_IFR_VARSTORE {
+ EFI_IFR_OP_HEADER Header;
+ EFI_GUID Guid;
+ EFI_VARSTORE_ID VarStoreId;
+ UINT16 Size;
+ UINT8 Name[1];
+} EFI_IFR_VARSTORE;
+
+typedef struct _EFI_IFR_VARSTORE_EFI {
+ EFI_IFR_OP_HEADER Header;
+ EFI_VARSTORE_ID VarStoreId;
+ EFI_GUID Guid;
+ UINT32 Attributes;
+} EFI_IFR_VARSTORE_EFI;
+
+typedef struct _EFI_IFR_VARSTORE_NAME_VALUE {
+ EFI_IFR_OP_HEADER Header;
+ EFI_VARSTORE_ID VarStoreId;
+ EFI_GUID Guid;
+} EFI_IFR_VARSTORE_NAME_VALUE;
+
+typedef struct _EFI_IFR_FORM_SET {
+ EFI_IFR_OP_HEADER Header;
+ EFI_GUID Guid;
+ EFI_STRING_ID FormSetTitle;
+ EFI_STRING_ID Help;
+} EFI_IFR_FORM_SET;
+
+typedef struct _EFI_IFR_END {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_END;
+
+typedef struct _EFI_IFR_FORM {
+ EFI_IFR_OP_HEADER Header;
+ UINT16 FormId;
+ EFI_STRING_ID FormTitle;
+} EFI_IFR_FORM;
+
+typedef struct _EFI_IFR_IMAGE {
+ EFI_IFR_OP_HEADER Header;
+ EFI_IMAGE_ID Id;
+} EFI_IFR_IMAGE;
+
+typedef struct _EFI_IFR_LOCKED {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_LOCKED;
+
+typedef struct _EFI_IFR_RULE {
+ EFI_IFR_OP_HEADER Header;
+ UINT8 RuleId;
+} EFI_IFR_RULE;
+
+typedef struct _EFI_IFR_DEFAULT {
+ EFI_IFR_OP_HEADER Header;
+ UINT16 DefaultId;
+ UINT8 Type;
+ EFI_IFR_TYPE_VALUE Value;
+} EFI_IFR_DEFAULT;
+
+typedef struct _EFI_IFR_VALUE {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_VALUE;
+
+typedef struct _EFI_IFR_SUBTITLE {
+ EFI_IFR_OP_HEADER Header;
+ EFI_IFR_STATEMENT_HEADER Statement;
+ UINT8 Flags;
+} EFI_IFR_SUBTITLE;
+
+#define EFI_IFR_FLAGS_HORIZONTAL 0x01
+
+typedef struct _EFI_IFR_CHECKBOX {
+ EFI_IFR_OP_HEADER Header;
+ EFI_IFR_QUESTION_HEADER Question;
+ UINT8 Flags;
+} EFI_IFR_CHECKBOX;
+
+#define EFI_IFR_CHECKBOX_DEFAULT 0x01
+#define EFI_IFR_CHECKBOX_DEFAULT_MFG 0x02
+
+typedef struct _EFI_IFR_TEXT {
+ EFI_IFR_OP_HEADER Header;
+ EFI_IFR_STATEMENT_HEADER Statement;
+ EFI_STRING_ID TextTwo;
+} EFI_IFR_TEXT;
+
+typedef struct _EFI_IFR_REF {
+ EFI_IFR_OP_HEADER Header;
+ EFI_IFR_QUESTION_HEADER Question;
+ EFI_FORM_ID FormId;
+} EFI_IFR_REF;
+
+typedef struct _EFI_IFR_REF2 {
+ EFI_IFR_OP_HEADER Header;
+ EFI_IFR_QUESTION_HEADER Question;
+ EFI_FORM_ID FormId;
+ EFI_QUESTION_ID QuestionId;
+} EFI_IFR_REF2;
+
+typedef struct _EFI_IFR_REF3 {
+ EFI_IFR_OP_HEADER Header;
+ EFI_IFR_QUESTION_HEADER Question;
+ EFI_FORM_ID FormId;
+ EFI_QUESTION_ID QuestionId;
+ EFI_GUID FormSetId;
+} EFI_IFR_REF3;
+
+typedef struct _EFI_IFR_REF4 {
+ EFI_IFR_OP_HEADER Header;
+ EFI_IFR_QUESTION_HEADER Question;
+ EFI_FORM_ID FormId;
+ EFI_QUESTION_ID QuestionId;
+ EFI_GUID FormSetId;
+ EFI_STRING_ID DevicePath;
+} EFI_IFR_REF4;
+
+typedef struct _EFI_IFR_RESET_BUTTON {
+ EFI_IFR_OP_HEADER Header;
+ EFI_IFR_QUESTION_HEADER Question;
+ EFI_DEFAULT_ID DefaultId;
+} EFI_IFR_RESET_BUTTON;
+
+typedef struct _EFI_IFR_ACTION {
+ EFI_IFR_OP_HEADER Header;
+ EFI_IFR_QUESTION_HEADER Question;
+ EFI_STRING_ID QuestionConfig;
+} EFI_IFR_ACTION;
+
+typedef struct _EFI_IFR_ACTION_1 {
+ EFI_IFR_OP_HEADER Header;
+ EFI_IFR_QUESTION_HEADER Question;
+} EFI_IFR_ACTION_1;
+
+typedef struct _EFI_IFR_DATE {
+ EFI_IFR_OP_HEADER Header;
+ EFI_IFR_QUESTION_HEADER Question;
+ UINT8 Flags;
+} EFI_IFR_DATE;
+
+//
+// Flags that describe the behavior of the question.
+//
+#define EFI_QF_DATE_YEAR_SUPPRESS 0x01
+#define EFI_QF_DATE_MONTH_SUPPRESS 0x02
+#define EFI_QF_DATE_DAY_SUPPRESS 0x04
+
+#define EFI_QF_DATE_STORAGE 0x30
+#define QF_DATE_STORAGE_NORMAL 0x00
+#define QF_DATE_STORAGE_TIME 0x10
+#define QF_DATE_STORAGE_WAKEUP 0x20
+
+typedef union {
+ struct {
+ UINT8 MinValue;
+ UINT8 MaxValue;
+ UINT8 Step;
+ } u8;
+ struct {
+ UINT16 MinValue;
+ UINT16 MaxValue;
+ UINT16 Step;
+ } u16;
+ struct {
+ UINT32 MinValue;
+ UINT32 MaxValue;
+ UINT32 Step;
+ } u32;
+ struct {
+ UINT64 MinValue;
+ UINT64 MaxValue;
+ UINT64 Step;
+ } u64;
+} MINMAXSTEP_DATA;
+
+typedef struct _EFI_IFR_NUMERIC {
+ EFI_IFR_OP_HEADER Header;
+ EFI_IFR_QUESTION_HEADER Question;
+ UINT8 Flags;
+ MINMAXSTEP_DATA data;
+} EFI_IFR_NUMERIC;
+
+//
+// Flags related to the numeric question
+//
+#define EFI_IFR_NUMERIC_SIZE 0x03
+#define EFI_IFR_NUMERIC_SIZE_1 0x00
+#define EFI_IFR_NUMERIC_SIZE_2 0x01
+#define EFI_IFR_NUMERIC_SIZE_4 0x02
+#define EFI_IFR_NUMERIC_SIZE_8 0x03
+
+#define EFI_IFR_DISPLAY 0x30
+#define EFI_IFR_DISPLAY_INT_DEC 0x00
+#define EFI_IFR_DISPLAY_UINT_DEC 0x10
+#define EFI_IFR_DISPLAY_UINT_HEX 0x20
+
+typedef struct _EFI_IFR_ONE_OF {
+ EFI_IFR_OP_HEADER Header;
+ EFI_IFR_QUESTION_HEADER Question;
+ UINT8 Flags;
+ MINMAXSTEP_DATA data;
+} EFI_IFR_ONE_OF;
+
+typedef struct _EFI_IFR_STRING {
+ EFI_IFR_OP_HEADER Header;
+ EFI_IFR_QUESTION_HEADER Question;
+ UINT8 MinSize;
+ UINT8 MaxSize;
+ UINT8 Flags;
+} EFI_IFR_STRING;
+
+#define EFI_IFR_STRING_MULTI_LINE 0x01
+
+typedef struct _EFI_IFR_PASSWORD {
+ EFI_IFR_OP_HEADER Header;
+ EFI_IFR_QUESTION_HEADER Question;
+ UINT16 MinSize;
+ UINT16 MaxSize;
+} EFI_IFR_PASSWORD;
+
+typedef struct _EFI_IFR_ORDERED_LIST {
+ EFI_IFR_OP_HEADER Header;
+ EFI_IFR_QUESTION_HEADER Question;
+ UINT8 MaxContainers;
+ UINT8 Flags;
+} EFI_IFR_ORDERED_LIST;
+
+#define EFI_IFR_UNIQUE_SET 0x01
+#define EFI_IFR_NO_EMPTY_SET 0x02
+
+typedef struct _EFI_IFR_TIME {
+ EFI_IFR_OP_HEADER Header;
+ EFI_IFR_QUESTION_HEADER Question;
+ UINT8 Flags;
+} EFI_IFR_TIME;
+
+//
+// A bit-mask that determines which unique settings are active for this opcode.
+//
+#define QF_TIME_HOUR_SUPPRESS 0x01
+#define QF_TIME_MINUTE_SUPPRESS 0x02
+#define QF_TIME_SECOND_SUPPRESS 0x04
+
+#define QF_TIME_STORAGE 0x30
+#define QF_TIME_STORAGE_NORMAL 0x00
+#define QF_TIME_STORAGE_TIME 0x10
+#define QF_TIME_STORAGE_WAKEUP 0x20
+
+typedef struct _EFI_IFR_DISABLE_IF {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_DISABLE_IF;
+
+typedef struct _EFI_IFR_SUPPRESS_IF {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_SUPPRESS_IF;
+
+typedef struct _EFI_IFR_GRAY_OUT_IF {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_GRAY_OUT_IF;
+
+typedef struct _EFI_IFR_INCONSISTENT_IF {
+ EFI_IFR_OP_HEADER Header;
+ EFI_STRING_ID Error;
+} EFI_IFR_INCONSISTENT_IF;
+
+typedef struct _EFI_IFR_NO_SUBMIT_IF {
+ EFI_IFR_OP_HEADER Header;
+ EFI_STRING_ID Error;
+} EFI_IFR_NO_SUBMIT_IF;
+
+typedef struct _EFI_IFR_REFRESH {
+ EFI_IFR_OP_HEADER Header;
+ UINT8 RefreshInterval;
+} EFI_IFR_REFRESH;
+
+typedef struct _EFI_IFR_VARSTORE_DEVICE {
+ EFI_IFR_OP_HEADER Header;
+ EFI_STRING_ID DevicePath;
+} EFI_IFR_VARSTORE_DEVICE;
+
+typedef struct _EFI_IFR_ONE_OF_OPTION {
+ EFI_IFR_OP_HEADER Header;
+ EFI_STRING_ID Option;
+ UINT8 Flags;
+ UINT8 Type;
+ EFI_IFR_TYPE_VALUE Value;
+} EFI_IFR_ONE_OF_OPTION;
+
+//
+// Types of the option's value.
+//
+#define EFI_IFR_TYPE_NUM_SIZE_8 0x00
+#define EFI_IFR_TYPE_NUM_SIZE_16 0x01
+#define EFI_IFR_TYPE_NUM_SIZE_32 0x02
+#define EFI_IFR_TYPE_NUM_SIZE_64 0x03
+#define EFI_IFR_TYPE_BOOLEAN 0x04
+#define EFI_IFR_TYPE_TIME 0x05
+#define EFI_IFR_TYPE_DATE 0x06
+#define EFI_IFR_TYPE_STRING 0x07
+#define EFI_IFR_TYPE_OTHER 0x08
+
+#define EFI_IFR_OPTION_DEFAULT 0x10
+#define EFI_IFR_OPTION_DEFAULT_MFG 0x20
+
+typedef struct _EFI_IFR_GUID {
+ EFI_IFR_OP_HEADER Header;
+ EFI_GUID Guid;
+ //Optional Data Follows
+} EFI_IFR_GUID;
+
+typedef struct _EFI_IFR_DUP {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_DUP;
+
+typedef struct _EFI_IFR_EQ_ID_ID {
+ EFI_IFR_OP_HEADER Header;
+ EFI_QUESTION_ID QuestionId1;
+ EFI_QUESTION_ID QuestionId2;
+} EFI_IFR_EQ_ID_ID;
+
+typedef struct _EFI_IFR_EQ_ID_VAL {
+ EFI_IFR_OP_HEADER Header;
+ EFI_QUESTION_ID QuestionId;
+ UINT16 Value;
+} EFI_IFR_EQ_ID_VAL;
+
+typedef struct _EFI_IFR_EQ_ID_LIST {
+ EFI_IFR_OP_HEADER Header;
+ EFI_QUESTION_ID QuestionId;
+ UINT16 ListLength;
+ UINT16 ValueList[1];
+} EFI_IFR_EQ_ID_LIST;
+
+typedef struct _EFI_IFR_UINT8 {
+ EFI_IFR_OP_HEADER Header;
+ UINT8 Value;
+} EFI_IFR_UINT8;
+
+typedef struct _EFI_IFR_UINT16 {
+ EFI_IFR_OP_HEADER Header;
+ UINT16 Value;
+} EFI_IFR_UINT16;
+
+typedef struct _EFI_IFR_UINT32 {
+ EFI_IFR_OP_HEADER Header;
+ UINT32 Value;
+} EFI_IFR_UINT32;
+
+typedef struct _EFI_IFR_UINT64 {
+ EFI_IFR_OP_HEADER Header;
+ UINT64 Value;
+} EFI_IFR_UINT64;
+
+typedef struct _EFI_IFR_QUESTION_REF1 {
+ EFI_IFR_OP_HEADER Header;
+ EFI_QUESTION_ID QuestionId;
+} EFI_IFR_QUESTION_REF1;
+
+typedef struct _EFI_IFR_QUESTION_REF2 {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_QUESTION_REF2;
+
+typedef struct _EFI_IFR_QUESTION_REF3 {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_QUESTION_REF3;
+
+typedef struct _EFI_IFR_QUESTION_REF3_2 {
+ EFI_IFR_OP_HEADER Header;
+ EFI_STRING_ID DevicePath;
+} EFI_IFR_QUESTION_REF3_2;
+
+typedef struct _EFI_IFR_QUESTION_REF3_3 {
+ EFI_IFR_OP_HEADER Header;
+ EFI_STRING_ID DevicePath;
+ EFI_GUID Guid;
+} EFI_IFR_QUESTION_REF3_3;
+
+typedef struct _EFI_IFR_RULE_REF {
+ EFI_IFR_OP_HEADER Header;
+ UINT8 RuleId;
+} EFI_IFR_RULE_REF;
+
+typedef struct _EFI_IFR_STRING_REF1 {
+ EFI_IFR_OP_HEADER Header;
+ EFI_STRING_ID StringId;
+} EFI_IFR_STRING_REF1;
+
+typedef struct _EFI_IFR_STRING_REF2 {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_STRING_REF2;
+
+typedef struct _EFI_IFR_THIS {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_THIS;
+
+typedef struct _EFI_IFR_TRUE {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_TRUE;
+
+typedef struct _EFI_IFR_FALSE {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_FALSE;
+
+typedef struct _EFI_IFR_ONE {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_ONE;
+
+typedef struct _EFI_IFR_ONES {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_ONES;
+
+typedef struct _EFI_IFR_ZERO {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_ZERO;
+
+typedef struct _EFI_IFR_UNDEFINED {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_UNDEFINED;
+
+typedef struct _EFI_IFR_VERSION {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_VERSION;
+
+typedef struct _EFI_IFR_LENGTH {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_LENGTH;
+
+typedef struct _EFI_IFR_NOT {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_NOT;
+
+typedef struct _EFI_IFR_BITWISE_NOT {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_BITWISE_NOT;
+
+typedef struct _EFI_IFR_TO_BOOLEAN {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_TO_BOOLEAN;
+
+//
+// For EFI_IFR_TO_STRING, when converting from
+// unsigned integers, these flags control the format:
+// 0 = unsigned decimal
+// 1 = signed decimal
+// 2 = hexadecimal (lower-case alpha)
+// 3 = hexadecimal (upper-case alpha)
+//
+#define EFI_IFR_STRING_UNSIGNED_DEC 0
+#define EFI_IFR_STRING_SIGNED_DEC 1
+#define EFI_IFR_STRING_LOWERCASE_HEX 2
+#define EFI_IFR_STRING_UPPERCASE_HEX 3
+//
+// When converting from a buffer, these flags control the format:
+// 0 = ASCII
+// 8 = Unicode
+//
+#define EFI_IFR_STRING_ASCII 0
+#define EFI_IFR_STRING_UNICODE 8
+
+typedef struct _EFI_IFR_TO_STRING {
+ EFI_IFR_OP_HEADER Header;
+ UINT8 Format;
+} EFI_IFR_TO_STRING;
+
+typedef struct _EFI_IFR_TO_UINT {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_TO_UINT;
+
+typedef struct _EFI_IFR_TO_UPPER {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_TO_UPPER;
+
+typedef struct _EFI_IFR_TO_LOWER {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_TO_LOWER;
+
+typedef struct _EFI_IFR_ADD {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_ADD;
+
+typedef struct _EFI_IFR_AND {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_AND;
+
+typedef struct _EFI_IFR_BITWISE_AND {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_BITWISE_AND;
+
+typedef struct _EFI_IFR_BITWISE_OR {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_BITWISE_OR;
+
+typedef struct _EFI_IFR_CATENATE {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_CATENATE;
+
+typedef struct _EFI_IFR_DIVIDE {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_DIVIDE;
+
+typedef struct _EFI_IFR_EQUAL {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_EQUAL;
+
+typedef struct _EFI_IFR_GREATER_EQUAL {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_GREATER_EQUAL;
+
+typedef struct _EFI_IFR_GREATER_THAN {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_GREATER_THAN;
+
+typedef struct _EFI_IFR_LESS_EQUAL {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_LESS_EQUAL;
+
+typedef struct _EFI_IFR_LESS_THAN {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_LESS_THAN;
+
+typedef struct _EFI_IFR_MATCH {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_MATCH;
+
+typedef struct _EFI_IFR_MULTIPLY {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_MULTIPLY;
+
+typedef struct _EFI_IFR_MODULO {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_MODULO;
+
+typedef struct _EFI_IFR_NOT_EQUAL {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_NOT_EQUAL;
+
+typedef struct _EFI_IFR_OR {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_OR;
+
+typedef struct _EFI_IFR_SHIFT_LEFT {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_SHIFT_LEFT;
+
+typedef struct _EFI_IFR_SHIFT_RIGHT {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_SHIFT_RIGHT;
+
+typedef struct _EFI_IFR_SUBTRACT {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_SUBTRACT;
+
+typedef struct _EFI_IFR_CONDITIONAL {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_CONDITIONAL;
+
+//
+// Flags governing the matching criteria of EFI_IFR_FIND
+//
+#define EFI_IFR_FF_CASE_SENSITIVE 0x00
+#define EFI_IFR_FF_CASE_INSENSITIVE 0x01
+
+typedef struct _EFI_IFR_FIND {
+ EFI_IFR_OP_HEADER Header;
+ UINT8 Format;
+} EFI_IFR_FIND;
+
+typedef struct _EFI_IFR_MID {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_MID;
+
+typedef struct _EFI_IFR_TOKEN {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_TOKEN;
+
+//
+// Flags specifying whether to find the first matching string
+// or the first non-matching string.
+//
+#define EFI_IFR_FLAGS_FIRST_MATCHING 0x00
+#define EFI_IFR_FLAGS_FIRST_NON_MATCHING 0x01
+
+typedef struct _EFI_IFR_SPAN {
+ EFI_IFR_OP_HEADER Header;
+ UINT8 Flags;
+} EFI_IFR_SPAN;
+
+//
+// Definitions for Keyboard Package
+// Section 27.3.9
+// Releated definitions are in Section of EFI_HII_DATABASE_PROTOCOL
+//
+
+typedef enum {
+ EfiKeyLCtrl,
+ EfiKeyA0,
+ EfiKeyLAlt,
+ EfiKeySpaceBar,
+ EfiKeyA2,
+ EfiKeyA3,
+ EfiKeyA4,
+ EfiKeyRCtrl,
+ EfiKeyLeftArrow,
+ EfiKeyDownArrow,
+ EfiKeyRightArrow,
+ EfiKeyZero,
+ EfiKeyPeriod,
+ EfiKeyEnter,
+ EfiKeyLShift,
+ EfiKeyB0,
+ EfiKeyB1,
+ EfiKeyB2,
+ EfiKeyB3,
+ EfiKeyB4,
+ EfiKeyB5,
+ EfiKeyB6,
+ EfiKeyB7,
+ EfiKeyB8,
+ EfiKeyB9,
+ EfiKeyB10,
+ EfiKeyRShift,
+ EfiKeyUpArrow,
+ EfiKeyOne,
+ EfiKeyTwo,
+ EfiKeyThree,
+ EfiKeyCapsLock,
+ EfiKeyC1,
+ EfiKeyC2,
+ EfiKeyC3,
+ EfiKeyC4,
+ EfiKeyC5,
+ EfiKeyC6,
+ EfiKeyC7,
+ EfiKeyC8,
+ EfiKeyC9,
+ EfiKeyC10,
+ EfiKeyC11,
+ EfiKeyC12,
+ EfiKeyFour,
+ EfiKeyFive,
+ EfiKeySix,
+ EfiKeyPlus,
+ EfiKeyTab,
+ EfiKeyD1,
+ EfiKeyD2,
+ EfiKeyD3,
+ EfiKeyD4,
+ EfiKeyD5,
+ EfiKeyD6,
+ EfiKeyD7,
+ EfiKeyD8,
+ EfiKeyD9,
+ EfiKeyD10,
+ EfiKeyD11,
+ EfiKeyD12,
+ EfiKeyD13,
+ EfiKeyDel,
+ EfiKeyEnd,
+ EfiKeyPgDn,
+ EfiKeySeven,
+ EfiKeyEight,
+ EfiKeyNine,
+ EfiKeyE0,
+ EfiKeyE1,
+ EfiKeyE2,
+ EfiKeyE3,
+ EfiKeyE4,
+ EfiKeyE5,
+ EfiKeyE6,
+ EfiKeyE7,
+ EfiKeyE8,
+ EfiKeyE9,
+ EfiKeyE10,
+ EfiKeyE11,
+ EfiKeyE12,
+ EfiKeyBackSpace,
+ EfiKeyIns,
+ EfiKeyHome,
+ EfiKeyPgUp,
+ EfiKeyNLck,
+ EfiKeySlash,
+ EfiKeyAsterisk,
+ EfiKeyMinus,
+ EfiKeyEsc,
+ EfiKeyF1,
+ EfiKeyF2,
+ EfiKeyF3,
+ EfiKeyF4,
+ EfiKeyF5,
+ EfiKeyF6,
+ EfiKeyF7,
+ EfiKeyF8,
+ EfiKeyF9,
+ EfiKeyF10,
+ EfiKeyF11,
+ EfiKeyF12,
+ EfiKeyPrint,
+ EfiKeySLck,
+ EfiKeyPause
+} EFI_KEY;
+
+typedef struct {
+ EFI_KEY Key;
+ CHAR16 Unicode;
+ CHAR16 ShiftedUnicode;
+ CHAR16 AltGrUnicode;
+ CHAR16 ShiftedAltGrUnicode;
+ UINT16 Modifier;
+ UINT16 AffectedAttribute;
+} EFI_KEY_DESCRIPTOR;
+
+///
+/// A key which is affected by all the standard shift modifiers.
+/// Most keys would be expected to have this bit active.
+///
+#define EFI_AFFECTED_BY_STANDARD_SHIFT 0x0001
+
+///
+/// This key is affected by the caps lock so that if a keyboard driver
+/// would need to disambiguate between a key which had a "1" defined
+/// versus a "a" character. Having this bit turned on would tell
+/// the keyboard driver to use the appropriate shifted state or not.
+///
+#define EFI_AFFECTED_BY_CAPS_LOCK 0x0002
+
+///
+/// Similar to the case of CAPS lock, if this bit is active, the key
+/// is affected by the num lock being turned on.
+///
+#define EFI_AFFECTED_BY_NUM_LOCK 0x0004
+
+typedef struct {
+ UINT16 LayoutLength;
+ EFI_GUID Guid;
+ UINT32 LayoutDescriptorStringOffset;
+ UINT8 DescriptorCount;
+ // EFI_KEY_DESCRIPTOR Descriptors[];
+} EFI_HII_KEYBOARD_LAYOUT;
+
+typedef struct {
+ EFI_HII_PACKAGE_HEADER Header;
+ UINT16 LayoutCount;
+ // EFI_HII_KEYBOARD_LAYOUT Layout[];
+} EFI_HII_KEYBOARD_PACKAGE_HDR;
+
+//
+// Modifier values
+//
+#define EFI_NULL_MODIFIER 0x0000
+#define EFI_LEFT_CONTROL_MODIFIER 0x0001
+#define EFI_RIGHT_CONTROL_MODIFIER 0x0002
+#define EFI_LEFT_ALT_MODIFIER 0x0003
+#define EFI_RIGHT_ALT_MODIFIER 0x0004
+#define EFI_ALT_GR_MODIFIER 0x0005
+#define EFI_INSERT_MODIFIER 0x0006
+#define EFI_DELETE_MODIFIER 0x0007
+#define EFI_PAGE_DOWN_MODIFIER 0x0008
+#define EFI_PAGE_UP_MODIFIER 0x0009
+#define EFI_HOME_MODIFIER 0x000A
+#define EFI_END_MODIFIER 0x000B
+#define EFI_LEFT_SHIFT_MODIFIER 0x000C
+#define EFI_RIGHT_SHIFT_MODIFIER 0x000D
+#define EFI_CAPS_LOCK_MODIFIER 0x000E
+#define EFI_NUM_LOCK_MODIFIER 0x000F
+#define EFI_LEFT_ARROW_MODIFIER 0x0010
+#define EFI_RIGHT_ARROW_MODIFIER 0x0011
+#define EFI_DOWN_ARROW_MODIFIER 0x0012
+#define EFI_UP_ARROW_MODIFIER 0x0013
+#define EFI_NS_KEY_MODIFIER 0x0014
+#define EFI_NS_KEY_DEPENDENCY_MODIFIER 0x0015
+#define EFI_FUNCTION_KEY_ONE_MODIFIER 0x0016
+#define EFI_FUNCTION_KEY_TWO_MODIFIER 0x0017
+#define EFI_FUNCTION_KEY_THREE_MODIFIER 0x0018
+#define EFI_FUNCTION_KEY_FOUR_MODIFIER 0x0019
+#define EFI_FUNCTION_KEY_FIVE_MODIFIER 0x001A
+#define EFI_FUNCTION_KEY_SIX_MODIFIER 0x001B
+#define EFI_FUNCTION_KEY_SEVEN_MODIFIER 0x001C
+#define EFI_FUNCTION_KEY_EIGHT_MODIFIER 0x001D
+#define EFI_FUNCTION_KEY_NINE_MODIFIER 0x001E
+#define EFI_FUNCTION_KEY_TEN_MODIFIER 0x001F
+#define EFI_FUNCTION_KEY_ELEVEN_MODIFIER 0x0020
+#define EFI_FUNCTION_KEY_TWELVE_MODIFIER 0x0021
+
+//
+// Keys that have multiple control functions based on modifier
+// settings are handled in the keyboard driver implementation.
+// For instance PRINT_KEY might have a modifier held down and
+// is still a nonprinting character, but might have an alternate
+// control function like SYSREQUEST
+//
+#define EFI_PRINT_MODIFIER 0x0022
+#define EFI_SYS_REQUEST_MODIFIER 0x0023
+#define EFI_SCROLL_LOCK_MODIFIER 0x0024
+#define EFI_PAUSE_MODIFIER 0x0025
+#define EFI_BREAK_MODIFIER 0x0026
+
+#define EFI_LEFT_LOGO_MODIFIER 0x0027
+#define EFI_RIGHT_LOGO_MODIFIER 0x0028
+#define EFI_MENU_MODIFIER 0x0029
+
+#pragma pack()
+
+
+
+///
+/// References to string tokens must use this macro to enable scanning for
+/// token usages.
+///
+///
+/// STRING_TOKEN is not defined in UEFI specification. But it is placed
+/// here for the easy access by C files and VFR source files.
+///
+#define STRING_TOKEN(t) t
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Uefi/UefiMultiPhase.h b/gpxe/src/include/gpxe/efi/Uefi/UefiMultiPhase.h
new file mode 100644
index 00000000..2d1af5ed
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Uefi/UefiMultiPhase.h
@@ -0,0 +1,210 @@
+/** @file
+ This includes some definitions introduced in UEFI that will be used in both PEI and DXE phases.
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __UEFI_MULTIPHASE_H__
+#define __UEFI_MULTIPHASE_H__
+
+#include <gpxe/efi/ProcessorBind.h>
+
+///
+/// Enumeration of memory types introduced in UEFI.
+///
+typedef enum {
+ EfiReservedMemoryType,
+ EfiLoaderCode,
+ EfiLoaderData,
+ EfiBootServicesCode,
+ EfiBootServicesData,
+ EfiRuntimeServicesCode,
+ EfiRuntimeServicesData,
+ EfiConventionalMemory,
+ EfiUnusableMemory,
+ EfiACPIReclaimMemory,
+ EfiACPIMemoryNVS,
+ EfiMemoryMappedIO,
+ EfiMemoryMappedIOPortSpace,
+ EfiPalCode,
+ EfiMaxMemoryType
+} EFI_MEMORY_TYPE;
+
+
+///
+/// Data structure that precedes all of the standard EFI table types.
+///
+typedef struct {
+ UINT64 Signature;
+ UINT32 Revision;
+ UINT32 HeaderSize;
+ UINT32 CRC32;
+ UINT32 Reserved;
+} EFI_TABLE_HEADER;
+
+///
+/// Attributes of variable.
+///
+#define EFI_VARIABLE_NON_VOLATILE 0x00000001
+#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002
+#define EFI_VARIABLE_RUNTIME_ACCESS 0x00000004
+#define EFI_VARIABLE_HARDWARE_ERROR_RECORD 0x00000008
+
+///
+/// This attribute is identified by the mnemonic 'HR'
+/// elsewhere in this specification.
+///
+#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x00000010
+
+//
+// _WIN_CERTIFICATE.wCertificateType
+//
+#define WIN_CERT_TYPE_EFI_PKCS115 0x0EF0
+#define WIN_CERT_TYPE_EFI_GUID 0x0EF1
+
+///
+/// The WIN_CERTIFICATE structure is part of the PE/COFF specification.
+///
+typedef struct _WIN_CERTIFICATE {
+ ///
+ /// The length of the entire certificate,
+ /// including the length of the header, in bytes.
+ ///
+ UINT32 dwLength;
+ ///
+ /// The revision level of the WIN_CERTIFICATE
+ /// structure. The current revision level is 0x0200.
+ ///
+ UINT16 wRevision;
+ ///
+ /// The certificate type. See WIN_CERT_TYPE_xxx for the UEFI
+ /// certificate types. The UEFI specification reserves the range of
+ /// certificate type values from 0x0EF0 to 0x0EFF.
+ ///
+ UINT16 wCertificateType;
+ ///
+ /// The following is the actual certificate. The format of
+ /// the certificate depends on wCertificateType.
+ ///
+ /// UINT8 bCertificate[ANYSIZE_ARRAY];
+ ///
+} WIN_CERTIFICATE;
+
+///
+/// WIN_CERTIFICATE_UEFI_GUID.CertType
+///
+#define EFI_CERT_TYPE_RSA2048_SHA256_GUID \
+ {0xa7717414, 0xc616, 0x4977, {0x94, 0x20, 0x84, 0x47, 0x12, 0xa7, 0x35, 0xbf } }
+
+//
+// WIN_CERTIFICATE_UEFI_GUID.CertData
+//
+typedef struct _EFI_CERT_BLOCK_RSA_2048_SHA256 {
+ UINT32 HashType;
+ UINT8 PublicKey[256];
+ UINT8 Signature[256];
+} EFI_CERT_BLOCK_RSA_2048_SHA256;
+
+
+///
+/// Certificate which encapsulates a GUID-specific digital signature
+///
+typedef struct _WIN_CERTIFICATE_UEFI_GUID {
+ ///
+ /// This is the standard WIN_CERTIFICATE header, where
+ /// wCertificateType is set to WIN_CERT_TYPE_UEFI_GUID.
+ ///
+ WIN_CERTIFICATE Hdr;
+ ///
+ /// This is the unique id which determines the
+ /// format of the CertData. In this case, the
+ /// value is EFI_CERT_TYPE_RSA2048_SHA256_GUID.
+ ///
+ EFI_GUID CertType;
+ ///
+ /// The following is the certificate data. The format of
+ /// the data is determined by the CertType. In this case the value is
+ /// EFI_CERT_BLOCK_RSA_2048_SHA256.
+ ///
+ /// UINT8 CertData[ANYSIZE_ARRAY];
+ ///
+} WIN_CERTIFICATE_UEFI_GUID;
+
+
+///
+/// Certificate which encapsulates the RSASSA_PKCS1-v1_5 digital signature.
+///
+/// The WIN_CERTIFICATE_UEFI_PKCS1_15 structure is derived from
+/// WIN_CERTIFICATE and encapsulate the information needed to
+/// implement the RSASSA-PKCS1-v1_5 digital signature algorithm as
+/// specified in RFC2437.
+///
+typedef struct _WIN_CERTIFICATE_EFI_PKCS1_15 {
+ ///
+ /// This is the standard WIN_CERTIFICATE header, where
+ /// wCertificateType is set to WIN_CERT_TYPE_UEFI_PKCS1_15.
+ ///
+ WIN_CERTIFICATE Hdr;
+ ///
+ /// This is the hashing algorithm which was performed on the
+ /// UEFI executable when creating the digital signature.
+ ///
+ EFI_GUID HashAlgorithm;
+ ///
+ /// The following is the actual digital signature. The
+ /// size of the signature is the same size as the key
+ /// (1024-bit key is 128 bytes) and can be determined by
+ /// subtracting the length of the other parts of this header
+ /// from the total length of the certificate as found in
+ /// Hdr.dwLength.
+ ///
+ /// UINT8 Signature[ANYSIZE_ARRAY];
+ ///
+} WIN_CERTIFICATE_EFI_PKCS1_15;
+
+
+
+///
+/// AuthInfo is a WIN_CERTIFICATE using the wCertificateType
+/// WIN_CERTIFICATE_UEFI_GUID and the CertType
+/// EFI_CERT_TYPE_RSA2048_SHA256. If the attribute specifies
+/// authenticated access, then the Data buffer should begin with an
+/// authentication descriptor prior to the data payload and DataSize
+/// should reflect the the data.and descriptor size. The caller
+/// shall digest the Monotonic Count value and the associated data
+/// for the variable update using the SHA-256 1-way hash algorithm.
+/// The ensuing the 32-byte digest will be signed using the private
+/// key associated w/ the public/private 2048-bit RSA key-pair. The
+/// WIN_CERTIFICATE shall be used to describe the signature of the
+/// Variable data *Data. In addition, the signature will also
+/// include the MonotonicCount value to guard against replay attacks
+///
+typedef struct {
+ ///
+ /// Included in the signature of
+ /// AuthInfo.Used to ensure freshness/no
+ /// replay. Incremented during each
+ /// "Write" access.
+ ///
+ UINT64 MonotonicCount;
+ ///
+ /// Provides the authorization for the variable
+ /// access. It is a signature across the
+ /// variable data and the Monotonic Count
+ /// value. Caller uses Private key that is
+ /// associated with a public key that has been
+ /// provisioned via the key exchange.
+ ///
+ WIN_CERTIFICATE_UEFI_GUID AuthInfo;
+} EFI_VARIABLE_AUTHENTICATION;
+
+#endif
+
diff --git a/gpxe/src/include/gpxe/efi/Uefi/UefiPxe.h b/gpxe/src/include/gpxe/efi/Uefi/UefiPxe.h
new file mode 100644
index 00000000..bb8ab410
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Uefi/UefiPxe.h
@@ -0,0 +1,1756 @@
+/** @file
+ This header file contains all of the PXE type definitions,
+ structure prototypes, global variables and constants that
+ are needed for porting PXE to EFI.
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+ @par Revision Reference:
+ 32/64-bit PXE specification:
+ alpha-4, 99-Dec-17
+
+**/
+
+#ifndef __EFI_PXE_H__
+#define __EFI_PXE_H__
+
+#pragma pack(1)
+
+#define PXE_BUSTYPE(a, b, c, d) \
+ ( \
+ (((PXE_UINT32) (d) & 0xFF) << 24) | (((PXE_UINT32) (c) & 0xFF) << 16) | (((PXE_UINT32) (b) & 0xFF) << 8) | \
+ ((PXE_UINT32) (a) & 0xFF) \
+ )
+
+///
+/// UNDI ROM ID and devive ID signature
+///
+#define PXE_BUSTYPE_PXE PXE_BUSTYPE ('!', 'P', 'X', 'E')
+
+///
+/// BUS ROM ID signatures
+///
+#define PXE_BUSTYPE_PCI PXE_BUSTYPE ('P', 'C', 'I', 'R')
+#define PXE_BUSTYPE_PC_CARD PXE_BUSTYPE ('P', 'C', 'C', 'R')
+#define PXE_BUSTYPE_USB PXE_BUSTYPE ('U', 'S', 'B', 'R')
+#define PXE_BUSTYPE_1394 PXE_BUSTYPE ('1', '3', '9', '4')
+
+#define PXE_SWAP_UINT16(n) ((((PXE_UINT16) (n) & 0x00FF) << 8) | (((PXE_UINT16) (n) & 0xFF00) >> 8))
+
+#define PXE_SWAP_UINT32(n) \
+ ((((PXE_UINT32)(n) & 0x000000FF) << 24) | \
+ (((PXE_UINT32)(n) & 0x0000FF00) << 8) | \
+ (((PXE_UINT32)(n) & 0x00FF0000) >> 8) | \
+ (((PXE_UINT32)(n) & 0xFF000000) >> 24))
+
+#define PXE_SWAP_UINT64(n) \
+ ((((PXE_UINT64)(n) & 0x00000000000000FFULL) << 56) | \
+ (((PXE_UINT64)(n) & 0x000000000000FF00ULL) << 40) | \
+ (((PXE_UINT64)(n) & 0x0000000000FF0000ULL) << 24) | \
+ (((PXE_UINT64)(n) & 0x00000000FF000000ULL) << 8) | \
+ (((PXE_UINT64)(n) & 0x000000FF00000000ULL) >> 8) | \
+ (((PXE_UINT64)(n) & 0x0000FF0000000000ULL) >> 24) | \
+ (((PXE_UINT64)(n) & 0x00FF000000000000ULL) >> 40) | \
+ (((PXE_UINT64)(n) & 0xFF00000000000000ULL) >> 56))
+
+
+#define PXE_CPBSIZE_NOT_USED 0 ///< zero
+#define PXE_DBSIZE_NOT_USED 0 ///< zero
+#define PXE_CPBADDR_NOT_USED (PXE_UINT64) 0 ///< zero
+#define PXE_DBADDR_NOT_USED (PXE_UINT64) 0 ///< zero
+#define PXE_CONST CONST
+
+#define PXE_VOLATILE volatile
+
+typedef VOID PXE_VOID;
+typedef UINT8 PXE_UINT8;
+typedef UINT16 PXE_UINT16;
+typedef UINT32 PXE_UINT32;
+typedef UINTN PXE_UINTN;
+
+///
+/// typedef unsigned long PXE_UINT64;
+///
+typedef UINT64 PXE_UINT64;
+
+typedef PXE_UINT8 PXE_BOOL;
+#define PXE_FALSE 0 ///< zero
+#define PXE_TRUE (!PXE_FALSE)
+
+typedef PXE_UINT16 PXE_OPCODE;
+
+///
+/// Return UNDI operational state.
+///
+#define PXE_OPCODE_GET_STATE 0x0000
+
+///
+/// Change UNDI operational state from Stopped to Started.
+///
+#define PXE_OPCODE_START 0x0001
+
+///
+/// Change UNDI operational state from Started to Stopped.
+///
+#define PXE_OPCODE_STOP 0x0002
+
+///
+/// Get UNDI initialization information.
+///
+#define PXE_OPCODE_GET_INIT_INFO 0x0003
+
+///
+/// Get NIC configuration information.
+///
+#define PXE_OPCODE_GET_CONFIG_INFO 0x0004
+
+///
+/// Changed UNDI operational state from Started to Initialized.
+///
+#define PXE_OPCODE_INITIALIZE 0x0005
+
+///
+/// Re-initialize the NIC H/W.
+///
+#define PXE_OPCODE_RESET 0x0006
+
+///
+/// Change the UNDI operational state from Initialized to Started.
+///
+#define PXE_OPCODE_SHUTDOWN 0x0007
+
+///
+/// Read & change state of external interrupt enables.
+///
+#define PXE_OPCODE_INTERRUPT_ENABLES 0x0008
+
+///
+/// Read & change state of packet receive filters.
+///
+#define PXE_OPCODE_RECEIVE_FILTERS 0x0009
+
+///
+/// Read & change station MAC address.
+///
+#define PXE_OPCODE_STATION_ADDRESS 0x000A
+
+///
+/// Read traffic statistics.
+///
+#define PXE_OPCODE_STATISTICS 0x000B
+
+///
+/// Convert multicast IP address to multicast MAC address.
+///
+#define PXE_OPCODE_MCAST_IP_TO_MAC 0x000C
+
+///
+/// Read or change non-volatile storage on the NIC.
+///
+#define PXE_OPCODE_NVDATA 0x000D
+
+///
+/// Get & clear interrupt status.
+///
+#define PXE_OPCODE_GET_STATUS 0x000E
+
+///
+/// Fill media header in packet for transmit.
+///
+#define PXE_OPCODE_FILL_HEADER 0x000F
+
+///
+/// Transmit packet(s).
+///
+#define PXE_OPCODE_TRANSMIT 0x0010
+
+///
+/// Receive packet.
+///
+#define PXE_OPCODE_RECEIVE 0x0011
+
+///
+/// Last valid PXE UNDI OpCode number.
+///
+#define PXE_OPCODE_LAST_VALID 0x0011
+
+typedef PXE_UINT16 PXE_OPFLAGS;
+
+#define PXE_OPFLAGS_NOT_USED 0x0000
+
+//
+// //////////////////////////////////////
+// UNDI Get State
+//
+// No OpFlags
+
+////////////////////////////////////////
+// UNDI Start
+//
+// No OpFlags
+
+////////////////////////////////////////
+// UNDI Stop
+//
+// No OpFlags
+
+////////////////////////////////////////
+// UNDI Get Init Info
+//
+// No Opflags
+
+////////////////////////////////////////
+// UNDI Get Config Info
+//
+// No Opflags
+
+///
+/// UNDI Initialize
+///
+#define PXE_OPFLAGS_INITIALIZE_CABLE_DETECT_MASK 0x0001
+#define PXE_OPFLAGS_INITIALIZE_DETECT_CABLE 0x0000
+#define PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE 0x0001
+
+///
+///
+/// UNDI Reset
+///
+#define PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS 0x0001
+#define PXE_OPFLAGS_RESET_DISABLE_FILTERS 0x0002
+
+///
+/// UNDI Shutdown
+///
+/// No OpFlags
+
+///
+/// UNDI Interrupt Enables
+///
+///
+/// Select whether to enable or disable external interrupt signals.
+/// Setting both enable and disable will return PXE_STATCODE_INVALID_OPFLAGS.
+///
+#define PXE_OPFLAGS_INTERRUPT_OPMASK 0xC000
+#define PXE_OPFLAGS_INTERRUPT_ENABLE 0x8000
+#define PXE_OPFLAGS_INTERRUPT_DISABLE 0x4000
+#define PXE_OPFLAGS_INTERRUPT_READ 0x0000
+
+///
+/// Enable receive interrupts. An external interrupt will be generated
+/// after a complete non-error packet has been received.
+///
+#define PXE_OPFLAGS_INTERRUPT_RECEIVE 0x0001
+
+///
+/// Enable transmit interrupts. An external interrupt will be generated
+/// after a complete non-error packet has been transmitted.
+///
+#define PXE_OPFLAGS_INTERRUPT_TRANSMIT 0x0002
+
+///
+/// Enable command interrupts. An external interrupt will be generated
+/// when command execution stops.
+///
+#define PXE_OPFLAGS_INTERRUPT_COMMAND 0x0004
+
+///
+/// Generate software interrupt. Setting this bit generates an external
+/// interrupt, if it is supported by the hardware.
+///
+#define PXE_OPFLAGS_INTERRUPT_SOFTWARE 0x0008
+
+///
+/// UNDI Receive Filters
+///
+///
+/// Select whether to enable or disable receive filters.
+/// Setting both enable and disable will return PXE_STATCODE_INVALID_OPCODE.
+///
+#define PXE_OPFLAGS_RECEIVE_FILTER_OPMASK 0xC000
+#define PXE_OPFLAGS_RECEIVE_FILTER_ENABLE 0x8000
+#define PXE_OPFLAGS_RECEIVE_FILTER_DISABLE 0x4000
+#define PXE_OPFLAGS_RECEIVE_FILTER_READ 0x0000
+
+///
+/// To reset the contents of the multicast MAC address filter list,
+/// set this OpFlag:
+///
+#define PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST 0x2000
+
+///
+/// Enable unicast packet receiving. Packets sent to the current station
+/// MAC address will be received.
+///
+#define PXE_OPFLAGS_RECEIVE_FILTER_UNICAST 0x0001
+
+///
+/// Enable broadcast packet receiving. Packets sent to the broadcast
+/// MAC address will be received.
+///
+#define PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST 0x0002
+
+///
+/// Enable filtered multicast packet receiving. Packets sent to any
+/// of the multicast MAC addresses in the multicast MAC address filter
+/// list will be received. If the filter list is empty, no multicast
+///
+#define PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST 0x0004
+
+///
+/// Enable promiscuous packet receiving. All packets will be received.
+///
+#define PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS 0x0008
+
+///
+/// Enable promiscuous multicast packet receiving. All multicast
+/// packets will be received.
+///
+#define PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST 0x0010
+
+///
+/// UNDI Station Address
+///
+#define PXE_OPFLAGS_STATION_ADDRESS_READ 0x0000
+#define PXE_OPFLAGS_STATION_ADDRESS_WRITE 0x0000
+#define PXE_OPFLAGS_STATION_ADDRESS_RESET 0x0001
+
+///
+/// UNDI Statistics
+///
+#define PXE_OPFLAGS_STATISTICS_READ 0x0000
+#define PXE_OPFLAGS_STATISTICS_RESET 0x0001
+
+///
+/// UNDI MCast IP to MAC
+///
+///
+/// Identify the type of IP address in the CPB.
+///
+#define PXE_OPFLAGS_MCAST_IP_TO_MAC_OPMASK 0x0003
+#define PXE_OPFLAGS_MCAST_IPV4_TO_MAC 0x0000
+#define PXE_OPFLAGS_MCAST_IPV6_TO_MAC 0x0001
+
+///
+/// UNDI NvData
+///
+///
+/// Select the type of non-volatile data operation.
+///
+#define PXE_OPFLAGS_NVDATA_OPMASK 0x0001
+#define PXE_OPFLAGS_NVDATA_READ 0x0000
+#define PXE_OPFLAGS_NVDATA_WRITE 0x0001
+
+///
+/// UNDI Get Status
+///
+///
+/// Return current interrupt status. This will also clear any interrupts
+/// that are currently set. This can be used in a polling routine. The
+/// interrupt flags are still set and cleared even when the interrupts
+/// are disabled.
+///
+#define PXE_OPFLAGS_GET_INTERRUPT_STATUS 0x0001
+
+///
+/// Return list of transmitted buffers for recycling. Transmit buffers
+/// must not be changed or unallocated until they have recycled. After
+/// issuing a transmit command, wait for a transmit complete interrupt.
+/// When a transmit complete interrupt is received, read the transmitted
+/// buffers. Do not plan on getting one buffer per interrupt. Some
+/// NICs and UNDIs may transmit multiple buffers per interrupt.
+///
+#define PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS 0x0002
+
+///
+/// UNDI Fill Header
+///
+#define PXE_OPFLAGS_FILL_HEADER_OPMASK 0x0001
+#define PXE_OPFLAGS_FILL_HEADER_FRAGMENTED 0x0001
+#define PXE_OPFLAGS_FILL_HEADER_WHOLE 0x0000
+
+///
+/// UNDI Transmit
+///
+///
+/// S/W UNDI only. Return after the packet has been transmitted. A
+/// transmit complete interrupt will still be generated and the transmit
+/// buffer will have to be recycled.
+///
+#define PXE_OPFLAGS_SWUNDI_TRANSMIT_OPMASK 0x0001
+#define PXE_OPFLAGS_TRANSMIT_BLOCK 0x0001
+#define PXE_OPFLAGS_TRANSMIT_DONT_BLOCK 0x0000
+
+#define PXE_OPFLAGS_TRANSMIT_OPMASK 0x0002
+#define PXE_OPFLAGS_TRANSMIT_FRAGMENTED 0x0002
+#define PXE_OPFLAGS_TRANSMIT_WHOLE 0x0000
+
+///
+/// UNDI Receive
+///
+/// No OpFlags
+///
+
+///
+/// PXE STATFLAGS
+///
+typedef PXE_UINT16 PXE_STATFLAGS;
+
+#define PXE_STATFLAGS_INITIALIZE 0x0000
+
+///
+/// Common StatFlags that can be returned by all commands.
+///
+///
+/// The COMMAND_COMPLETE and COMMAND_FAILED status flags must be
+/// implemented by all UNDIs. COMMAND_QUEUED is only needed by UNDIs
+/// that support command queuing.
+///
+#define PXE_STATFLAGS_STATUS_MASK 0xC000
+#define PXE_STATFLAGS_COMMAND_COMPLETE 0xC000
+#define PXE_STATFLAGS_COMMAND_FAILED 0x8000
+#define PXE_STATFLAGS_COMMAND_QUEUED 0x4000
+
+///
+/// UNDI Get State
+///
+#define PXE_STATFLAGS_GET_STATE_MASK 0x0003
+#define PXE_STATFLAGS_GET_STATE_INITIALIZED 0x0002
+#define PXE_STATFLAGS_GET_STATE_STARTED 0x0001
+#define PXE_STATFLAGS_GET_STATE_STOPPED 0x0000
+
+///
+/// UNDI Start
+///
+/// No additional StatFlags
+///
+
+///
+/// UNDI Get Init Info
+///
+#define PXE_STATFLAGS_CABLE_DETECT_MASK 0x0001
+#define PXE_STATFLAGS_CABLE_DETECT_NOT_SUPPORTED 0x0000
+#define PXE_STATFLAGS_CABLE_DETECT_SUPPORTED 0x0001
+
+///
+/// UNDI Initialize
+///
+#define PXE_STATFLAGS_INITIALIZED_NO_MEDIA 0x0001
+
+///
+/// UNDI Reset
+///
+#define PXE_STATFLAGS_RESET_NO_MEDIA 0x0001
+
+///
+/// UNDI Shutdown
+///
+/// No additional StatFlags
+
+///
+/// UNDI Interrupt Enables
+///
+///
+/// If set, receive interrupts are enabled.
+///
+#define PXE_STATFLAGS_INTERRUPT_RECEIVE 0x0001
+
+///
+/// If set, transmit interrupts are enabled.
+///
+#define PXE_STATFLAGS_INTERRUPT_TRANSMIT 0x0002
+
+///
+/// If set, command interrupts are enabled.
+///
+#define PXE_STATFLAGS_INTERRUPT_COMMAND 0x0004
+
+///
+/// UNDI Receive Filters
+///
+
+///
+/// If set, unicast packets will be received.
+///
+#define PXE_STATFLAGS_RECEIVE_FILTER_UNICAST 0x0001
+
+///
+/// If set, broadcast packets will be received.
+///
+#define PXE_STATFLAGS_RECEIVE_FILTER_BROADCAST 0x0002
+
+///
+/// If set, multicast packets that match up with the multicast address
+/// filter list will be received.
+///
+#define PXE_STATFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST 0x0004
+
+///
+/// If set, all packets will be received.
+///
+#define PXE_STATFLAGS_RECEIVE_FILTER_PROMISCUOUS 0x0008
+
+///
+/// If set, all multicast packets will be received.
+///
+#define PXE_STATFLAGS_RECEIVE_FILTER_ALL_MULTICAST 0x0010
+
+///
+/// UNDI Station Address
+///
+/// No additional StatFlags
+///
+
+///
+/// UNDI Statistics
+///
+/// No additional StatFlags
+///
+
+///
+//// UNDI MCast IP to MAC
+////
+//// No additional StatFlags
+
+///
+/// UNDI NvData
+///
+/// No additional StatFlags
+///
+
+///
+/// UNDI Get Status
+///
+
+///
+/// Use to determine if an interrupt has occurred.
+///
+#define PXE_STATFLAGS_GET_STATUS_INTERRUPT_MASK 0x000F
+#define PXE_STATFLAGS_GET_STATUS_NO_INTERRUPTS 0x0000
+
+///
+/// If set, at least one receive interrupt occurred.
+///
+#define PXE_STATFLAGS_GET_STATUS_RECEIVE 0x0001
+
+///
+/// If set, at least one transmit interrupt occurred.
+///
+#define PXE_STATFLAGS_GET_STATUS_TRANSMIT 0x0002
+
+///
+/// If set, at least one command interrupt occurred.
+///
+#define PXE_STATFLAGS_GET_STATUS_COMMAND 0x0004
+
+///
+/// If set, at least one software interrupt occurred.
+///
+#define PXE_STATFLAGS_GET_STATUS_SOFTWARE 0x0008
+
+///
+/// This flag is set if the transmitted buffer queue is empty. This flag
+/// will be set if all transmitted buffer addresses get written into the DB.
+///
+#define PXE_STATFLAGS_GET_STATUS_TXBUF_QUEUE_EMPTY 0x0010
+
+///
+/// This flag is set if no transmitted buffer addresses were written
+/// into the DB. (This could be because DBsize was too small.)
+///
+#define PXE_STATFLAGS_GET_STATUS_NO_TXBUFS_WRITTEN 0x0020
+
+///
+/// UNDI Fill Header
+///
+/// No additional StatFlags
+///
+
+///
+/// UNDI Transmit
+///
+/// No additional StatFlags.
+
+///
+/// UNDI Receive
+///
+
+///
+/// No additional StatFlags.
+///
+typedef PXE_UINT16 PXE_STATCODE;
+
+#define PXE_STATCODE_INITIALIZE 0x0000
+
+///
+/// Common StatCodes returned by all UNDI commands, UNDI protocol functions
+/// and BC protocol functions.
+///
+#define PXE_STATCODE_SUCCESS 0x0000
+
+#define PXE_STATCODE_INVALID_CDB 0x0001
+#define PXE_STATCODE_INVALID_CPB 0x0002
+#define PXE_STATCODE_BUSY 0x0003
+#define PXE_STATCODE_QUEUE_FULL 0x0004
+#define PXE_STATCODE_ALREADY_STARTED 0x0005
+#define PXE_STATCODE_NOT_STARTED 0x0006
+#define PXE_STATCODE_NOT_SHUTDOWN 0x0007
+#define PXE_STATCODE_ALREADY_INITIALIZED 0x0008
+#define PXE_STATCODE_NOT_INITIALIZED 0x0009
+#define PXE_STATCODE_DEVICE_FAILURE 0x000A
+#define PXE_STATCODE_NVDATA_FAILURE 0x000B
+#define PXE_STATCODE_UNSUPPORTED 0x000C
+#define PXE_STATCODE_BUFFER_FULL 0x000D
+#define PXE_STATCODE_INVALID_PARAMETER 0x000E
+#define PXE_STATCODE_INVALID_UNDI 0x000F
+#define PXE_STATCODE_IPV4_NOT_SUPPORTED 0x0010
+#define PXE_STATCODE_IPV6_NOT_SUPPORTED 0x0011
+#define PXE_STATCODE_NOT_ENOUGH_MEMORY 0x0012
+#define PXE_STATCODE_NO_DATA 0x0013
+
+typedef PXE_UINT16 PXE_IFNUM;
+
+///
+/// This interface number must be passed to the S/W UNDI Start command.
+///
+#define PXE_IFNUM_START 0x0000
+
+///
+/// This interface number is returned by the S/W UNDI Get State and
+/// Start commands if information in the CDB, CPB or DB is invalid.
+///
+#define PXE_IFNUM_INVALID 0x0000
+
+typedef PXE_UINT16 PXE_CONTROL;
+
+///
+/// Setting this flag directs the UNDI to queue this command for later
+/// execution if the UNDI is busy and it supports command queuing.
+/// If queuing is not supported, a PXE_STATCODE_INVALID_CONTROL error
+/// is returned. If the queue is full, a PXE_STATCODE_CDB_QUEUE_FULL
+/// error is returned.
+///
+#define PXE_CONTROL_QUEUE_IF_BUSY 0x0002
+
+///
+/// These two bit values are used to determine if there are more UNDI
+/// CDB structures following this one. If the link bit is set, there
+/// must be a CDB structure following this one. Execution will start
+/// on the next CDB structure as soon as this one completes successfully.
+/// If an error is generated by this command, execution will stop.
+///
+#define PXE_CONTROL_LINK 0x0001
+#define PXE_CONTROL_LAST_CDB_IN_LIST 0x0000
+
+typedef PXE_UINT8 PXE_FRAME_TYPE;
+
+#define PXE_FRAME_TYPE_NONE 0x00
+#define PXE_FRAME_TYPE_UNICAST 0x01
+#define PXE_FRAME_TYPE_BROADCAST 0x02
+#define PXE_FRAME_TYPE_FILTERED_MULTICAST 0x03
+#define PXE_FRAME_TYPE_PROMISCUOUS 0x04
+#define PXE_FRAME_TYPE_PROMISCUOUS_MULTICAST 0x05
+
+#define PXE_FRAME_TYPE_MULTICAST PXE_FRAME_TYPE_FILTERED_MULTICAST
+
+typedef PXE_UINT32 PXE_IPV4;
+
+typedef PXE_UINT32 PXE_IPV6[4];
+#define PXE_MAC_LENGTH 32
+
+typedef PXE_UINT8 PXE_MAC_ADDR[PXE_MAC_LENGTH];
+
+typedef PXE_UINT8 PXE_IFTYPE;
+typedef UINT16 PXE_MEDIA_PROTOCOL;
+
+///
+/// This information is from the ARP section of RFC 1700.
+///
+/// 1 Ethernet (10Mb) [JBP]
+/// 2 Experimental Ethernet (3Mb) [JBP]
+/// 3 Amateur Radio AX.25 [PXK]
+/// 4 Proteon ProNET Token Ring [JBP]
+/// 5 Chaos [GXP]
+/// 6 IEEE 802 Networks [JBP]
+/// 7 ARCNET [JBP]
+/// 8 Hyperchannel [JBP]
+/// 9 Lanstar [TU]
+/// 10 Autonet Short Address [MXB1]
+/// 11 LocalTalk [JKR1]
+/// 12 LocalNet (IBM* PCNet or SYTEK* LocalNET) [JXM]
+/// 13 Ultra link [RXD2]
+/// 14 SMDS [GXC1]
+/// 15 Frame Relay [AGM]
+/// 16 Asynchronous Transmission Mode (ATM) [JXB2]
+/// 17 HDLC [JBP]
+/// 18 Fibre Channel [Yakov Rekhter]
+/// 19 Asynchronous Transmission Mode (ATM) [Mark Laubach]
+/// 20 Serial Line [JBP]
+/// 21 Asynchronous Transmission Mode (ATM) [MXB1]
+///
+/// * Other names and brands may be claimed as the property of others.
+///
+#define PXE_IFTYPE_ETHERNET 0x01
+#define PXE_IFTYPE_TOKENRING 0x04
+#define PXE_IFTYPE_FIBRE_CHANNEL 0x12
+
+typedef struct s_pxe_hw_undi {
+ PXE_UINT32 Signature; ///< PXE_ROMID_SIGNATURE
+ PXE_UINT8 Len; ///< sizeof(PXE_HW_UNDI)
+ PXE_UINT8 Fudge; ///< makes 8-bit cksum equal zero
+ PXE_UINT8 Rev; ///< PXE_ROMID_REV
+ PXE_UINT8 IFcnt; ///< physical connector count
+ PXE_UINT8 MajorVer; ///< PXE_ROMID_MAJORVER
+ PXE_UINT8 MinorVer; ///< PXE_ROMID_MINORVER
+ PXE_UINT16 reserved; ///< zero, not used
+ PXE_UINT32 Implementation; ///< implementation flags
+ ///< reserved ///< vendor use
+ ///< UINT32 Status; ///< status port
+ ///< UINT32 Command; ///< command port
+ ///< UINT64 CDBaddr; ///< CDB address port
+ ///<
+} PXE_HW_UNDI;
+
+///
+/// Status port bit definitions
+///
+
+///
+/// UNDI operation state
+///
+#define PXE_HWSTAT_STATE_MASK 0xC0000000
+#define PXE_HWSTAT_BUSY 0xC0000000
+#define PXE_HWSTAT_INITIALIZED 0x80000000
+#define PXE_HWSTAT_STARTED 0x40000000
+#define PXE_HWSTAT_STOPPED 0x00000000
+
+///
+/// If set, last command failed
+///
+#define PXE_HWSTAT_COMMAND_FAILED 0x20000000
+
+///
+/// If set, identifies enabled receive filters
+///
+#define PXE_HWSTAT_PROMISCUOUS_MULTICAST_RX_ENABLED 0x00001000
+#define PXE_HWSTAT_PROMISCUOUS_RX_ENABLED 0x00000800
+#define PXE_HWSTAT_BROADCAST_RX_ENABLED 0x00000400
+#define PXE_HWSTAT_MULTICAST_RX_ENABLED 0x00000200
+#define PXE_HWSTAT_UNICAST_RX_ENABLED 0x00000100
+
+///
+/// If set, identifies enabled external interrupts
+///
+#define PXE_HWSTAT_SOFTWARE_INT_ENABLED 0x00000080
+#define PXE_HWSTAT_TX_COMPLETE_INT_ENABLED 0x00000040
+#define PXE_HWSTAT_PACKET_RX_INT_ENABLED 0x00000020
+#define PXE_HWSTAT_CMD_COMPLETE_INT_ENABLED 0x00000010
+
+///
+/// If set, identifies pending interrupts
+///
+#define PXE_HWSTAT_SOFTWARE_INT_PENDING 0x00000008
+#define PXE_HWSTAT_TX_COMPLETE_INT_PENDING 0x00000004
+#define PXE_HWSTAT_PACKET_RX_INT_PENDING 0x00000002
+#define PXE_HWSTAT_CMD_COMPLETE_INT_PENDING 0x00000001
+
+///
+/// Command port definitions
+///
+
+///
+/// If set, CDB identified in CDBaddr port is given to UNDI.
+/// If not set, other bits in this word will be processed.
+///
+#define PXE_HWCMD_ISSUE_COMMAND 0x80000000
+#define PXE_HWCMD_INTS_AND_FILTS 0x00000000
+
+///
+/// Use these to enable/disable receive filters.
+///
+#define PXE_HWCMD_PROMISCUOUS_MULTICAST_RX_ENABLE 0x00001000
+#define PXE_HWCMD_PROMISCUOUS_RX_ENABLE 0x00000800
+#define PXE_HWCMD_BROADCAST_RX_ENABLE 0x00000400
+#define PXE_HWCMD_MULTICAST_RX_ENABLE 0x00000200
+#define PXE_HWCMD_UNICAST_RX_ENABLE 0x00000100
+
+///
+/// Use these to enable/disable external interrupts
+///
+#define PXE_HWCMD_SOFTWARE_INT_ENABLE 0x00000080
+#define PXE_HWCMD_TX_COMPLETE_INT_ENABLE 0x00000040
+#define PXE_HWCMD_PACKET_RX_INT_ENABLE 0x00000020
+#define PXE_HWCMD_CMD_COMPLETE_INT_ENABLE 0x00000010
+
+///
+/// Use these to clear pending external interrupts
+///
+#define PXE_HWCMD_CLEAR_SOFTWARE_INT 0x00000008
+#define PXE_HWCMD_CLEAR_TX_COMPLETE_INT 0x00000004
+#define PXE_HWCMD_CLEAR_PACKET_RX_INT 0x00000002
+#define PXE_HWCMD_CLEAR_CMD_COMPLETE_INT 0x00000001
+
+typedef struct s_pxe_sw_undi {
+ PXE_UINT32 Signature; ///< PXE_ROMID_SIGNATURE
+ PXE_UINT8 Len; ///< sizeof(PXE_SW_UNDI)
+ PXE_UINT8 Fudge; ///< makes 8-bit cksum zero
+ PXE_UINT8 Rev; ///< PXE_ROMID_REV
+ PXE_UINT8 IFcnt; ///< physical connector count
+ PXE_UINT8 MajorVer; ///< PXE_ROMID_MAJORVER
+ PXE_UINT8 MinorVer; ///< PXE_ROMID_MINORVER
+ PXE_UINT16 reserved1; ///< zero, not used
+ PXE_UINT32 Implementation; ///< Implementation flags
+ PXE_UINT64 EntryPoint; ///< API entry point
+ PXE_UINT8 reserved2[3]; ///< zero, not used
+ PXE_UINT8 BusCnt; ///< number of bustypes supported
+ PXE_UINT32 BusType[1]; ///< list of supported bustypes
+} PXE_SW_UNDI;
+
+typedef union u_pxe_undi {
+ PXE_HW_UNDI hw;
+ PXE_SW_UNDI sw;
+} PXE_UNDI;
+
+///
+/// Signature of !PXE structure
+///
+#define PXE_ROMID_SIGNATURE PXE_BUSTYPE ('!', 'P', 'X', 'E')
+
+///
+/// !PXE structure format revision
+///
+#define PXE_ROMID_REV 0x02
+
+///
+/// UNDI command interface revision. These are the values that get sent
+/// in option 94 (Client Network Interface Identifier) in the DHCP Discover
+/// and PXE Boot Server Request packets.
+///
+#define PXE_ROMID_MAJORVER 0x03
+#define PXE_ROMID_MINORVER 0x01
+
+///
+/// Implementation flags
+///
+#define PXE_ROMID_IMP_HW_UNDI 0x80000000
+#define PXE_ROMID_IMP_SW_VIRT_ADDR 0x40000000
+#define PXE_ROMID_IMP_64BIT_DEVICE 0x00010000
+#define PXE_ROMID_IMP_FRAG_SUPPORTED 0x00008000
+#define PXE_ROMID_IMP_CMD_LINK_SUPPORTED 0x00004000
+#define PXE_ROMID_IMP_CMD_QUEUE_SUPPORTED 0x00002000
+#define PXE_ROMID_IMP_MULTI_FRAME_SUPPORTED 0x00001000
+#define PXE_ROMID_IMP_NVDATA_SUPPORT_MASK 0x00000C00
+#define PXE_ROMID_IMP_NVDATA_BULK_WRITABLE 0x00000C00
+#define PXE_ROMID_IMP_NVDATA_SPARSE_WRITABLE 0x00000800
+#define PXE_ROMID_IMP_NVDATA_READ_ONLY 0x00000400
+#define PXE_ROMID_IMP_NVDATA_NOT_AVAILABLE 0x00000000
+#define PXE_ROMID_IMP_STATISTICS_SUPPORTED 0x00000200
+#define PXE_ROMID_IMP_STATION_ADDR_SETTABLE 0x00000100
+#define PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED 0x00000080
+#define PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED 0x00000040
+#define PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED 0x00000020
+#define PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED 0x00000010
+#define PXE_ROMID_IMP_SOFTWARE_INT_SUPPORTED 0x00000008
+#define PXE_ROMID_IMP_TX_COMPLETE_INT_SUPPORTED 0x00000004
+#define PXE_ROMID_IMP_PACKET_RX_INT_SUPPORTED 0x00000002
+#define PXE_ROMID_IMP_CMD_COMPLETE_INT_SUPPORTED 0x00000001
+
+typedef struct s_pxe_cdb {
+ PXE_OPCODE OpCode;
+ PXE_OPFLAGS OpFlags;
+ PXE_UINT16 CPBsize;
+ PXE_UINT16 DBsize;
+ PXE_UINT64 CPBaddr;
+ PXE_UINT64 DBaddr;
+ PXE_STATCODE StatCode;
+ PXE_STATFLAGS StatFlags;
+ PXE_UINT16 IFnum;
+ PXE_CONTROL Control;
+} PXE_CDB;
+
+typedef union u_pxe_ip_addr {
+ PXE_IPV6 IPv6;
+ PXE_IPV4 IPv4;
+} PXE_IP_ADDR;
+
+typedef union pxe_device {
+ ///
+ /// PCI and PC Card NICs are both identified using bus, device
+ /// and function numbers. For PC Card, this may require PC
+ /// Card services to be loaded in the BIOS or preboot
+ /// environment.
+ ///
+ struct {
+ ///
+ /// See S/W UNDI ROMID structure definition for PCI and
+ /// PCC BusType definitions.
+ ///
+ PXE_UINT32 BusType;
+
+ ///
+ /// Bus, device & function numbers that locate this device.
+ ///
+ PXE_UINT16 Bus;
+ PXE_UINT8 Device;
+ PXE_UINT8 Function;
+ }
+ PCI, PCC;
+
+} PXE_DEVICE;
+
+///
+/// cpb and db definitions
+///
+#define MAX_PCI_CONFIG_LEN 64 ///< # of dwords
+#define MAX_EEPROM_LEN 128 ///< # of dwords
+#define MAX_XMIT_BUFFERS 32 ///< recycling Q length for xmit_done
+#define MAX_MCAST_ADDRESS_CNT 8
+
+typedef struct s_pxe_cpb_start_30 {
+ ///
+ /// PXE_VOID Delay(UINTN microseconds);
+ ///
+ /// UNDI will never request a delay smaller than 10 microseconds
+ /// and will always request delays in increments of 10 microseconds.
+ /// The Delay() CallBack routine must delay between n and n + 10
+ /// microseconds before returning control to the UNDI.
+ ///
+ /// This field cannot be set to zero.
+ ///
+ UINT64 Delay;
+
+ ///
+ /// PXE_VOID Block(UINT32 enable);
+ ///
+ /// UNDI may need to block multi-threaded/multi-processor access to
+ /// critical code sections when programming or accessing the network
+ /// device. To this end, a blocking service is needed by the UNDI.
+ /// When UNDI needs a block, it will call Block() passing a non-zero
+ /// value. When UNDI no longer needs a block, it will call Block()
+ /// with a zero value. When called, if the Block() is already enabled,
+ /// do not return control to the UNDI until the previous Block() is
+ /// disabled.
+ ///
+ /// This field cannot be set to zero.
+ ///
+ UINT64 Block;
+
+ ///
+ /// PXE_VOID Virt2Phys(UINT64 virtual, UINT64 physical_ptr);
+ ///
+ /// UNDI will pass the virtual address of a buffer and the virtual
+ /// address of a 64-bit physical buffer. Convert the virtual address
+ /// to a physical address and write the result to the physical address
+ /// buffer. If virtual and physical addresses are the same, just
+ /// copy the virtual address to the physical address buffer.
+ ///
+ /// This field can be set to zero if virtual and physical addresses
+ /// are equal.
+ ///
+ UINT64 Virt2Phys;
+ ///
+ /// PXE_VOID Mem_IO(UINT8 read_write, UINT8 len, UINT64 port,
+ /// UINT64 buf_addr);
+ ///
+ /// UNDI will read or write the device io space using this call back
+ /// function. It passes the number of bytes as the len parameter and it
+ /// will be either 1,2,4 or 8.
+ ///
+ /// This field can not be set to zero.
+ ///
+ UINT64 Mem_IO;
+} PXE_CPB_START_30;
+
+typedef struct s_pxe_cpb_start_31 {
+ ///
+ /// PXE_VOID Delay(UINT64 UnqId, UINTN microseconds);
+ ///
+ /// UNDI will never request a delay smaller than 10 microseconds
+ /// and will always request delays in increments of 10 microseconds.
+ /// The Delay() CallBack routine must delay between n and n + 10
+ /// microseconds before returning control to the UNDI.
+ ///
+ /// This field cannot be set to zero.
+ ///
+ UINT64 Delay;
+
+ ///
+ /// PXE_VOID Block(UINT64 unq_id, UINT32 enable);
+ ///
+ /// UNDI may need to block multi-threaded/multi-processor access to
+ /// critical code sections when programming or accessing the network
+ /// device. To this end, a blocking service is needed by the UNDI.
+ /// When UNDI needs a block, it will call Block() passing a non-zero
+ /// value. When UNDI no longer needs a block, it will call Block()
+ /// with a zero value. When called, if the Block() is already enabled,
+ /// do not return control to the UNDI until the previous Block() is
+ /// disabled.
+ ///
+ /// This field cannot be set to zero.
+ ///
+ UINT64 Block;
+
+ ///
+ /// PXE_VOID Virt2Phys(UINT64 UnqId, UINT64 virtual, UINT64 physical_ptr);
+ ///
+ /// UNDI will pass the virtual address of a buffer and the virtual
+ /// address of a 64-bit physical buffer. Convert the virtual address
+ /// to a physical address and write the result to the physical address
+ /// buffer. If virtual and physical addresses are the same, just
+ /// copy the virtual address to the physical address buffer.
+ ///
+ /// This field can be set to zero if virtual and physical addresses
+ /// are equal.
+ ///
+ UINT64 Virt2Phys;
+ ///
+ /// PXE_VOID Mem_IO(UINT64 UnqId, UINT8 read_write, UINT8 len, UINT64 port,
+ /// UINT64 buf_addr);
+ ///
+ /// UNDI will read or write the device io space using this call back
+ /// function. It passes the number of bytes as the len parameter and it
+ /// will be either 1,2,4 or 8.
+ ///
+ /// This field can not be set to zero.
+ ///
+ UINT64 Mem_IO;
+ ///
+ /// PXE_VOID Map_Mem(UINT64 unq_id, UINT64 virtual_addr, UINT32 size,
+ /// UINT32 Direction, UINT64 mapped_addr);
+ ///
+ /// UNDI will pass the virtual address of a buffer, direction of the data
+ /// flow from/to the mapped buffer (the constants are defined below)
+ /// and a place holder (pointer) for the mapped address.
+ /// This call will Map the given address to a physical DMA address and write
+ /// the result to the mapped_addr pointer. If there is no need to
+ /// map the given address to a lower address (i.e. the given address is
+ /// associated with a physical address that is already compatible to be
+ /// used with the DMA, it converts the given virtual address to it's
+ /// physical address and write that in the mapped address pointer.
+ ///
+ /// This field can be set to zero if there is no mapping service available
+ ///
+ UINT64 Map_Mem;
+
+ ///
+ /// PXE_VOID UnMap_Mem(UINT64 unq_id, UINT64 virtual_addr, UINT32 size,
+ /// UINT32 Direction, UINT64 mapped_addr);
+ ///
+ /// UNDI will pass the virtual and mapped addresses of a buffer
+ /// This call will un map the given address
+ ///
+ /// This field can be set to zero if there is no unmapping service available
+ ///
+ UINT64 UnMap_Mem;
+
+ ///
+ /// PXE_VOID Sync_Mem(UINT64 unq_id, UINT64 virtual,
+ /// UINT32 size, UINT32 Direction, UINT64 mapped_addr);
+ ///
+ /// UNDI will pass the virtual and mapped addresses of a buffer
+ /// This call will synchronize the contents of both the virtual and mapped
+ /// buffers for the given Direction.
+ ///
+ /// This field can be set to zero if there is no service available
+ ///
+ UINT64 Sync_Mem;
+
+ ///
+ /// protocol driver can provide anything for this Unique_ID, UNDI remembers
+ /// that as just a 64bit value assocaited to the interface specified by
+ /// the ifnum and gives it back as a parameter to all the call-back routines
+ /// when calling for that interface!
+ ///
+ UINT64 Unique_ID;
+} PXE_CPB_START_31;
+
+#define TO_AND_FROM_DEVICE 0
+#define FROM_DEVICE 1
+#define TO_DEVICE 2
+
+#define PXE_DELAY_MILLISECOND 1000
+#define PXE_DELAY_SECOND 1000000
+#define PXE_IO_READ 0
+#define PXE_IO_WRITE 1
+#define PXE_MEM_READ 2
+#define PXE_MEM_WRITE 4
+
+typedef struct s_pxe_db_get_init_info {
+ ///
+ /// Minimum length of locked memory buffer that must be given to
+ /// the Initialize command. Giving UNDI more memory will generally
+ /// give better performance.
+ ///
+ /// If MemoryRequired is zero, the UNDI does not need and will not
+ /// use system memory to receive and transmit packets.
+ ///
+ PXE_UINT32 MemoryRequired;
+
+ ///
+ /// Maximum frame data length for Tx/Rx excluding the media header.
+ ///
+ PXE_UINT32 FrameDataLen;
+
+ ///
+ /// Supported link speeds are in units of mega bits. Common ethernet
+ /// values are 10, 100 and 1000. Unused LinkSpeeds[] entries are zero
+ /// filled.
+ ///
+ PXE_UINT32 LinkSpeeds[4];
+
+ ///
+ /// Number of non-volatile storage items.
+ ///
+ PXE_UINT32 NvCount;
+
+ ///
+ /// Width of non-volatile storage item in bytes. 0, 1, 2 or 4
+ ///
+ PXE_UINT16 NvWidth;
+
+ ///
+ /// Media header length. This is the typical media header length for
+ /// this UNDI. This information is needed when allocating receive
+ /// and transmit buffers.
+ ///
+ PXE_UINT16 MediaHeaderLen;
+
+ ///
+ /// Number of bytes in the NIC hardware (MAC) address.
+ ///
+ PXE_UINT16 HWaddrLen;
+
+ ///
+ /// Maximum number of multicast MAC addresses in the multicast
+ /// MAC address filter list.
+ ///
+ PXE_UINT16 MCastFilterCnt;
+
+ ///
+ /// Default number and size of transmit and receive buffers that will
+ /// be allocated by the UNDI. If MemoryRequired is non-zero, this
+ /// allocation will come out of the memory buffer given to the Initialize
+ /// command. If MemoryRequired is zero, this allocation will come out of
+ /// memory on the NIC.
+ ///
+ PXE_UINT16 TxBufCnt;
+ PXE_UINT16 TxBufSize;
+ PXE_UINT16 RxBufCnt;
+ PXE_UINT16 RxBufSize;
+
+ ///
+ /// Hardware interface types defined in the Assigned Numbers RFC
+ /// and used in DHCP and ARP packets.
+ /// See the PXE_IFTYPE typedef and PXE_IFTYPE_xxx macros.
+ ///
+ PXE_UINT8 IFtype;
+
+ ///
+ /// Supported duplex. See PXE_DUPLEX_xxxxx #defines below.
+ ///
+ PXE_UINT8 SupportedDuplexModes;
+
+ ///
+ /// Supported loopback options. See PXE_LOOPBACK_xxxxx #defines below.
+ ///
+ PXE_UINT8 SupportedLoopBackModes;
+} PXE_DB_GET_INIT_INFO;
+
+#define PXE_MAX_TXRX_UNIT_ETHER 1500
+
+#define PXE_HWADDR_LEN_ETHER 0x0006
+#define PXE_MAC_HEADER_LEN_ETHER 0x000E
+
+#define PXE_DUPLEX_ENABLE_FULL_SUPPORTED 1
+#define PXE_DUPLEX_FORCE_FULL_SUPPORTED 2
+
+#define PXE_LOOPBACK_INTERNAL_SUPPORTED 1
+#define PXE_LOOPBACK_EXTERNAL_SUPPORTED 2
+
+typedef struct s_pxe_pci_config_info {
+ ///
+ /// This is the flag field for the PXE_DB_GET_CONFIG_INFO union.
+ /// For PCI bus devices, this field is set to PXE_BUSTYPE_PCI.
+ ///
+ UINT32 BusType;
+
+ ///
+ /// This identifies the PCI network device that this UNDI interface
+ /// is bound to.
+ ///
+ UINT16 Bus;
+ UINT8 Device;
+ UINT8 Function;
+
+ ///
+ /// This is a copy of the PCI configuration space for this
+ /// network device.
+ ///
+ union {
+ UINT8 Byte[256];
+ UINT16 Word[128];
+ UINT32 Dword[64];
+ } Config;
+} PXE_PCI_CONFIG_INFO;
+
+typedef struct s_pxe_pcc_config_info {
+ ///
+ /// This is the flag field for the PXE_DB_GET_CONFIG_INFO union.
+ /// For PCC bus devices, this field is set to PXE_BUSTYPE_PCC.
+ ///
+ PXE_UINT32 BusType;
+
+ ///
+ /// This identifies the PCC network device that this UNDI interface
+ /// is bound to.
+ ///
+ PXE_UINT16 Bus;
+ PXE_UINT8 Device;
+ PXE_UINT8 Function;
+
+ ///
+ /// This is a copy of the PCC configuration space for this
+ /// network device.
+ ///
+ union {
+ PXE_UINT8 Byte[256];
+ PXE_UINT16 Word[128];
+ PXE_UINT32 Dword[64];
+ } Config;
+} PXE_PCC_CONFIG_INFO;
+
+typedef union u_pxe_db_get_config_info {
+ PXE_PCI_CONFIG_INFO pci;
+ PXE_PCC_CONFIG_INFO pcc;
+} PXE_DB_GET_CONFIG_INFO;
+
+typedef struct s_pxe_cpb_initialize {
+ ///
+ /// Address of first (lowest) byte of the memory buffer. This buffer must
+ /// be in contiguous physical memory and cannot be swapped out. The UNDI
+ /// will be using this for transmit and receive buffering.
+ ///
+ PXE_UINT64 MemoryAddr;
+
+ ///
+ /// MemoryLength must be greater than or equal to MemoryRequired
+ /// returned by the Get Init Info command.
+ ///
+ PXE_UINT32 MemoryLength;
+
+ ///
+ /// Desired link speed in Mbit/sec. Common ethernet values are 10, 100
+ /// and 1000. Setting a value of zero will auto-detect and/or use the
+ /// default link speed (operation depends on UNDI/NIC functionality).
+ ///
+ PXE_UINT32 LinkSpeed;
+
+ ///
+ /// Suggested number and size of receive and transmit buffers to
+ /// allocate. If MemoryAddr and MemoryLength are non-zero, this
+ /// allocation comes out of the supplied memory buffer. If MemoryAddr
+ /// and MemoryLength are zero, this allocation comes out of memory
+ /// on the NIC.
+ ///
+ /// If these fields are set to zero, the UNDI will allocate buffer
+ /// counts and sizes as it sees fit.
+ ///
+ PXE_UINT16 TxBufCnt;
+ PXE_UINT16 TxBufSize;
+ PXE_UINT16 RxBufCnt;
+ PXE_UINT16 RxBufSize;
+
+ ///
+ /// The following configuration parameters are optional and must be zero
+ /// to use the default values.
+ ///
+ PXE_UINT8 DuplexMode;
+
+ PXE_UINT8 LoopBackMode;
+} PXE_CPB_INITIALIZE;
+
+#define PXE_DUPLEX_DEFAULT 0x00
+#define PXE_FORCE_FULL_DUPLEX 0x01
+#define PXE_ENABLE_FULL_DUPLEX 0x02
+#define PXE_FORCE_HALF_DUPLEX 0x04
+#define PXE_DISABLE_FULL_DUPLEX 0x08
+
+#define LOOPBACK_NORMAL 0
+#define LOOPBACK_INTERNAL 1
+#define LOOPBACK_EXTERNAL 2
+
+typedef struct s_pxe_db_initialize {
+ ///
+ /// Actual amount of memory used from the supplied memory buffer. This
+ /// may be less that the amount of memory suppllied and may be zero if
+ /// the UNDI and network device do not use external memory buffers.
+ ///
+ /// Memory used by the UNDI and network device is allocated from the
+ /// lowest memory buffer address.
+ ///
+ PXE_UINT32 MemoryUsed;
+
+ ///
+ /// Actual number and size of receive and transmit buffers that were
+ /// allocated.
+ ///
+ PXE_UINT16 TxBufCnt;
+ PXE_UINT16 TxBufSize;
+ PXE_UINT16 RxBufCnt;
+ PXE_UINT16 RxBufSize;
+} PXE_DB_INITIALIZE;
+
+typedef struct s_pxe_cpb_receive_filters {
+ ///
+ /// List of multicast MAC addresses. This list, if present, will
+ /// replace the existing multicast MAC address filter list.
+ ///
+ PXE_MAC_ADDR MCastList[MAX_MCAST_ADDRESS_CNT];
+} PXE_CPB_RECEIVE_FILTERS;
+
+typedef struct s_pxe_db_receive_filters {
+ ///
+ /// Filtered multicast MAC address list.
+ ///
+ PXE_MAC_ADDR MCastList[MAX_MCAST_ADDRESS_CNT];
+} PXE_DB_RECEIVE_FILTERS;
+
+typedef struct s_pxe_cpb_station_address {
+ ///
+ /// If supplied and supported, the current station MAC address
+ /// will be changed.
+ ///
+ PXE_MAC_ADDR StationAddr;
+} PXE_CPB_STATION_ADDRESS;
+
+typedef struct s_pxe_dpb_station_address {
+ ///
+ /// Current station MAC address.
+ ///
+ PXE_MAC_ADDR StationAddr;
+
+ ///
+ /// Station broadcast MAC address.
+ ///
+ PXE_MAC_ADDR BroadcastAddr;
+
+ ///
+ /// Permanent station MAC address.
+ ///
+ PXE_MAC_ADDR PermanentAddr;
+} PXE_DB_STATION_ADDRESS;
+
+typedef struct s_pxe_db_statistics {
+ ///
+ /// Bit field identifying what statistic data is collected by the
+ /// UNDI/NIC.
+ /// If bit 0x00 is set, Data[0x00] is collected.
+ /// If bit 0x01 is set, Data[0x01] is collected.
+ /// If bit 0x20 is set, Data[0x20] is collected.
+ /// If bit 0x21 is set, Data[0x21] is collected.
+ /// Etc.
+ ///
+ PXE_UINT64 Supported;
+
+ ///
+ /// Statistic data.
+ ///
+ PXE_UINT64 Data[64];
+} PXE_DB_STATISTICS;
+
+///
+/// Total number of frames received. Includes frames with errors and
+/// dropped frames.
+///
+#define PXE_STATISTICS_RX_TOTAL_FRAMES 0x00
+
+///
+/// Number of valid frames received and copied into receive buffers.
+///
+#define PXE_STATISTICS_RX_GOOD_FRAMES 0x01
+
+///
+/// Number of frames below the minimum length for the media.
+/// This would be <64 for ethernet.
+///
+#define PXE_STATISTICS_RX_UNDERSIZE_FRAMES 0x02
+
+///
+/// Number of frames longer than the maxminum length for the
+/// media. This would be >1500 for ethernet.
+///
+#define PXE_STATISTICS_RX_OVERSIZE_FRAMES 0x03
+
+///
+/// Valid frames that were dropped because receive buffers were full.
+///
+#define PXE_STATISTICS_RX_DROPPED_FRAMES 0x04
+
+///
+/// Number of valid unicast frames received and not dropped.
+///
+#define PXE_STATISTICS_RX_UNICAST_FRAMES 0x05
+
+///
+/// Number of valid broadcast frames received and not dropped.
+///
+#define PXE_STATISTICS_RX_BROADCAST_FRAMES 0x06
+
+///
+/// Number of valid mutlicast frames received and not dropped.
+///
+#define PXE_STATISTICS_RX_MULTICAST_FRAMES 0x07
+
+///
+/// Number of frames w/ CRC or alignment errors.
+///
+#define PXE_STATISTICS_RX_CRC_ERROR_FRAMES 0x08
+
+///
+/// Total number of bytes received. Includes frames with errors
+/// and dropped frames.
+///
+#define PXE_STATISTICS_RX_TOTAL_BYTES 0x09
+
+///
+/// Transmit statistics.
+///
+#define PXE_STATISTICS_TX_TOTAL_FRAMES 0x0A
+#define PXE_STATISTICS_TX_GOOD_FRAMES 0x0B
+#define PXE_STATISTICS_TX_UNDERSIZE_FRAMES 0x0C
+#define PXE_STATISTICS_TX_OVERSIZE_FRAMES 0x0D
+#define PXE_STATISTICS_TX_DROPPED_FRAMES 0x0E
+#define PXE_STATISTICS_TX_UNICAST_FRAMES 0x0F
+#define PXE_STATISTICS_TX_BROADCAST_FRAMES 0x10
+#define PXE_STATISTICS_TX_MULTICAST_FRAMES 0x11
+#define PXE_STATISTICS_TX_CRC_ERROR_FRAMES 0x12
+#define PXE_STATISTICS_TX_TOTAL_BYTES 0x13
+
+///
+/// Number of collisions detection on this subnet.
+///
+#define PXE_STATISTICS_COLLISIONS 0x14
+
+///
+/// Number of frames destined for unsupported protocol.
+///
+#define PXE_STATISTICS_UNSUPPORTED_PROTOCOL 0x15
+
+typedef struct s_pxe_cpb_mcast_ip_to_mac {
+ ///
+ /// Multicast IP address to be converted to multicast MAC address.
+ ///
+ PXE_IP_ADDR IP;
+} PXE_CPB_MCAST_IP_TO_MAC;
+
+typedef struct s_pxe_db_mcast_ip_to_mac {
+ ///
+ /// Multicast MAC address.
+ ///
+ PXE_MAC_ADDR MAC;
+} PXE_DB_MCAST_IP_TO_MAC;
+
+typedef struct s_pxe_cpb_nvdata_sparse {
+ ///
+ /// NvData item list. Only items in this list will be updated.
+ ///
+ struct {
+ ///
+ /// Non-volatile storage address to be changed.
+ ///
+ PXE_UINT32 Addr;
+
+ ///
+ /// Data item to write into above storage address.
+ ///
+ union {
+ PXE_UINT8 Byte;
+ PXE_UINT16 Word;
+ PXE_UINT32 Dword;
+ } Data;
+ } Item[MAX_EEPROM_LEN];
+} PXE_CPB_NVDATA_SPARSE;
+
+///
+/// When using bulk update, the size of the CPB structure must be
+/// the same size as the non-volatile NIC storage.
+///
+typedef union u_pxe_cpb_nvdata_bulk {
+ ///
+ /// Array of byte-wide data items.
+ ///
+ PXE_UINT8 Byte[MAX_EEPROM_LEN << 2];
+
+ ///
+ /// Array of word-wide data items.
+ ///
+ PXE_UINT16 Word[MAX_EEPROM_LEN << 1];
+
+ ///
+ /// Array of dword-wide data items.
+ ///
+ PXE_UINT32 Dword[MAX_EEPROM_LEN];
+} PXE_CPB_NVDATA_BULK;
+
+typedef struct s_pxe_db_nvdata {
+ ///
+ /// Arrays of data items from non-volatile storage.
+ ///
+ union {
+ ///
+ /// Array of byte-wide data items.
+ ///
+ PXE_UINT8 Byte[MAX_EEPROM_LEN << 2];
+
+ ///
+ /// Array of word-wide data items.
+ ///
+ PXE_UINT16 Word[MAX_EEPROM_LEN << 1];
+
+ ///
+ /// Array of dword-wide data items.
+ ///
+ PXE_UINT32 Dword[MAX_EEPROM_LEN];
+ } Data;
+} PXE_DB_NVDATA;
+
+typedef struct s_pxe_db_get_status {
+ ///
+ /// Length of next receive frame (header + data). If this is zero,
+ /// there is no next receive frame available.
+ ///
+ PXE_UINT32 RxFrameLen;
+
+ ///
+ /// Reserved, set to zero.
+ ///
+ PXE_UINT32 reserved;
+
+ ///
+ /// Addresses of transmitted buffers that need to be recycled.
+ ///
+ PXE_UINT64 TxBuffer[MAX_XMIT_BUFFERS];
+} PXE_DB_GET_STATUS;
+
+typedef struct s_pxe_cpb_fill_header {
+ ///
+ /// Source and destination MAC addresses. These will be copied into
+ /// the media header without doing byte swapping.
+ ///
+ PXE_MAC_ADDR SrcAddr;
+ PXE_MAC_ADDR DestAddr;
+
+ ///
+ /// Address of first byte of media header. The first byte of packet data
+ /// follows the last byte of the media header.
+ ///
+ PXE_UINT64 MediaHeader;
+
+ ///
+ /// Length of packet data in bytes (not including the media header).
+ ///
+ PXE_UINT32 PacketLen;
+
+ ///
+ /// Protocol type. This will be copied into the media header without
+ /// doing byte swapping. Protocol type numbers can be obtained from
+ /// the Assigned Numbers RFC 1700.
+ ///
+ PXE_UINT16 Protocol;
+
+ ///
+ /// Length of the media header in bytes.
+ ///
+ PXE_UINT16 MediaHeaderLen;
+} PXE_CPB_FILL_HEADER;
+
+#define PXE_PROTOCOL_ETHERNET_IP 0x0800
+#define PXE_PROTOCOL_ETHERNET_ARP 0x0806
+#define MAX_XMIT_FRAGMENTS 16
+
+typedef struct s_pxe_cpb_fill_header_fragmented {
+ ///
+ /// Source and destination MAC addresses. These will be copied into
+ /// the media header without doing byte swapping.
+ ///
+ PXE_MAC_ADDR SrcAddr;
+ PXE_MAC_ADDR DestAddr;
+
+ ///
+ /// Length of packet data in bytes (not including the media header).
+ ///
+ PXE_UINT32 PacketLen;
+
+ ///
+ /// Protocol type. This will be copied into the media header without
+ /// doing byte swapping. Protocol type numbers can be obtained from
+ /// the Assigned Numbers RFC 1700.
+ ///
+ PXE_MEDIA_PROTOCOL Protocol;
+
+ ///
+ /// Length of the media header in bytes.
+ ///
+ PXE_UINT16 MediaHeaderLen;
+
+ ///
+ /// Number of packet fragment descriptors.
+ ///
+ PXE_UINT16 FragCnt;
+
+ ///
+ /// Reserved, must be set to zero.
+ ///
+ PXE_UINT16 reserved;
+
+ ///
+ /// Array of packet fragment descriptors. The first byte of the media
+ /// header is the first byte of the first fragment.
+ ///
+ struct {
+ ///
+ /// Address of this packet fragment.
+ ///
+ PXE_UINT64 FragAddr;
+
+ ///
+ /// Length of this packet fragment.
+ ///
+ PXE_UINT32 FragLen;
+
+ ///
+ /// Reserved, must be set to zero.
+ ///
+ PXE_UINT32 reserved;
+ } FragDesc[MAX_XMIT_FRAGMENTS];
+}
+PXE_CPB_FILL_HEADER_FRAGMENTED;
+
+typedef struct s_pxe_cpb_transmit {
+ ///
+ /// Address of first byte of frame buffer. This is also the first byte
+ /// of the media header.
+ ///
+ PXE_UINT64 FrameAddr;
+
+ ///
+ /// Length of the data portion of the frame buffer in bytes. Do not
+ /// include the length of the media header.
+ ///
+ PXE_UINT32 DataLen;
+
+ ///
+ /// Length of the media header in bytes.
+ ///
+ PXE_UINT16 MediaheaderLen;
+
+ ///
+ /// Reserved, must be zero.
+ ///
+ PXE_UINT16 reserved;
+} PXE_CPB_TRANSMIT;
+
+typedef struct s_pxe_cpb_transmit_fragments {
+ ///
+ /// Length of packet data in bytes (not including the media header).
+ ///
+ PXE_UINT32 FrameLen;
+
+ ///
+ /// Length of the media header in bytes.
+ ///
+ PXE_UINT16 MediaheaderLen;
+
+ ///
+ /// Number of packet fragment descriptors.
+ ///
+ PXE_UINT16 FragCnt;
+
+ ///
+ /// Array of frame fragment descriptors. The first byte of the first
+ /// fragment is also the first byte of the media header.
+ ///
+ struct {
+ ///
+ /// Address of this frame fragment.
+ ///
+ PXE_UINT64 FragAddr;
+
+ ///
+ /// Length of this frame fragment.
+ ///
+ PXE_UINT32 FragLen;
+
+ ///
+ /// Reserved, must be set to zero.
+ ///
+ PXE_UINT32 reserved;
+ } FragDesc[MAX_XMIT_FRAGMENTS];
+}
+PXE_CPB_TRANSMIT_FRAGMENTS;
+
+typedef struct s_pxe_cpb_receive {
+ ///
+ /// Address of first byte of receive buffer. This is also the first byte
+ /// of the frame header.
+ ///
+ PXE_UINT64 BufferAddr;
+
+ ///
+ /// Length of receive buffer. This must be large enough to hold the
+ /// received frame (media header + data). If the length of smaller than
+ /// the received frame, data will be lost.
+ ///
+ PXE_UINT32 BufferLen;
+
+ ///
+ /// Reserved, must be set to zero.
+ ///
+ PXE_UINT32 reserved;
+} PXE_CPB_RECEIVE;
+
+typedef struct s_pxe_db_receive {
+ ///
+ /// Source and destination MAC addresses from media header.
+ ///
+ PXE_MAC_ADDR SrcAddr;
+ PXE_MAC_ADDR DestAddr;
+
+ ///
+ /// Length of received frame. May be larger than receive buffer size.
+ /// The receive buffer will not be overwritten. This is how to tell
+ /// if data was lost because the receive buffer was too small.
+ ///
+ PXE_UINT32 FrameLen;
+
+ ///
+ /// Protocol type from media header.
+ ///
+ PXE_MEDIA_PROTOCOL Protocol;
+
+ ///
+ /// Length of media header in received frame.
+ ///
+ PXE_UINT16 MediaHeaderLen;
+
+ ///
+ /// Type of receive frame.
+ ///
+ PXE_FRAME_TYPE Type;
+
+ ///
+ /// Reserved, must be zero.
+ ///
+ PXE_UINT8 reserved[7];
+
+} PXE_DB_RECEIVE;
+
+#pragma pack()
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Uefi/UefiSpec.h b/gpxe/src/include/gpxe/efi/Uefi/UefiSpec.h
new file mode 100644
index 00000000..03e7b6cc
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Uefi/UefiSpec.h
@@ -0,0 +1,1916 @@
+/** @file
+ Include file that supports UEFI.
+
+ This include file must only contain things defined in the UEFI 2.1 specification.
+ If a code construct is defined in the UEFI 2.1 specification it must be included
+ by this include file.
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __UEFI_SPEC_H__
+#define __UEFI_SPEC_H__
+
+#include <gpxe/efi/Uefi/UefiMultiPhase.h>
+
+#include <gpxe/efi/Protocol/DevicePath.h>
+#include <gpxe/efi/Protocol/SimpleTextIn.h>
+#include <gpxe/efi/Protocol/SimpleTextOut.h>
+
+///
+/// Enumeration of memory allocation.
+///
+typedef enum {
+ AllocateAnyPages,
+ AllocateMaxAddress,
+ AllocateAddress,
+ MaxAllocateType
+} EFI_ALLOCATE_TYPE;
+
+//
+// Bit definitions for EFI_TIME.Daylight
+//
+#define EFI_TIME_ADJUST_DAYLIGHT 0x01
+#define EFI_TIME_IN_DAYLIGHT 0x02
+
+///
+/// Value definition for EFI_TIME.TimeZone
+///
+#define EFI_UNSPECIFIED_TIMEZONE 0x07FF
+
+//
+// Memory cacheability attributes
+//
+#define EFI_MEMORY_UC 0x0000000000000001ULL
+#define EFI_MEMORY_WC 0x0000000000000002ULL
+#define EFI_MEMORY_WT 0x0000000000000004ULL
+#define EFI_MEMORY_WB 0x0000000000000008ULL
+#define EFI_MEMORY_UCE 0x0000000000000010ULL
+//
+// Physical memory protection attributes
+//
+#define EFI_MEMORY_WP 0x0000000000001000ULL
+#define EFI_MEMORY_RP 0x0000000000002000ULL
+#define EFI_MEMORY_XP 0x0000000000004000ULL
+//
+// Runtime memory attribute
+//
+#define EFI_MEMORY_RUNTIME 0x8000000000000000ULL
+
+///
+/// Memory descriptor version number
+///
+#define EFI_MEMORY_DESCRIPTOR_VERSION 1
+
+///
+/// Definition of memory descriptor
+///
+typedef struct {
+ UINT32 Type;
+ EFI_PHYSICAL_ADDRESS PhysicalStart;
+ EFI_VIRTUAL_ADDRESS VirtualStart;
+ UINT64 NumberOfPages;
+ UINT64 Attribute;
+} EFI_MEMORY_DESCRIPTOR;
+
+///
+/// Build macros to find next EFI_MEMORY_DESCRIPTOR.
+///
+#define NEXT_MEMORY_DESCRIPTOR(_Ptr, _Size) ((EFI_MEMORY_DESCRIPTOR *) (((UINT8 *) (_Ptr)) + (_Size)))
+
+///
+/// Declare forward referenced data structures
+///
+typedef struct _EFI_SYSTEM_TABLE EFI_SYSTEM_TABLE;
+
+/**
+ Allocates memory pages from the system.
+
+ @param Type The type of allocation to perform.
+ @param MemoryType The type of memory to allocate.
+ @param Pages The number of contiguous 4 KB pages to allocate.
+ @param Memory Pointer to a physical address. On input, the way in which the address is
+ used depends on the value of Type.
+
+ @retval EFI_SUCCESS The requested pages were allocated.
+ @retval EFI_INVALID_PARAMETER 1) Type is not AllocateAnyPages or
+ AllocateMaxAddress or AllocateAddress.
+ 2) MemoryType is in the range
+ EfiMaxMemoryType..0x7FFFFFFF.
+ @retval EFI_OUT_OF_RESOURCES The pages could not be allocated.
+ @retval EFI_NOT_FOUND The requested pages could not be found.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ALLOCATE_PAGES)(
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ IN OUT EFI_PHYSICAL_ADDRESS *Memory
+ );
+
+/**
+ Frees memory pages.
+
+ @param Memory The base physical address of the pages to be freed.
+ @param Pages The number of contiguous 4 KB pages to free.
+
+ @retval EFI_SUCCESS The requested pages were freed.
+ @retval EFI_INVALID_PARAMETER Memory is not a page-aligned address or Pages is invalid.
+ @retval EFI_NOT_FOUND The requested memory pages were not allocated with
+ AllocatePages().
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FREE_PAGES)(
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN Pages
+ );
+
+/**
+ Returns the current memory map.
+
+ @param MemoryMapSize A pointer to the size, in bytes, of the MemoryMap buffer.
+ On input, this is the size of the buffer allocated by the caller.
+ On output, it is the size of the buffer returned by the firmware if
+ the buffer was large enough, or the size of the buffer needed to contain
+ the map if the buffer was too small.
+ @param MemoryMap A pointer to the buffer in which firmware places the current memory
+ map.
+ @param MapKey A pointer to the location in which firmware returns the key for the
+ current memory map.
+ @param DescriptorSize A pointer to the location in which firmware returns the size, in bytes, of
+ an individual EFI_MEMORY_DESCRIPTOR.
+ @param DescriptorVersion A pointer to the location in which firmware returns the version number
+ associated with the EFI_MEMORY_DESCRIPTOR.
+
+ @retval EFI_SUCCESS The memory map was returned in the MemoryMap buffer.
+ @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current buffer size
+ needed to hold the memory map is returned in MemoryMapSize.
+ @retval EFI_INVALID_PARAMETER 1) MemoryMapSize is NULL.
+ 2) The MemoryMap buffer is not too small and MemoryMap is
+ NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_MEMORY_MAP)(
+ IN OUT UINTN *MemoryMapSize,
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ OUT UINTN *MapKey,
+ OUT UINTN *DescriptorSize,
+ OUT UINT32 *DescriptorVersion
+ );
+
+/**
+ Allocates pool memory.
+
+ @param PoolType The type of pool to allocate.
+ @param Size The number of bytes to allocate from the pool.
+ @param Buffer A pointer to a pointer to the allocated buffer if the call succeeds;
+ undefined otherwise.
+
+ @retval EFI_SUCCESS The requested number of bytes was allocated.
+ @retval EFI_OUT_OF_RESOURCES The pool requested could not be allocated.
+ @retval EFI_INVALID_PARAMETER PoolType was invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ALLOCATE_POOL)(
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN Size,
+ OUT VOID **Buffer
+ );
+
+/**
+ Returns pool memory to the system.
+
+ @param Buffer Pointer to the buffer to free.
+
+ @retval EFI_SUCCESS The memory was returned to the system.
+ @retval EFI_INVALID_PARAMETER Buffer was invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FREE_POOL)(
+ IN VOID *Buffer
+ );
+
+/**
+ Changes the runtime addressing mode of EFI firmware from physical to virtual.
+
+ @param MemoryMapSize The size in bytes of VirtualMap.
+ @param DescriptorSize The size in bytes of an entry in the VirtualMap.
+ @param DescriptorVersion The version of the structure entries in VirtualMap.
+ @param VirtualMap An array of memory descriptors which contain new virtual
+ address mapping information for all runtime ranges.
+
+ @retval EFI_SUCCESS The virtual address map has been applied.
+ @retval EFI_UNSUPPORTED EFI firmware is not at runtime, or the EFI firmware is already in
+ virtual address mapped mode.
+ @retval EFI_INVALID_PARAMETER DescriptorSize or DescriptorVersion is invalid.
+ @retval EFI_NO_MAPPING A virtual address was not supplied for a range in the memory
+ map that requires a mapping.
+ @retval EFI_NOT_FOUND A virtual address was supplied for an address that is not found
+ in the memory map.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SET_VIRTUAL_ADDRESS_MAP)(
+ IN UINTN MemoryMapSize,
+ IN UINTN DescriptorSize,
+ IN UINT32 DescriptorVersion,
+ IN EFI_MEMORY_DESCRIPTOR *VirtualMap
+ );
+
+/**
+ Connects one or more drivers to a controller.
+
+ @param ControllerHandle The handle of the controller to which driver(s) are to be connected.
+ @param DriverImageHandle A pointer to an ordered list handles that support the
+ EFI_DRIVER_BINDING_PROTOCOL.
+ @param RemainingDevicePath A pointer to the device path that specifies a child of the
+ controller specified by ControllerHandle.
+ @param Recursive If TRUE, then ConnectController() is called recursively
+ until the entire tree of controllers below the controller specified
+ by ControllerHandle have been created. If FALSE, then
+ the tree of controllers is only expanded one level.
+
+ @retval EFI_SUCCESS 1) One or more drivers were connected to ControllerHandle.
+ 2) No drivers were connected to ControllerHandle, but
+ RemainingDevicePath is not NULL, and it is an End Device
+ Path Node.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+ @retval EFI_NOT_FOUND 1) There are no EFI_DRIVER_BINDING_PROTOCOL instances
+ present in the system.
+ 2) No drivers were connected to ControllerHandle.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CONNECT_CONTROLLER)(
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE *DriverImageHandle, OPTIONAL
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath, OPTIONAL
+ IN BOOLEAN Recursive
+ );
+
+/**
+ Disconnects one or more drivers from a controller.
+
+ @param ControllerHandle The handle of the controller from which driver(s) are to be disconnected.
+ @param DriverImageHandle The driver to disconnect from ControllerHandle.
+ If DriverImageHandle is NULL, then all the drivers currently managing
+ ControllerHandle are disconnected from ControllerHandle.
+ @param ChildHandle The handle of the child to destroy.
+ If ChildHandle is NULL, then all the children of ControllerHandle are
+ destroyed before the drivers are disconnected from ControllerHandle.
+
+ @retval EFI_SUCCESS 1) One or more drivers were disconnected from the controller.
+ 2) On entry, no drivers are managing ControllerHandle.
+ 3) DriverImageHandle is not NULL, and on entry
+ DriverImageHandle is not managing ControllerHandle.
+ @retval EFI_INVALID_PARAMETER 1) ControllerHandle is not a valid EFI_HANDLE.
+ 2) DriverImageHandle is not NULL, and it is not a valid EFI_HANDLE.
+ 3) ChildHandle is not NULL, and it is not a valid EFI_HANDLE.
+ 4) DriverImageHandle does not support the EFI_DRIVER_BINDING_PROTOCOL.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to disconnect any drivers from
+ ControllerHandle.
+ @retval EFI_DEVICE_ERROR The controller could not be disconnected because of a device error.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_DISCONNECT_CONTROLLER)(
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE DriverImageHandle, OPTIONAL
+ IN EFI_HANDLE ChildHandle OPTIONAL
+ );
+
+
+
+//
+// ConvertPointer DebugDisposition type.
+//
+#define EFI_OPTIONAL_PTR 0x00000001
+#define EFI_OPTIONAL_POINTER EFI_OPTIONAL_PTR
+
+/**
+ Determines the new virtual address that is to be used on subsequent memory accesses.
+
+ @param DebugDisposition Supplies type information for the pointer being converted.
+ @param Address A pointer to a pointer that is to be fixed to be the value needed
+ for the new virtual address mappings being applied.
+
+ @retval EFI_SUCCESS The pointer pointed to by Address was modified.
+ @retval EFI_INVALID_PARAMETER 1) Address is NULL.
+ 2) *Address is NULL and DebugDisposition does
+ not have the EFI_OPTIONAL_PTR bit set.
+ @retval EFI_NOT_FOUND The pointer pointed to by Address was not found to be part
+ of the current memory map. This is normally fatal.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CONVERT_POINTER)(
+ IN UINTN DebugDisposition,
+ IN OUT VOID **Address
+ );
+
+
+//
+// These types can be ORed together as needed - for example,
+// EVT_TIMER might be Ored with EVT_NOTIFY_WAIT or
+// EVT_NOTIFY_SIGNAL.
+//
+#define EVT_TIMER 0x80000000
+#define EVT_RUNTIME 0x40000000
+#define EVT_NOTIFY_WAIT 0x00000100
+#define EVT_NOTIFY_SIGNAL 0x00000200
+
+#define EVT_SIGNAL_EXIT_BOOT_SERVICES 0x00000201
+#define EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE 0x60000202
+
+//
+// The event's NotifyContext pointer points to a runtime memory
+// address.
+// The event is deprecated in UEFI2.0 and later specifications.
+//
+#define EVT_RUNTIME_CONTEXT 0x20000000
+
+
+/**
+ Invoke a notification event
+
+ @param Event Event whose notification function is being invoked.
+ @param Context Pointer to the notification function's context,
+ which is implementation-dependent.
+
+**/
+typedef
+VOID
+(EFIAPI *EFI_EVENT_NOTIFY)(
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Creates an event.
+
+ @param Type The type of event to create and its mode and attributes.
+ @param NotifyTpl The task priority level of event notifications, if needed.
+ @param NotifyFunction Pointer to the event's notification function, if any.
+ @param NotifyContext Pointer to the notification function's context; corresponds to parameter
+ Context in the notification function.
+ @param Event Pointer to the newly created event if the call succeeds; undefined
+ otherwise.
+
+ @retval EFI_SUCCESS The event structure was created.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The event could not be allocated.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CREATE_EVENT)(
+ IN UINT32 Type,
+ IN EFI_TPL NotifyTpl,
+ IN EFI_EVENT_NOTIFY NotifyFunction,
+ IN VOID *NotifyContext,
+ OUT EFI_EVENT *Event
+ );
+
+/**
+ Creates an event in a group.
+
+ @param Type The type of event to create and its mode and attributes.
+ @param NotifyTpl The task priority level of event notifications,if needed.
+ @param NotifyFunction Pointer to the event's notification function, if any.
+ @param NotifyContext Pointer to the notification function's context; corresponds to parameter
+ Context in the notification function.
+ @param EventGroup Pointer to the unique identifier of the group to which this event belongs.
+ If this is NULL, then the function behaves as if the parameters were passed
+ to CreateEvent.
+ @param Event Pointer to the newly created event if the call succeeds; undefined
+ otherwise.
+
+ @retval EFI_SUCCESS The event structure was created.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The event could not be allocated.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CREATE_EVENT_EX)(
+ IN UINT32 Type,
+ IN EFI_TPL NotifyTpl,
+ IN EFI_EVENT_NOTIFY NotifyFunction OPTIONAL,
+ IN CONST VOID *NotifyContext OPTIONAL,
+ IN CONST EFI_GUID *EventGroup OPTIONAL,
+ OUT EFI_EVENT *Event
+ );
+
+///
+/// Timer delay types
+///
+typedef enum {
+ TimerCancel,
+ TimerPeriodic,
+ TimerRelative
+} EFI_TIMER_DELAY;
+
+/**
+ Sets the type of timer and the trigger time for a timer event.
+
+ @param Event The timer event that is to be signaled at the specified time.
+ @param Type The type of time that is specified in TriggerTime.
+ @param TriggerTime The number of 100ns units until the timer expires.
+ A TriggerTime of 0 is legal.
+ If Type is TimerRelative and TriggerTime is 0, then the timer
+ event will be signaled on the next timer tick.
+ If Type is TimerPeriodic and TriggerTime is 0, then the timer
+ event will be signaled on every timer tick.
+
+ @retval EFI_SUCCESS The event has been set to be signaled at the requested time.
+ @retval EFI_INVALID_PARAMETER Event or Type is not valid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SET_TIMER)(
+ IN EFI_EVENT Event,
+ IN EFI_TIMER_DELAY Type,
+ IN UINT64 TriggerTime
+ );
+
+/**
+ Signals an event.
+
+ @param Event The event to signal.
+
+ @retval EFI_SUCCESS The event has been signaled.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIGNAL_EVENT)(
+ IN EFI_EVENT Event
+ );
+
+/**
+ Stops execution until an event is signaled.
+
+ @param NumberOfEvents The number of events in the Event array.
+ @param Event An array of EFI_EVENT.
+ @param Index Pointer to the index of the event which satisfied the wait condition.
+
+ @retval EFI_SUCCESS The event indicated by Index was signaled.
+ @retval EFI_INVALID_PARAMETER 1) NumberOfEvents is 0.
+ 2) The event indicated by Index is of type
+ EVT_NOTIFY_SIGNAL.
+ @retval EFI_UNSUPPORTED The current TPL is not TPL_APPLICATION.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_WAIT_FOR_EVENT)(
+ IN UINTN NumberOfEvents,
+ IN EFI_EVENT *Event,
+ OUT UINTN *Index
+ );
+
+/**
+ Closes an event.
+
+ @param Event The event to close.
+
+ @retval EFI_SUCCESS The event has been closed.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CLOSE_EVENT)(
+ IN EFI_EVENT Event
+ );
+
+/**
+ Checks whether an event is in the signaled state.
+
+ @param Event The event to check.
+
+ @retval EFI_SUCCESS The event is in the signaled state.
+ @retval EFI_NOT_READY The event is not in the signaled state.
+ @retval EFI_INVALID_PARAMETER Event is of type EVT_NOTIFY_SIGNAL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CHECK_EVENT)(
+ IN EFI_EVENT Event
+ );
+
+
+//
+// Task priority level
+//
+#define TPL_APPLICATION 4
+#define TPL_CALLBACK 8
+#define TPL_NOTIFY 16
+#define TPL_HIGH_LEVEL 31
+
+
+/**
+ Raises a task's priority level and returns its previous level.
+
+ @param NewTpl The new task priority level.
+
+ @return Previous task priority level
+
+**/
+typedef
+EFI_TPL
+(EFIAPI *EFI_RAISE_TPL)(
+ IN EFI_TPL NewTpl
+ );
+
+/**
+ Restores a task's priority level to its previous value.
+
+ @param OldTpl The previous task priority level to restore.
+
+**/
+typedef
+VOID
+(EFIAPI *EFI_RESTORE_TPL)(
+ IN EFI_TPL OldTpl
+ );
+
+/**
+ Returns the value of a variable.
+
+ @param VariableName A Null-terminated Unicode string that is the name of the
+ vendor's variable.
+ @param VendorGuid A unique identifier for the vendor.
+ @param Attributes If not NULL, a pointer to the memory location to return the
+ attributes bitmask for the variable.
+ @param DataSize On input, the size in bytes of the return Data buffer.
+ On output the size of data returned in Data.
+ @param Data The buffer to return the contents of the variable.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND The variable was not found.
+ @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the result.
+ @retval EFI_INVALID_PARAMETER VariableName is NULL.
+ @retval EFI_INVALID_PARAMETER VendorGuid is NULL.
+ @retval EFI_INVALID_PARAMETER DataSize is NULL.
+ @retval EFI_INVALID_PARAMETER The DataSize is not too small and Data is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error.
+ @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_VARIABLE)(
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT UINT32 *Attributes, OPTIONAL
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data
+ );
+
+/**
+ Enumerates the current variable names.
+
+ @param VariableNameSize The size of the VariableName buffer.
+ @param VariableName On input, supplies the last VariableName that was returned
+ by GetNextVariableName(). On output, returns the Nullterminated
+ Unicode string of the current variable.
+ @param VendorGuid On input, supplies the last VendorGuid that was returned by
+ GetNextVariableName(). On output, returns the
+ VendorGuid of the current variable.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND The next variable was not found.
+ @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the result.
+ @retval EFI_INVALID_PARAMETER VariableNameSize is NULL.
+ @retval EFI_INVALID_PARAMETER VariableName is NULL.
+ @retval EFI_INVALID_PARAMETER VendorGuid is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_NEXT_VARIABLE_NAME)(
+ IN OUT UINTN *VariableNameSize,
+ IN OUT CHAR16 *VariableName,
+ IN OUT EFI_GUID *VendorGuid
+ );
+
+/**
+ Sets the value of a variable.
+
+ @param VariableName A Null-terminated Unicode string that is the name of the
+ vendor's variable.
+ @param VendorGuid A unique identifier for the vendor.
+ @param Attributes Attributes bitmask to set for the variable.
+ @param DataSize The size in bytes of the Data buffer.
+ @param Data The contents for the variable.
+
+ @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as
+ defined by the Attributes.
+ @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied, or the
+ DataSize exceeds the maximum allowed.
+ @retval EFI_INVALID_PARAMETER VariableName is an empty Unicode string.
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error.
+ @retval EFI_WRITE_PROTECTED The variable in question is read-only.
+ @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted.
+ @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure.
+ @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SET_VARIABLE)(
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ );
+
+
+///
+/// This provides the capabilities of the
+/// real time clock device as exposed through the EFI interfaces.
+///
+typedef struct {
+ UINT32 Resolution;
+ UINT32 Accuracy;
+ BOOLEAN SetsToZero;
+} EFI_TIME_CAPABILITIES;
+
+/**
+ Returns the current time and date information, and the time-keeping capabilities
+ of the hardware platform.
+
+ @param Time A pointer to storage to receive a snapshot of the current time.
+ @param Capabilities An optional pointer to a buffer to receive the real time clock
+ device's capabilities.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_INVALID_PARAMETER Time is NULL.
+ @retval EFI_DEVICE_ERROR The time could not be retrieved due to hardware error.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_TIME)(
+ OUT EFI_TIME *Time,
+ OUT EFI_TIME_CAPABILITIES *Capabilities OPTIONAL
+ );
+
+/**
+ Sets the current local time and date information.
+
+ @param Time A pointer to the current time.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_INVALID_PARAMETER A time field is out of range.
+ @retval EFI_DEVICE_ERROR The time could not be set due due to hardware error.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SET_TIME)(
+ IN EFI_TIME *Time
+ );
+
+/**
+ Returns the current wakeup alarm clock setting.
+
+ @param Enabled Indicates if the alarm is currently enabled or disabled.
+ @param Pending Indicates if the alarm signal is pending and requires acknowledgement.
+ @param Time The current alarm setting.
+
+ @retval EFI_SUCCESS The alarm settings were returned.
+ @retval EFI_INVALID_PARAMETER Enabled is NULL.
+ @retval EFI_INVALID_PARAMETER Pending is NULL.
+ @retval EFI_INVALID_PARAMETER Time is NULL.
+ @retval EFI_DEVICE_ERROR The wakeup time could not be retrieved due to a hardware error.
+ @retval EFI_UNSUPPORTED A wakeup timer is not supported on this platform.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_WAKEUP_TIME)(
+ OUT BOOLEAN *Enabled,
+ OUT BOOLEAN *Pending,
+ OUT EFI_TIME *Time
+ );
+
+/**
+ Sets the system wakeup alarm clock time.
+
+ @param Enabled Enable or disable the wakeup alarm.
+ @param Time If Enable is TRUE, the time to set the wakeup alarm for.
+ If Enable is FALSE, then this parameter is optional, and may be NULL.
+
+ @retval EFI_SUCCESS If Enable is TRUE, then the wakeup alarm was enabled. If
+ Enable is FALSE, then the wakeup alarm was disabled.
+ @retval EFI_INVALID_PARAMETER A time field is out of range.
+ @retval EFI_DEVICE_ERROR The wakeup time could not be set due to a hardware error.
+ @retval EFI_UNSUPPORTED A wakeup timer is not supported on this platform.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SET_WAKEUP_TIME)(
+ IN BOOLEAN Enable,
+ IN EFI_TIME *Time OPTIONAL
+ );
+
+/**
+ This is the declaration of an EFI image entry point. This entry point is
+ the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
+ both device drivers and bus drivers.
+
+ @param ImageHandle The firmware allocated handle for the UEFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_IMAGE_ENTRY_POINT)(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+/**
+ Loads an EFI image into memory.
+
+ @param BootPolicy If TRUE, indicates that the request originates from the boot
+ manager, and that the boot manager is attempting to load
+ FilePath as a boot selection. Ignored if SourceBuffer is
+ not NULL.
+ @param ParentImageHandle The caller's image handle.
+ @param DevicePath The DeviceHandle specific file path from which the image is
+ loaded.
+ @param SourceBuffer If not NULL, a pointer to the memory location containing a copy
+ of the image to be loaded.
+ @param SourceSize The size in bytes of SourceBuffer. Ignored if SourceBuffer is NULL.
+ @param ImageHandle Pointer to the returned image handle that is created when the
+ image is successfully loaded.
+
+ @retval EFI_SUCCESS Image was loaded into memory correctly.
+ @retval EFI_NOT_FOUND Both SourceBuffer and DevicePath are NULL.
+ @retval EFI_INVALID_PARAMETER One or more parametes are invalid.
+ @retval EFI_UNSUPPORTED The image type is not supported.
+ @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient resources.
+ @retval EFI_LOAD_ERROR Image was not loaded because the image format was corrupt or not
+ understood.
+ @retval EFI_DEVICE_ERROR Image was not loaded because the device returned a read error.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_IMAGE_LOAD)(
+ IN BOOLEAN BootPolicy,
+ IN EFI_HANDLE ParentImageHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN VOID *SourceBuffer OPTIONAL,
+ IN UINTN SourceSize,
+ OUT EFI_HANDLE *ImageHandle
+ );
+
+/**
+ Transfers control to a loaded image's entry point.
+
+ @param ImageHandle Handle of image to be started.
+ @param ExitDataSize Pointer to the size, in bytes, of ExitData.
+ @param ExitData Pointer to a pointer to a data buffer that includes a Null-terminated
+ Unicode string, optionally followed by additional binary data.
+
+ @retval EFI_INVALID_PARAMETER ImageHandle is either an invalid image handle or the image
+ has already been initialized with StartImage
+ @return Exit code from image
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_IMAGE_START)(
+ IN EFI_HANDLE ImageHandle,
+ OUT UINTN *ExitDataSize,
+ OUT CHAR16 **ExitData OPTIONAL
+ );
+
+/**
+ Terminates a loaded EFI image and returns control to boot services.
+
+ @param ImageHandle Handle that identifies the image.
+ @param ExitStatus The image's exit code.
+ @param ExitDataSize The size, in bytes, of ExitData.
+ @param ExitData Pointer to a data buffer that includes a Null-terminated Unicode string,
+ optionally followed by additional binary data.
+
+ @retval EFI_SUCCESS The image specified by ImageHandle was unloaded.
+ @retval EFI_INVALID_PARAMETER The image specified by ImageHandle has been loaded and
+ started with LoadImage() and StartImage(), but the
+ image is not the currently executing image.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_EXIT)(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_STATUS ExitStatus,
+ IN UINTN ExitDataSize,
+ IN CHAR16 *ExitData OPTIONAL
+ );
+
+/**
+ Unloads an image.
+
+ @param ImageHandle Handle that identifies the image to be unloaded.
+
+ @retval EFI_SUCCESS The image has been unloaded.
+ @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle.
+ @retval EFI_UNSUPPORTED The image has been started, and does not support unload.
+ @return Exit code from the image's unload handler
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_IMAGE_UNLOAD)(
+ IN EFI_HANDLE ImageHandle
+ );
+
+/**
+ Terminates all boot services.
+
+ @param ImageHandle Handle that identifies the exiting image.
+ @param MapKey Key to the latest memory map.
+
+ @retval EFI_SUCCESS Boot services have been terminated.
+ @retval EFI_INVALID_PARAMETER MapKey is incorrect.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_EXIT_BOOT_SERVICES)(
+ IN EFI_HANDLE ImageHandle,
+ IN UINTN MapKey
+ );
+
+/**
+ Induces a fine-grained stall.
+
+ @param Microseconds The number of microseconds to stall execution.
+
+ @retval EFI_SUCCESS Execution was stalled at least the requested number of
+ Microseconds.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_STALL)(
+ IN UINTN Microseconds
+ );
+
+/**
+ Sets the system's watchdog timer.
+
+ @param Timeout The number of seconds to set the watchdog timer to.
+ @param WatchdogCode The numeric code to log on a watchdog timer timeout event.
+ @param DataSize The size, in bytes, of WatchdogData.
+ @param WatchdogData A data buffer that includes a Null-terminated Unicode string, optionally
+ followed by additional binary data.
+
+ @retval EFI_SUCCESS The timeout has been set.
+ @retval EFI_INVALID_PARAMETER The supplied WatchdogCode is invalid.
+ @retval EFI_UNSUPPORTED The system does not have a watchdog timer.
+ @retval EFI_DEVICE_ERROR The watch dog timer could not be programmed due to a hardware
+ error.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SET_WATCHDOG_TIMER)(
+ IN UINTN Timeout,
+ IN UINT64 WatchdogCode,
+ IN UINTN DataSize,
+ IN CHAR16 *WatchdogData OPTIONAL
+ );
+
+///
+/// Enumeration of reset types.
+///
+typedef enum {
+ EfiResetCold,
+ EfiResetWarm,
+ EfiResetShutdown,
+ EfiResetUpdate
+} EFI_RESET_TYPE;
+
+/**
+ Resets the entire platform.
+
+ @param ResetType The type of reset to perform.
+ @param ResetStatus The status code for the reset.
+ @param DataSize The size, in bytes, of WatchdogData.
+ @param ResetData For a ResetType of EfiResetCold, EfiResetWarm, or
+ EfiResetShutdown the data buffer starts with a Null-terminated
+ Unicode string, optionally followed by additional binary data.
+
+**/
+typedef
+VOID
+(EFIAPI *EFI_RESET_SYSTEM)(
+ IN EFI_RESET_TYPE ResetType,
+ IN EFI_STATUS ResetStatus,
+ IN UINTN DataSize,
+ IN CHAR16 *ResetData OPTIONAL
+ );
+
+/**
+ Returns a monotonically increasing count for the platform.
+
+ @param Count Pointer to returned value.
+
+ @retval EFI_SUCCESS The next monotonic count was returned.
+ @retval EFI_INVALID_PARAMETER Count is NULL.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_NEXT_MONOTONIC_COUNT)(
+ OUT UINT64 *Count
+ );
+
+/**
+ Returns the next high 32 bits of the platform's monotonic counter.
+
+ @param HighCount Pointer to returned value.
+
+ @retval EFI_SUCCESS The next high monotonic count was returned.
+ @retval EFI_INVALID_PARAMETER HighCount is NULL.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_NEXT_HIGH_MONO_COUNT)(
+ OUT UINT32 *HighCount
+ );
+
+/**
+ Computes and returns a 32-bit CRC for a data buffer.
+
+ @param Data A pointer to the buffer on which the 32-bit CRC is to be computed.
+ @param DataSize The number of bytes in the buffer Data.
+ @param Crc32 The 32-bit CRC that was computed for the data buffer specified by Data
+ and DataSize.
+
+ @retval EFI_SUCCESS The 32-bit CRC was computed for the data buffer and returned in
+ Crc32.
+ @retval EFI_INVALID_PARAMETER Data is NULL.
+ @retval EFI_INVALID_PARAMETER Crc32 is NULL.
+ @retval EFI_INVALID_PARAMETER DataSize is 0.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CALCULATE_CRC32)(
+ IN VOID *Data,
+ IN UINTN DataSize,
+ OUT UINT32 *Crc32
+ );
+
+/**
+ Copies the contents of one buffer to another buffer.
+
+ @param Destination Pointer to the destination buffer of the memory copy.
+ @param Source Pointer to the source buffer of the memory copy.
+ @param Length Number of bytes to copy from Source to Destination.
+
+**/
+typedef
+VOID
+(EFIAPI *EFI_COPY_MEM)(
+ IN VOID *Destination,
+ IN VOID *Source,
+ IN UINTN Length
+ );
+
+/**
+ The SetMem() function fills a buffer with a specified value.
+
+ @param Buffer Pointer to the buffer to fill.
+ @param Size Number of bytes in Buffer to fill.
+ @param Value Value to fill Buffer with.
+
+**/
+typedef
+VOID
+(EFIAPI *EFI_SET_MEM)(
+ IN VOID *Buffer,
+ IN UINTN Size,
+ IN UINT8 Value
+ );
+
+
+//
+// Protocol handler functions
+//
+typedef enum {
+ EFI_NATIVE_INTERFACE
+} EFI_INTERFACE_TYPE;
+
+/**
+ Installs a protocol interface on a device handle. If the handle does not exist, it is created and added
+ to the list of handles in the system. InstallMultipleProtocolInterfaces() performs
+ more error checking than InstallProtocolInterface(), so it is recommended that
+ InstallMultipleProtocolInterfaces() be used in place of
+ InstallProtocolInterface()
+
+ @param Handle A pointer to the EFI_HANDLE on which the interface is to be installed.
+ @param Protocol The numeric ID of the protocol interface.
+ @param InterfaceType Indicates whether Interface is supplied in native form.
+ @param Interface A pointer to the protocol interface.
+
+ @retval EFI_SUCCESS The protocol interface was installed.
+ @retval EFI_OUT_OF_RESOURCES Space for a new handle could not be allocated.
+ @retval EFI_INVALID_PARAMETER Handle is NULL.
+ @retval EFI_INVALID_PARAMETER Protocol is NULL.
+ @retval EFI_INVALID_PARAMETER InterfaceType is not EFI_NATIVE_INTERFACE.
+ @retval EFI_INVALID_PARAMETER Protocol is already installed on the handle specified by Handle.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_INSTALL_PROTOCOL_INTERFACE)(
+ IN OUT EFI_HANDLE *Handle,
+ IN EFI_GUID *Protocol,
+ IN EFI_INTERFACE_TYPE InterfaceType,
+ IN VOID *Interface
+ );
+
+/**
+ Installs one or more protocol interfaces into the boot services environment.
+
+ @param Handle The handle to install the new protocol interfaces on, or NULL if a new
+ handle is to be allocated.
+ @param ... A variable argument list containing pairs of protocol GUIDs and protocol
+ interfaces.
+
+ @retval EFI_SUCCESS All the protocol interface was installed.
+ @retval EFI_OUT_OF_RESOURCES There was not enough memory in pool to install all the protocols.
+ @retval EFI_ALREADY_STARTED A Device Path Protocol instance was passed in that is already present in
+ the handle database.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES)(
+ IN OUT EFI_HANDLE *Handle,
+ ...
+ );
+
+/**
+ Reinstalls a protocol interface on a device handle.
+
+ @param Handle Handle on which the interface is to be reinstalled.
+ @param Protocol The numeric ID of the interface.
+ @param OldInterface A pointer to the old interface. NULL can be used if a structure is not
+ associated with Protocol.
+ @param NewInterface A pointer to the new interface.
+
+ @retval EFI_SUCCESS The protocol interface was reinstalled.
+ @retval EFI_NOT_FOUND The OldInterface on the handle was not found.
+ @retval EFI_ACCESS_DENIED The protocol interface could not be reinstalled,
+ because OldInterface is still being used by a
+ driver that will not release it.
+ @retval EFI_INVALID_PARAMETER Handle is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER Protocol is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_REINSTALL_PROTOCOL_INTERFACE)(
+ IN EFI_HANDLE Handle,
+ IN EFI_GUID *Protocol,
+ IN VOID *OldInterface,
+ IN VOID *NewInterface
+ );
+
+/**
+ Removes a protocol interface from a device handle. It is recommended that
+ UninstallMultipleProtocolInterfaces() be used in place of
+ UninstallProtocolInterface().
+
+ @param Handle The handle on which the interface was installed.
+ @param Protocol The numeric ID of the interface.
+ @param Interface A pointer to the interface.
+
+ @retval EFI_SUCCESS The interface was removed.
+ @retval EFI_NOT_FOUND The interface was not found.
+ @retval EFI_ACCESS_DENIED The interface was not removed because the interface
+ is still being used by a driver.
+ @retval EFI_INVALID_PARAMETER Handle is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER Protocol is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_UNINSTALL_PROTOCOL_INTERFACE)(
+ IN EFI_HANDLE Handle,
+ IN EFI_GUID *Protocol,
+ IN VOID *Interface
+ );
+
+/**
+ Removes one or more protocol interfaces into the boot services environment.
+
+ @param Handle The handle to remove the protocol interfaces from.
+ @param ... A variable argument list containing pairs of protocol GUIDs and
+ protocol interfaces.
+
+ @retval EFI_SUCCESS All the protocol interfaces were removed.
+ @retval EFI_INVALID_PARAMETER One of the protocol interfaces was not previously installed on Handle.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES)(
+ IN EFI_HANDLE Handle,
+ ...
+ );
+
+/**
+ Queries a handle to determine if it supports a specified protocol.
+
+ @param Handle The handle being queried.
+ @param Protocol The published unique identifier of the protocol.
+ @param Interface Supplies the address where a pointer to the corresponding Protocol
+ Interface is returned.
+
+ @retval EFI_SUCCESS The interface information for the specified protocol was returned.
+ @retval EFI_UNSUPPORTED The device does not support the specified protocol.
+ @retval EFI_INVALID_PARAMETER Handle is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER Protocol is NULL.
+ @retval EFI_INVALID_PARAMETER Interface is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_HANDLE_PROTOCOL)(
+ IN EFI_HANDLE Handle,
+ IN EFI_GUID *Protocol,
+ OUT VOID **Interface
+ );
+
+#define EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL 0x00000001
+#define EFI_OPEN_PROTOCOL_GET_PROTOCOL 0x00000002
+#define EFI_OPEN_PROTOCOL_TEST_PROTOCOL 0x00000004
+#define EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 0x00000008
+#define EFI_OPEN_PROTOCOL_BY_DRIVER 0x00000010
+#define EFI_OPEN_PROTOCOL_EXCLUSIVE 0x00000020
+
+/**
+ Queries a handle to determine if it supports a specified protocol. If the protocol is supported by the
+ handle, it opens the protocol on behalf of the calling agent.
+
+ @param Handle The handle for the protocol interface that is being opened.
+ @param Protocol The published unique identifier of the protocol.
+ @param Interface Supplies the address where a pointer to the corresponding Protocol
+ Interface is returned.
+ @param AgentHandle The handle of the agent that is opening the protocol interface
+ specified by Protocol and Interface.
+ @param ControllerHandle If the agent that is opening a protocol is a driver that follows the
+ UEFI Driver Model, then this parameter is the controller handle
+ that requires the protocol interface. If the agent does not follow
+ the UEFI Driver Model, then this parameter is optional and may
+ be NULL.
+ @param Attributes The open mode of the protocol interface specified by Handle
+ and Protocol.
+
+ @retval EFI_SUCCESS An item was added to the open list for the protocol interface, and the
+ protocol interface was returned in Interface.
+ @retval EFI_UNSUPPORTED Handle does not support Protocol.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_ACCESS_DENIED Required attributes can't be supported in current environment.
+ @retval EFI_ALREADY_STARTED Item on the open list already has requierd attributes whose agent
+ handle is the same as AgentHandle.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_OPEN_PROTOCOL)(
+ IN EFI_HANDLE Handle,
+ IN EFI_GUID *Protocol,
+ OUT VOID **Interface, OPTIONAL
+ IN EFI_HANDLE AgentHandle,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINT32 Attributes
+ );
+
+
+/**
+ Closes a protocol on a handle that was opened using OpenProtocol().
+
+ @param Handle The handle for the protocol interface that was previously opened
+ with OpenProtocol(), and is now being closed.
+ @param Protocol The published unique identifier of the protocol.
+ @param AgentHandle The handle of the agent that is closing the protocol interface.
+ @param ControllerHandle If the agent that opened a protocol is a driver that follows the
+ UEFI Driver Model, then this parameter is the controller handle
+ that required the protocol interface.
+
+ @retval EFI_SUCCESS The protocol instance was closed.
+ @retval EFI_INVALID_PARAMETER 1) Handle is not a valid EFI_HANDLE.
+ 2) AgentHandle is not a valid EFI_HANDLE.
+ 3) ControllerHandle is not NULL and ControllerHandle is not a valid EFI_HANDLE.
+ 4) Protocol is NULL.
+ @retval EFI_NOT_FOUND 1) Handle does not support the protocol specified by Protocol.
+ 2) The protocol interface specified by Handle and Protocol is not
+ currently open by AgentHandle and ControllerHandle.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CLOSE_PROTOCOL)(
+ IN EFI_HANDLE Handle,
+ IN EFI_GUID *Protocol,
+ IN EFI_HANDLE AgentHandle,
+ IN EFI_HANDLE ControllerHandle
+ );
+
+
+typedef struct {
+ EFI_HANDLE AgentHandle;
+ EFI_HANDLE ControllerHandle;
+ UINT32 Attributes;
+ UINT32 OpenCount;
+} EFI_OPEN_PROTOCOL_INFORMATION_ENTRY;
+
+/**
+ Retrieves the list of agents that currently have a protocol interface opened.
+
+ @param Handle The handle for the protocol interface that is being queried.
+ @param Protocol The published unique identifier of the protocol.
+ @param EntryBuffer A pointer to a buffer of open protocol information in the form of
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY structures.
+ @param EntryCount A pointer to the number of entries in EntryBuffer.
+
+ @retval EFI_SUCCESS The open protocol information was returned in EntryBuffer, and the
+ number of entries was returned EntryCount.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to allocate EntryBuffer.
+ @retval EFI_NOT_FOUND Handle does not support the protocol specified by Protocol.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_OPEN_PROTOCOL_INFORMATION)(
+ IN EFI_HANDLE Handle,
+ IN EFI_GUID *Protocol,
+ OUT EFI_OPEN_PROTOCOL_INFORMATION_ENTRY **EntryBuffer,
+ OUT UINTN *EntryCount
+ );
+
+/**
+ Retrieves the list of protocol interface GUIDs that are installed on a handle in a buffer allocated
+ from pool.
+
+ @param Handle The handle from which to retrieve the list of protocol interface
+ GUIDs.
+ @param ProtocolBuffer A pointer to the list of protocol interface GUID pointers that are
+ installed on Handle.
+ @param ProtocolBufferCount A pointer to the number of GUID pointers present in
+ ProtocolBuffer.
+
+ @retval EFI_SUCCESS The list of protocol interface GUIDs installed on Handle was returned in
+ ProtocolBuffer. The number of protocol interface GUIDs was
+ returned in ProtocolBufferCount.
+ @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the results.
+ @retval EFI_INVALID_PARAMETER Handle is NULL.
+ @retval EFI_INVALID_PARAMETER Handle is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER ProtocolBuffer is NULL.
+ @retval EFI_INVALID_PARAMETER ProtocolBufferCount is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PROTOCOLS_PER_HANDLE)(
+ IN EFI_HANDLE Handle,
+ OUT EFI_GUID ***ProtocolBuffer,
+ OUT UINTN *ProtocolBufferCount
+ );
+
+/**
+ Creates an event that is to be signaled whenever an interface is installed for a specified protocol.
+
+ @param Protocol The numeric ID of the protocol for which the event is to be registered.
+ @param Event Event that is to be signaled whenever a protocol interface is registered
+ for Protocol.
+ @param Registration A pointer to a memory location to receive the registration value.
+
+ @retval EFI_SUCCESS The notification event has been registered.
+ @retval EFI_OUT_OF_RESOURCES Space for the notification event could not be allocated.
+ @retval EFI_INVALID_PARAMETER Protocol is NULL.
+ @retval EFI_INVALID_PARAMETER Event is NULL.
+ @retval EFI_INVALID_PARAMETER Registration is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_REGISTER_PROTOCOL_NOTIFY)(
+ IN EFI_GUID *Protocol,
+ IN EFI_EVENT Event,
+ OUT VOID **Registration
+ );
+
+
+typedef enum {
+ AllHandles,
+ ByRegisterNotify,
+ ByProtocol
+} EFI_LOCATE_SEARCH_TYPE;
+
+/**
+ Returns an array of handles that support a specified protocol.
+
+ @param SearchType Specifies which handle(s) are to be returned.
+ @param Protocol Specifies the protocol to search by.
+ @param SearchKey Specifies the search key.
+ @param BufferSize On input, the size in bytes of Buffer. On output, the size in bytes of
+ the array returned in Buffer (if the buffer was large enough) or the
+ size, in bytes, of the buffer needed to obtain the array (if the buffer was
+ not large enough).
+ @param Buffer The buffer in which the array is returned.
+
+ @retval EFI_SUCCESS The array of handles was returned.
+ @retval EFI_NOT_FOUND No handles match the search.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small for the result.
+ @retval EFI_INVALID_PARAMETER SearchType is not a member of EFI_LOCATE_SEARCH_TYPE.
+ @retval EFI_INVALID_PARAMETER SearchType is ByRegisterNotify and SearchKey is NULL.
+ @retval EFI_INVALID_PARAMETER SearchType is ByProtocol and Protocol is NULL.
+ @retval EFI_INVALID_PARAMETER One or more matches are found and BufferSize is NULL.
+ @retval EFI_INVALID_PARAMETER BufferSize is large enough for the result and Buffer is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_LOCATE_HANDLE)(
+ IN EFI_LOCATE_SEARCH_TYPE SearchType,
+ IN EFI_GUID *Protocol, OPTIONAL
+ IN VOID *SearchKey, OPTIONAL
+ IN OUT UINTN *BufferSize,
+ OUT EFI_HANDLE *Buffer
+ );
+
+/**
+ Locates the handle to a device on the device path that supports the specified protocol.
+
+ @param Protocol Specifies the protocol to search for.
+ @param DevicePath On input, a pointer to a pointer to the device path. On output, the device
+ path pointer is modified to point to the remaining part of the device
+ path.
+ @param Device A pointer to the returned device handle.
+
+ @retval EFI_SUCCESS The resulting handle was returned.
+ @retval EFI_NOT_FOUND No handles match the search.
+ @retval EFI_INVALID_PARAMETER Protocol is NULL.
+ @retval EFI_INVALID_PARAMETER DevicePath is NULL.
+ @retval EFI_INVALID_PARAMETER A handle matched the search and Device is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_LOCATE_DEVICE_PATH)(
+ IN EFI_GUID *Protocol,
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
+ OUT EFI_HANDLE *Device
+ );
+
+/**
+ Adds, updates, or removes a configuration table entry from the EFI System Table.
+
+ @param Guid A pointer to the GUID for the entry to add, update, or remove.
+ @param Table A pointer to the configuration table for the entry to add, update, or
+ remove. May be NULL.
+
+ @retval EFI_SUCCESS The (Guid, Table) pair was added, updated, or removed.
+ @retval EFI_NOT_FOUND An attempt was made to delete a nonexistent entry.
+ @retval EFI_INVALID_PARAMETER Guid is not valid.
+ @retval EFI_OUT_OF_RESOURCES There is not enough memory available to complete the operation.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_INSTALL_CONFIGURATION_TABLE)(
+ IN EFI_GUID *Guid,
+ IN VOID *Table
+ );
+
+
+/**
+ Returns an array of handles that support the requested protocol in a buffer allocated from pool.
+
+ @param SearchType Specifies which handle(s) are to be returned.
+ @param Protocol Provides the protocol to search by.
+ This parameter is only valid for a SearchType of ByProtocol.
+ @param SearchKey Supplies the search key depending on the SearchType.
+ @param NoHandles The number of handles returned in Buffer.
+ @param Buffer A pointer to the buffer to return the requested array of handles that
+ support Protocol.
+
+ @retval EFI_SUCCESS The array of handles was returned in Buffer, and the number of
+ handles in Buffer was returned in NoHandles.
+ @retval EFI_NOT_FOUND No handles match the search.
+ @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results.
+ @retval EFI_INVALID_PARAMETER NoHandles is NULL.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_LOCATE_HANDLE_BUFFER)(
+ IN EFI_LOCATE_SEARCH_TYPE SearchType,
+ IN EFI_GUID *Protocol, OPTIONAL
+ IN VOID *SearchKey, OPTIONAL
+ IN OUT UINTN *NoHandles,
+ OUT EFI_HANDLE **Buffer
+ );
+
+/**
+ Returns the first protocol instance that matches the given protocol.
+
+ @param Protocol Provides the protocol to search for.
+ @param Registration Optional registration key returned from
+ RegisterProtocolNotify().
+ @param Interface On return, a pointer to the first interface that matches Protocol and
+ Registration.
+
+ @retval EFI_SUCCESS A protocol instance matching Protocol was found and returned in
+ Interface.
+ @retval EFI_NOT_FOUND No protocol instances were found that match Protocol and
+ Registration.
+ @retval EFI_INVALID_PARAMETER Interface is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_LOCATE_PROTOCOL)(
+ IN EFI_GUID *Protocol,
+ IN VOID *Registration, OPTIONAL
+ OUT VOID **Interface
+ );
+
+typedef struct {
+ UINT64 Length;
+ union {
+ EFI_PHYSICAL_ADDRESS DataBlock;
+ EFI_PHYSICAL_ADDRESS ContinuationPointer;
+ } Union;
+} EFI_CAPSULE_BLOCK_DESCRIPTOR;
+
+typedef struct {
+ EFI_GUID CapsuleGuid;
+ UINT32 HeaderSize;
+ UINT32 Flags;
+ UINT32 CapsuleImageSize;
+} EFI_CAPSULE_HEADER;
+
+//
+// The EFI System Table entry must point to an array of capsules
+// that contain the same CapsuleGuid value. The array must be
+// prefixed by a UINT32 that represents the size of the array of capsules.
+//
+typedef struct {
+ UINT32 CapsuleArrayNumber;
+ VOID* CapsulePtr[1];
+} EFI_CAPSULE_TABLE;
+
+#define CAPSULE_FLAGS_PERSIST_ACROSS_RESET 0x00010000
+#define CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE 0x00020000
+
+/**
+ Passes capsules to the firmware with both virtual and physical mapping. Depending on the intended
+ consumption, the firmware may process the capsule immediately. If the payload should persist
+ across a system reset, the reset value returned from EFI_QueryCapsuleCapabilities must
+ be passed into ResetSystem() and will cause the capsule to be processed by the firmware as
+ part of the reset process.
+
+ @param CapsuleHeaderArray Virtual pointer to an array of virtual pointers to the capsules
+ being passed into update capsule.
+ @param CapsuleCount Number of pointers to EFI_CAPSULE_HEADER in
+ CaspuleHeaderArray.
+ @param ScatterGatherList Physical pointer to a set of
+ EFI_CAPSULE_BLOCK_DESCRIPTOR that describes the
+ location in physical memory of a set of capsules.
+
+ @retval EFI_SUCCESS Valid capsule was passed. If
+ CAPSULE_FLAGS_PERSIT_ACROSS_RESET is not set, the
+ capsule has been successfully processed by the firmware.
+ @retval EFI_DEVICE_ERROR The capsule update was started, but failed due to a device error.
+ @retval EFI_INVALID_PARAMETER CapsuleSize is NULL.
+ @retval EFI_UNSUPPORTED The capsule type is not supported on this platform.
+ @retval EFI_OUT_OF_RESOURCES There were insufficient resources to process the capsule.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_UPDATE_CAPSULE)(
+ IN EFI_CAPSULE_HEADER **CapsuleHeaderArray,
+ IN UINTN CapsuleCount,
+ IN EFI_PHYSICAL_ADDRESS ScatterGatherList OPTIONAL
+ );
+
+/**
+ Returns if the capsule can be supported via UpdateCapsule().
+
+ @param CapsuleHeaderArray Virtual pointer to an array of virtual pointers to the capsules
+ being passed into update capsule.
+ @param CapsuleCount Number of pointers to EFI_CAPSULE_HEADER in
+ CaspuleHeaderArray.
+ @param MaxiumCapsuleSize On output the maximum size that UpdateCapsule() can
+ support as an argument to UpdateCapsule() via
+ CapsuleHeaderArray and ScatterGatherList.
+ @param ResetType Returns the type of reset required for the capsule update.
+
+ @retval EFI_SUCCESS Valid answer returned.
+ @retval EFI_UNSUPPORTED The capsule type is not supported on this platform, and
+ MaximumCapsuleSize and ResetType are undefined.
+ @retval EFI_INVALID_PARAMETER MaximumCapsuleSize is NULL.
+ @retval EFI_OUT_OF_RESOURCES There were insufficient resources to process the query request.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_QUERY_CAPSULE_CAPABILITIES)(
+ IN EFI_CAPSULE_HEADER **CapsuleHeaderArray,
+ IN UINTN CapsuleCount,
+ OUT UINT64 *MaximumCapsuleSize,
+ OUT EFI_RESET_TYPE *ResetType
+ );
+
+/**
+ Returns information about the EFI variables.
+
+ @param Attributes Attributes bitmask to specify the type of variables on
+ which to return information.
+ @param MaximumVariableStorageSize On output the maximum size of the storage space
+ available for the EFI variables associated with the
+ attributes specified.
+ @param RemainingVariableStorageSize Returns the remaining size of the storage space
+ available for the EFI variables associated with the
+ attributes specified.
+ @param MaximumVariableSize Returns the maximum size of the individual EFI
+ variables associated with the attributes specified.
+
+ @retval EFI_SUCCESS Valid answer returned.
+ @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied
+ @retval EFI_UNSUPPORTED The attribute is not supported on this platform, and the
+ MaximumVariableStorageSize,
+ RemainingVariableStorageSize, MaximumVariableSize
+ are undefined.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_QUERY_VARIABLE_INFO)(
+ IN UINT32 Attributes,
+ OUT UINT64 *MaximumVariableStorageSize,
+ OUT UINT64 *RemainingVariableStorageSize,
+ OUT UINT64 *MaximumVariableSize
+ );
+
+
+//
+// EFI Runtime Services Table
+//
+#define EFI_SYSTEM_TABLE_SIGNATURE 0x5453595320494249ULL
+#define EFI_SYSTEM_TABLE_REVISION ((2<<16) | (10))
+#define EFI_2_10_SYSTEM_TABLE_REVISION ((2<<16) | (10))
+#define EFI_2_00_SYSTEM_TABLE_REVISION ((2<<16) | (00))
+#define EFI_1_10_SYSTEM_TABLE_REVISION ((1<<16) | (10))
+#define EFI_1_02_SYSTEM_TABLE_REVISION ((1<<16) | (02))
+
+#define EFI_RUNTIME_SERVICES_SIGNATURE 0x56524553544e5552ULL
+#define EFI_RUNTIME_SERVICES_REVISION EFI_2_10_SYSTEM_TABLE_REVISION
+
+///
+/// EFI Runtime Services Table
+///
+typedef struct {
+ ///
+ /// The table header for the EFI Runtime Services Table.
+ ///
+ EFI_TABLE_HEADER Hdr;
+
+ //
+ // Time Services
+ //
+ EFI_GET_TIME GetTime;
+ EFI_SET_TIME SetTime;
+ EFI_GET_WAKEUP_TIME GetWakeupTime;
+ EFI_SET_WAKEUP_TIME SetWakeupTime;
+
+ //
+ // Virtual Memory Services
+ //
+ EFI_SET_VIRTUAL_ADDRESS_MAP SetVirtualAddressMap;
+ EFI_CONVERT_POINTER ConvertPointer;
+
+ //
+ // Variable Services
+ //
+ EFI_GET_VARIABLE GetVariable;
+ EFI_GET_NEXT_VARIABLE_NAME GetNextVariableName;
+ EFI_SET_VARIABLE SetVariable;
+
+ //
+ // Miscellaneous Services
+ //
+ EFI_GET_NEXT_HIGH_MONO_COUNT GetNextHighMonotonicCount;
+ EFI_RESET_SYSTEM ResetSystem;
+
+ //
+ // UEFI 2.0 Capsule Services
+ //
+ EFI_UPDATE_CAPSULE UpdateCapsule;
+ EFI_QUERY_CAPSULE_CAPABILITIES QueryCapsuleCapabilities;
+
+ //
+ // Miscellaneous UEFI 2.0 Service
+ //
+ EFI_QUERY_VARIABLE_INFO QueryVariableInfo;
+} EFI_RUNTIME_SERVICES;
+
+
+#define EFI_BOOT_SERVICES_SIGNATURE 0x56524553544f4f42ULL
+#define EFI_BOOT_SERVICES_REVISION EFI_2_10_SYSTEM_TABLE_REVISION
+
+///
+/// EFI Boot Services Table
+///
+typedef struct {
+ ///
+ /// The table header for the EFI Boot Services Table.
+ ///
+ EFI_TABLE_HEADER Hdr;
+
+ //
+ // Task Priority Services
+ //
+ EFI_RAISE_TPL RaiseTPL;
+ EFI_RESTORE_TPL RestoreTPL;
+
+ //
+ // Memory Services
+ //
+ EFI_ALLOCATE_PAGES AllocatePages;
+ EFI_FREE_PAGES FreePages;
+ EFI_GET_MEMORY_MAP GetMemoryMap;
+ EFI_ALLOCATE_POOL AllocatePool;
+ EFI_FREE_POOL FreePool;
+
+ //
+ // Event & Timer Services
+ //
+ EFI_CREATE_EVENT CreateEvent;
+ EFI_SET_TIMER SetTimer;
+ EFI_WAIT_FOR_EVENT WaitForEvent;
+ EFI_SIGNAL_EVENT SignalEvent;
+ EFI_CLOSE_EVENT CloseEvent;
+ EFI_CHECK_EVENT CheckEvent;
+
+ //
+ // Protocol Handler Services
+ //
+ EFI_INSTALL_PROTOCOL_INTERFACE InstallProtocolInterface;
+ EFI_REINSTALL_PROTOCOL_INTERFACE ReinstallProtocolInterface;
+ EFI_UNINSTALL_PROTOCOL_INTERFACE UninstallProtocolInterface;
+ EFI_HANDLE_PROTOCOL HandleProtocol;
+ VOID *Reserved;
+ EFI_REGISTER_PROTOCOL_NOTIFY RegisterProtocolNotify;
+ EFI_LOCATE_HANDLE LocateHandle;
+ EFI_LOCATE_DEVICE_PATH LocateDevicePath;
+ EFI_INSTALL_CONFIGURATION_TABLE InstallConfigurationTable;
+
+ //
+ // Image Services
+ //
+ EFI_IMAGE_LOAD LoadImage;
+ EFI_IMAGE_START StartImage;
+ EFI_EXIT Exit;
+ EFI_IMAGE_UNLOAD UnloadImage;
+ EFI_EXIT_BOOT_SERVICES ExitBootServices;
+
+ //
+ // Miscellaneous Services
+ //
+ EFI_GET_NEXT_MONOTONIC_COUNT GetNextMonotonicCount;
+ EFI_STALL Stall;
+ EFI_SET_WATCHDOG_TIMER SetWatchdogTimer;
+
+ //
+ // DriverSupport Services
+ //
+ EFI_CONNECT_CONTROLLER ConnectController;
+ EFI_DISCONNECT_CONTROLLER DisconnectController;
+
+ //
+ // Open and Close Protocol Services
+ //
+ EFI_OPEN_PROTOCOL OpenProtocol;
+ EFI_CLOSE_PROTOCOL CloseProtocol;
+ EFI_OPEN_PROTOCOL_INFORMATION OpenProtocolInformation;
+
+ //
+ // Library Services
+ //
+ EFI_PROTOCOLS_PER_HANDLE ProtocolsPerHandle;
+ EFI_LOCATE_HANDLE_BUFFER LocateHandleBuffer;
+ EFI_LOCATE_PROTOCOL LocateProtocol;
+ EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES InstallMultipleProtocolInterfaces;
+ EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES UninstallMultipleProtocolInterfaces;
+
+ //
+ // 32-bit CRC Services
+ //
+ EFI_CALCULATE_CRC32 CalculateCrc32;
+
+ //
+ // Miscellaneous Services
+ //
+ EFI_COPY_MEM CopyMem;
+ EFI_SET_MEM SetMem;
+ EFI_CREATE_EVENT_EX CreateEventEx;
+} EFI_BOOT_SERVICES;
+
+///
+/// Contains a set of GUID/pointer pairs comprised of the ConfigurationTable field in the
+/// EFI System Table.
+///
+typedef struct{
+ ///
+ /// The 128-bit GUID value that uniquely identifies the system configuration table.
+ ///
+ EFI_GUID VendorGuid;
+ ///
+ /// A pointer to the table associated with VendorGuid.
+ ///
+ VOID *VendorTable;
+} EFI_CONFIGURATION_TABLE;
+
+///
+/// EFI System Table
+///
+struct _EFI_SYSTEM_TABLE {
+ ///
+ /// The table header for the EFI System Table.
+ ///
+ EFI_TABLE_HEADER Hdr;
+ ///
+ /// A pointer to a null terminated Unicode string that identifies
+ /// the vendor that produces the system firmware for the platform.
+ ///
+ CHAR16 *FirmwareVendor;
+ ///
+ /// A firmware vendor specific value that identifies the revision
+ /// of the system firmware for the platform.
+ ///
+ UINT32 FirmwareRevision;
+ ///
+ /// The handle for the active console input device.
+ ///
+ EFI_HANDLE ConsoleInHandle;
+ ///
+ /// A pointer to the SIMPLE_INPUT_PROTOCOL interface that is
+ /// associated with ConsoleInHandle.
+ ///
+ EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ConIn;
+ ///
+ /// The handle for the active console output device.
+ ///
+ EFI_HANDLE ConsoleOutHandle;
+ ///
+ /// A pointer to the SIMPLE_TEXT_OUTPUT_PROTOCOL interface
+ /// that is associated with ConsoleOutHandle.
+ ///
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
+ ///
+ /// The handle for the active standard error console device.
+ ///
+ EFI_HANDLE StandardErrorHandle;
+ ///
+ /// A pointer to the SIMPLE_TEXT_OUTPUT_PROTOCOL interface
+ /// that is associated with StandardErrorHandle.
+ ///
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *StdErr;
+ ///
+ /// A pointer to the EFI Runtime Services Table.
+ ///
+ EFI_RUNTIME_SERVICES *RuntimeServices;
+ ///
+ /// A pointer to the EFI Boot Services Table.
+ ///
+ EFI_BOOT_SERVICES *BootServices;
+ ///
+ /// The number of system configuration tables in the buffer ConfigurationTable.
+ ///
+ UINTN NumberOfTableEntries;
+ ///
+ /// A pointer to the system configuration tables.
+ /// The number of entries in the table is NumberOfTableEntries.
+ ///
+ EFI_CONFIGURATION_TABLE *ConfigurationTable;
+};
+
+//
+// EFI Load Options Attributes
+//
+#define LOAD_OPTION_ACTIVE 0x00000001
+#define LOAD_OPTION_FORCE_RECONNECT 0x00000002
+#define LOAD_OPTION_HIDDEN 0x00000008
+#define LOAD_OPTION_CATEGORY 0x00001F00
+
+#define LOAD_OPTION_CATEGORY_BOOT 0x00000000
+#define LOAD_OPTION_CATEGORY_APP 0x00000100
+
+#define EFI_BOOT_OPTION_SUPPORT_KEY 0x00000001
+#define EFI_BOOT_OPTION_SUPPORT_APP 0x00000002
+#define EFI_BOOT_OPTION_SUPPORT_COUNT 0x00000300
+
+typedef union {
+ struct {
+ UINT32 Revision : 8;
+ UINT32 ShiftPressed : 1;
+ UINT32 ControlPressed : 1;
+ UINT32 AltPressed : 1;
+ UINT32 LogoPressed : 1;
+ UINT32 MenuPressed : 1;
+ UINT32 SysReqPessed : 1;
+ UINT32 Reserved : 16;
+ UINT32 InputKeyCount : 2;
+ } Options;
+ UINT32 PackedValue;
+} HOT_KEY_EFI_KEY_DATA;
+
+typedef struct {
+ HOT_KEY_EFI_KEY_DATA KeyOptions;
+ UINT32 BootOptionCrc;
+ UINT16 BootOption;
+//EFI_INPUT_KEY Keys[];
+} EFI_KEY_OPTION;
+
+#define EFI_KEY_OPTION_SHIFT 0x00000001
+#define EFI_KEY_OPTION_CONTROL 0x00000002
+#define EFI_KEY_OPTION_ALT 0x00000004
+#define EFI_KEY_OPTION_LOGO 0x00000008
+#define EFI_KEY_OPTION_MENU 0x00000010
+#define EFI_KEY_OPTION_SYSREQ 0x00000020
+#define EFI_KEY_CODE_COUNT 0x00000300
+
+
+//
+// EFI File location to boot from on removable media devices
+//
+#define EFI_REMOVABLE_MEDIA_FILE_NAME_IA32 L"\\EFI\\BOOT\\BOOTIA32.EFI"
+#define EFI_REMOVABLE_MEDIA_FILE_NAME_IA64 L"\\EFI\\BOOT\\BOOTIA64.EFI"
+#define EFI_REMOVABLE_MEDIA_FILE_NAME_X64 L"\\EFI\\BOOT\\BOOTX64.EFI"
+
+#if defined (MDE_CPU_IA32)
+ #define EFI_REMOVABLE_MEDIA_FILE_NAME EFI_REMOVABLE_MEDIA_FILE_NAME_IA32
+#elif defined (MDE_CPU_IPF)
+ #define EFI_REMOVABLE_MEDIA_FILE_NAME EFI_REMOVABLE_MEDIA_FILE_NAME_IA64
+#elif defined (MDE_CPU_X64)
+ #define EFI_REMOVABLE_MEDIA_FILE_NAME EFI_REMOVABLE_MEDIA_FILE_NAME_X64
+#elif defined (MDE_CPU_EBC)
+#else
+ #error Unknown Processor Type
+#endif
+
+#include <gpxe/efi/Uefi/UefiPxe.h>
+#include <gpxe/efi/Uefi/UefiGpt.h>
+#include <gpxe/efi/Uefi/UefiInternalFormRepresentation.h>
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/X64/ProcessorBind.h b/gpxe/src/include/gpxe/efi/X64/ProcessorBind.h
new file mode 100644
index 00000000..fe6c413b
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/X64/ProcessorBind.h
@@ -0,0 +1,247 @@
+/** @file
+ Processor or Compiler specific defines and types x64 (Intel(r) EM64T, AMD64).
+
+ Copyright (c) 2006, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __PROCESSOR_BIND_H__
+#define __PROCESSOR_BIND_H__
+
+///
+/// Define the processor type so other code can make processor based choices
+///
+#define MDE_CPU_X64
+
+
+//
+// Make sure we are useing the correct packing rules per EFI specification
+//
+#ifndef __GNUC__
+#pragma pack()
+#endif
+
+
+#if __INTEL_COMPILER
+//
+// Disable ICC's remark #869: "Parameter" was never referenced warning.
+// This is legal ANSI C code so we disable the remark that is turned on with -Wall
+//
+#pragma warning ( disable : 869 )
+
+//
+// Disable ICC's remark #1418: external function definition with no prior declaration.
+// This is legal ANSI C code so we disable the remark that is turned on with /W4
+//
+#pragma warning ( disable : 1418 )
+
+//
+// Disable ICC's remark #1419: external declaration in primary source file
+// This is legal ANSI C code so we disable the remark that is turned on with /W4
+//
+#pragma warning ( disable : 1419 )
+
+#endif
+
+
+#if _MSC_EXTENSIONS
+
+//
+// Disable warning that make it impossible to compile at /W4
+// This only works for Microsoft* tools
+//
+
+//
+// Disabling bitfield type checking warnings.
+//
+#pragma warning ( disable : 4214 )
+
+//
+// Disabling the unreferenced formal parameter warnings.
+//
+#pragma warning ( disable : 4100 )
+
+//
+// Disable slightly different base types warning as CHAR8 * can not be set
+// to a constant string.
+//
+#pragma warning ( disable : 4057 )
+
+//
+// ASSERT(FALSE) or while (TRUE) are legal constructes so supress this warning
+//
+#pragma warning ( disable : 4127 )
+
+//
+// This warning is caused by functions defined but not used. For precompiled header only.
+//
+#pragma warning ( disable : 4505 )
+
+//
+// This warning is caused by empty (after preprocessing) souce file. For precompiled header only.
+//
+#pragma warning ( disable : 4206 )
+
+#endif
+
+
+#if !defined(__GNUC__) && (__STDC_VERSION__ < 199901L)
+ //
+ // No ANSI C 2000 stdint.h integer width declarations, so define equivalents
+ //
+
+ #if _MSC_EXTENSIONS
+
+
+ //
+ // use Microsoft C complier dependent interger width types
+ //
+ typedef unsigned __int64 UINT64;
+ typedef __int64 INT64;
+ typedef unsigned __int32 UINT32;
+ typedef __int32 INT32;
+ typedef unsigned short UINT16;
+ typedef unsigned short CHAR16;
+ typedef short INT16;
+ typedef unsigned char BOOLEAN;
+ typedef unsigned char UINT8;
+ typedef char CHAR8;
+ typedef char INT8;
+ #else
+ #ifdef _EFI_P64
+ //
+ // P64 - is Intel Itanium(TM) speak for pointers being 64-bit and longs and ints
+ // are 32-bits
+ //
+ typedef unsigned long long UINT64;
+ typedef long long INT64;
+ typedef unsigned int UINT32;
+ typedef int INT32;
+ typedef unsigned short CHAR16;
+ typedef unsigned short UINT16;
+ typedef short INT16;
+ typedef unsigned char BOOLEAN;
+ typedef unsigned char UINT8;
+ typedef char CHAR8;
+ typedef char INT8;
+ #else
+ //
+ // Assume LP64 - longs and pointers are 64-bit. Ints are 32-bit.
+ //
+ typedef unsigned long UINT64;
+ typedef long INT64;
+ typedef unsigned int UINT32;
+ typedef int INT32;
+ typedef unsigned short UINT16;
+ typedef unsigned short CHAR16;
+ typedef short INT16;
+ typedef unsigned char BOOLEAN;
+ typedef unsigned char UINT8;
+ typedef char CHAR8;
+ typedef char INT8;
+ #endif
+ #endif
+
+ #define UINT8_MAX 0xff
+
+#else
+ //
+ // Use ANSI C 2000 stdint.h integer width declarations
+ //
+ #include <stdint.h>
+ typedef uint8_t BOOLEAN;
+ typedef int8_t INT8;
+ typedef uint8_t UINT8;
+ typedef int16_t INT16;
+ typedef uint16_t UINT16;
+ typedef int32_t INT32;
+ typedef uint32_t UINT32;
+ typedef int64_t INT64;
+ typedef uint64_t UINT64;
+ typedef char CHAR8;
+ typedef uint16_t CHAR16;
+
+#endif
+
+typedef UINT64 UINTN;
+typedef INT64 INTN;
+
+
+//
+// Processor specific defines
+//
+#define MAX_BIT 0x8000000000000000ULL
+#define MAX_2_BITS 0xC000000000000000ULL
+
+//
+// Maximum legal X64 address
+//
+#define MAX_ADDRESS 0xFFFFFFFFFFFFFFFFULL
+
+//
+// The stack alignment required for X64
+//
+#define CPU_STACK_ALIGNMENT 16
+
+//
+// Modifier to ensure that all protocol member functions and EFI intrinsics
+// use the correct C calling convention. All protocol member functions and
+// EFI intrinsics are required to modify thier member functions with EFIAPI.
+//
+#if _MSC_EXTENSIONS
+ ///
+ /// Define the standard calling convention reguardless of optimization level.
+ /// __cdecl is Microsoft* specific C extension.
+ ///
+ #define EFIAPI __cdecl
+#elif __GNUC__
+ ///
+ /// Define the standard calling convention reguardless of optimization level.
+ /// The GCC support assumes a GCC compiler that supports the EFI ABI. The EFI
+ /// ABI is much closer to the x64 Microsoft* ABI than standard x64 (x86-64)
+ /// GCC ABI. Thus a standard x64 (x86-64) GCC compiler can not be used for
+ /// x64. Warning the assembly code in the MDE x64 does not follow the correct
+ /// ABI for the standard x64 (x86-64) GCC.
+ ///
+ #define EFIAPI __attribute__((ms_abi))
+#else
+ ///
+ /// The default for a non Microsoft* or GCC compiler is to assume the EFI ABI
+ /// is the standard.
+ ///
+ #define EFIAPI
+#endif
+
+//
+// The Microsoft* C compiler can removed references to unreferenced data items
+// if the /OPT:REF linker option is used. We defined a macro as this is a
+// a non standard extension
+//
+#if _MSC_EXTENSIONS
+ #define GLOBAL_REMOVE_IF_UNREFERENCED __declspec(selectany)
+#else
+ #define GLOBAL_REMOVE_IF_UNREFERENCED
+#endif
+
+//
+// For symbol name in GNU assembly code, an extra "_" is necessary
+//
+#if __GNUC__
+ #if defined(linux)
+ #define ASM_PFX(name) name
+ #else
+ #define ASM_PFX(name) _##name
+ #endif
+#endif
+
+#define FUNCTION_ENTRY_POINT(p) (p)
+
+#endif
+
diff --git a/gpxe/src/include/gpxe/efi/efi.h b/gpxe/src/include/gpxe/efi/efi.h
new file mode 100644
index 00000000..c7f63b6c
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/efi.h
@@ -0,0 +1,131 @@
+#ifndef _EFI_H
+#define _EFI_H
+
+/** @file
+ *
+ * EFI API
+ *
+ * The intention is to include near-verbatim copies of the EFI headers
+ * required by gPXE. This is achieved using the import.pl script in
+ * this directory. Run the import script to update the local copies
+ * of the headers:
+ *
+ * ./import.pl /path/to/edk2/edk2
+ *
+ * where /path/to/edk2/edk2 is the path to your local checkout of the
+ * EFI Development Kit.
+ *
+ * Note that import.pl will modify any #include lines in each imported
+ * header to reflect its new location within the gPXE tree. It will
+ * also tidy up the file by removing carriage return characters and
+ * trailing whitespace.
+ *
+ *
+ * At the time of writing, there are a few other modifications to
+ * these headers that are present in my personal edk2 tree, that are
+ * not yet committed back to the main edk2 repository. These
+ * modifications are fixes for compilation on case-dependent
+ * filesystems, compilation under -mrtd and -mregparm=3, etc.
+ */
+
+/* EFI headers rudely redefine NULL */
+#undef NULL
+
+/* Include the top-level EFI header files */
+#include <gpxe/efi/Uefi.h>
+#include <gpxe/efi/PiDxe.h>
+
+/* Reset any trailing #pragma pack directives */
+#pragma pack()
+
+#include <gpxe/tables.h>
+#include <gpxe/uuid.h>
+
+/** An EFI protocol used by gPXE */
+struct efi_protocol {
+ /** GUID */
+ union {
+ /** EFI protocol GUID */
+ EFI_GUID guid;
+ /** UUID structure understood by gPXE */
+ union uuid uuid;
+ } u;
+ /** Variable containing pointer to protocol structure */
+ void **protocol;
+};
+
+/** Declare an EFI protocol used by gPXE */
+#define __efi_protocol \
+ __table ( struct efi_protocol, efi_protocols, 01 )
+
+/** Declare an EFI protocol to be required by gPXE
+ *
+ * @v _protocol EFI protocol name
+ * @v _ptr Pointer to protocol instance
+ */
+#define EFI_REQUIRE_PROTOCOL( _protocol, _ptr ) \
+ struct efi_protocol __ ## _protocol __efi_protocol = { \
+ .u.guid = _protocol ## _GUID, \
+ .protocol = ( ( void ** ) ( void * ) \
+ ( ( (_ptr) == ( ( _protocol ** ) NULL ) ) ? \
+ (_ptr) : (_ptr) ) ), \
+ }
+
+/** An EFI configuration table used by gPXE */
+struct efi_config_table {
+ /** GUID */
+ union {
+ /** EFI configuration table GUID */
+ EFI_GUID guid;
+ /** UUID structure understood by gPXE */
+ union uuid uuid;
+ } u;
+ /** Variable containing pointer to configuration table */
+ void **table;
+ /** Table is required for operation */
+ int required;
+};
+
+/** Declare an EFI configuration table used by gPXE */
+#define __efi_config_table \
+ __table ( struct efi_config_table, efi_config_tables, 01 )
+
+/** Declare an EFI configuration table to be used by gPXE
+ *
+ * @v _table EFI configuration table name
+ * @v _ptr Pointer to configuration table
+ * @v _required Table is required for operation
+ */
+#define EFI_USE_TABLE( _table, _ptr, _required ) \
+ struct efi_config_table __ ## _table __efi_config_table = { \
+ .u.guid = _table ## _GUID, \
+ .table = ( ( void ** ) ( void * ) (_ptr) ), \
+ .required = (_required), \
+ }
+
+/** Convert a gPXE status code to an EFI status code
+ *
+ * FIXME: actually perform some kind of conversion. gPXE error codes
+ * will be detected as EFI error codes; both have the top bit set, and
+ * the success return code is zero for both. Anything that just
+ * reports a numerical error will be OK, anything attempting to
+ * interpret the value or to display a text equivalent will be
+ * screwed.
+ */
+#define RC_TO_EFIRC( rc ) (rc)
+
+/** Convert an EFI status code to a gPXE status code
+ *
+ * FIXME: as above
+ */
+#define EFIRC_TO_RC( efirc ) (efirc)
+
+extern EFI_HANDLE efi_image_handle;
+extern EFI_SYSTEM_TABLE *efi_systab;
+
+extern const char * efi_strerror ( EFI_STATUS efirc );
+extern EFI_STATUS efi_init ( EFI_HANDLE image_handle,
+ EFI_SYSTEM_TABLE *systab );
+extern int efi_snp_install ( void );
+
+#endif /* _EFI_H */
diff --git a/gpxe/src/include/gpxe/efi/efi_io.h b/gpxe/src/include/gpxe/efi/efi_io.h
new file mode 100644
index 00000000..93f559db
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/efi_io.h
@@ -0,0 +1,178 @@
+#ifndef _GPXE_EFI_IO_H
+#define _GPXE_EFI_IO_H
+
+/** @file
+ *
+ * gPXE I/O API for EFI
+ *
+ * EFI runs with flat physical addressing, so the various mappings
+ * between virtual addresses, I/O addresses and bus addresses are all
+ * no-ops. I/O is handled using the EFI_CPU_IO_PROTOCOL.
+ */
+
+#ifdef IOAPI_EFI
+#define IOAPI_PREFIX_efi
+#else
+#define IOAPI_PREFIX_efi __efi_
+#endif
+
+extern unsigned long long efi_ioread ( volatile void *io_addr,
+ size_t size );
+extern void efi_iowrite ( unsigned long long data, volatile void *io_addr,
+ size_t size );
+extern void efi_ioreads ( volatile void *io_addr, void *data,
+ size_t size, unsigned int count );
+extern void efi_iowrites ( volatile void *io_addr, const void *data,
+ size_t size, unsigned int count );
+
+/*
+ * Physical<->Bus and Bus<->I/O address mappings
+ *
+ * EFI runs with flat physical addressing, so these are all no-ops.
+ *
+ */
+
+static inline __always_inline unsigned long
+IOAPI_INLINE ( efi, phys_to_bus ) ( unsigned long phys_addr ) {
+ return phys_addr;
+}
+
+static inline __always_inline unsigned long
+IOAPI_INLINE ( efi, bus_to_phys ) ( unsigned long bus_addr ) {
+ return bus_addr;
+}
+
+static inline __always_inline void *
+IOAPI_INLINE ( efi, ioremap ) ( unsigned long bus_addr, size_t len __unused ) {
+ return ( ( void * ) bus_addr );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, iounmap ) ( volatile const void *io_addr __unused ) {
+ /* Nothing to do */
+}
+
+static inline __always_inline unsigned long
+IOAPI_INLINE ( efi, io_to_bus ) ( volatile const void *io_addr ) {
+ return ( ( unsigned long ) io_addr );
+}
+
+/*
+ * I/O functions
+ *
+ */
+
+static inline __always_inline uint8_t
+IOAPI_INLINE ( efi, readb ) ( volatile uint8_t *io_addr ) {
+ return efi_ioread ( io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline uint16_t
+IOAPI_INLINE ( efi, readw ) ( volatile uint16_t *io_addr ) {
+ return efi_ioread ( io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline uint32_t
+IOAPI_INLINE ( efi, readl ) ( volatile uint32_t *io_addr ) {
+ return efi_ioread ( io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline uint64_t
+IOAPI_INLINE ( efi, readq ) ( volatile uint64_t *io_addr ) {
+ return efi_ioread ( io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, writeb ) ( uint8_t data, volatile uint8_t *io_addr ) {
+ efi_iowrite ( data, io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, writew ) ( uint16_t data, volatile uint16_t *io_addr ) {
+ efi_iowrite ( data, io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, writel ) ( uint32_t data, volatile uint32_t *io_addr ) {
+ efi_iowrite ( data, io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, writeq ) ( uint64_t data, volatile uint64_t *io_addr ) {
+ efi_iowrite ( data, io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline uint8_t
+IOAPI_INLINE ( efi, inb ) ( volatile uint8_t *io_addr ) {
+ return efi_ioread ( io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline uint16_t
+IOAPI_INLINE ( efi, inw ) ( volatile uint16_t *io_addr ) {
+ return efi_ioread ( io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline uint32_t
+IOAPI_INLINE ( efi, inl ) ( volatile uint32_t *io_addr ) {
+ return efi_ioread ( io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, outb ) ( uint8_t data, volatile uint8_t *io_addr ) {
+ efi_iowrite ( data, io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, outw ) ( uint16_t data, volatile uint16_t *io_addr ) {
+ efi_iowrite ( data, io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, outl ) ( uint32_t data, volatile uint32_t *io_addr ) {
+ efi_iowrite ( data, io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, insb ) ( volatile uint8_t *io_addr, uint8_t *data,
+ unsigned int count ) {
+ efi_ioreads ( io_addr, data, sizeof ( *io_addr ), count );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, insw ) ( volatile uint16_t *io_addr, uint16_t *data,
+ unsigned int count ) {
+ efi_ioreads ( io_addr, data, sizeof ( *io_addr ), count );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, insl ) ( volatile uint32_t *io_addr, uint32_t *data,
+ unsigned int count ) {
+ efi_ioreads ( io_addr, data, sizeof ( *io_addr ), count );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, outsb ) ( volatile uint8_t *io_addr, const uint8_t *data,
+ unsigned int count ) {
+ efi_iowrites ( io_addr, data, sizeof ( *io_addr ), count );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, outsw ) ( volatile uint16_t *io_addr, const uint16_t *data,
+ unsigned int count ) {
+ efi_iowrites ( io_addr, data, sizeof ( *io_addr ), count );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, outsl ) ( volatile uint32_t *io_addr, const uint32_t *data,
+ unsigned int count ) {
+ efi_iowrites ( io_addr, data, sizeof ( *io_addr ), count );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, mb ) ( void ) {
+ /* Do nothing; EFI readl()/writel() calls already act as
+ * memory barriers.
+ */
+}
+
+#endif /* _GPXE_EFI_IO_H */
diff --git a/gpxe/src/include/gpxe/efi/efi_pci.h b/gpxe/src/include/gpxe/efi/efi_pci.h
new file mode 100644
index 00000000..8be331ab
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/efi_pci.h
@@ -0,0 +1,146 @@
+#ifndef _GPXE_EFI_PCI_H
+#define _GPXE_EFI_PCI_H
+
+/** @file
+ *
+ * gPXE PCI I/O API for EFI
+ *
+ */
+
+#ifdef PCIAPI_EFI
+#define PCIAPI_PREFIX_efi
+#else
+#define PCIAPI_PREFIX_efi __efi_
+#endif
+
+/* EFI PCI width codes defined by EFI spec */
+#define EFIPCI_WIDTH_BYTE 0
+#define EFIPCI_WIDTH_WORD 1
+#define EFIPCI_WIDTH_DWORD 2
+
+#define EFIPCI_LOCATION( _offset, _width ) \
+ ( (_offset) | ( (_width) << 16 ) )
+#define EFIPCI_OFFSET( _location ) ( (_location) & 0xffff )
+#define EFIPCI_WIDTH( _location ) ( (_location) >> 16 )
+
+struct pci_device;
+
+extern int efipci_read ( struct pci_device *pci, unsigned long location,
+ void *value );
+extern int efipci_write ( struct pci_device *pci, unsigned long location,
+ unsigned long value );
+
+/**
+ * Determine maximum PCI bus number within system
+ *
+ * @ret max_bus Maximum bus number
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( efi, pci_max_bus ) ( void ) {
+ /* No way to work this out via EFI */
+ return 0xff;
+}
+
+/**
+ * Read byte from PCI configuration space via EFI
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value read
+ * @ret rc Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( efi, pci_read_config_byte ) ( struct pci_device *pci,
+ unsigned int where,
+ uint8_t *value ) {
+ return efipci_read ( pci,
+ EFIPCI_LOCATION ( where, EFIPCI_WIDTH_BYTE ),
+ value );
+}
+
+/**
+ * Read word from PCI configuration space via EFI
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value read
+ * @ret rc Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( efi, pci_read_config_word ) ( struct pci_device *pci,
+ unsigned int where,
+ uint16_t *value ) {
+ return efipci_read ( pci,
+ EFIPCI_LOCATION ( where, EFIPCI_WIDTH_WORD ),
+ value );
+}
+
+/**
+ * Read dword from PCI configuration space via EFI
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value read
+ * @ret rc Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( efi, pci_read_config_dword ) ( struct pci_device *pci,
+ unsigned int where,
+ uint32_t *value ) {
+ return efipci_read ( pci,
+ EFIPCI_LOCATION ( where, EFIPCI_WIDTH_DWORD ),
+ value );
+}
+
+/**
+ * Write byte to PCI configuration space via EFI
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value to be written
+ * @ret rc Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( efi, pci_write_config_byte ) ( struct pci_device *pci,
+ unsigned int where,
+ uint8_t value ) {
+ return efipci_write ( pci,
+ EFIPCI_LOCATION ( where, EFIPCI_WIDTH_BYTE ),
+ value );
+}
+
+/**
+ * Write word to PCI configuration space via EFI
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value to be written
+ * @ret rc Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( efi, pci_write_config_word ) ( struct pci_device *pci,
+ unsigned int where,
+ uint16_t value ) {
+ return efipci_write ( pci,
+ EFIPCI_LOCATION ( where, EFIPCI_WIDTH_WORD ),
+ value );
+}
+
+/**
+ * Write dword to PCI configuration space via EFI
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value to be written
+ * @ret rc Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( efi, pci_write_config_dword ) ( struct pci_device *pci,
+ unsigned int where,
+ uint32_t value ) {
+ return efipci_write ( pci,
+ EFIPCI_LOCATION ( where, EFIPCI_WIDTH_DWORD ),
+ value );
+}
+
+#endif /* _GPXE_EFI_PCI_H */
diff --git a/gpxe/src/include/gpxe/efi/efi_smbios.h b/gpxe/src/include/gpxe/efi/efi_smbios.h
new file mode 100644
index 00000000..df947de5
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/efi_smbios.h
@@ -0,0 +1,16 @@
+#ifndef _GPXE_EFI_SMBIOS_H
+#define _GPXE_EFI_SMBIOS_H
+
+/** @file
+ *
+ * gPXE SMBIOS API for EFI
+ *
+ */
+
+#ifdef SMBIOS_EFI
+#define SMBIOS_PREFIX_efi
+#else
+#define SMBIOS_PREFIX_efi __efi_
+#endif
+
+#endif /* _GPXE_EFI_SMBIOS_H */
diff --git a/gpxe/src/include/gpxe/efi/efi_timer.h b/gpxe/src/include/gpxe/efi/efi_timer.h
new file mode 100644
index 00000000..c332c9d6
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/efi_timer.h
@@ -0,0 +1,16 @@
+#ifndef _GPXE_EFI_TIMER_H
+#define _GPXE_EFI_TIMER_H
+
+/** @file
+ *
+ * gPXE timer API for EFI
+ *
+ */
+
+#ifdef TIMER_EFI
+#define TIMER_PREFIX_efi
+#else
+#define TIMER_PREFIX_efi __efi_
+#endif
+
+#endif /* _GPXE_EFI_TIMER_H */
diff --git a/gpxe/src/include/gpxe/efi/efi_uaccess.h b/gpxe/src/include/gpxe/efi/efi_uaccess.h
new file mode 100644
index 00000000..bae5fb41
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/efi_uaccess.h
@@ -0,0 +1,88 @@
+#ifndef _GPXE_EFI_UACCESS_H
+#define _GPXE_EFI_UACCESS_H
+
+/** @file
+ *
+ * gPXE user access API for EFI
+ *
+ * EFI runs with flat physical addressing, so the various mappings
+ * between virtual addresses, I/O addresses and bus addresses are all
+ * no-ops.
+ */
+
+#ifdef UACCESS_EFI
+#define UACCESS_PREFIX_efi
+#else
+#define UACCESS_PREFIX_efi __efi_
+#endif
+
+/**
+ * Convert physical address to user pointer
+ *
+ * @v phys_addr Physical address
+ * @ret userptr User pointer
+ */
+static inline __always_inline userptr_t
+UACCESS_INLINE ( efi, phys_to_user ) ( unsigned long phys_addr ) {
+ return phys_addr;
+}
+
+/**
+ * Convert user buffer to physical address
+ *
+ * @v userptr User pointer
+ * @v offset Offset from user pointer
+ * @ret phys_addr Physical address
+ */
+static inline __always_inline unsigned long
+UACCESS_INLINE ( efi, user_to_phys ) ( userptr_t userptr, off_t offset ) {
+ return ( userptr + offset );
+}
+
+static inline __always_inline userptr_t
+UACCESS_INLINE ( efi, virt_to_user ) ( volatile const void *addr ) {
+ return trivial_virt_to_user ( addr );
+}
+
+static inline __always_inline void *
+UACCESS_INLINE ( efi, user_to_virt ) ( userptr_t userptr, off_t offset ) {
+ return trivial_user_to_virt ( userptr, offset );
+}
+
+static inline __always_inline userptr_t
+UACCESS_INLINE ( efi, userptr_add ) ( userptr_t userptr, off_t offset ) {
+ return trivial_userptr_add ( userptr, offset );
+}
+
+static inline __always_inline void
+UACCESS_INLINE ( efi, memcpy_user ) ( userptr_t dest, off_t dest_off,
+ userptr_t src, off_t src_off,
+ size_t len ) {
+ trivial_memcpy_user ( dest, dest_off, src, src_off, len );
+}
+
+static inline __always_inline void
+UACCESS_INLINE ( efi, memmove_user ) ( userptr_t dest, off_t dest_off,
+ userptr_t src, off_t src_off,
+ size_t len ) {
+ trivial_memmove_user ( dest, dest_off, src, src_off, len );
+}
+
+static inline __always_inline void
+UACCESS_INLINE ( efi, memset_user ) ( userptr_t buffer, off_t offset,
+ int c, size_t len ) {
+ trivial_memset_user ( buffer, offset, c, len );
+}
+
+static inline __always_inline size_t
+UACCESS_INLINE ( efi, strlen_user ) ( userptr_t buffer, off_t offset ) {
+ return trivial_strlen_user ( buffer, offset );
+}
+
+static inline __always_inline off_t
+UACCESS_INLINE ( efi, memchr_user ) ( userptr_t buffer, off_t offset,
+ int c, size_t len ) {
+ return trivial_memchr_user ( buffer, offset, c, len );
+}
+
+#endif /* _GPXE_EFI_UACCESS_H */
diff --git a/gpxe/src/include/gpxe/efi/efi_umalloc.h b/gpxe/src/include/gpxe/efi/efi_umalloc.h
new file mode 100644
index 00000000..def17b2d
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/efi_umalloc.h
@@ -0,0 +1,16 @@
+#ifndef _GPXE_EFI_UMALLOC_H
+#define _GPXE_EFI_UMALLOC_H
+
+/** @file
+ *
+ * gPXE user memory allocation API for EFI
+ *
+ */
+
+#ifdef UMALLOC_EFI
+#define UMALLOC_PREFIX_efi
+#else
+#define UMALLOC_PREFIX_efi __efi_
+#endif
+
+#endif /* _GPXE_EFI_UMALLOC_H */
diff --git a/gpxe/src/include/gpxe/efi/import.pl b/gpxe/src/include/gpxe/efi/import.pl
new file mode 100755
index 00000000..16993944
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/import.pl
@@ -0,0 +1,75 @@
+#!/usr/bin/perl -w
+
+use File::Spec::Functions qw ( :ALL );
+use File::Find;
+use File::Path;
+use FindBin;
+use strict;
+use warnings;
+
+sub try_import_file {
+ my $gpxedir = shift;
+ my $edkdirs = shift;
+ my $filename = shift;
+
+ # Skip everything except headers
+ return unless $filename =~ /\.h$/;
+ print "$filename...";
+
+ my $outfile = catfile ( $gpxedir, $filename );
+ foreach my $edkdir ( @$edkdirs ) {
+ my $infile = catfile ( $edkdir, $filename );
+ if ( -e $infile ) {
+ # We have found a matching source file - import it
+ print "$infile\n";
+ open my $infh, "<$infile" or die "Could not open $infile: $!\n";
+ ( undef, my $outdir, undef ) = splitpath ( $outfile );
+ mkpath ( $outdir );
+ open my $outfh, ">$outfile" or die "Could not open $outfile: $!\n";
+ my @dependencies = ();
+ while ( <$infh> ) {
+ # Strip CR and trailing whitespace
+ s/\r//g;
+ s/\s*$//g;
+ chomp;
+ # Update include lines, and record included files
+ if ( s/^\#include\s+[<\"](\S+)[>\"]/\#include <gpxe\/efi\/$1>/ ) {
+ push @dependencies, $1;
+ }
+ print $outfh "$_\n";
+ }
+ close $outfh;
+ close $infh;
+ # Recurse to handle any included files that we don't already have
+ foreach my $dependency ( @dependencies ) {
+ if ( ! -e catfile ( $gpxedir, $dependency ) ) {
+ print "...following dependency on $dependency\n";
+ try_import_file ( $gpxedir, $edkdirs, $dependency );
+ }
+ }
+ return;
+ }
+ }
+ print "no equivalent found\n";
+}
+
+# Identify edk import directories
+die "Syntax $0 /path/to/edk2/edk2\n" unless @ARGV == 1;
+my $edktop = shift;
+die "Directory \"$edktop\" does not appear to contain the EFI EDK2\n"
+ unless -e catfile ( $edktop, "MdePkg" );
+my $edkdirs = [ catfile ( $edktop, "MdePkg/Include" ),
+ catfile ( $edktop, "IntelFrameworkPkg/Include" ) ];
+
+# Identify gPXE EFI includes directory
+my $gpxedir = $FindBin::Bin;
+die "Directory \"$gpxedir\" does not appear to contain the gPXE EFI includes\n"
+ unless -e catfile ( $gpxedir, "../../../include/gpxe/efi" );
+
+print "Importing EFI headers into $gpxedir\nfrom ";
+print join ( "\n and ", @$edkdirs )."\n";
+
+# Import headers
+find ( { wanted => sub {
+ try_import_file ( $gpxedir, $edkdirs, abs2rel ( $_, $gpxedir ) );
+}, no_chdir => 1 }, $gpxedir );
diff --git a/gpxe/src/include/gpxe/embedded.h b/gpxe/src/include/gpxe/embedded.h
deleted file mode 100644
index ec457055..00000000
--- a/gpxe/src/include/gpxe/embedded.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef _GPXE_EMBEDDED_H
-#define _GPXE_EMBEDDED_H
-
-#include <gpxe/image.h>
-
-struct image *embedded_image(void);
-
-#endif
-
diff --git a/gpxe/src/include/gpxe/errfile.h b/gpxe/src/include/gpxe/errfile.h
index ca0abebf..dcfd4e4a 100644
--- a/gpxe/src/include/gpxe/errfile.h
+++ b/gpxe/src/include/gpxe/errfile.h
@@ -106,10 +106,13 @@
#define ERRFILE_e1000_hw ( ERRFILE_DRIVER | 0x00490000 )
#define ERRFILE_mtnic ( ERRFILE_DRIVER | 0x004a0000 )
#define ERRFILE_phantom ( ERRFILE_DRIVER | 0x004b0000 )
+#define ERRFILE_ne2k_isa ( ERRFILE_DRIVER | 0x004c0000 )
+#define ERRFILE_b44 ( ERRFILE_DRIVER | 0x004d0000 )
#define ERRFILE_scsi ( ERRFILE_DRIVER | 0x00700000 )
#define ERRFILE_arbel ( ERRFILE_DRIVER | 0x00710000 )
#define ERRFILE_hermon ( ERRFILE_DRIVER | 0x00720000 )
+#define ERRFILE_linda ( ERRFILE_DRIVER | 0x00730000 )
#define ERRFILE_aoe ( ERRFILE_NET | 0x00000000 )
#define ERRFILE_arp ( ERRFILE_NET | 0x00010000 )
@@ -134,11 +137,16 @@
#define ERRFILE_netdev_settings ( ERRFILE_NET | 0x00140000 )
#define ERRFILE_dhcppkt ( ERRFILE_NET | 0x00150000 )
#define ERRFILE_slam ( ERRFILE_NET | 0x00160000 )
+#define ERRFILE_ib_sma ( ERRFILE_NET | 0x00170000 )
+#define ERRFILE_ib_packet ( ERRFILE_NET | 0x00180000 )
+#define ERRFILE_icmp ( ERRFILE_NET | 0x00190000 )
#define ERRFILE_image ( ERRFILE_IMAGE | 0x00000000 )
#define ERRFILE_elf ( ERRFILE_IMAGE | 0x00010000 )
#define ERRFILE_script ( ERRFILE_IMAGE | 0x00020000 )
#define ERRFILE_segment ( ERRFILE_IMAGE | 0x00030000 )
+#define ERRFILE_efi_image ( ERRFILE_IMAGE | 0x00040000 )
+#define ERRFILE_embedded ( ERRFILE_IMAGE | 0x00050000 )
#define ERRFILE_asn1 ( ERRFILE_OTHER | 0x00000000 )
#define ERRFILE_chap ( ERRFILE_OTHER | 0x00010000 )
@@ -156,6 +164,14 @@
#define ERRFILE_tls ( ERRFILE_OTHER | 0x000d0000 )
#define ERRFILE_ifmgmt ( ERRFILE_OTHER | 0x000e0000 )
#define ERRFILE_iscsiboot ( ERRFILE_OTHER | 0x000f0000 )
+#define ERRFILE_efi_pci ( ERRFILE_OTHER | 0x00100000 )
+#define ERRFILE_efi_snp ( ERRFILE_OTHER | 0x00110000 )
+#define ERRFILE_smbios ( ERRFILE_OTHER | 0x00120000 )
+#define ERRFILE_smbios_settings ( ERRFILE_OTHER | 0x00130000 )
+#define ERRFILE_efi_smbios ( ERRFILE_OTHER | 0x00140000 )
+#define ERRFILE_pxemenu ( ERRFILE_OTHER | 0x00150000 )
+#define ERRFILE_x509 ( ERRFILE_OTHER | 0x00160000 )
+#define ERRFILE_login_ui ( ERRFILE_OTHER | 0x00170000 )
/** @} */
diff --git a/gpxe/src/include/gpxe/ethernet.h b/gpxe/src/include/gpxe/ethernet.h
index 158fe066..ff0fd6c1 100644
--- a/gpxe/src/include/gpxe/ethernet.h
+++ b/gpxe/src/include/gpxe/ethernet.h
@@ -9,6 +9,7 @@
#include <stdint.h>
#include <gpxe/netdevice.h>
+#include <gpxe/if_ether.h>
extern struct ll_protocol ethernet_protocol;
@@ -26,6 +27,7 @@ static inline struct net_device * alloc_etherdev ( size_t priv_size ) {
netdev = alloc_netdev ( priv_size );
if ( netdev ) {
netdev->ll_protocol = &ethernet_protocol;
+ netdev->max_pkt_len = ETH_FRAME_LEN;
}
return netdev;
}
diff --git a/gpxe/src/include/gpxe/fakedhcp.h b/gpxe/src/include/gpxe/fakedhcp.h
index 990b56af..550b74f7 100644
--- a/gpxe/src/include/gpxe/fakedhcp.h
+++ b/gpxe/src/include/gpxe/fakedhcp.h
@@ -15,7 +15,7 @@ extern int create_fakedhcpdiscover ( struct net_device *netdev,
void *data, size_t max_len );
extern int create_fakedhcpack ( struct net_device *netdev,
void *data, size_t max_len );
-extern int create_fakeproxydhcpack ( struct net_device *netdev,
- void *data, size_t max_len );
+extern int create_fakepxebsack ( struct net_device *netdev,
+ void *data, size_t max_len );
#endif /* _GPXE_FAKEDHCP_H */
diff --git a/gpxe/src/include/gpxe/features.h b/gpxe/src/include/gpxe/features.h
index 107ff085..32c31694 100644
--- a/gpxe/src/include/gpxe/features.h
+++ b/gpxe/src/include/gpxe/features.h
@@ -46,21 +46,21 @@
#define DHCP_EB_FEATURE_PXE 0x21 /**< PXE format */
#define DHCP_EB_FEATURE_ELF 0x22 /**< ELF format */
#define DHCP_EB_FEATURE_COMBOOT 0x23 /**< COMBOOT format */
+#define DHCP_EB_FEATURE_EFI 0x24 /**< EFI format */
/** @} */
/** Declare a feature code for DHCP */
-#define __dhcp_feature( category ) \
- __table ( uint8_t, dhcp_features, category )
+#define __dhcp_feature __table ( uint8_t, dhcp_features, 01 )
/** Construct a DHCP feature table entry */
-#define DHCP_FEATURE( category, feature_opt, version ) \
- _DHCP_FEATURE ( category, OBJECT, feature_opt, version )
-#define _DHCP_FEATURE( category, _name, feature_opt, version ) \
- __DHCP_FEATURE ( category, _name, feature_opt, version )
-#define __DHCP_FEATURE( category, _name, feature_opt, version ) \
- uint8_t __dhcp_feature_ ## _name [] __dhcp_feature ( category ) = { \
- feature_opt, DHCP_BYTE ( version ) \
+#define DHCP_FEATURE( feature_opt, ... ) \
+ _DHCP_FEATURE ( OBJECT, feature_opt, __VA_ARGS__ )
+#define _DHCP_FEATURE( _name, feature_opt, ... ) \
+ __DHCP_FEATURE ( _name, feature_opt, __VA_ARGS__ )
+#define __DHCP_FEATURE( _name, feature_opt, ... ) \
+ uint8_t __dhcp_feature_ ## _name [] __dhcp_feature = { \
+ feature_opt, DHCP_OPTION ( __VA_ARGS__ ) \
};
/** A named feature */
@@ -86,6 +86,10 @@ struct feature {
/** Declare a feature */
#define FEATURE( category, text, feature_opt, version ) \
FEATURE_NAME ( category, text ); \
- DHCP_FEATURE ( category, feature_opt, version );
+ DHCP_FEATURE ( feature_opt, version );
+
+/** Declare the version number feature */
+#define FEATURE_VERSION( ... ) \
+ DHCP_FEATURE ( DHCP_ENCAPSULATED ( DHCP_EB_VERSION ), __VA_ARGS__ )
#endif /* _GPXE_FEATURES_H */
diff --git a/gpxe/src/include/gpxe/i2c.h b/gpxe/src/include/gpxe/i2c.h
index bfaee8fb..9d229546 100644
--- a/gpxe/src/include/gpxe/i2c.h
+++ b/gpxe/src/include/gpxe/i2c.h
@@ -8,6 +8,7 @@
*/
#include <stdint.h>
+#include <gpxe/bitbash.h>
/** An I2C device
*
@@ -15,10 +16,35 @@
* is accessed via an I2C interface.
*/
struct i2c_device {
- /** Address of this device */
- unsigned int address;
- /** Flag indicating a ten-bit address format */
- int tenbit;
+ /** Address of this device
+ *
+ * The actual address sent on the bus will look like
+ *
+ * <start> <device address> <word address overflow> <r/w>
+ *
+ * The "word address overflow" is any excess bits from the
+ * word address, i.e. any portion that does not fit within the
+ * defined word address length.
+ */
+ unsigned int dev_addr;
+ /** Device address length, in bytes
+ *
+ * This is the number of bytes that comprise the device
+ * address, defined to be the portion that terminates with the
+ * read/write bit.
+ */
+ unsigned int dev_addr_len;
+ /** Word adddress length, in bytes
+ *
+ * This is the number of bytes that comprise the word address,
+ * defined to be the portion that starts after the read/write
+ * bit and ends before the first data byte.
+ *
+ * For some devices, this length will be zero (i.e. the word
+ * address is contained entirely within the "word address
+ * overflow").
+ */
+ unsigned int word_addr_len;
};
/** An I2C interface
@@ -91,6 +117,9 @@ enum {
/** Delay required for bit-bashing operation */
#define I2C_UDELAY 5
+/** Maximum number of cycles to use when attempting a bus reset */
+#define I2C_RESET_MAX_CYCLES 32
+
/**
* Check presence of I2C device
*
@@ -106,6 +135,35 @@ static inline int i2c_check_presence ( struct i2c_interface *i2c,
return i2c->write ( i2c, i2cdev, 0, NULL, 0 );
}
-extern void init_i2c_bit_basher ( struct i2c_bit_basher *i2cbit );
+extern int init_i2c_bit_basher ( struct i2c_bit_basher *i2cbit,
+ struct bit_basher_operations *bash_op );
+
+/**
+ * Initialise generic I2C EEPROM device
+ *
+ * @v i2cdev I2C device
+ */
+static inline __always_inline void
+init_i2c_eeprom ( struct i2c_device *i2cdev, unsigned int dev_addr ) {
+ i2cdev->dev_addr = dev_addr;
+ i2cdev->dev_addr_len = 1;
+ i2cdev->word_addr_len = 1;
+}
+
+/**
+ * Initialise Atmel AT24C11
+ *
+ * @v i2cdev I2C device
+ */
+static inline __always_inline void
+init_at24c11 ( struct i2c_device *i2cdev ) {
+ /* This chip has no device address; it must be the only chip
+ * on the bus. The word address is contained entirely within
+ * the device address field.
+ */
+ i2cdev->dev_addr = 0;
+ i2cdev->dev_addr_len = 1;
+ i2cdev->word_addr_len = 0;
+}
#endif /* _GPXE_I2C_H */
diff --git a/gpxe/src/include/gpxe/ib_mad.h b/gpxe/src/include/gpxe/ib_mad.h
new file mode 100644
index 00000000..6c4e95b7
--- /dev/null
+++ b/gpxe/src/include/gpxe/ib_mad.h
@@ -0,0 +1,364 @@
+#ifndef _GPXE_IB_MAD_H
+#define _GPXE_IB_MAD_H
+
+/** @file
+ *
+ * Infiniband management datagrams
+ *
+ */
+
+#include <stdint.h>
+#include <gpxe/ib_packet.h>
+
+/*****************************************************************************
+ *
+ * Subnet management MADs
+ *
+ *****************************************************************************
+ */
+
+/** A subnet management header
+ *
+ * Defined in sections 14.2.1.1 and 14.2.1.2 of the IBA.
+ */
+struct ib_smp_hdr {
+ uint64_t mkey;
+ uint16_t slid;
+ uint16_t dlid;
+ uint8_t reserved[28];
+} __attribute__ (( packed ));
+
+/** Subnet management class version */
+#define IB_SMP_CLASS_VERSION 1
+
+/** Subnet management direction bit
+ *
+ * This bit resides in the "status" field in the MAD header.
+ */
+#define IB_SMP_STATUS_D_INBOUND 0x8000
+
+/* Subnet management attributes */
+#define IB_SMP_ATTR_NOTICE 0x0002
+#define IB_SMP_ATTR_NODE_DESC 0x0010
+#define IB_SMP_ATTR_NODE_INFO 0x0011
+#define IB_SMP_ATTR_SWITCH_INFO 0x0012
+#define IB_SMP_ATTR_GUID_INFO 0x0014
+#define IB_SMP_ATTR_PORT_INFO 0x0015
+#define IB_SMP_ATTR_PKEY_TABLE 0x0016
+#define IB_SMP_ATTR_SL_TO_VL_TABLE 0x0017
+#define IB_SMP_ATTR_VL_ARB_TABLE 0x0018
+#define IB_SMP_ATTR_LINEAR_FORWARD_TABLE 0x0019
+#define IB_SMP_ATTR_RANDOM_FORWARD_TABLE 0x001A
+#define IB_SMP_ATTR_MCAST_FORWARD_TABLE 0x001B
+#define IB_SMP_ATTR_SM_INFO 0x0020
+#define IB_SMP_ATTR_VENDOR_DIAG 0x0030
+#define IB_SMP_ATTR_LED_INFO 0x0031
+#define IB_SMP_ATTR_VENDOR_MASK 0xFF00
+
+/**
+ * A Node Description attribute
+ *
+ * Defined in section 14.2.5.2 of the IBA
+ */
+struct ib_node_desc {
+ char node_string[64];
+} __attribute__ (( packed ));
+
+/** A Node Information attribute
+ *
+ * Defined in section 14.2.5.3 of the IBA.
+ */
+struct ib_node_info {
+ uint8_t base_version;
+ uint8_t class_version;
+ uint8_t node_type;
+ uint8_t num_ports;
+ uint8_t sys_guid[8];
+ uint8_t node_guid[8];
+ uint8_t port_guid[8];
+ uint16_t partition_cap;
+ uint16_t device_id;
+ uint32_t revision;
+ uint8_t local_port_num;
+ uint8_t vendor_id[3];
+} __attribute__ ((packed));
+
+#define IB_NODE_TYPE_HCA 0x01
+#define IB_NODE_TYPE_SWITCH 0x02
+#define IB_NODE_TYPE_ROUTER 0x03
+
+/** A GUID Information attribute
+ *
+ * Defined in section 14.2.5.5 of the IBA.
+ */
+struct ib_guid_info {
+ uint8_t guid[8][8];
+} __attribute__ (( packed ));
+
+/** A Port Information attribute
+ *
+ * Defined in section 14.2.5.6 of the IBA.
+ */
+struct ib_port_info {
+ uint64_t mkey;
+ uint8_t gid_prefix[8];
+ uint16_t lid;
+ uint16_t mastersm_lid;
+ uint32_t cap_mask;
+ uint16_t diag_code;
+ uint16_t mkey_lease_period;
+ uint8_t local_port_num;
+ uint8_t link_width_enabled;
+ uint8_t link_width_supported;
+ uint8_t link_width_active;
+ uint8_t link_speed_supported__port_state;
+ uint8_t port_phys_state__link_down_def_state;
+ uint8_t mkey_prot_bits__lmc;
+ uint8_t link_speed_active__link_speed_enabled;
+ uint8_t neighbour_mtu__mastersm_sl;
+ uint8_t vl_cap__init_type;
+ uint8_t vl_high_limit;
+ uint8_t vl_arbitration_high_cap;
+ uint8_t vl_arbitration_low_cap;
+ uint8_t init_type_reply__mtu_cap;
+ uint8_t vl_stall_count__hoq_life;
+ uint8_t operational_vls__enforcement;
+ uint16_t mkey_violations;
+ uint16_t pkey_violations;
+ uint16_t qkey_violations;
+ uint8_t guid_cap;
+ uint8_t client_reregister__subnet_timeout;
+ uint8_t resp_time_value;
+ uint8_t local_phy_errors__overrun_errors;
+ uint16_t max_credit_hint;
+ uint32_t link_round_trip_latency;
+} __attribute__ (( packed ));
+
+#define IB_LINK_WIDTH_1X 0x01
+#define IB_LINK_WIDTH_4X 0x02
+#define IB_LINK_WIDTH_8X 0x04
+#define IB_LINK_WIDTH_12X 0x08
+
+#define IB_LINK_SPEED_SDR 0x01
+#define IB_LINK_SPEED_DDR 0x02
+#define IB_LINK_SPEED_QDR 0x04
+
+#define IB_PORT_STATE_DOWN 0x01
+#define IB_PORT_STATE_INIT 0x02
+#define IB_PORT_STATE_ARMED 0x03
+#define IB_PORT_STATE_ACTIVE 0x04
+
+#define IB_PORT_PHYS_STATE_SLEEP 0x01
+#define IB_PORT_PHYS_STATE_POLLING 0x02
+
+#define IB_MTU_256 0x01
+#define IB_MTU_512 0x02
+#define IB_MTU_1024 0x03
+#define IB_MTU_2048 0x04
+#define IB_MTU_4096 0x05
+
+#define IB_VL_0 0x01
+#define IB_VL_0_1 0x02
+#define IB_VL_0_3 0x03
+#define IB_VL_0_7 0x04
+#define IB_VL_0_14 0x05
+
+/** A Partition Key Table attribute
+ *
+ * Defined in section 14.2.5.7 of the IBA.
+ */
+struct ib_pkey_table {
+ uint16_t pkey[32];
+} __attribute__ (( packed ));
+
+/** A subnet management attribute */
+union ib_smp_data {
+ struct ib_node_desc node_desc;
+ struct ib_node_info node_info;
+ struct ib_guid_info guid_info;
+ struct ib_port_info port_info;
+ struct ib_pkey_table pkey_table;
+ uint8_t bytes[64];
+} __attribute__ (( packed ));
+
+/** A subnet management directed route path */
+struct ib_smp_dr_path {
+ uint8_t hops[64];
+} __attribute__ (( packed ));
+
+/** Subnet management MAD class-specific data */
+struct ib_smp_class_specific {
+ uint8_t hop_pointer;
+ uint8_t hop_count;
+} __attribute__ (( packed ));
+
+/*****************************************************************************
+ *
+ * Subnet administration MADs
+ *
+ *****************************************************************************
+ */
+
+struct ib_rmpp_hdr {
+ uint32_t raw[3];
+} __attribute__ (( packed ));
+
+struct ib_sa_hdr {
+ uint32_t sm_key[2];
+ uint16_t reserved;
+ uint16_t attrib_offset;
+ uint32_t comp_mask[2];
+} __attribute__ (( packed ));
+
+#define IB_SA_ATTR_MC_MEMBER_REC 0x38
+#define IB_SA_ATTR_PATH_REC 0x35
+
+struct ib_path_record {
+ uint32_t reserved0[2];
+ struct ib_gid dgid;
+ struct ib_gid sgid;
+ uint16_t dlid;
+ uint16_t slid;
+ uint32_t hop_limit__flow_label__raw_traffic;
+ uint32_t pkey__numb_path__reversible__tclass;
+ uint8_t reserved1;
+ uint8_t reserved__sl;
+ uint8_t mtu_selector__mtu;
+ uint8_t rate_selector__rate;
+ uint32_t preference__packet_lifetime__packet_lifetime_selector;
+ uint32_t reserved2[35];
+} __attribute__ (( packed ));
+
+#define IB_SA_PATH_REC_DGID (1<<2)
+#define IB_SA_PATH_REC_SGID (1<<3)
+
+struct ib_mc_member_record {
+ struct ib_gid mgid;
+ struct ib_gid port_gid;
+ uint32_t qkey;
+ uint16_t mlid;
+ uint8_t mtu_selector__mtu;
+ uint8_t tclass;
+ uint16_t pkey;
+ uint8_t rate_selector__rate;
+ uint8_t packet_lifetime_selector__packet_lifetime;
+ uint32_t sl__flow_label__hop_limit;
+ uint8_t scope__join_state;
+ uint8_t proxy_join__reserved;
+ uint16_t reserved0;
+ uint32_t reserved1[37];
+} __attribute__ (( packed ));
+
+#define IB_SA_MCMEMBER_REC_MGID (1<<0)
+#define IB_SA_MCMEMBER_REC_PORT_GID (1<<1)
+#define IB_SA_MCMEMBER_REC_QKEY (1<<2)
+#define IB_SA_MCMEMBER_REC_MLID (1<<3)
+#define IB_SA_MCMEMBER_REC_MTU_SELECTOR (1<<4)
+#define IB_SA_MCMEMBER_REC_MTU (1<<5)
+#define IB_SA_MCMEMBER_REC_TRAFFIC_CLASS (1<<6)
+#define IB_SA_MCMEMBER_REC_PKEY (1<<7)
+#define IB_SA_MCMEMBER_REC_RATE_SELECTOR (1<<8)
+#define IB_SA_MCMEMBER_REC_RATE (1<<9)
+#define IB_SA_MCMEMBER_REC_PACKET_LIFE_TIME_SELECTOR (1<<10)
+#define IB_SA_MCMEMBER_REC_PACKET_LIFE_TIME (1<<11)
+#define IB_SA_MCMEMBER_REC_SL (1<<12)
+#define IB_SA_MCMEMBER_REC_FLOW_LABEL (1<<13)
+#define IB_SA_MCMEMBER_REC_HOP_LIMIT (1<<14)
+#define IB_SA_MCMEMBER_REC_SCOPE (1<<15)
+#define IB_SA_MCMEMBER_REC_JOIN_STATE (1<<16)
+#define IB_SA_MCMEMBER_REC_PROXY_JOIN (1<<17)
+
+union ib_sa_data {
+ struct ib_path_record path_record;
+ struct ib_mc_member_record mc_member_record;
+} __attribute__ (( packed ));
+
+/*****************************************************************************
+ *
+ * MADs
+ *
+ *****************************************************************************
+ */
+
+/** Management datagram class_specific data */
+union ib_mad_class_specific {
+ uint16_t raw;
+ struct ib_smp_class_specific smp;
+} __attribute__ (( packed ));
+
+/** A management datagram common header
+ *
+ * Defined in section 13.4.2 of the IBA.
+ */
+struct ib_mad_hdr {
+ uint8_t base_version;
+ uint8_t mgmt_class;
+ uint8_t class_version;
+ uint8_t method;
+ uint16_t status;
+ union ib_mad_class_specific class_specific;
+ uint32_t tid[2];
+ uint16_t attr_id;
+ uint8_t reserved[2];
+ uint32_t attr_mod;
+} __attribute__ (( packed ));
+
+/* Management base version */
+#define IB_MGMT_BASE_VERSION 1
+
+/* Management classes */
+#define IB_MGMT_CLASS_SUBN_LID_ROUTED 0x01
+#define IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE 0x81
+#define IB_MGMT_CLASS_SUBN_ADM 0x03
+#define IB_MGMT_CLASS_PERF_MGMT 0x04
+#define IB_MGMT_CLASS_BM 0x05
+#define IB_MGMT_CLASS_DEVICE_MGMT 0x06
+#define IB_MGMT_CLASS_CM 0x07
+#define IB_MGMT_CLASS_SNMP 0x08
+#define IB_MGMT_CLASS_VENDOR_RANGE2_START 0x30
+#define IB_MGMT_CLASS_VENDOR_RANGE2_END 0x4F
+
+/* Management methods */
+#define IB_MGMT_METHOD_GET 0x01
+#define IB_MGMT_METHOD_SET 0x02
+#define IB_MGMT_METHOD_GET_RESP 0x81
+#define IB_MGMT_METHOD_SEND 0x03
+#define IB_MGMT_METHOD_TRAP 0x05
+#define IB_MGMT_METHOD_REPORT 0x06
+#define IB_MGMT_METHOD_REPORT_RESP 0x86
+#define IB_MGMT_METHOD_TRAP_REPRESS 0x07
+#define IB_MGMT_METHOD_DELETE 0x15
+
+/* Status codes */
+#define IB_MGMT_STATUS_OK 0x0000
+#define IB_MGMT_STATUS_BAD_VERSION 0x0001
+#define IB_MGMT_STATUS_UNSUPPORTED_METHOD 0x0002
+#define IB_MGMT_STATUS_UNSUPPORTED_METHOD_ATTR 0x0003
+#define IB_MGMT_STATUS_INVALID_VALUE 0x0004
+
+/** A subnet management MAD */
+struct ib_mad_smp {
+ struct ib_mad_hdr mad_hdr;
+ struct ib_smp_hdr smp_hdr;
+ union ib_smp_data smp_data;
+ struct ib_smp_dr_path initial_path;
+ struct ib_smp_dr_path return_path;
+} __attribute__ (( packed ));
+
+/** A subnet administration MAD */
+struct ib_mad_sa {
+ struct ib_mad_hdr mad_hdr;
+ struct ib_rmpp_hdr rmpp_hdr;
+ struct ib_sa_hdr sa_hdr;
+ union ib_sa_data sa_data;
+} __attribute__ (( packed ));
+
+/** A management datagram */
+union ib_mad {
+ struct ib_mad_hdr hdr;
+ struct ib_mad_smp smp;
+ struct ib_mad_sa sa;
+ uint8_t bytes[256];
+} __attribute__ (( packed ));
+
+#endif /* _GPXE_IB_MAD_H */
diff --git a/gpxe/src/include/gpxe/ib_packet.h b/gpxe/src/include/gpxe/ib_packet.h
new file mode 100644
index 00000000..5374802c
--- /dev/null
+++ b/gpxe/src/include/gpxe/ib_packet.h
@@ -0,0 +1,147 @@
+#ifndef _GPXE_IB_PACKET_H
+#define _GPXE_IB_PACKET_H
+
+/** @file
+ *
+ * Infiniband packet format
+ *
+ */
+
+struct ib_device;
+struct ib_queue_pair;
+struct ib_address_vector;
+struct io_buffer;
+
+/** Half of an Infiniband Global Identifier */
+struct ib_gid_half {
+ uint8_t bytes[8];
+};
+
+/** An Infiniband Global Identifier */
+struct ib_gid {
+ union {
+ uint8_t bytes[16];
+ uint16_t words[8];
+ uint32_t dwords[4];
+ struct ib_gid_half half[2];
+ } u;
+};
+
+/** An Infiniband Local Route Header */
+struct ib_local_route_header {
+ /** Virtual lane and link version */
+ uint8_t vl__lver;
+ /** Service level and next link header */
+ uint8_t sl__lnh;
+ /** Destination LID */
+ uint16_t dlid;
+ /** Packet length */
+ uint16_t length;
+ /** Source LID */
+ uint16_t slid;
+} __attribute__ (( packed ));
+
+/** Infiniband virtual lanes */
+enum ib_vl {
+ IB_VL_DEFAULT = 0,
+ IB_VL_SMP = 15,
+};
+
+/** An Infiniband Link Next Header value */
+enum ib_lnh {
+ IB_LNH_RAW = 0,
+ IB_LNH_IPv6 = 1,
+ IB_LNH_BTH = 2,
+ IB_LNH_GRH = 3
+};
+
+/** Default Infiniband LID */
+#define IB_LID_NONE 0xffff
+
+/** Test for multicast LID */
+#define IB_LID_MULTICAST( lid ) ( ( (lid) >= 0xc000 ) && ( (lid) <= 0xfffe ) )
+
+/** An Infiniband Global Route Header */
+struct ib_global_route_header {
+ /** IP version, traffic class, and flow label
+ *
+ * 4 bits : Version of the GRH
+ * 8 bits : Traffic class
+ * 20 bits : Flow label
+ */
+ uint32_t ipver__tclass__flowlabel;
+ /** Payload length */
+ uint16_t paylen;
+ /** Next header */
+ uint8_t nxthdr;
+ /** Hop limit */
+ uint8_t hoplmt;
+ /** Source GID */
+ struct ib_gid sgid;
+ /** Destiniation GID */
+ struct ib_gid dgid;
+} __attribute__ (( packed ));
+
+#define IB_GRH_IPVER_IPv6 0x06
+#define IB_GRH_NXTHDR_IBA 0x1b
+
+/** An Infiniband Base Transport Header */
+struct ib_base_transport_header {
+ /** Opcode */
+ uint8_t opcode;
+ /** Transport header version, pad count, migration and solicitation */
+ uint8_t se__m__padcnt__tver;
+ /** Partition key */
+ uint16_t pkey;
+ /** Destination queue pair */
+ uint32_t dest_qp;
+ /** Packet sequence number and acknowledge request */
+ uint32_t ack__psn;
+} __attribute__ (( packed ));
+
+/** An Infiniband BTH opcode */
+enum ib_bth_opcode {
+ BTH_OPCODE_UD_SEND = 0x64,
+};
+
+/** Default Infiniband partition key */
+#define IB_PKEY_NONE 0xffff
+
+/** Subnet management queue pair number */
+#define IB_QPN_SMP 0
+
+/** An Infiniband Datagram Extended Transport Header */
+struct ib_datagram_extended_transport_header {
+ /** Queue key */
+ uint32_t qkey;
+ /** Source queue pair */
+ uint32_t src_qp;
+} __attribute__ (( packed ));
+
+/** All known IB header formats */
+union ib_headers {
+ struct ib_local_route_header lrh;
+ struct {
+ struct ib_local_route_header lrh;
+ struct ib_global_route_header grh;
+ struct ib_base_transport_header bth;
+ struct ib_datagram_extended_transport_header deth;
+ } __attribute__ (( packed )) lrh__grh__bth__deth;
+ struct {
+ struct ib_local_route_header lrh;
+ struct ib_base_transport_header bth;
+ struct ib_datagram_extended_transport_header deth;
+ } __attribute__ (( packed )) lrh__bth__deth;
+} __attribute__ (( packed ));
+
+/** Maximum size required for IB headers */
+#define IB_MAX_HEADER_SIZE sizeof ( union ib_headers )
+
+extern int ib_push ( struct ib_device *ibdev, struct io_buffer *iobuf,
+ struct ib_queue_pair *qp, size_t payload_len,
+ const struct ib_address_vector *av );
+extern int ib_pull ( struct ib_device *ibdev, struct io_buffer *iobuf,
+ struct ib_queue_pair **qp, size_t *payload_len,
+ struct ib_address_vector *av );
+
+#endif /* _GPXE_IB_PACKET_H */
diff --git a/gpxe/src/include/gpxe/ib_sma.h b/gpxe/src/include/gpxe/ib_sma.h
new file mode 100644
index 00000000..835ed4ea
--- /dev/null
+++ b/gpxe/src/include/gpxe/ib_sma.h
@@ -0,0 +1,63 @@
+#ifndef _GPXE_IB_SMA_H
+#define _GPXE_IB_SMA_H
+
+/** @file
+ *
+ * Infiniband Subnet Management Agent
+ *
+ */
+
+#include <gpxe/infiniband.h>
+#include <gpxe/process.h>
+
+/** Infiniband Subnet Management Agent operations */
+struct ib_sma_operations {
+ /** Set port information
+ *
+ * @v ibdev Infiniband device
+ * @v port_info New port information
+ */
+ int ( * set_port_info ) ( struct ib_device *ibdev,
+ const struct ib_port_info *port_info );
+};
+
+/** An Infiniband Subnet Management Agent */
+struct ib_sma {
+ /** Infiniband device */
+ struct ib_device *ibdev;
+ /** SMA operations */
+ struct ib_sma_operations *op;
+ /** SMA completion queue */
+ struct ib_completion_queue *cq;
+ /** SMA queue pair */
+ struct ib_queue_pair *qp;
+ /** Poll process */
+ struct process poll;
+};
+
+/** SMA payload size allocated for received packets */
+#define IB_SMA_PAYLOAD_LEN 2048
+
+/** SMA number of send WQEs
+ *
+ * This is a policy decision.
+ */
+#define IB_SMA_NUM_SEND_WQES 4
+
+/** SMA number of receive WQEs
+ *
+ * This is a policy decision.
+ */
+#define IB_SMA_NUM_RECV_WQES 2
+
+/** SMA number of completion queue entries
+ *
+ * This is a policy decision
+ */
+#define IB_SMA_NUM_CQES 8
+
+extern int ib_create_sma ( struct ib_sma *sma, struct ib_device *ibdev,
+ struct ib_sma_operations *op );
+extern void ib_destroy_sma ( struct ib_sma *sma );
+
+#endif /* _GPXE_IB_SMA_H */
diff --git a/gpxe/src/include/gpxe/ib_smc.h b/gpxe/src/include/gpxe/ib_smc.h
new file mode 100644
index 00000000..bb9020bf
--- /dev/null
+++ b/gpxe/src/include/gpxe/ib_smc.h
@@ -0,0 +1,18 @@
+#ifndef _GPXE_IB_SMC_H
+#define _GPXE_IB_SMC_H
+
+/** @file
+ *
+ * Infiniband Subnet Management Client
+ *
+ */
+
+#include <gpxe/infiniband.h>
+
+typedef int ( * ib_local_mad_t ) ( struct ib_device *ibdev,
+ union ib_mad *mad );
+
+extern int ib_smc_update ( struct ib_device *ibdev,
+ ib_local_mad_t local_mad );
+
+#endif /* _GPXE_IB_SMC_H */
diff --git a/gpxe/src/include/gpxe/icmp.h b/gpxe/src/include/gpxe/icmp.h
new file mode 100644
index 00000000..49ade2f2
--- /dev/null
+++ b/gpxe/src/include/gpxe/icmp.h
@@ -0,0 +1,23 @@
+#ifndef _GPXE_ICMP_H
+#define _GPXE_ICMP_H
+
+/** @file
+ *
+ * ICMP protocol
+ *
+ */
+
+/** An ICMP header */
+struct icmp_header {
+ /** Type */
+ uint8_t type;
+ /** Code */
+ uint8_t code;
+ /** Checksum */
+ uint16_t chksum;
+} __attribute__ (( packed ));
+
+#define ICMP_ECHO_RESPONSE 0
+#define ICMP_ECHO_REQUEST 8
+
+#endif /* _GPXE_ICMP_H */
diff --git a/gpxe/src/include/gpxe/image.h b/gpxe/src/include/gpxe/image.h
index 76dc3b8f..f8b1482e 100644
--- a/gpxe/src/include/gpxe/image.h
+++ b/gpxe/src/include/gpxe/image.h
@@ -46,6 +46,21 @@ struct image {
userptr_t user;
unsigned long ul;
} priv;
+
+ /** Replacement image
+ *
+ * An image wishing to replace itself with another image (in a
+ * style similar to a Unix exec() call) should return from its
+ * exec() method with the replacement image set to point to
+ * the new image. The new image must already be in a suitable
+ * state for execution (i.e. loaded).
+ *
+ * If an image unregisters itself as a result of being
+ * executed, it must make sure that its replacement image (if
+ * any) is registered, otherwise the replacement is likely to
+ * be freed before it can be executed.
+ */
+ struct image *replacement;
};
/** Image is loaded */
@@ -79,6 +94,10 @@ struct image_type {
*
* @v image Loaded image
* @ret rc Return status code
+ *
+ * Note that the image may be invalidated by the act of
+ * execution, i.e. an image is allowed to choose to unregister
+ * (and so potentially free) itself.
*/
int ( * exec ) ( struct image *image );
};
diff --git a/gpxe/src/include/gpxe/in.h b/gpxe/src/include/gpxe/in.h
index 40e4d407..831a6110 100644
--- a/gpxe/src/include/gpxe/in.h
+++ b/gpxe/src/include/gpxe/in.h
@@ -71,7 +71,7 @@ struct sockaddr_in {
char pad[ sizeof ( struct sockaddr ) - sizeof ( sa_family_t )
- sizeof ( uint16_t )
- sizeof ( struct in_addr ) ];
-};
+} __attribute__ (( may_alias ));
/**
* IPv6 socket address
@@ -87,7 +87,7 @@ struct sockaddr_in6 {
uint32_t sin6_flowinfo; /* Flow number */
struct in6_addr sin6_addr; /* 128-bit destination address */
uint32_t sin6_scope_id; /* Scope ID */
-};
+} __attribute__ (( may_alias ));
extern int inet_aton ( const char *cp, struct in_addr *inp );
extern char * inet_ntoa ( struct in_addr in );
diff --git a/gpxe/src/include/gpxe/infiniband.h b/gpxe/src/include/gpxe/infiniband.h
index f9e65348..196b5950 100644
--- a/gpxe/src/include/gpxe/infiniband.h
+++ b/gpxe/src/include/gpxe/infiniband.h
@@ -10,6 +10,8 @@
#include <stdint.h>
#include <gpxe/refcnt.h>
#include <gpxe/device.h>
+#include <gpxe/ib_packet.h>
+#include <gpxe/ib_mad.h>
/** Subnet administrator QPN */
#define IB_SA_QPN 1
@@ -20,38 +22,9 @@
/** Subnet administrator queue key */
#define IB_GLOBAL_QKEY 0x80010000UL
-/** An Infiniband Global Identifier */
-struct ib_gid {
- union {
- uint8_t bytes[16];
- uint16_t words[8];
- uint32_t dwords[4];
- } u;
-};
-
-/** An Infiniband Global Route Header */
-struct ib_global_route_header {
- /** IP version, traffic class, and flow label
- *
- * 4 bits : Version of the GRH
- * 8 bits : Traffic class
- * 20 bits : Flow label
- */
- uint32_t ipver_tclass_flowlabel;
- /** Payload length */
- uint16_t paylen;
- /** Next header */
- uint8_t nxthdr;
- /** Hop limit */
- uint8_t hoplmt;
- /** Source GID */
- struct ib_gid sgid;
- /** Destiniation GID */
- struct ib_gid dgid;
-} __attribute__ (( packed ));
-
struct ib_device;
struct ib_queue_pair;
+struct ib_address_vector;
struct ib_completion_queue;
/** An Infiniband Work Queue */
@@ -66,6 +39,8 @@ struct ib_work_queue {
struct list_head list;
/** Number of work queue entries */
unsigned int num_wqes;
+ /** Number of occupied work queue entries */
+ unsigned int fill;
/** Next work queue entry index
*
* This is the index of the next entry to be filled (i.e. the
@@ -80,8 +55,20 @@ struct ib_work_queue {
void *drv_priv;
};
+/** An Infiniband multicast GID */
+struct ib_multicast_gid {
+ /** List of multicast GIDs on this QP */
+ struct list_head list;
+ /** Multicast GID */
+ struct ib_gid gid;
+};
+
/** An Infiniband Queue Pair */
struct ib_queue_pair {
+ /** Containing Infiniband device */
+ struct ib_device *ibdev;
+ /** List of queue pairs on this Infiniband device */
+ struct list_head list;
/** Queue Pair Number */
unsigned long qpn;
/** Queue key */
@@ -90,6 +77,8 @@ struct ib_queue_pair {
struct ib_work_queue send;
/** Receive queue */
struct ib_work_queue recv;
+ /** List of multicast GIDs */
+ struct list_head mgids;
/** Driver private data */
void *drv_priv;
/** Queue owner private data */
@@ -101,6 +90,58 @@ enum ib_queue_pair_mods {
IB_MODIFY_QKEY = 0x0001,
};
+/** An Infiniband Address Vector */
+struct ib_address_vector {
+ /** Queue Pair Number */
+ unsigned long qpn;
+ /** Queue key
+ *
+ * Not specified for received packets.
+ */
+ unsigned long qkey;
+ /** Local ID */
+ unsigned int lid;
+ /** Rate
+ *
+ * Not specified for received packets.
+ */
+ unsigned int rate;
+ /** Service level */
+ unsigned int sl;
+ /** GID is present */
+ unsigned int gid_present;
+ /** GID, if present */
+ struct ib_gid gid;
+};
+
+/** Infiniband completion queue operations */
+struct ib_completion_queue_operations {
+ /**
+ * Complete Send WQE
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ * @v iobuf I/O buffer
+ * @v rc Completion status code
+ */
+ void ( * complete_send ) ( struct ib_device *ibdev,
+ struct ib_queue_pair *qp,
+ struct io_buffer *iobuf, int rc );
+ /**
+ * Complete Receive WQE
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ * @v av Address vector, or NULL
+ * @v iobuf I/O buffer
+ * @v rc Completion status code
+ */
+ void ( * complete_recv ) ( struct ib_device *ibdev,
+ struct ib_queue_pair *qp,
+ struct ib_address_vector *av,
+ struct io_buffer *iobuf, int rc );
+};
+
/** An Infiniband Completion Queue */
struct ib_completion_queue {
/** Completion queue number */
@@ -117,53 +158,12 @@ struct ib_completion_queue {
unsigned long next_idx;
/** List of work queues completing to this queue */
struct list_head work_queues;
+ /** Completion queue operations */
+ struct ib_completion_queue_operations *op;
/** Driver private data */
void *drv_priv;
};
-/** An Infiniband completion */
-struct ib_completion {
- /** Syndrome
- *
- * If non-zero, then the completion is in error.
- */
- unsigned int syndrome;
- /** Length */
- size_t len;
-};
-
-/** An Infiniband completion handler
- *
- * @v ibdev Infiniband device
- * @v qp Queue pair
- * @v completion Completion
- * @v iobuf I/O buffer
- */
-typedef void ( * ib_completer_t ) ( struct ib_device *ibdev,
- struct ib_queue_pair *qp,
- struct ib_completion *completion,
- struct io_buffer *iobuf );
-
-/** An Infiniband Address Vector */
-struct ib_address_vector {
- /** Destination Queue Pair */
- unsigned int dest_qp;
- /** Queue key */
- unsigned long qkey;
- /** Destination Local ID */
- unsigned int dlid;
- /** Rate */
- unsigned int rate;
- /** Service level */
- unsigned int sl;
- /** GID is present */
- unsigned int gid_present;
- /** GID */
- struct ib_gid gid;
-};
-
-struct ib_mad_hdr;
-
/**
* Infiniband device operations
*
@@ -246,15 +246,12 @@ struct ib_device_operations {
*
* @v ibdev Infiniband device
* @v cq Completion queue
- * @v complete_send Send completion handler
- * @v complete_recv Receive completion handler
*
- * The completion handler takes ownership of the I/O buffer.
+ * The relevant completion handler (specified at completion
+ * queue creation time) takes ownership of the I/O buffer.
*/
void ( * poll_cq ) ( struct ib_device *ibdev,
- struct ib_completion_queue *cq,
- ib_completer_t complete_send,
- ib_completer_t complete_recv );
+ struct ib_completion_queue *cq );
/**
* Poll event queue
*
@@ -293,16 +290,6 @@ struct ib_device_operations {
void ( * mcast_detach ) ( struct ib_device *ibdev,
struct ib_queue_pair *qp,
struct ib_gid *gid );
- /**
- * Issue management datagram
- *
- * @v ibdev Infiniband device
- * @v mad Management datagram
- * @v len Length of management datagram
- * @ret rc Return status code
- */
- int ( * mad ) ( struct ib_device *ibdev, struct ib_mad_hdr *mad,
- size_t len );
};
/** An Infiniband device */
@@ -313,26 +300,44 @@ struct ib_device {
struct list_head list;
/** Underlying device */
struct device *dev;
+ /** List of queue pairs */
+ struct list_head qps;
/** Infiniband operations */
struct ib_device_operations *op;
/** Port number */
unsigned int port;
- /** Link state */
- int link_up;
+ /** Port open request counter */
+ unsigned int open_count;
+
+ /** Port state */
+ uint8_t port_state;
+ /** Link width */
+ uint8_t link_width;
+ /** Link speed */
+ uint8_t link_speed;
/** Port GID */
- struct ib_gid port_gid;
+ struct ib_gid gid;
+ /** Port LID */
+ uint16_t lid;
/** Subnet manager LID */
- unsigned long sm_lid;
+ uint16_t sm_lid;
+ /** Subnet manager SL */
+ uint8_t sm_sl;
/** Partition key */
- unsigned int pkey;
+ uint16_t pkey;
+
+ /** Outbound packet sequence number */
+ uint32_t psn;
+
/** Driver private data */
void *drv_priv;
/** Owner private data */
void *owner_priv;
};
-extern struct ib_completion_queue * ib_create_cq ( struct ib_device *ibdev,
- unsigned int num_cqes );
+extern struct ib_completion_queue *
+ib_create_cq ( struct ib_device *ibdev, unsigned int num_cqes,
+ struct ib_completion_queue_operations *op );
extern void ib_destroy_cq ( struct ib_device *ibdev,
struct ib_completion_queue *cq );
extern struct ib_queue_pair *
@@ -343,115 +348,60 @@ extern int ib_modify_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp,
unsigned long mod_list, unsigned long qkey );
extern void ib_destroy_qp ( struct ib_device *ibdev,
struct ib_queue_pair *qp );
+extern struct ib_queue_pair * ib_find_qp_qpn ( struct ib_device *ibdev,
+ unsigned long qpn );
+extern struct ib_queue_pair * ib_find_qp_mgid ( struct ib_device *ibdev,
+ struct ib_gid *gid );
extern struct ib_work_queue * ib_find_wq ( struct ib_completion_queue *cq,
unsigned long qpn, int is_send );
+extern int ib_post_send ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+ struct ib_address_vector *av,
+ struct io_buffer *iobuf );
+extern int ib_post_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+ struct io_buffer *iobuf );
+extern void ib_complete_send ( struct ib_device *ibdev,
+ struct ib_queue_pair *qp,
+ struct io_buffer *iobuf, int rc );
+extern void ib_complete_recv ( struct ib_device *ibdev,
+ struct ib_queue_pair *qp,
+ struct ib_address_vector *av,
+ struct io_buffer *iobuf, int rc );
+extern int ib_open ( struct ib_device *ibdev );
+extern void ib_close ( struct ib_device *ibdev );
+extern int ib_mcast_attach ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+ struct ib_gid *gid );
+extern void ib_mcast_detach ( struct ib_device *ibdev,
+ struct ib_queue_pair *qp, struct ib_gid *gid );
extern struct ib_device * alloc_ibdev ( size_t priv_size );
extern int register_ibdev ( struct ib_device *ibdev );
extern void unregister_ibdev ( struct ib_device *ibdev );
extern void ib_link_state_changed ( struct ib_device *ibdev );
+extern struct list_head ib_devices;
-/**
- * Post send work queue entry
- *
- * @v ibdev Infiniband device
- * @v qp Queue pair
- * @v av Address vector
- * @v iobuf I/O buffer
- * @ret rc Return status code
- */
-static inline __attribute__ (( always_inline )) int
-ib_post_send ( struct ib_device *ibdev, struct ib_queue_pair *qp,
- struct ib_address_vector *av, struct io_buffer *iobuf ) {
- return ibdev->op->post_send ( ibdev, qp, av, iobuf );
-}
-
-/**
- * Post receive work queue entry
- *
- * @v ibdev Infiniband device
- * @v qp Queue pair
- * @v iobuf I/O buffer
- * @ret rc Return status code
- */
-static inline __attribute__ (( always_inline )) int
-ib_post_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp,
- struct io_buffer *iobuf ) {
- return ibdev->op->post_recv ( ibdev, qp, iobuf );
-}
+/** Iterate over all network devices */
+#define for_each_ibdev( ibdev ) \
+ list_for_each_entry ( (ibdev), &ib_devices, list )
/**
* Poll completion queue
*
* @v ibdev Infiniband device
* @v cq Completion queue
- * @v complete_send Send completion handler
- * @v complete_recv Receive completion handler
- */
-static inline __attribute__ (( always_inline )) void
-ib_poll_cq ( struct ib_device *ibdev, struct ib_completion_queue *cq,
- ib_completer_t complete_send, ib_completer_t complete_recv ) {
- ibdev->op->poll_cq ( ibdev, cq, complete_send, complete_recv );
-}
-
-/**
- * Open port
- *
- * @v ibdev Infiniband device
- * @ret rc Return status code
- */
-static inline __attribute__ (( always_inline )) int
-ib_open ( struct ib_device *ibdev ) {
- return ibdev->op->open ( ibdev );
-}
-
-/**
- * Close port
- *
- * @v ibdev Infiniband device
- */
-static inline __attribute__ (( always_inline )) void
-ib_close ( struct ib_device *ibdev ) {
- ibdev->op->close ( ibdev );
-}
-
-/**
- * Attach to multicast group
- *
- * @v ibdev Infiniband device
- * @v qp Queue pair
- * @v gid Multicast GID
- * @ret rc Return status code
*/
-static inline __attribute__ (( always_inline )) int
-ib_mcast_attach ( struct ib_device *ibdev, struct ib_queue_pair *qp,
- struct ib_gid *gid ) {
- return ibdev->op->mcast_attach ( ibdev, qp, gid );
+static inline __always_inline void
+ib_poll_cq ( struct ib_device *ibdev, struct ib_completion_queue *cq ) {
+ ibdev->op->poll_cq ( ibdev, cq );
}
/**
- * Detach from multicast group
+ * Check link state
*
* @v ibdev Infiniband device
- * @v qp Queue pair
- * @v gid Multicast GID
- */
-static inline __attribute__ (( always_inline )) void
-ib_mcast_detach ( struct ib_device *ibdev, struct ib_queue_pair *qp,
- struct ib_gid *gid ) {
- ibdev->op->mcast_detach ( ibdev, qp, gid );
-}
-
-/**
- * Issue management datagram
- *
- * @v ibdev Infiniband device
- * @v mad Management datagram
- * @v len Length of management datagram
- * @ret rc Return status code
+ * @ret link_up Link is up
*/
-static inline __attribute__ (( always_inline )) int
-ib_mad ( struct ib_device *ibdev, struct ib_mad_hdr *mad, size_t len ) {
- return ibdev->op->mad ( ibdev, mad, len );
+static inline __always_inline int
+ib_link_ok ( struct ib_device *ibdev ) {
+ return ( ibdev->port_state == IB_PORT_STATE_ACTIVE );
}
/**
@@ -460,7 +410,7 @@ ib_mad ( struct ib_device *ibdev, struct ib_mad_hdr *mad, size_t len ) {
* @v ibdev Infiniband device
* @ret ibdev Infiniband device
*/
-static inline __attribute__ (( always_inline )) struct ib_device *
+static inline __always_inline struct ib_device *
ibdev_get ( struct ib_device *ibdev ) {
ref_get ( &ibdev->refcnt );
return ibdev;
@@ -471,7 +421,7 @@ ibdev_get ( struct ib_device *ibdev ) {
*
* @v ibdev Infiniband device
*/
-static inline __attribute__ (( always_inline )) void
+static inline __always_inline void
ibdev_put ( struct ib_device *ibdev ) {
ref_put ( &ibdev->refcnt );
}
@@ -482,7 +432,7 @@ ibdev_put ( struct ib_device *ibdev ) {
* @v wq Work queue
* @v priv Private data
*/
-static inline __attribute__ (( always_inline )) void
+static inline __always_inline void
ib_wq_set_drvdata ( struct ib_work_queue *wq, void *priv ) {
wq->drv_priv = priv;
}
@@ -493,7 +443,7 @@ ib_wq_set_drvdata ( struct ib_work_queue *wq, void *priv ) {
* @v wq Work queue
* @ret priv Private data
*/
-static inline __attribute__ (( always_inline )) void *
+static inline __always_inline void *
ib_wq_get_drvdata ( struct ib_work_queue *wq ) {
return wq->drv_priv;
}
@@ -504,7 +454,7 @@ ib_wq_get_drvdata ( struct ib_work_queue *wq ) {
* @v qp Queue pair
* @v priv Private data
*/
-static inline __attribute__ (( always_inline )) void
+static inline __always_inline void
ib_qp_set_drvdata ( struct ib_queue_pair *qp, void *priv ) {
qp->drv_priv = priv;
}
@@ -515,7 +465,7 @@ ib_qp_set_drvdata ( struct ib_queue_pair *qp, void *priv ) {
* @v qp Queue pair
* @ret priv Private data
*/
-static inline __attribute__ (( always_inline )) void *
+static inline __always_inline void *
ib_qp_get_drvdata ( struct ib_queue_pair *qp ) {
return qp->drv_priv;
}
@@ -526,7 +476,7 @@ ib_qp_get_drvdata ( struct ib_queue_pair *qp ) {
* @v qp Queue pair
* @v priv Private data
*/
-static inline __attribute__ (( always_inline )) void
+static inline __always_inline void
ib_qp_set_ownerdata ( struct ib_queue_pair *qp, void *priv ) {
qp->owner_priv = priv;
}
@@ -537,7 +487,7 @@ ib_qp_set_ownerdata ( struct ib_queue_pair *qp, void *priv ) {
* @v qp Queue pair
* @ret priv Private data
*/
-static inline __attribute__ (( always_inline )) void *
+static inline __always_inline void *
ib_qp_get_ownerdata ( struct ib_queue_pair *qp ) {
return qp->owner_priv;
}
@@ -548,7 +498,7 @@ ib_qp_get_ownerdata ( struct ib_queue_pair *qp ) {
* @v cq Completion queue
* @v priv Private data
*/
-static inline __attribute__ (( always_inline )) void
+static inline __always_inline void
ib_cq_set_drvdata ( struct ib_completion_queue *cq, void *priv ) {
cq->drv_priv = priv;
}
@@ -559,7 +509,7 @@ ib_cq_set_drvdata ( struct ib_completion_queue *cq, void *priv ) {
* @v cq Completion queue
* @ret priv Private data
*/
-static inline __attribute__ (( always_inline )) void *
+static inline __always_inline void *
ib_cq_get_drvdata ( struct ib_completion_queue *cq ) {
return cq->drv_priv;
}
@@ -570,7 +520,7 @@ ib_cq_get_drvdata ( struct ib_completion_queue *cq ) {
* @v ibdev Infiniband device
* @v priv Private data
*/
-static inline __attribute__ (( always_inline )) void
+static inline __always_inline void
ib_set_drvdata ( struct ib_device *ibdev, void *priv ) {
ibdev->drv_priv = priv;
}
@@ -581,7 +531,7 @@ ib_set_drvdata ( struct ib_device *ibdev, void *priv ) {
* @v ibdev Infiniband device
* @ret priv Private data
*/
-static inline __attribute__ (( always_inline )) void *
+static inline __always_inline void *
ib_get_drvdata ( struct ib_device *ibdev ) {
return ibdev->drv_priv;
}
@@ -592,7 +542,7 @@ ib_get_drvdata ( struct ib_device *ibdev ) {
* @v ibdev Infiniband device
* @v priv Private data
*/
-static inline __attribute__ (( always_inline )) void
+static inline __always_inline void
ib_set_ownerdata ( struct ib_device *ibdev, void *priv ) {
ibdev->owner_priv = priv;
}
@@ -603,201 +553,9 @@ ib_set_ownerdata ( struct ib_device *ibdev, void *priv ) {
* @v ibdev Infiniband device
* @ret priv Private data
*/
-static inline __attribute__ (( always_inline )) void *
+static inline __always_inline void *
ib_get_ownerdata ( struct ib_device *ibdev ) {
return ibdev->owner_priv;
}
-/*****************************************************************************
- *
- * Management datagrams
- *
- * Portions Copyright (c) 2004 Mellanox Technologies Ltd. All rights
- * reserved.
- *
- */
-
-/* Management base version */
-#define IB_MGMT_BASE_VERSION 1
-
-/* Management classes */
-#define IB_MGMT_CLASS_SUBN_LID_ROUTED 0x01
-#define IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE 0x81
-#define IB_MGMT_CLASS_SUBN_ADM 0x03
-#define IB_MGMT_CLASS_PERF_MGMT 0x04
-#define IB_MGMT_CLASS_BM 0x05
-#define IB_MGMT_CLASS_DEVICE_MGMT 0x06
-#define IB_MGMT_CLASS_CM 0x07
-#define IB_MGMT_CLASS_SNMP 0x08
-#define IB_MGMT_CLASS_VENDOR_RANGE2_START 0x30
-#define IB_MGMT_CLASS_VENDOR_RANGE2_END 0x4F
-
-/* Management methods */
-#define IB_MGMT_METHOD_GET 0x01
-#define IB_MGMT_METHOD_SET 0x02
-#define IB_MGMT_METHOD_GET_RESP 0x81
-#define IB_MGMT_METHOD_SEND 0x03
-#define IB_MGMT_METHOD_TRAP 0x05
-#define IB_MGMT_METHOD_REPORT 0x06
-#define IB_MGMT_METHOD_REPORT_RESP 0x86
-#define IB_MGMT_METHOD_TRAP_REPRESS 0x07
-#define IB_MGMT_METHOD_DELETE 0x15
-#define IB_MGMT_METHOD_RESP 0x80
-
-/* Subnet management attributes */
-#define IB_SMP_ATTR_NOTICE 0x0002
-#define IB_SMP_ATTR_NODE_DESC 0x0010
-#define IB_SMP_ATTR_NODE_INFO 0x0011
-#define IB_SMP_ATTR_SWITCH_INFO 0x0012
-#define IB_SMP_ATTR_GUID_INFO 0x0014
-#define IB_SMP_ATTR_PORT_INFO 0x0015
-#define IB_SMP_ATTR_PKEY_TABLE 0x0016
-#define IB_SMP_ATTR_SL_TO_VL_TABLE 0x0017
-#define IB_SMP_ATTR_VL_ARB_TABLE 0x0018
-#define IB_SMP_ATTR_LINEAR_FORWARD_TABLE 0x0019
-#define IB_SMP_ATTR_RANDOM_FORWARD_TABLE 0x001A
-#define IB_SMP_ATTR_MCAST_FORWARD_TABLE 0x001B
-#define IB_SMP_ATTR_SM_INFO 0x0020
-#define IB_SMP_ATTR_VENDOR_DIAG 0x0030
-#define IB_SMP_ATTR_LED_INFO 0x0031
-#define IB_SMP_ATTR_VENDOR_MASK 0xFF00
-
-#define IB_SA_ATTR_MC_MEMBER_REC 0x38
-#define IB_SA_ATTR_PATH_REC 0x35
-
-#define IB_SA_MCMEMBER_REC_MGID (1<<0)
-#define IB_SA_MCMEMBER_REC_PORT_GID (1<<1)
-#define IB_SA_MCMEMBER_REC_QKEY (1<<2)
-#define IB_SA_MCMEMBER_REC_MLID (1<<3)
-#define IB_SA_MCMEMBER_REC_MTU_SELECTOR (1<<4)
-#define IB_SA_MCMEMBER_REC_MTU (1<<5)
-#define IB_SA_MCMEMBER_REC_TRAFFIC_CLASS (1<<6)
-#define IB_SA_MCMEMBER_REC_PKEY (1<<7)
-#define IB_SA_MCMEMBER_REC_RATE_SELECTOR (1<<8)
-#define IB_SA_MCMEMBER_REC_RATE (1<<9)
-#define IB_SA_MCMEMBER_REC_PACKET_LIFE_TIME_SELECTOR (1<<10)
-#define IB_SA_MCMEMBER_REC_PACKET_LIFE_TIME (1<<11)
-#define IB_SA_MCMEMBER_REC_SL (1<<12)
-#define IB_SA_MCMEMBER_REC_FLOW_LABEL (1<<13)
-#define IB_SA_MCMEMBER_REC_HOP_LIMIT (1<<14)
-#define IB_SA_MCMEMBER_REC_SCOPE (1<<15)
-#define IB_SA_MCMEMBER_REC_JOIN_STATE (1<<16)
-#define IB_SA_MCMEMBER_REC_PROXY_JOIN (1<<17)
-
-#define IB_SA_PATH_REC_DGID (1<<2)
-#define IB_SA_PATH_REC_SGID (1<<3)
-
-struct ib_mad_hdr {
- uint8_t base_version;
- uint8_t mgmt_class;
- uint8_t class_version;
- uint8_t method;
- uint16_t status;
- uint16_t class_specific;
- uint32_t tid[2];
- uint16_t attr_id;
- uint16_t resv;
- uint32_t attr_mod;
-} __attribute__ (( packed ));
-
-struct ib_sa_hdr {
- uint32_t sm_key[2];
- uint16_t reserved;
- uint16_t attrib_offset;
- uint32_t comp_mask[2];
-} __attribute__ (( packed ));
-
-struct ib_rmpp_hdr {
- uint32_t raw[3];
-} __attribute__ (( packed ));
-
-struct ib_mad_data {
- struct ib_mad_hdr mad_hdr;
- uint8_t data[232];
-} __attribute__ (( packed ));
-
-struct ib_mad_guid_info {
- struct ib_mad_hdr mad_hdr;
- uint32_t mkey[2];
- uint32_t reserved[8];
- uint8_t gid_local[8];
-} __attribute__ (( packed ));
-
-struct ib_mad_port_info {
- struct ib_mad_hdr mad_hdr;
- uint32_t mkey[2];
- uint32_t reserved[8];
- uint32_t mkey2[2];
- uint8_t gid_prefix[8];
- uint16_t lid;
- uint16_t mastersm_lid;
- uint32_t cap_mask;
- uint16_t diag_code;
- uint16_t mkey_lease_period;
- uint8_t local_port_num;
- uint8_t link_width_enabled;
- uint8_t link_width_supported;
- uint8_t link_width_active;
- uint8_t port_state__link_speed_supported;
- uint8_t link_down_def_state__port_phys_state;
- uint8_t lmc__r1__mkey_prot_bits;
- uint8_t link_speed_enabled__link_speed_active;
-} __attribute__ (( packed ));
-
-struct ib_mad_pkey_table {
- struct ib_mad_hdr mad_hdr;
- uint32_t mkey[2];
- uint32_t reserved[8];
- uint16_t pkey[16][2];
-} __attribute__ (( packed ));
-
-struct ib_mad_path_record {
- struct ib_mad_hdr mad_hdr;
- struct ib_rmpp_hdr rmpp_hdr;
- struct ib_sa_hdr sa_hdr;
- uint32_t reserved0[2];
- struct ib_gid dgid;
- struct ib_gid sgid;
- uint16_t dlid;
- uint16_t slid;
- uint32_t hop_limit__flow_label__raw_traffic;
- uint32_t pkey__numb_path__reversible__tclass;
- uint8_t reserved1;
- uint8_t reserved__sl;
- uint8_t mtu_selector__mtu;
- uint8_t rate_selector__rate;
- uint32_t preference__packet_lifetime__packet_lifetime_selector;
- uint32_t reserved2[35];
-} __attribute__ (( packed ));
-
-struct ib_mad_mc_member_record {
- struct ib_mad_hdr mad_hdr;
- struct ib_rmpp_hdr rmpp_hdr;
- struct ib_sa_hdr sa_hdr;
- struct ib_gid mgid;
- struct ib_gid port_gid;
- uint32_t qkey;
- uint16_t mlid;
- uint8_t mtu_selector__mtu;
- uint8_t tclass;
- uint16_t pkey;
- uint8_t rate_selector__rate;
- uint8_t packet_lifetime_selector__packet_lifetime;
- uint32_t sl__flow_label__hop_limit;
- uint8_t scope__join_state;
- uint8_t proxy_join__reserved;
- uint16_t reserved0;
- uint32_t reserved1[37];
-} __attribute__ (( packed ));
-
-union ib_mad {
- struct ib_mad_hdr mad_hdr;
- struct ib_mad_data data;
- struct ib_mad_guid_info guid_info;
- struct ib_mad_port_info port_info;
- struct ib_mad_pkey_table pkey_table;
- struct ib_mad_path_record path_record;
- struct ib_mad_mc_member_record mc_member_record;
-} __attribute__ (( packed ));
-
#endif /* _GPXE_INFINIBAND_H */
diff --git a/gpxe/src/include/gpxe/init.h b/gpxe/src/include/gpxe/init.h
index d2b450d7..e0e9f9c8 100644
--- a/gpxe/src/include/gpxe/init.h
+++ b/gpxe/src/include/gpxe/init.h
@@ -63,6 +63,7 @@ struct startup_fn {
#define STARTUP_EARLY 01 /**< Early startup */
#define STARTUP_NORMAL 02 /**< Normal startup */
+#define STARTUP_LATE 03 /**< Late startup */
/** @} */
diff --git a/gpxe/src/include/gpxe/io.h b/gpxe/src/include/gpxe/io.h
new file mode 100644
index 00000000..ebb8ba30
--- /dev/null
+++ b/gpxe/src/include/gpxe/io.h
@@ -0,0 +1,504 @@
+#ifndef _GPXE_IO_H
+#define _GPXE_IO_H
+
+/** @file
+ *
+ * gPXE I/O API
+ *
+ * The I/O API provides methods for reading from and writing to
+ * memory-mapped and I/O-mapped devices.
+ *
+ * The standard methods (readl()/writel() etc.) do not strictly check
+ * the type of the address parameter; this is because traditional
+ * usage does not necessarily provide the correct pointer type. For
+ * example, code written for ISA devices at fixed I/O addresses (such
+ * as the keyboard controller) tend to use plain integer constants for
+ * the address parameter.
+ */
+
+#include <stdint.h>
+#include <gpxe/api.h>
+#include <config/ioapi.h>
+#include <gpxe/uaccess.h>
+
+/**
+ * Calculate static inline I/O API function name
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ * @ret _subsys_func Subsystem API function
+ */
+#define IOAPI_INLINE( _subsys, _api_func ) \
+ SINGLE_API_INLINE ( IOAPI_PREFIX_ ## _subsys, _api_func )
+
+/**
+ * Provide an I/O API implementation
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ * @v _func Implementing function
+ */
+#define PROVIDE_IOAPI( _subsys, _api_func, _func ) \
+ PROVIDE_SINGLE_API ( IOAPI_PREFIX_ ## _subsys, _api_func, _func )
+
+/**
+ * Provide a static inline I/O API implementation
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ */
+#define PROVIDE_IOAPI_INLINE( _subsys, _api_func ) \
+ PROVIDE_SINGLE_API_INLINE ( IOAPI_PREFIX_ ## _subsys, _api_func )
+
+/* Include all architecture-independent I/O API headers */
+#include <gpxe/efi/efi_io.h>
+
+/* Include all architecture-dependent I/O API headers */
+#include <bits/io.h>
+
+/**
+ * Wrap an I/O read
+ *
+ * @v _func I/O API function
+ * @v _type Data type
+ * @v io_addr I/O address
+ * @v _prefix Prefix for address in debug message
+ * @v _ndigits Number of hex digits for this data type
+ */
+#define IOAPI_READ( _func, _type, io_addr, _prefix, _ndigits ) ( { \
+ volatile _type *_io_addr = \
+ ( ( volatile _type * ) ( intptr_t ) (io_addr) ); \
+ _type _data = _func ( _io_addr ); \
+ DBGIO ( "[" _prefix " %08lx] => %0" #_ndigits "llx\n", \
+ io_to_bus ( _io_addr ), ( unsigned long long ) _data ); \
+ _data; } )
+
+/**
+ * Wrap an I/O write
+ *
+ * @v _func I/O API function
+ * @v _type Data type
+ * @v data Value to write
+ * @v io_addr I/O address
+ * @v _prefix Prefix for address in debug message
+ * @v _ndigits Number of hex digits for this data type
+ */
+#define IOAPI_WRITE( _func, _type, data, io_addr, _prefix, _ndigits ) do { \
+ volatile _type *_io_addr = \
+ ( ( volatile _type * ) ( intptr_t ) (io_addr) ); \
+ _type _data = (data); \
+ DBGIO ( "[" _prefix " %08lx] <= %0" #_ndigits "llx\n", \
+ io_to_bus ( _io_addr ), ( unsigned long long ) _data ); \
+ _func ( _data, _io_addr ); \
+ } while ( 0 )
+
+/**
+ * Wrap an I/O string read
+ *
+ * @v _func I/O API function
+ * @v _type Data type
+ * @v io_addr I/O address
+ * @v data Data buffer
+ * @v count Number of elements to read
+ * @v _prefix Prefix for address in debug message
+ * @v _ndigits Number of hex digits for this data type
+ */
+#define IOAPI_READS( _func, _type, io_addr, data, count, _prefix, _ndigits ) \
+ do { \
+ volatile _type *_io_addr = \
+ ( ( volatile _type * ) ( intptr_t ) (io_addr) ); \
+ void *_data_void = (data); /* Check data is a pointer */ \
+ _type * _data = ( ( _type * ) _data_void ); \
+ const _type * _dbg_data = _data; \
+ unsigned int _count = (count); \
+ unsigned int _dbg_count = _count; \
+ _func ( _io_addr, _data, _count ); \
+ DBGIO ( "[" _prefix " %08lx] =>", io_to_bus ( _io_addr ) ); \
+ while ( _dbg_count-- ) { \
+ DBGIO ( " %0" #_ndigits "llx", \
+ ( ( unsigned long long ) *(_dbg_data++) ) ); \
+ } \
+ DBGIO ( "\n" ); \
+ } while ( 0 )
+
+/**
+ * Wrap an I/O string write
+ *
+ * @v _func I/O API function
+ * @v _type Data type
+ * @v io_addr I/O address
+ * @v data Data buffer
+ * @v count Number of elements to write
+ * @v _prefix Prefix for address in debug message
+ * @v _ndigits Number of hex digits for this data type
+ */
+#define IOAPI_WRITES( _func, _type, io_addr, data, count, _prefix, _ndigits ) \
+ do { \
+ volatile _type *_io_addr = \
+ ( ( volatile _type * ) ( intptr_t ) (io_addr) ); \
+ const void *_data_void = (data); /* Check data is a pointer */ \
+ const _type * _data = ( ( const _type * ) _data_void ); \
+ const _type * _dbg_data = _data; \
+ unsigned int _count = (count); \
+ unsigned int _dbg_count = _count; \
+ DBGIO ( "[" _prefix " %08lx] <=", io_to_bus ( _io_addr ) ); \
+ while ( _dbg_count-- ) { \
+ DBGIO ( " %0" #_ndigits "llx", \
+ ( ( unsigned long long ) *(_dbg_data++) ) ); \
+ } \
+ DBGIO ( "\n" ); \
+ _func ( _io_addr, _data, _count ); \
+ } while ( 0 )
+
+/**
+ * Convert physical address to a bus address
+ *
+ * @v phys_addr Physical address
+ * @ret bus_addr Bus address
+ */
+unsigned long phys_to_bus ( unsigned long phys_addr );
+
+/**
+ * Convert bus address to a physical address
+ *
+ * @v bus_addr Bus address
+ * @ret phys_addr Physical address
+ */
+unsigned long bus_to_phys ( unsigned long bus_addr );
+
+/**
+ * Convert virtual address to a bus address
+ *
+ * @v addr Virtual address
+ * @ret bus_addr Bus address
+ */
+static inline __always_inline unsigned long
+virt_to_bus ( volatile const void *addr ) {
+ return phys_to_bus ( virt_to_phys ( addr ) );
+}
+
+/**
+ * Convert bus address to a virtual address
+ *
+ * @v bus_addr Bus address
+ * @ret addr Virtual address
+ *
+ * This operation is not available under all memory models.
+ */
+static inline __always_inline void * bus_to_virt ( unsigned long bus_addr ) {
+ return phys_to_virt ( bus_to_phys ( bus_addr ) );
+}
+
+/**
+ * Map bus address as an I/O address
+ *
+ * @v bus_addr Bus address
+ * @v len Length of region
+ * @ret io_addr I/O address
+ */
+void * ioremap ( unsigned long bus_addr, size_t len );
+
+/**
+ * Unmap I/O address
+ *
+ * @v io_addr I/O address
+ */
+void iounmap ( volatile const void *io_addr );
+
+/**
+ * Convert I/O address to bus address (for debug only)
+ *
+ * @v io_addr I/O address
+ * @ret bus_addr Bus address
+ */
+unsigned long io_to_bus ( volatile const void *io_addr );
+
+/**
+ * Read byte from memory-mapped device
+ *
+ * @v io_addr I/O address
+ * @ret data Value read
+ */
+uint8_t readb ( volatile uint8_t *io_addr );
+#define readb( io_addr ) IOAPI_READ ( readb, uint8_t, io_addr, "MEM", 2 )
+
+/**
+ * Read 16-bit word from memory-mapped device
+ *
+ * @v io_addr I/O address
+ * @ret data Value read
+ */
+uint16_t readw ( volatile uint16_t *io_addr );
+#define readw( io_addr ) IOAPI_READ ( readw, uint16_t, io_addr, "MEM", 4 )
+
+/**
+ * Read 32-bit dword from memory-mapped device
+ *
+ * @v io_addr I/O address
+ * @ret data Value read
+ */
+uint32_t readl ( volatile uint32_t *io_addr );
+#define readl( io_addr ) IOAPI_READ ( readl, uint32_t, io_addr, "MEM", 8 )
+
+/**
+ * Read 64-bit qword from memory-mapped device
+ *
+ * @v io_addr I/O address
+ * @ret data Value read
+ */
+uint64_t readq ( volatile uint64_t *io_addr );
+#define readq( io_addr ) IOAPI_READ ( readq, uint64_t, io_addr, "MEM", 16 )
+
+/**
+ * Write byte to memory-mapped device
+ *
+ * @v data Value to write
+ * @v io_addr I/O address
+ */
+void writeb ( uint8_t data, volatile uint8_t *io_addr );
+#define writeb( data, io_addr ) \
+ IOAPI_WRITE ( writeb, uint8_t, data, io_addr, "MEM", 2 )
+
+/**
+ * Write 16-bit word to memory-mapped device
+ *
+ * @v data Value to write
+ * @v io_addr I/O address
+ */
+void writew ( uint16_t data, volatile uint16_t *io_addr );
+#define writew( data, io_addr ) \
+ IOAPI_WRITE ( writew, uint16_t, data, io_addr, "MEM", 4 )
+
+/**
+ * Write 32-bit dword to memory-mapped device
+ *
+ * @v data Value to write
+ * @v io_addr I/O address
+ */
+void writel ( uint32_t data, volatile uint32_t *io_addr );
+#define writel( data, io_addr ) \
+ IOAPI_WRITE ( writel, uint32_t, data, io_addr, "MEM", 8 )
+
+/**
+ * Write 64-bit qword to memory-mapped device
+ *
+ * @v data Value to write
+ * @v io_addr I/O address
+ */
+void writeq ( uint64_t data, volatile uint64_t *io_addr );
+#define writeq( data, io_addr ) \
+ IOAPI_WRITE ( writeq, uint64_t, data, io_addr, "MEM", 16 )
+
+/**
+ * Read byte from I/O-mapped device
+ *
+ * @v io_addr I/O address
+ * @ret data Value read
+ */
+uint8_t inb ( volatile uint8_t *io_addr );
+#define inb( io_addr ) IOAPI_READ ( inb, uint8_t, io_addr, "IO", 2 )
+
+/**
+ * Read 16-bit word from I/O-mapped device
+ *
+ * @v io_addr I/O address
+ * @ret data Value read
+ */
+uint16_t inw ( volatile uint16_t *io_addr );
+#define inw( io_addr ) IOAPI_READ ( inw, uint16_t, io_addr, "IO", 4 )
+
+/**
+ * Read 32-bit dword from I/O-mapped device
+ *
+ * @v io_addr I/O address
+ * @ret data Value read
+ */
+uint32_t inl ( volatile uint32_t *io_addr );
+#define inl( io_addr ) IOAPI_READ ( inl, uint32_t, io_addr, "IO", 8 )
+
+/**
+ * Write byte to I/O-mapped device
+ *
+ * @v data Value to write
+ * @v io_addr I/O address
+ */
+void outb ( uint8_t data, volatile uint8_t *io_addr );
+#define outb( data, io_addr ) \
+ IOAPI_WRITE ( outb, uint8_t, data, io_addr, "IO", 2 )
+
+/**
+ * Write 16-bit word to I/O-mapped device
+ *
+ * @v data Value to write
+ * @v io_addr I/O address
+ */
+void outw ( uint16_t data, volatile uint16_t *io_addr );
+#define outw( data, io_addr ) \
+ IOAPI_WRITE ( outw, uint16_t, data, io_addr, "IO", 4 )
+
+/**
+ * Write 32-bit dword to I/O-mapped device
+ *
+ * @v data Value to write
+ * @v io_addr I/O address
+ */
+void outl ( uint32_t data, volatile uint32_t *io_addr );
+#define outl( data, io_addr ) \
+ IOAPI_WRITE ( outl, uint32_t, data, io_addr, "IO", 8 )
+
+/**
+ * Read bytes from I/O-mapped device
+ *
+ * @v io_addr I/O address
+ * @v data Data buffer
+ * @v count Number of bytes to read
+ */
+void insb ( volatile uint8_t *io_addr, uint8_t *data, unsigned int count );
+#define insb( io_addr, data, count ) \
+ IOAPI_READS ( insb, uint8_t, io_addr, data, count, "IO", 2 )
+
+/**
+ * Read 16-bit words from I/O-mapped device
+ *
+ * @v io_addr I/O address
+ * @v data Data buffer
+ * @v count Number of words to read
+ */
+void insw ( volatile uint16_t *io_addr, uint16_t *data, unsigned int count );
+#define insw( io_addr, data, count ) \
+ IOAPI_READS ( insw, uint16_t, io_addr, data, count, "IO", 4 )
+
+/**
+ * Read 32-bit words from I/O-mapped device
+ *
+ * @v io_addr I/O address
+ * @v data Data buffer
+ * @v count Number of words to read
+ */
+void insl ( volatile uint32_t *io_addr, uint32_t *data, unsigned int count );
+#define insl( io_addr, data, count ) \
+ IOAPI_READS ( insl, uint32_t, io_addr, data, count, "IO", 8 )
+
+/**
+ * Write bytes to I/O-mapped device
+ *
+ * @v io_addr I/O address
+ * @v data Data buffer
+ * @v count Number of bytes to write
+ */
+void outsb ( volatile uint8_t *io_addr, const uint8_t *data,
+ unsigned int count );
+#define outsb( io_addr, data, count ) \
+ IOAPI_WRITES ( outsb, uint8_t, io_addr, data, count, "IO", 2 )
+
+/**
+ * Write 16-bit words to I/O-mapped device
+ *
+ * @v io_addr I/O address
+ * @v data Data buffer
+ * @v count Number of words to write
+ */
+void outsw ( volatile uint16_t *io_addr, const uint16_t *data,
+ unsigned int count );
+#define outsw( io_addr, data, count ) \
+ IOAPI_WRITES ( outsw, uint16_t, io_addr, data, count, "IO", 4 )
+
+/**
+ * Write 32-bit words to I/O-mapped device
+ *
+ * @v io_addr I/O address
+ * @v data Data buffer
+ * @v count Number of words to write
+ */
+void outsl ( volatile uint32_t *io_addr, const uint32_t *data,
+ unsigned int count );
+#define outsl( io_addr, data, count ) \
+ IOAPI_WRITES ( outsl, uint32_t, io_addr, data, count, "IO", 8 )
+
+/**
+ * Slow down I/O
+ *
+ */
+void iodelay ( void );
+
+/**
+ * Read value from I/O-mapped device, slowly
+ *
+ * @v _func Function to use to read value
+ * @v data Value to write
+ * @v io_addr I/O address
+ */
+#define INX_P( _func, _type, io_addr ) ( { \
+ _type _data = _func ( (io_addr) ); \
+ iodelay(); \
+ _data; } )
+
+/**
+ * Read byte from I/O-mapped device
+ *
+ * @v io_addr I/O address
+ * @ret data Value read
+ */
+#define inb_p( io_addr ) INX_P ( inb, uint8_t, io_addr )
+
+/**
+ * Read 16-bit word from I/O-mapped device
+ *
+ * @v io_addr I/O address
+ * @ret data Value read
+ */
+#define inw_p( io_addr ) INX_P ( inw, uint16_t, io_addr )
+
+/**
+ * Read 32-bit dword from I/O-mapped device
+ *
+ * @v io_addr I/O address
+ * @ret data Value read
+ */
+#define inl_p( io_addr ) INX_P ( inl, uint32_t, io_addr )
+
+/**
+ * Write value to I/O-mapped device, slowly
+ *
+ * @v _func Function to use to write value
+ * @v data Value to write
+ * @v io_addr I/O address
+ */
+#define OUTX_P( _func, data, io_addr ) do { \
+ _func ( (data), (io_addr) ); \
+ iodelay(); \
+ } while ( 0 )
+
+/**
+ * Write byte to I/O-mapped device, slowly
+ *
+ * @v data Value to write
+ * @v io_addr I/O address
+ */
+#define outb_p( data, io_addr ) OUTX_P ( outb, data, io_addr )
+
+/**
+ * Write 16-bit word to I/O-mapped device, slowly
+ *
+ * @v data Value to write
+ * @v io_addr I/O address
+ */
+#define outw_p( data, io_addr ) OUTX_P ( outw, data, io_addr )
+
+/**
+ * Write 32-bit dword to I/O-mapped device, slowly
+ *
+ * @v data Value to write
+ * @v io_addr I/O address
+ */
+#define outl_p( data, io_addr ) OUTX_P ( outl, data, io_addr )
+
+/**
+ * Memory barrier
+ *
+ */
+void mb ( void );
+#define rmb() mb()
+#define wmb() mb()
+
+#endif /* _GPXE_IO_H */
diff --git a/gpxe/src/include/gpxe/iobuf.h b/gpxe/src/include/gpxe/iobuf.h
index ff787754..6d1a58a4 100644
--- a/gpxe/src/include/gpxe/iobuf.h
+++ b/gpxe/src/include/gpxe/iobuf.h
@@ -181,6 +181,44 @@ static inline size_t iob_tailroom ( struct io_buffer *iobuf ) {
return ( iobuf->end - iobuf->tail );
}
+/**
+ * Create a temporary I/O buffer
+ *
+ * @v iobuf I/O buffer
+ * @v data Data buffer
+ * @v len Length of data
+ * @v max_len Length of buffer
+ *
+ * It is sometimes useful to use the iob_xxx() methods on temporary
+ * data buffers.
+ */
+static inline void iob_populate ( struct io_buffer *iobuf,
+ void *data, size_t len, size_t max_len ) {
+ iobuf->head = iobuf->data = data;
+ iobuf->tail = ( data + len );
+ iobuf->end = ( data + max_len );
+}
+
+/**
+ * Disown an I/O buffer
+ *
+ * @v iobuf I/O buffer
+ *
+ * There are many functions that take ownership of the I/O buffer they
+ * are passed as a parameter. The caller should not retain a pointer
+ * to the I/O buffer. Use iob_disown() to automatically nullify the
+ * caller's pointer, e.g.:
+ *
+ * xfer_deliver_iob ( xfer, iob_disown ( iobuf ) );
+ *
+ * This will ensure that iobuf is set to NULL for any code after the
+ * call to xfer_deliver_iob().
+ */
+#define iob_disown( iobuf ) ( { \
+ struct io_buffer *__iobuf = (iobuf); \
+ (iobuf) = NULL; \
+ __iobuf; } )
+
extern struct io_buffer * __malloc alloc_iob ( size_t len );
extern void free_iob ( struct io_buffer *iobuf );
extern void iob_pad ( struct io_buffer *iobuf, size_t min_len );
diff --git a/gpxe/src/include/gpxe/ipoib.h b/gpxe/src/include/gpxe/ipoib.h
index bcbdc4c6..80adee5b 100644
--- a/gpxe/src/include/gpxe/ipoib.h
+++ b/gpxe/src/include/gpxe/ipoib.h
@@ -8,6 +8,9 @@
#include <gpxe/infiniband.h>
+/** IPoIB packet length */
+#define IPOIB_PKT_LEN 2048
+
/** IPoIB MAC address length */
#define IPOIB_ALEN 20
@@ -23,33 +26,30 @@ struct ipoib_mac {
} __attribute__ (( packed ));
/** IPoIB link-layer header length */
-#define IPOIB_HLEN 24
-
-/**
- * IPoIB link-layer header pseudo portion
- *
- * This part doesn't actually exist on the wire, but it provides a
- * convenient way to fit into the typical network device model.
- */
-struct ipoib_pseudo_hdr {
- /** Peer address */
- struct ipoib_mac peer;
-} __attribute__ (( packed ));
+#define IPOIB_HLEN 4
-/** IPoIB link-layer header real portion */
-struct ipoib_real_hdr {
+/** IPoIB link-layer header */
+struct ipoib_hdr {
/** Network-layer protocol */
uint16_t proto;
/** Reserved, must be zero */
- uint16_t reserved;
-} __attribute__ (( packed ));
-
-/** An IPoIB link-layer header */
-struct ipoib_hdr {
- /** Pseudo portion */
- struct ipoib_pseudo_hdr pseudo;
- /** Real portion */
- struct ipoib_real_hdr real;
+ union {
+ /** Reserved, must be zero */
+ uint16_t reserved;
+ /** Peer addresses
+ *
+ * We use these fields internally to represent the
+ * peer addresses using a lookup key. There simply
+ * isn't enough room in the IPoIB header to store
+ * literal source or destination MAC addresses.
+ */
+ struct {
+ /** Destination address key */
+ uint8_t dest;
+ /** Source address key */
+ uint8_t src;
+ } __attribute__ (( packed )) peer;
+ } __attribute__ (( packed )) u;
} __attribute__ (( packed ));
extern struct ll_protocol ipoib_protocol;
@@ -68,6 +68,7 @@ static inline struct net_device * alloc_ipoibdev ( size_t priv_size ) {
netdev = alloc_netdev ( priv_size );
if ( netdev ) {
netdev->ll_protocol = &ipoib_protocol;
+ netdev->max_pkt_len = IPOIB_PKT_LEN;
}
return netdev;
}
diff --git a/gpxe/src/include/gpxe/keys.h b/gpxe/src/include/gpxe/keys.h
index 7a0b5101..3da8a1ff 100644
--- a/gpxe/src/include/gpxe/keys.h
+++ b/gpxe/src/include/gpxe/keys.h
@@ -52,26 +52,23 @@
*
* The names are chosen to match those used by curses. The values are
* chosen to facilitate easy conversion from a received ANSI escape
- * sequence to a KEY_XXX constant. The KEY_XXX constant is simply
- * 0x100 plus the first byte following CSI in the ANSI escape
- * sequence. For example, KEY_LEFT is 0x144, since a left cursor key
- * is transmitted as the ANSI sequence "^[[D".
+ * sequence to a KEY_XXX constant.
*/
-#define KEY_ANSI( character ) ( 0x100 + (character) )
+#define KEY_ANSI( n, terminator ) ( 0x100 * ( (n) + 1 ) + (terminator) )
#define KEY_MIN 0x101
-#define KEY_UP KEY_ANSI ( 'A' ) /**< Up arrow */
-#define KEY_DOWN KEY_ANSI ( 'B' ) /**< Down arrow */
-#define KEY_RIGHT KEY_ANSI ( 'C' ) /**< Right arrow */
-#define KEY_LEFT KEY_ANSI ( 'D' ) /**< Left arrow */
-#define KEY_END KEY_ANSI ( 'F' ) /**< End */
-#define KEY_HOME KEY_ANSI ( 'H' ) /**< Home */
-#define KEY_IC KEY_ANSI ( '2' ) /**< Insert */
-#define KEY_DC KEY_ANSI ( '3' ) /**< Delete */
-#define KEY_PPAGE KEY_ANSI ( '5' ) /**< Page up */
-#define KEY_NPAGE KEY_ANSI ( '6' ) /**< Page down */
-#define KEY_MAX 0x1ff
+#define KEY_UP KEY_ANSI ( 0, 'A' ) /**< Up arrow */
+#define KEY_DOWN KEY_ANSI ( 0, 'B' ) /**< Down arrow */
+#define KEY_RIGHT KEY_ANSI ( 0, 'C' ) /**< Right arrow */
+#define KEY_LEFT KEY_ANSI ( 0, 'D' ) /**< Left arrow */
+#define KEY_END KEY_ANSI ( 0, 'F' ) /**< End */
+#define KEY_HOME KEY_ANSI ( 0, 'H' ) /**< Home */
+#define KEY_IC KEY_ANSI ( 2, '~' ) /**< Insert */
+#define KEY_DC KEY_ANSI ( 3, '~' ) /**< Delete */
+#define KEY_PPAGE KEY_ANSI ( 5, '~' ) /**< Page up */
+#define KEY_NPAGE KEY_ANSI ( 6, '~' ) /**< Page down */
+#define KEY_F8 KEY_ANSI ( 19, '~' ) /**< F8 (for PXE) */
/* Not in the [KEY_MIN,KEY_MAX] range; terminals seem to send these as
* normal ASCII values.
diff --git a/gpxe/src/include/gpxe/login_ui.h b/gpxe/src/include/gpxe/login_ui.h
new file mode 100644
index 00000000..d92ba8f3
--- /dev/null
+++ b/gpxe/src/include/gpxe/login_ui.h
@@ -0,0 +1,12 @@
+#ifndef _GPXE_LOGIN_UI_H
+#define _GPXE_LOGIN_UI_H
+
+/** @file
+ *
+ * Login UI
+ *
+ */
+
+extern int login_ui ( void );
+
+#endif /* _GPXE_LOGIN_UI_H */
diff --git a/gpxe/src/include/gpxe/nap.h b/gpxe/src/include/gpxe/nap.h
new file mode 100644
index 00000000..f9ae3cf4
--- /dev/null
+++ b/gpxe/src/include/gpxe/nap.h
@@ -0,0 +1,54 @@
+#ifndef _GPXE_NAP_H
+#define _GPXE_NAP_H
+
+/** @file
+ *
+ * CPU sleeping
+ *
+ */
+
+#include <gpxe/api.h>
+#include <config/nap.h>
+
+/**
+ * Calculate static inline CPU sleeping API function name
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ * @ret _subsys_func Subsystem API function
+ */
+#define NAP_INLINE( _subsys, _api_func ) \
+ SINGLE_API_INLINE ( NAP_PREFIX_ ## _subsys, _api_func )
+
+/**
+ * Provide an CPU sleeping API implementation
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ * @v _func Implementing function
+ */
+#define PROVIDE_NAP( _subsys, _api_func, _func ) \
+ PROVIDE_SINGLE_API ( NAP_PREFIX_ ## _subsys, _api_func, _func )
+
+/**
+ * Provide a static inline CPU sleeping API implementation
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ */
+#define PROVIDE_NAP_INLINE( _subsys, _api_func ) \
+ PROVIDE_SINGLE_API_INLINE ( NAP_PREFIX_ ## _subsys, _api_func )
+
+/* Include all architecture-independent I/O API headers */
+#include <gpxe/null_nap.h>
+
+/* Include all architecture-dependent I/O API headers */
+#include <bits/nap.h>
+
+/**
+ * Sleep until next CPU interrupt
+ *
+ */
+void cpu_nap ( void );
+
+#endif /* _GPXE_NAP_H */
diff --git a/gpxe/src/include/gpxe/netdevice.h b/gpxe/src/include/gpxe/netdevice.h
index cdc8cbad..f1585de0 100644
--- a/gpxe/src/include/gpxe/netdevice.h
+++ b/gpxe/src/include/gpxe/netdevice.h
@@ -23,7 +23,7 @@ struct device;
#define MAX_LL_ADDR_LEN 20
/** Maximum length of a link-layer header */
-#define MAX_LL_HEADER_LEN 32
+#define MAX_LL_HEADER_LEN 6
/** Maximum length of a network-layer address */
#define MAX_NET_ADDR_LEN 4
@@ -79,34 +79,24 @@ struct ll_protocol {
* Add link-layer header
*
* @v iobuf I/O buffer
- * @v netdev Network device
- * @v net_protocol Network-layer protocol
* @v ll_dest Link-layer destination address
+ * @v ll_source Source link-layer address
+ * @v net_proto Network-layer protocol, in network-byte order
* @ret rc Return status code
- *
- * This method should prepend in the link-layer header
- * (e.g. the Ethernet DIX header).
*/
- int ( * push ) ( struct io_buffer *iobuf, struct net_device *netdev,
- struct net_protocol *net_protocol,
- const void *ll_dest );
+ int ( * push ) ( struct io_buffer *iobuf, const void *ll_dest,
+ const void *ll_source, uint16_t net_proto );
/**
* Remove link-layer header
*
- * @v iobuf I/O buffer
- * @v netdev Network device
- * @v net_proto Network-layer protocol, in network-byte order
- * @v ll_source Source link-layer address
- * @ret rc Return status code
- *
- * This method should strip off the link-layer header
- * (e.g. the Ethernet DIX header) and return the protocol and
- * source link-layer address. The method must not alter the
- * packet content, and may return the link-layer address as a
- * pointer to data within the packet.
+ * @v iobuf I/O buffer
+ * @ret ll_dest Link-layer destination address
+ * @ret ll_source Source link-layer address
+ * @ret net_proto Network-layer protocol, in network-byte order
+ * @ret rc Return status code
*/
- int ( * pull ) ( struct io_buffer *iobuf, struct net_device *netdev,
- uint16_t *net_proto, const void **ll_source );
+ int ( * pull ) ( struct io_buffer *iobuf, const void **ll_dest,
+ const void **ll_source, uint16_t *net_proto );
/**
* Transcribe link-layer address
*
@@ -120,6 +110,16 @@ struct ll_protocol {
* allocated.
*/
const char * ( * ntoa ) ( const void * ll_addr );
+ /**
+ * Hash multicast address
+ *
+ * @v af Address family
+ * @v net_addr Network-layer address
+ * @v ll_addr Link-layer address to fill in
+ * @ret rc Return status code
+ */
+ int ( * mc_hash ) ( unsigned int af, const void *net_addr,
+ void *ll_addr );
/** Link-layer protocol
*
* This is an ARPHRD_XXX constant, in network byte order.
@@ -193,16 +193,25 @@ struct net_device_operations {
void ( * irq ) ( struct net_device *netdev, int enable );
};
+/** Network device error */
+struct net_device_error {
+ /** Error status code */
+ int rc;
+ /** Error count */
+ unsigned int count;
+};
+
+/** Maximum number of unique errors that we will keep track of */
+#define NETDEV_MAX_UNIQUE_ERRORS 4
+
/** Network device statistics */
struct net_device_stats {
- /** Count of successfully completed transmissions */
- unsigned int tx_ok;
- /** Count of transmission errors */
- unsigned int tx_err;
- /** Count of successfully received packets */
- unsigned int rx_ok;
- /** Count of reception errors */
- unsigned int rx_err;
+ /** Count of successful completions */
+ unsigned int good;
+ /** Count of error completions */
+ unsigned int bad;
+ /** Error breakdowns */
+ struct net_device_error errors[NETDEV_MAX_UNIQUE_ERRORS];
};
/**
@@ -220,6 +229,8 @@ struct net_device {
struct refcnt refcnt;
/** List of network devices */
struct list_head list;
+ /** List of open network devices */
+ struct list_head open_list;
/** Name of this network device */
char name[8];
/** Underlying hardware device */
@@ -241,12 +252,19 @@ struct net_device {
* This is the bitwise-OR of zero or more NETDEV_XXX constants.
*/
unsigned int state;
+ /** Maximum packet length
+ *
+ * This length includes any link-layer headers.
+ */
+ size_t max_pkt_len;
/** TX packet queue */
struct list_head tx_queue;
/** RX packet queue */
struct list_head rx_queue;
- /** Device statistics */
- struct net_device_stats stats;
+ /** TX statistics */
+ struct net_device_stats tx_stats;
+ /** RX statistics */
+ struct net_device_stats rx_stats;
/** Configuration settings applicable to this device */
struct simple_settings settings;
@@ -408,6 +426,7 @@ extern void netdev_irq ( struct net_device *netdev, int enable );
extern struct net_device * find_netdev ( const char *name );
extern struct net_device * find_netdev_by_location ( unsigned int bus_type,
unsigned int location );
+extern struct net_device * last_opened_netdev ( void );
extern int net_tx ( struct io_buffer *iobuf, struct net_device *netdev,
struct net_protocol *net_protocol, const void *ll_dest );
extern int net_rx ( struct io_buffer *iobuf, struct net_device *netdev,
diff --git a/gpxe/src/include/gpxe/null_nap.h b/gpxe/src/include/gpxe/null_nap.h
new file mode 100644
index 00000000..6dd0cda3
--- /dev/null
+++ b/gpxe/src/include/gpxe/null_nap.h
@@ -0,0 +1,21 @@
+#ifndef _GPXE_NULL_NAP_H
+#define _GPXE_NULL_NAP_H
+
+/** @file
+ *
+ * Null CPU sleeping
+ *
+ */
+
+#ifdef NAP_NULL
+#define NAP_PREFIX_null
+#else
+#define NAP_PREFIX_null __null_
+#endif
+
+static inline __always_inline void
+NAP_INLINE ( null, cpu_nap ) ( void ) {
+ /* Do nothing */
+}
+
+#endif /* _GPXE_NULL_NAP_H */
diff --git a/gpxe/src/include/gpxe/open.h b/gpxe/src/include/gpxe/open.h
index beab0a1f..81d5fc24 100644
--- a/gpxe/src/include/gpxe/open.h
+++ b/gpxe/src/include/gpxe/open.h
@@ -9,10 +9,10 @@
#include <stdarg.h>
#include <gpxe/tables.h>
+#include <gpxe/socket.h>
struct xfer_interface;
struct uri;
-struct sockaddr;
/** Location types */
enum {
diff --git a/gpxe/src/include/gpxe/pci.h b/gpxe/src/include/gpxe/pci.h
index 90721574..1ccdb100 100644
--- a/gpxe/src/include/gpxe/pci.h
+++ b/gpxe/src/include/gpxe/pci.h
@@ -19,7 +19,7 @@
#include <stdint.h>
#include <gpxe/device.h>
#include <gpxe/tables.h>
-#include <pci_io.h>
+#include <gpxe/pci_io.h>
#include "pci_ids.h"
/*
diff --git a/gpxe/src/include/gpxe/pci_io.h b/gpxe/src/include/gpxe/pci_io.h
new file mode 100644
index 00000000..365166c8
--- /dev/null
+++ b/gpxe/src/include/gpxe/pci_io.h
@@ -0,0 +1,122 @@
+#ifndef _GPXE_PCI_IO_H
+#define _GPXE_PCI_IO_H
+
+/** @file
+ *
+ * PCI I/O API
+ *
+ */
+
+#include <stdint.h>
+#include <gpxe/api.h>
+#include <config/ioapi.h>
+
+/**
+ * Calculate static inline PCI I/O API function name
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ * @ret _subsys_func Subsystem API function
+ */
+#define PCIAPI_INLINE( _subsys, _api_func ) \
+ SINGLE_API_INLINE ( PCIAPI_PREFIX_ ## _subsys, _api_func )
+
+/**
+ * Provide a PCI I/O API implementation
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ * @v _func Implementing function
+ */
+#define PROVIDE_PCIAPI( _subsys, _api_func, _func ) \
+ PROVIDE_SINGLE_API ( PCIAPI_PREFIX_ ## _subsys, _api_func, _func )
+
+/**
+ * Provide a static inline PCI I/O API implementation
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ */
+#define PROVIDE_PCIAPI_INLINE( _subsys, _api_func ) \
+ PROVIDE_SINGLE_API_INLINE ( PCIAPI_PREFIX_ ## _subsys, _api_func )
+
+/* Include all architecture-independent I/O API headers */
+#include <gpxe/efi/efi_pci.h>
+
+/* Include all architecture-dependent I/O API headers */
+#include <bits/pci_io.h>
+
+/**
+ * Determine maximum PCI bus number within system
+ *
+ * @ret max_bus Maximum bus number
+ */
+int pci_max_bus ( void );
+
+/**
+ * Read byte from PCI configuration space
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value read
+ * @ret rc Return status code
+ */
+int pci_read_config_byte ( struct pci_device *pci, unsigned int where,
+ uint8_t *value );
+
+/**
+ * Read 16-bit word from PCI configuration space
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value read
+ * @ret rc Return status code
+ */
+int pci_read_config_word ( struct pci_device *pci, unsigned int where,
+ uint16_t *value );
+
+/**
+ * Read 32-bit dword from PCI configuration space
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value read
+ * @ret rc Return status code
+ */
+int pci_read_config_dword ( struct pci_device *pci, unsigned int where,
+ uint32_t *value );
+
+/**
+ * Write byte to PCI configuration space
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value to be written
+ * @ret rc Return status code
+ */
+int pci_write_config_byte ( struct pci_device *pci, unsigned int where,
+ uint8_t value );
+
+/**
+ * Write 16-bit word to PCI configuration space
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value to be written
+ * @ret rc Return status code
+ */
+int pci_write_config_word ( struct pci_device *pci, unsigned int where,
+ uint16_t value );
+
+/**
+ * Write 32-bit dword to PCI configuration space
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value to be written
+ * @ret rc Return status code
+ */
+int pci_write_config_dword ( struct pci_device *pci, unsigned int where,
+ uint32_t value );
+
+#endif /* _GPXE_PCI_IO_H */
diff --git a/gpxe/src/include/gpxe/resolv.h b/gpxe/src/include/gpxe/resolv.h
index 7c1ee6e2..e73c8201 100644
--- a/gpxe/src/include/gpxe/resolv.h
+++ b/gpxe/src/include/gpxe/resolv.h
@@ -10,8 +10,8 @@
#include <gpxe/refcnt.h>
#include <gpxe/interface.h>
#include <gpxe/tables.h>
+#include <gpxe/socket.h>
-struct sockaddr;
struct resolv_interface;
/** Name resolution interface operations */
diff --git a/gpxe/src/include/gpxe/retry.h b/gpxe/src/include/gpxe/retry.h
index ec57db9e..1e7fde4c 100644
--- a/gpxe/src/include/gpxe/retry.h
+++ b/gpxe/src/include/gpxe/retry.h
@@ -19,6 +19,8 @@
struct retry_timer {
/** List of active timers */
struct list_head list;
+ /** Timer is currently running */
+ unsigned int running;
/** Timeout value (in ticks) */
unsigned long timeout;
/** Minimum timeout value (in ticks)
@@ -31,10 +33,7 @@ struct retry_timer {
* A value of zero means "use default timeout."
*/
unsigned long max_timeout;
- /** Start time (in ticks)
- *
- * A start time of zero indicates a stopped timer.
- */
+ /** Start time (in ticks) */
unsigned long start;
/** Retry count */
unsigned int count;
@@ -74,7 +73,7 @@ static inline void start_timer_nodelay ( struct retry_timer *timer ) {
*/
static inline __attribute__ (( always_inline )) unsigned long
timer_running ( struct retry_timer *timer ) {
- return ( timer->start );
+ return ( timer->running );
}
#endif /* _GPXE_RETRY_H */
diff --git a/gpxe/src/include/gpxe/rotate.h b/gpxe/src/include/gpxe/rotate.h
new file mode 100644
index 00000000..42ec7196
--- /dev/null
+++ b/gpxe/src/include/gpxe/rotate.h
@@ -0,0 +1,27 @@
+#ifndef _GPXE_ROTATE_H
+#define _GPXE_ROTATE_H
+
+/** @file
+ *
+ * Bit operations
+ */
+
+#include <stdint.h>
+
+static inline uint32_t rol32 ( uint32_t data, unsigned int rotation ) {
+ return ( ( data << rotation ) | ( data >> ( 32 - rotation ) ) );
+}
+
+static inline uint32_t ror32 ( uint32_t data, unsigned int rotation ) {
+ return ( ( data >> rotation ) | ( data << ( 32 - rotation ) ) );
+}
+
+static inline uint64_t rol64 ( uint64_t data, unsigned int rotation ) {
+ return ( ( data << rotation ) | ( data >> ( 64 - rotation ) ) );
+}
+
+static inline uint64_t ror64 ( uint64_t data, unsigned int rotation ) {
+ return ( ( data >> rotation ) | ( data << ( 64 - rotation ) ) );
+}
+
+#endif /* _GPXE_ROTATE_H */
diff --git a/gpxe/src/include/gpxe/sanboot.h b/gpxe/src/include/gpxe/sanboot.h
new file mode 100644
index 00000000..ea26a356
--- /dev/null
+++ b/gpxe/src/include/gpxe/sanboot.h
@@ -0,0 +1,14 @@
+#ifndef _GPXE_SANBOOT_H
+#define _GPXE_SANBOOT_H
+
+#include <gpxe/tables.h>
+
+struct sanboot_protocol {
+ const char *prefix;
+ int ( * boot ) ( const char *root_path );
+};
+
+#define __sanboot_protocol \
+ __table ( struct sanboot_protocol, sanboot_protocols, 01 )
+
+#endif /* _GPXE_SANBOOT_H */
diff --git a/gpxe/src/include/gpxe/settings.h b/gpxe/src/include/gpxe/settings.h
index ee7dacee..9e62cdea 100644
--- a/gpxe/src/include/gpxe/settings.h
+++ b/gpxe/src/include/gpxe/settings.h
@@ -72,6 +72,14 @@ struct settings {
struct refcnt *refcnt;
/** Name */
const char *name;
+ /** Tag magic
+ *
+ * This value will be ORed in to any numerical tags
+ * constructed by parse_setting_name(), and can be used to
+ * avoid e.g. attempting to retrieve the subnet mask from
+ * SMBIOS, or the system UUID from DHCP.
+ */
+ unsigned int tag_magic;
/** Parent settings block */
struct settings *parent;
/** Sibling settings blocks */
@@ -167,6 +175,9 @@ extern int fetch_setting_len ( struct settings *settings,
extern int fetch_string_setting ( struct settings *settings,
struct setting *setting,
char *data, size_t len );
+extern int fetch_string_setting_copy ( struct settings *settings,
+ struct setting *setting,
+ char **data );
extern int fetch_ipv4_setting ( struct settings *settings,
struct setting *setting, struct in_addr *inp );
extern int fetch_int_setting ( struct settings *settings,
@@ -207,16 +218,17 @@ extern struct setting ip_setting __setting;
extern struct setting netmask_setting __setting;
extern struct setting gateway_setting __setting;
extern struct setting dns_setting __setting;
+extern struct setting domain_setting __setting;
extern struct setting hostname_setting __setting;
extern struct setting filename_setting __setting;
extern struct setting root_path_setting __setting;
extern struct setting username_setting __setting;
extern struct setting password_setting __setting;
extern struct setting priority_setting __setting;
-extern struct setting bios_drive_setting __setting;
extern struct setting uuid_setting __setting;
extern struct setting next_server_setting __setting;
extern struct setting mac_setting __setting;
+extern struct setting user_class_setting __setting;
/**
* Initialise a settings block
@@ -225,16 +237,19 @@ extern struct setting mac_setting __setting;
* @v op Settings block operations
* @v refcnt Containing object reference counter, or NULL
* @v name Settings block name
+ * @v tag_magic Tag magic
*/
static inline void settings_init ( struct settings *settings,
struct settings_operations *op,
struct refcnt *refcnt,
- const char *name ) {
+ const char *name,
+ unsigned int tag_magic ) {
INIT_LIST_HEAD ( &settings->siblings );
INIT_LIST_HEAD ( &settings->children );
settings->op = op;
settings->refcnt = refcnt;
settings->name = name;
+ settings->tag_magic = tag_magic;
}
/**
@@ -248,7 +263,7 @@ static inline void simple_settings_init ( struct simple_settings *simple,
struct refcnt *refcnt,
const char *name ) {
settings_init ( &simple->settings, &simple_settings_operations,
- refcnt, name );
+ refcnt, name, 0 );
}
/**
@@ -289,4 +304,16 @@ static inline int delete_named_setting ( const char *name ) {
return storef_named_setting ( name, NULL );
}
+/**
+ * Check existence of setting
+ *
+ * @v settings Settings block, or NULL to search all blocks
+ * @v setting Setting to fetch
+ * @ret exists Setting exists
+ */
+static inline int setting_exists ( struct settings *settings,
+ struct setting *setting ) {
+ return ( fetch_setting_len ( settings, setting ) >= 0 );
+}
+
#endif /* _GPXE_SETTINGS_H */
diff --git a/gpxe/src/include/gpxe/smbios.h b/gpxe/src/include/gpxe/smbios.h
new file mode 100644
index 00000000..2b0fcbd1
--- /dev/null
+++ b/gpxe/src/include/gpxe/smbios.h
@@ -0,0 +1,140 @@
+#ifndef _GPXE_SMBIOS_H
+#define _GPXE_SMBIOS_H
+
+/** @file
+ *
+ * System Management BIOS
+ *
+ */
+
+#include <stdint.h>
+#include <gpxe/api.h>
+#include <config/general.h>
+#include <gpxe/uaccess.h>
+
+/**
+ * Provide an SMBIOS API implementation
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ * @v _func Implementing function
+ */
+#define PROVIDE_SMBIOS( _subsys, _api_func, _func ) \
+ PROVIDE_SINGLE_API ( SMBIOS_PREFIX_ ## _subsys, _api_func, _func )
+
+/* Include all architecture-independent SMBIOS API headers */
+#include <gpxe/efi/efi_smbios.h>
+
+/* Include all architecture-dependent SMBIOS API headers */
+#include <bits/smbios.h>
+
+/** Signature for SMBIOS entry point */
+#define SMBIOS_SIGNATURE \
+ ( ( '_' << 0 ) + ( 'S' << 8 ) + ( 'M' << 16 ) + ( '_' << 24 ) )
+
+/**
+ * SMBIOS entry point
+ *
+ * This is the single table which describes the list of SMBIOS
+ * structures. It is located by scanning through the BIOS segment.
+ */
+struct smbios_entry {
+ /** Signature
+ *
+ * Must be equal to SMBIOS_SIGNATURE
+ */
+ uint32_t signature;
+ /** Checksum */
+ uint8_t checksum;
+ /** Length */
+ uint8_t len;
+ /** Major version */
+ uint8_t major;
+ /** Minor version */
+ uint8_t minor;
+ /** Maximum structure size */
+ uint16_t max;
+ /** Entry point revision */
+ uint8_t revision;
+ /** Formatted area */
+ uint8_t formatted[5];
+ /** DMI Signature */
+ uint8_t dmi_signature[5];
+ /** DMI checksum */
+ uint8_t dmi_checksum;
+ /** Structure table length */
+ uint16_t smbios_len;
+ /** Structure table address */
+ uint32_t smbios_address;
+ /** Number of SMBIOS structures */
+ uint16_t smbios_count;
+ /** BCD revision */
+ uint8_t bcd_revision;
+} __attribute__ (( packed ));
+
+/** An SMBIOS structure header */
+struct smbios_header {
+ /** Type */
+ uint8_t type;
+ /** Length */
+ uint8_t len;
+ /** Handle */
+ uint16_t handle;
+} __attribute__ (( packed ));
+
+/** SMBIOS structure descriptor */
+struct smbios_structure {
+ /** Copy of SMBIOS structure header */
+ struct smbios_header header;
+ /** Offset of structure within SMBIOS */
+ size_t offset;
+ /** Length of strings section */
+ size_t strings_len;
+};
+
+/** SMBIOS system information structure */
+struct smbios_system_information {
+ /** SMBIOS structure header */
+ struct smbios_header header;
+ /** Manufacturer string */
+ uint8_t manufacturer;
+ /** Product string */
+ uint8_t product;
+ /** Version string */
+ uint8_t version;
+ /** Serial number string */
+ uint8_t serial;
+ /** UUID */
+ uint8_t uuid[16];
+ /** Wake-up type */
+ uint8_t wakeup;
+} __attribute__ (( packed ));
+
+/** SMBIOS system information structure type */
+#define SMBIOS_TYPE_SYSTEM_INFORMATION 1
+
+/**
+ * SMBIOS entry point descriptor
+ *
+ * This contains the information from the SMBIOS entry point that we
+ * care about.
+ */
+struct smbios {
+ /** Start of SMBIOS structures */
+ userptr_t address;
+ /** Length of SMBIOS structures */
+ size_t len;
+ /** Number of SMBIOS structures */
+ unsigned int count;
+};
+
+extern int find_smbios ( struct smbios *smbios );
+extern int find_smbios_structure ( unsigned int type,
+ struct smbios_structure *structure );
+extern int read_smbios_structure ( struct smbios_structure *structure,
+ void *data, size_t len );
+extern int read_smbios_string ( struct smbios_structure *structure,
+ unsigned int index,
+ void *data, size_t len );
+
+#endif /* _GPXE_SMBIOS_H */
diff --git a/gpxe/src/include/gpxe/socket.h b/gpxe/src/include/gpxe/socket.h
index 9c7afb87..b683bed6 100644
--- a/gpxe/src/include/gpxe/socket.h
+++ b/gpxe/src/include/gpxe/socket.h
@@ -7,6 +7,8 @@
*
*/
+#include <stdint.h>
+
/**
* @defgroup commtypes Communication semantics
*
@@ -14,12 +16,14 @@
*/
/** Connection-based, reliable streams */
-#define SOCK_STREAM ( ( int ) TCP_SOCK_STREAM )
-extern char TCP_SOCK_STREAM[];
+extern int tcp_sock_stream;
+#define TCP_SOCK_STREAM 0x1
+#define SOCK_STREAM tcp_sock_stream
/** Connectionless, unreliable streams */
-#define SOCK_DGRAM ( ( int ) UDP_SOCK_DGRAM )
-extern char UDP_SOCK_DGRAM[];
+extern int udp_sock_dgram;
+#define UDP_SOCK_DGRAM 0x2
+#define SOCK_DGRAM udp_sock_dgram
/** @} */
@@ -90,6 +94,6 @@ struct sockaddr {
* family.
*/
char pad[ SA_LEN - sizeof ( sa_family_t ) ];
-};
+} __attribute__ (( may_alias ));
#endif /* _GPXE_SOCKET_H */
diff --git a/gpxe/src/include/gpxe/tcpip.h b/gpxe/src/include/gpxe/tcpip.h
index c0fadd23..da89530e 100644
--- a/gpxe/src/include/gpxe/tcpip.h
+++ b/gpxe/src/include/gpxe/tcpip.h
@@ -40,7 +40,7 @@ struct sockaddr_tcpip {
*/
char pad[ sizeof ( struct sockaddr ) -
( sizeof ( sa_family_t ) + sizeof ( uint16_t ) ) ];
-};
+} __attribute__ (( may_alias ));
/**
* A transport-layer protocol of the TCP/IP stack (eg. UDP, TCP, etc)
@@ -82,6 +82,7 @@ struct tcpip_net_protocol {
*
* @v iobuf I/O buffer
* @v tcpip_protocol Transport-layer protocol
+ * @v st_src Source address, or NULL to use default
* @v st_dest Destination address
* @v netdev Network device (or NULL to route automatically)
* @v trans_csum Transport-layer checksum to complete, or NULL
@@ -91,6 +92,7 @@ struct tcpip_net_protocol {
*/
int ( * tx ) ( struct io_buffer *iobuf,
struct tcpip_protocol *tcpip_protocol,
+ struct sockaddr_tcpip *st_src,
struct sockaddr_tcpip *st_dest,
struct net_device *netdev,
uint16_t *trans_csum );
@@ -107,7 +109,8 @@ struct tcpip_net_protocol {
extern int tcpip_rx ( struct io_buffer *iobuf, uint8_t tcpip_proto,
struct sockaddr_tcpip *st_src,
struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum );
-extern int tcpip_tx ( struct io_buffer *iobuf, struct tcpip_protocol *tcpip,
+extern int tcpip_tx ( struct io_buffer *iobuf, struct tcpip_protocol *tcpip,
+ struct sockaddr_tcpip *st_src,
struct sockaddr_tcpip *st_dest,
struct net_device *netdev,
uint16_t *trans_csum );
diff --git a/gpxe/src/include/gpxe/timer.h b/gpxe/src/include/gpxe/timer.h
index b7057225..862d87b3 100644
--- a/gpxe/src/include/gpxe/timer.h
+++ b/gpxe/src/include/gpxe/timer.h
@@ -1,41 +1,74 @@
-#ifndef GPXE_TIMER_H
-#define GPXE_TIMER_H
+#ifndef _GPXE_TIMER_H
+#define _GPXE_TIMER_H
-#include <stddef.h>
-#include <gpxe/tables.h>
+/** @file
+ *
+ * gPXE timer API
+ *
+ * The timer API provides udelay() for fixed delays, and currticks()
+ * for a monotonically increasing tick counter.
+ */
-typedef unsigned long tick_t;
+#include <gpxe/api.h>
+#include <config/timer.h>
-#define MSECS_IN_SEC (1000)
-#define USECS_IN_SEC (1000*1000)
-#define USECS_IN_MSEC (1000)
+/**
+ * Calculate static inline timer API function name
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ * @ret _subsys_func Subsystem API function
+ */
+#define TIMER_INLINE( _subsys, _api_func ) \
+ SINGLE_API_INLINE ( TIMER_PREFIX_ ## _subsys, _api_func )
-#define TICKS_PER_SEC USECS_IN_SEC
+/**
+ * Provide a timer API implementation
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ * @v _func Implementing function
+ */
+#define PROVIDE_TIMER( _subsys, _api_func, _func ) \
+ PROVIDE_SINGLE_API ( TIMER_PREFIX_ ## _subsys, _api_func, _func )
-extern tick_t currticks ( void );
+/**
+ * Provide a static inline timer API implementation
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ */
+#define PROVIDE_TIMER_INLINE( _subsys, _api_func ) \
+ PROVIDE_SINGLE_API_INLINE ( TIMER_PREFIX_ ## _subsys, _api_func )
-extern void generic_currticks_udelay ( unsigned int usecs );
+/* Include all architecture-independent I/O API headers */
+#include <gpxe/efi/efi_timer.h>
-/** A timer */
-struct timer {
- /** Initialise timer
- *
- * @ret rc Return status code
- */
- int ( * init ) ( void );
- /** Read current time
- *
- * @ret ticks Current time, in ticks
- */
- tick_t ( * currticks ) ( void );
- /** Delay
- *
- * @v usecs Time to delay, in microseconds
- */
- void ( * udelay ) ( unsigned int usecs );
-};
+/* Include all architecture-dependent I/O API headers */
+#include <bits/timer.h>
-#define __timer( order ) __table ( struct timer, timers, order )
+/**
+ * Delay for a fixed number of microseconds
+ *
+ * @v usecs Number of microseconds for which to delay
+ */
+void udelay ( unsigned long usecs );
-#endif /* GPXE_TIMER_H */
+/**
+ * Get current system time in ticks
+ *
+ * @ret ticks Current time, in ticks
+ */
+unsigned long currticks ( void );
+/**
+ * Get number of ticks per second
+ *
+ * @ret ticks_per_sec Number of ticks per second
+ */
+unsigned long ticks_per_sec ( void );
+
+/** Number of ticks per second */
+#define TICKS_PER_SEC ( ticks_per_sec() )
+
+#endif /* _GPXE_TIMER_H */
diff --git a/gpxe/src/include/gpxe/tls.h b/gpxe/src/include/gpxe/tls.h
index a8cf16ef..182bc49d 100644
--- a/gpxe/src/include/gpxe/tls.h
+++ b/gpxe/src/include/gpxe/tls.h
@@ -14,6 +14,7 @@
#include <gpxe/crypto.h>
#include <gpxe/md5.h>
#include <gpxe/sha1.h>
+#include <gpxe/x509.h>
/** A TLS header */
struct tls_header {
@@ -109,6 +110,22 @@ struct tls_cipherspec {
void *mac_secret;
};
+/** TLS pre-master secret */
+struct tls_pre_master_secret {
+ /** TLS version */
+ uint16_t version;
+ /** Random data */
+ uint8_t random[46];
+} __attribute__ (( packed ));
+
+/** TLS client random data */
+struct tls_client_random {
+ /** GMT Unix time */
+ uint32_t gmt_unix_time;
+ /** Random data */
+ uint8_t random[28];
+} __attribute__ (( packed ));
+
/** A TLS session */
struct tls_session {
/** Reference counter */
@@ -128,23 +145,20 @@ struct tls_session {
/** Next RX cipher specification */
struct tls_cipherspec rx_cipherspec_pending;
/** Premaster secret */
- uint8_t pre_master_secret[48];
+ struct tls_pre_master_secret pre_master_secret;
/** Master secret */
uint8_t master_secret[48];
/** Server random bytes */
uint8_t server_random[32];
/** Client random bytes */
- uint8_t client_random[32];
+ struct tls_client_random client_random;
/** MD5 context for handshake verification */
uint8_t handshake_md5_ctx[MD5_CTX_SIZE];
/** SHA1 context for handshake verification */
uint8_t handshake_sha1_ctx[SHA1_CTX_SIZE];
/** Hack: server RSA public key */
- uint8_t *rsa_mod;
- size_t rsa_mod_len;
- uint8_t *rsa_pub_exp;
- size_t rsa_pub_exp_len;
+ struct x509_rsa_public_key rsa;
/** TX sequence number */
uint64_t tx_seq;
diff --git a/gpxe/src/include/gpxe/uaccess.h b/gpxe/src/include/gpxe/uaccess.h
index 05f89e03..33aaed18 100644
--- a/gpxe/src/include/gpxe/uaccess.h
+++ b/gpxe/src/include/gpxe/uaccess.h
@@ -19,9 +19,324 @@
*
*/
-#include <bits/uaccess.h>
+#include <stdint.h>
+#include <string.h>
+#include <gpxe/api.h>
+#include <config/ioapi.h>
+
+/**
+ * A pointer to a user buffer
+ *
+ */
+typedef unsigned long userptr_t;
/** Equivalent of NULL for user pointers */
#define UNULL ( ( userptr_t ) 0 )
+/**
+ * @defgroup uaccess_trivial Trivial user access API implementations
+ *
+ * User access API implementations that can be used by environments in
+ * which virtual addresses allow access to all of memory.
+ *
+ * @{
+ *
+ */
+
+/**
+ * Convert virtual address to user pointer
+ *
+ * @v addr Virtual address
+ * @ret userptr User pointer
+ */
+static inline __always_inline userptr_t
+trivial_virt_to_user ( volatile const void *addr ) {
+ return ( ( userptr_t ) addr );
+}
+
+/**
+ * Convert user pointer to virtual address
+ *
+ * @v userptr User pointer
+ * @v offset Offset from user pointer
+ * @ret addr Virtual address
+ *
+ * This operation is not available under all memory models.
+ */
+static inline __always_inline void *
+trivial_user_to_virt ( userptr_t userptr, off_t offset ) {
+ return ( ( void * ) userptr + offset );
+}
+
+/**
+ * Add offset to user pointer
+ *
+ * @v userptr User pointer
+ * @v offset Offset
+ * @ret userptr New pointer value
+ */
+static inline __always_inline userptr_t
+trivial_userptr_add ( userptr_t userptr, off_t offset ) {
+ return ( userptr + offset );
+}
+
+/**
+ * Copy data between user buffers
+ *
+ * @v dest Destination
+ * @v dest_off Destination offset
+ * @v src Source
+ * @v src_off Source offset
+ * @v len Length
+ */
+static inline __always_inline void
+trivial_memcpy_user ( userptr_t dest, off_t dest_off,
+ userptr_t src, off_t src_off, size_t len ) {
+ memcpy ( ( ( void * ) dest + dest_off ),
+ ( ( void * ) src + src_off ), len );
+}
+
+/**
+ * Copy data between user buffers, allowing for overlap
+ *
+ * @v dest Destination
+ * @v dest_off Destination offset
+ * @v src Source
+ * @v src_off Source offset
+ * @v len Length
+ */
+static inline __always_inline void
+trivial_memmove_user ( userptr_t dest, off_t dest_off,
+ userptr_t src, off_t src_off, size_t len ) {
+ memmove ( ( ( void * ) dest + dest_off ),
+ ( ( void * ) src + src_off ), len );
+}
+
+/**
+ * Fill user buffer with a constant byte
+ *
+ * @v buffer User buffer
+ * @v offset Offset within buffer
+ * @v c Constant byte with which to fill
+ * @v len Length
+ */
+static inline __always_inline void
+trivial_memset_user ( userptr_t buffer, off_t offset, int c, size_t len ) {
+ memset ( ( ( void * ) buffer + offset ), c, len );
+}
+
+/**
+ * Find length of NUL-terminated string in user buffer
+ *
+ * @v buffer User buffer
+ * @v offset Offset within buffer
+ * @ret len Length of string (excluding NUL)
+ */
+static inline __always_inline size_t
+trivial_strlen_user ( userptr_t buffer, off_t offset ) {
+ return strlen ( ( void * ) buffer + offset );
+}
+
+/**
+ * Find character in user buffer
+ *
+ * @v buffer User buffer
+ * @v offset Starting offset within buffer
+ * @v c Character to search for
+ * @v len Length of user buffer
+ * @ret offset Offset of character, or <0 if not found
+ */
+static inline __always_inline off_t
+trivial_memchr_user ( userptr_t buffer, off_t offset, int c, size_t len ) {
+ void *found;
+
+ found = memchr ( ( ( void * ) buffer + offset ), c, len );
+ return ( found ? ( found - ( void * ) buffer ) : -1 );
+}
+
+/** @} */
+
+/**
+ * Calculate static inline user access API function name
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ * @ret _subsys_func Subsystem API function
+ */
+#define UACCESS_INLINE( _subsys, _api_func ) \
+ SINGLE_API_INLINE ( UACCESS_PREFIX_ ## _subsys, _api_func )
+
+/**
+ * Provide an user access API implementation
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ * @v _func Implementing function
+ */
+#define PROVIDE_UACCESS( _subsys, _api_func, _func ) \
+ PROVIDE_SINGLE_API ( UACCESS_PREFIX_ ## _subsys, _api_func, _func )
+
+/**
+ * Provide a static inline user access API implementation
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ */
+#define PROVIDE_UACCESS_INLINE( _subsys, _api_func ) \
+ PROVIDE_SINGLE_API_INLINE ( UACCESS_PREFIX_ ## _subsys, _api_func )
+
+/* Include all architecture-independent user access API headers */
+#include <gpxe/efi/efi_uaccess.h>
+
+/* Include all architecture-dependent user access API headers */
+#include <bits/uaccess.h>
+
+/**
+ * Convert physical address to user pointer
+ *
+ * @v phys_addr Physical address
+ * @ret userptr User pointer
+ */
+userptr_t phys_to_user ( unsigned long phys_addr );
+
+/**
+ * Convert user pointer to physical address
+ *
+ * @v userptr User pointer
+ * @v offset Offset from user pointer
+ * @ret phys_addr Physical address
+ */
+unsigned long user_to_phys ( userptr_t userptr, off_t offset );
+
+/**
+ * Convert virtual address to user pointer
+ *
+ * @v addr Virtual address
+ * @ret userptr User pointer
+ */
+userptr_t virt_to_user ( volatile const void *addr );
+
+/**
+ * Convert user pointer to virtual address
+ *
+ * @v userptr User pointer
+ * @v offset Offset from user pointer
+ * @ret addr Virtual address
+ *
+ * This operation is not available under all memory models.
+ */
+void * user_to_virt ( userptr_t userptr, off_t offset );
+
+/**
+ * Add offset to user pointer
+ *
+ * @v userptr User pointer
+ * @v offset Offset
+ * @ret userptr New pointer value
+ */
+userptr_t userptr_add ( userptr_t userptr, off_t offset );
+
+/**
+ * Convert virtual address to a physical address
+ *
+ * @v addr Virtual address
+ * @ret phys_addr Physical address
+ */
+static inline __always_inline unsigned long
+virt_to_phys ( volatile const void *addr ) {
+ return user_to_phys ( virt_to_user ( addr ), 0 );
+}
+
+/**
+ * Convert physical address to a virtual address
+ *
+ * @v addr Virtual address
+ * @ret phys_addr Physical address
+ *
+ * This operation is not available under all memory models.
+ */
+static inline __always_inline void * phys_to_virt ( unsigned long phys_addr ) {
+ return user_to_virt ( phys_to_user ( phys_addr ), 0 );
+}
+
+/**
+ * Copy data between user buffers
+ *
+ * @v dest Destination
+ * @v dest_off Destination offset
+ * @v src Source
+ * @v src_off Source offset
+ * @v len Length
+ */
+void memcpy_user ( userptr_t dest, off_t dest_off,
+ userptr_t src, off_t src_off, size_t len );
+
+/**
+ * Copy data to user buffer
+ *
+ * @v dest Destination
+ * @v dest_off Destination offset
+ * @v src Source
+ * @v len Length
+ */
+static inline __always_inline void
+copy_to_user ( userptr_t dest, off_t dest_off, const void *src, size_t len ) {
+ memcpy_user ( dest, dest_off, virt_to_user ( src ), 0, len );
+}
+
+/**
+ * Copy data from user buffer
+ *
+ * @v dest Destination
+ * @v src Source
+ * @v src_off Source offset
+ * @v len Length
+ */
+static inline __always_inline void
+copy_from_user ( void *dest, userptr_t src, off_t src_off, size_t len ) {
+ memcpy_user ( virt_to_user ( dest ), 0, src, src_off, len );
+}
+
+/**
+ * Copy data between user buffers, allowing for overlap
+ *
+ * @v dest Destination
+ * @v dest_off Destination offset
+ * @v src Source
+ * @v src_off Source offset
+ * @v len Length
+ */
+void memmove_user ( userptr_t dest, off_t dest_off,
+ userptr_t src, off_t src_off, size_t len );
+
+/**
+ * Fill user buffer with a constant byte
+ *
+ * @v userptr User buffer
+ * @v offset Offset within buffer
+ * @v c Constant byte with which to fill
+ * @v len Length
+ */
+void memset_user ( userptr_t userptr, off_t offset, int c, size_t len );
+
+/**
+ * Find length of NUL-terminated string in user buffer
+ *
+ * @v userptr User buffer
+ * @v offset Offset within buffer
+ * @ret len Length of string (excluding NUL)
+ */
+size_t strlen_user ( userptr_t userptr, off_t offset );
+
+/**
+ * Find character in user buffer
+ *
+ * @v userptr User buffer
+ * @v offset Starting offset within buffer
+ * @v c Character to search for
+ * @v len Length of user buffer
+ * @ret offset Offset of character, or <0 if not found
+ */
+off_t memchr_user ( userptr_t userptr, off_t offset, int c, size_t len );
+
#endif /* _GPXE_UACCESS_H */
diff --git a/gpxe/src/include/gpxe/udp.h b/gpxe/src/include/gpxe/udp.h
index cb0e44eb..e515f650 100644
--- a/gpxe/src/include/gpxe/udp.h
+++ b/gpxe/src/include/gpxe/udp.h
@@ -15,7 +15,6 @@
#include <gpxe/if_ether.h>
struct xfer_interface;
-struct sockaddr;
/**
* UDP constants
diff --git a/gpxe/src/include/gpxe/umalloc.h b/gpxe/src/include/gpxe/umalloc.h
index 49ec22b4..e6fc7bf0 100644
--- a/gpxe/src/include/gpxe/umalloc.h
+++ b/gpxe/src/include/gpxe/umalloc.h
@@ -8,10 +8,59 @@
*
*/
+#include <gpxe/api.h>
+#include <config/umalloc.h>
#include <gpxe/uaccess.h>
-extern userptr_t umalloc ( size_t size );
-extern userptr_t urealloc ( userptr_t ptr, size_t new_size );
-extern void ufree ( userptr_t ptr );
+/**
+ * Provide a user memory allocation API implementation
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ * @v _func Implementing function
+ */
+#define PROVIDE_UMALLOC( _subsys, _api_func, _func ) \
+ PROVIDE_SINGLE_API ( UMALLOC_PREFIX_ ## _subsys, _api_func, _func )
+
+/* Include all architecture-independent I/O API headers */
+#include <gpxe/efi/efi_umalloc.h>
+
+/* Include all architecture-dependent I/O API headers */
+#include <bits/umalloc.h>
+
+/**
+ * Reallocate external memory
+ *
+ * @v userptr Memory previously allocated by umalloc(), or UNULL
+ * @v new_size Requested size
+ * @ret userptr Allocated memory, or UNULL
+ *
+ * Calling realloc() with a new size of zero is a valid way to free a
+ * memory block.
+ */
+userptr_t urealloc ( userptr_t userptr, size_t new_size );
+
+/**
+ * Allocate external memory
+ *
+ * @v size Requested size
+ * @ret userptr Memory, or UNULL
+ *
+ * Memory is guaranteed to be aligned to a page boundary.
+ */
+static inline __always_inline userptr_t umalloc ( size_t size ) {
+ return urealloc ( UNULL, size );
+}
+
+/**
+ * Free external memory
+ *
+ * @v userptr Memory allocated by umalloc(), or UNULL
+ *
+ * If @c ptr is UNULL, no action is taken.
+ */
+static inline __always_inline void ufree ( userptr_t userptr ) {
+ urealloc ( userptr, 0 );
+}
#endif /* _GPXE_UMALLOC_H */
diff --git a/gpxe/src/include/gpxe/uri.h b/gpxe/src/include/gpxe/uri.h
index 37f3aac9..3803868d 100644
--- a/gpxe/src/include/gpxe/uri.h
+++ b/gpxe/src/include/gpxe/uri.h
@@ -7,6 +7,7 @@
*
*/
+#include <stddef.h>
#include <stdlib.h>
#include <gpxe/refcnt.h>
diff --git a/gpxe/src/drivers/net/virtio-pci.h b/gpxe/src/include/gpxe/virtio-pci.h
index ba0604d5..f0c17e8d 100644
--- a/gpxe/src/drivers/net/virtio-pci.h
+++ b/gpxe/src/include/gpxe/virtio-pci.h
@@ -37,58 +37,61 @@
/* Virtio ABI version, this must match exactly */
#define VIRTIO_PCI_ABI_VERSION 0
-static inline u32 vp_get_features(struct nic *nic)
+static inline u32 vp_get_features(unsigned int ioaddr)
{
- return inl(nic->ioaddr + VIRTIO_PCI_HOST_FEATURES);
+ return inl(ioaddr + VIRTIO_PCI_HOST_FEATURES);
}
-static inline void vp_set_features(struct nic *nic, u32 features)
+static inline void vp_set_features(unsigned int ioaddr, u32 features)
{
- outl(features, nic->ioaddr + VIRTIO_PCI_GUEST_FEATURES);
+ outl(features, ioaddr + VIRTIO_PCI_GUEST_FEATURES);
}
-static inline void vp_get(struct nic *nic, unsigned offset,
+static inline void vp_get(unsigned int ioaddr, unsigned offset,
void *buf, unsigned len)
{
u8 *ptr = buf;
unsigned i;
for (i = 0; i < len; i++)
- ptr[i] = inb(nic->ioaddr + VIRTIO_PCI_CONFIG + offset + i);
+ ptr[i] = inb(ioaddr + VIRTIO_PCI_CONFIG + offset + i);
}
-static inline u8 vp_get_status(struct nic *nic)
+static inline u8 vp_get_status(unsigned int ioaddr)
{
- return inb(nic->ioaddr + VIRTIO_PCI_STATUS);
+ return inb(ioaddr + VIRTIO_PCI_STATUS);
}
-static inline void vp_set_status(struct nic *nic, u8 status)
+static inline void vp_set_status(unsigned int ioaddr, u8 status)
{
if (status == 0) /* reset */
return;
- outb(status, nic->ioaddr + VIRTIO_PCI_STATUS);
+ outb(status, ioaddr + VIRTIO_PCI_STATUS);
}
-static inline void vp_reset(struct nic *nic)
+static inline void vp_reset(unsigned int ioaddr)
{
- outb(0, nic->ioaddr + VIRTIO_PCI_STATUS);
- (void)inb(nic->ioaddr + VIRTIO_PCI_ISR);
+ outb(0, ioaddr + VIRTIO_PCI_STATUS);
+ (void)inb(ioaddr + VIRTIO_PCI_ISR);
}
-static inline void vp_notify(struct nic *nic, int queue_index)
+static inline void vp_notify(unsigned int ioaddr, int queue_index)
{
- outw(queue_index, nic->ioaddr + VIRTIO_PCI_QUEUE_NOTIFY);
+ outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_NOTIFY);
}
-static inline void vp_del_vq(struct nic *nic, int queue_index)
+static inline void vp_del_vq(unsigned int ioaddr, int queue_index)
{
/* select the queue */
- outw(queue_index, nic->ioaddr + VIRTIO_PCI_QUEUE_SEL);
+ outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_SEL);
/* deactivate the queue */
- outl(0, nic->ioaddr + VIRTIO_PCI_QUEUE_PFN);
+ outl(0, ioaddr + VIRTIO_PCI_QUEUE_PFN);
}
+
+int vp_find_vq(unsigned int ioaddr, int queue_index,
+ struct vring_virtqueue *vq);
#endif /* _VIRTIO_PCI_H_ */
diff --git a/gpxe/src/drivers/net/virtio-ring.h b/gpxe/src/include/gpxe/virtio-ring.h
index 33060b11..e96dd371 100644
--- a/gpxe/src/drivers/net/virtio-ring.h
+++ b/gpxe/src/include/gpxe/virtio-ring.h
@@ -58,6 +58,29 @@ struct vring {
struct vring_used *used;
};
+#define vring_size(num) \
+ (((((sizeof(struct vring_desc) * num) + \
+ (sizeof(struct vring_avail) + sizeof(u16) * num)) \
+ + PAGE_MASK) & ~PAGE_MASK) + \
+ (sizeof(struct vring_used) + sizeof(struct vring_used_elem) * num))
+
+typedef unsigned char virtio_queue_t[PAGE_MASK + vring_size(MAX_QUEUE_NUM)];
+
+struct vring_virtqueue {
+ virtio_queue_t queue;
+ struct vring vring;
+ u16 free_head;
+ u16 last_used_idx;
+ u16 vdata[MAX_QUEUE_NUM];
+ /* PCI */
+ int queue_index;
+};
+
+struct vring_list {
+ char *addr;
+ unsigned int length;
+};
+
static inline void vring_init(struct vring *vr,
unsigned int num, unsigned char *queue)
{
@@ -85,9 +108,35 @@ static inline void vring_init(struct vring *vr,
vr->desc[i].next = 0;
}
-#define vring_size(num) \
- (((((sizeof(struct vring_desc) * num) + \
- (sizeof(struct vring_avail) + sizeof(u16) * num)) \
- + PAGE_MASK) & ~PAGE_MASK) + \
- (sizeof(struct vring_used) + sizeof(struct vring_used_elem) * num))
+static inline void vring_enable_cb(struct vring_virtqueue *vq)
+{
+ vq->vring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;
+}
+
+static inline void vring_disable_cb(struct vring_virtqueue *vq)
+{
+ vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
+}
+
+
+/*
+ * vring_more_used
+ *
+ * is there some used buffers ?
+ *
+ */
+
+static inline int vring_more_used(struct vring_virtqueue *vq)
+{
+ wmb();
+ return vq->last_used_idx != vq->vring.used->idx;
+}
+
+void vring_detach(struct vring_virtqueue *vq, unsigned int head);
+int vring_get_buf(struct vring_virtqueue *vq, unsigned int *len);
+void vring_add_buf(struct vring_virtqueue *vq, struct vring_list list[],
+ unsigned int out, unsigned int in,
+ int index, int num_added);
+void vring_kick(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added);
+
#endif /* _VIRTIO_RING_H_ */
diff --git a/gpxe/src/include/gpxe/x509.h b/gpxe/src/include/gpxe/x509.h
new file mode 100644
index 00000000..071e1de5
--- /dev/null
+++ b/gpxe/src/include/gpxe/x509.h
@@ -0,0 +1,39 @@
+#ifndef _GPXE_X509_H
+#define _GPXE_X509_H
+
+/** @file
+ *
+ * X.509 certificates
+ *
+ */
+
+#include <stdint.h>
+
+struct asn1_cursor;
+
+/** An X.509 RSA public key */
+struct x509_rsa_public_key {
+ /** Modulus */
+ uint8_t *modulus;
+ /** Modulus length */
+ size_t modulus_len;
+ /** Exponent */
+ uint8_t *exponent;
+ /** Exponent length */
+ size_t exponent_len;
+};
+
+/**
+ * Free X.509 RSA public key
+ *
+ * @v rsa_pubkey RSA public key
+ */
+static inline void
+x509_free_rsa_public_key ( struct x509_rsa_public_key *rsa_pubkey ) {
+ free ( rsa_pubkey->modulus );
+}
+
+extern int x509_rsa_public_key ( const struct asn1_cursor *certificate,
+ struct x509_rsa_public_key *rsa_pubkey );
+
+#endif /* _GPXE_X509_H */
diff --git a/gpxe/src/include/gpxe/xfer.h b/gpxe/src/include/gpxe/xfer.h
index 9575bf69..e592fa38 100644
--- a/gpxe/src/include/gpxe/xfer.h
+++ b/gpxe/src/include/gpxe/xfer.h
@@ -149,8 +149,8 @@ extern int xfer_deliver_raw ( struct xfer_interface *xfer,
const void *data, size_t len );
extern int xfer_vprintf ( struct xfer_interface *xfer,
const char *format, va_list args );
-extern int xfer_printf ( struct xfer_interface *xfer,
- const char *format, ... );
+extern int __attribute__ (( format ( printf, 2, 3 ) ))
+xfer_printf ( struct xfer_interface *xfer, const char *format, ... );
extern int xfer_seek ( struct xfer_interface *xfer, off_t offset, int whence );
extern void ignore_xfer_close ( struct xfer_interface *xfer, int rc );
diff --git a/gpxe/src/include/nic.h b/gpxe/src/include/nic.h
index 65e4be71..186b2ea4 100644
--- a/gpxe/src/include/nic.h
+++ b/gpxe/src/include/nic.h
@@ -17,6 +17,7 @@
#include <gpxe/isa.h>
#include <gpxe/eisa.h>
#include <gpxe/mca.h>
+#include <gpxe/io.h>
#include "dhcp.h"
typedef enum {
diff --git a/gpxe/src/include/stddef.h b/gpxe/src/include/stddef.h
index 6f91d219..11ea9345 100644
--- a/gpxe/src/include/stddef.h
+++ b/gpxe/src/include/stddef.h
@@ -15,4 +15,10 @@
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
+/* __WCHAR_TYPE__ is defined by gcc and will change if -fshort-wchar is used */
+#ifndef __WCHAR_TYPE__
+#define __WCHAR_TYPE__ long int
+#endif
+typedef __WCHAR_TYPE__ wchar_t;
+
#endif /* STDDEF_H */
diff --git a/gpxe/src/include/stdlib.h b/gpxe/src/include/stdlib.h
index ae996962..838a22ac 100644
--- a/gpxe/src/include/stdlib.h
+++ b/gpxe/src/include/stdlib.h
@@ -68,5 +68,6 @@ static inline void srand ( unsigned int seed ) {
*/
extern int system ( const char *command );
+extern __asmcall int main ( void );
#endif /* STDLIB_H */
diff --git a/gpxe/src/include/unistd.h b/gpxe/src/include/unistd.h
index 7c44a0ce..dc1f67f6 100644
--- a/gpxe/src/include/unistd.h
+++ b/gpxe/src/include/unistd.h
@@ -4,7 +4,6 @@
#include <stddef.h>
#include <stdarg.h>
-unsigned int sleep ( unsigned int seconds );
extern int execv ( const char *command, char * const argv[] );
/**
@@ -22,10 +21,21 @@ extern int execv ( const char *command, char * const argv[] );
rc; \
} )
-void udelay(unsigned int usecs);
-void mdelay(unsigned int msecs);
+/* Pick up udelay() */
+#include <gpxe/timer.h>
-#define usleep(x) udelay(x)
+/*
+ * sleep() prototype is defined by POSIX.1. usleep() prototype is
+ * defined by 4.3BSD. udelay() and mdelay() prototypes are chosen to
+ * be reasonably sensible.
+ *
+ */
+
+extern unsigned int sleep ( unsigned int seconds );
+extern void mdelay ( unsigned long msecs );
+static inline __always_inline void usleep ( unsigned long usecs ) {
+ udelay ( usecs );
+}
#endif /* _UNISTD_H */
diff --git a/gpxe/src/include/usr/aoeboot.h b/gpxe/src/include/usr/aoeboot.h
deleted file mode 100644
index 0421ebcc..00000000
--- a/gpxe/src/include/usr/aoeboot.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _USR_AOEBOOT_H
-#define _USR_AOEBOOT_H
-
-extern int aoeboot ( const char *root_path );
-
-#endif /* _USR_AOEBOOT_H */
diff --git a/gpxe/src/include/usr/autoboot.h b/gpxe/src/include/usr/autoboot.h
index b64cbb8e..1e9647c3 100644
--- a/gpxe/src/include/usr/autoboot.h
+++ b/gpxe/src/include/usr/autoboot.h
@@ -7,9 +7,15 @@
*
*/
+#include <gpxe/in.h>
+struct net_device;
+
extern int shutdown_exit_flags;
extern void autoboot ( void );
+extern int boot_next_server_and_filename ( struct in_addr next_server,
+ const char *filename );
extern int boot_root_path ( const char *root_path );
+extern int pxe_menu_boot ( struct net_device *netdev );
#endif /* _USR_AUTOBOOT_H */
diff --git a/gpxe/src/include/usr/dhcpmgmt.h b/gpxe/src/include/usr/dhcpmgmt.h
index 2757a1c1..0f275600 100644
--- a/gpxe/src/include/usr/dhcpmgmt.h
+++ b/gpxe/src/include/usr/dhcpmgmt.h
@@ -9,6 +9,7 @@
struct net_device;
-int dhcp ( struct net_device *netdev );
+extern int dhcp ( struct net_device *netdev );
+extern int pxebs ( struct net_device *netdev, unsigned int pxe_type );
#endif /* _USR_DHCPMGMT_H */
diff --git a/gpxe/src/include/usr/iscsiboot.h b/gpxe/src/include/usr/iscsiboot.h
deleted file mode 100644
index b17951d5..00000000
--- a/gpxe/src/include/usr/iscsiboot.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _USR_ISCSIBOOT_H
-#define _USR_ISCSIBOOT_H
-
-extern int iscsiboot ( const char *root_path );
-
-#endif /* _USR_ISCSIBOOT_H */
diff --git a/gpxe/src/interface/efi/efi_console.c b/gpxe/src/interface/efi/efi_console.c
new file mode 100644
index 00000000..b78de618
--- /dev/null
+++ b/gpxe/src/interface/efi/efi_console.c
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stddef.h>
+#include <assert.h>
+#include <gpxe/efi/efi.h>
+#include <gpxe/ansiesc.h>
+#include <console.h>
+
+#define ATTR_BOLD 0x08
+
+#define ATTR_FCOL_MASK 0x07
+#define ATTR_FCOL_BLACK 0x00
+#define ATTR_FCOL_BLUE 0x01
+#define ATTR_FCOL_GREEN 0x02
+#define ATTR_FCOL_CYAN 0x03
+#define ATTR_FCOL_RED 0x04
+#define ATTR_FCOL_MAGENTA 0x05
+#define ATTR_FCOL_YELLOW 0x06
+#define ATTR_FCOL_WHITE 0x07
+
+#define ATTR_BCOL_MASK 0x70
+#define ATTR_BCOL_BLACK 0x00
+#define ATTR_BCOL_BLUE 0x10
+#define ATTR_BCOL_GREEN 0x20
+#define ATTR_BCOL_CYAN 0x30
+#define ATTR_BCOL_RED 0x40
+#define ATTR_BCOL_MAGENTA 0x50
+#define ATTR_BCOL_YELLOW 0x60
+#define ATTR_BCOL_WHITE 0x70
+
+#define ATTR_DEFAULT ATTR_FCOL_WHITE
+
+/** Current character attribute */
+static unsigned int efi_attr = ATTR_DEFAULT;
+
+/**
+ * Handle ANSI CUP (cursor position)
+ *
+ * @v count Parameter count
+ * @v params[0] Row (1 is top)
+ * @v params[1] Column (1 is left)
+ */
+static void efi_handle_cup ( unsigned int count __unused, int params[] ) {
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *conout = efi_systab->ConOut;
+ int cx = ( params[1] - 1 );
+ int cy = ( params[0] - 1 );
+
+ if ( cx < 0 )
+ cx = 0;
+ if ( cy < 0 )
+ cy = 0;
+
+ conout->SetCursorPosition ( conout, cx, cy );
+}
+
+/**
+ * Handle ANSI ED (erase in page)
+ *
+ * @v count Parameter count
+ * @v params[0] Region to erase
+ */
+static void efi_handle_ed ( unsigned int count __unused,
+ int params[] __unused ) {
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *conout = efi_systab->ConOut;
+
+ /* We assume that we always clear the whole screen */
+ assert ( params[0] == ANSIESC_ED_ALL );
+
+ conout->ClearScreen ( conout );
+}
+
+/**
+ * Handle ANSI SGR (set graphics rendition)
+ *
+ * @v count Parameter count
+ * @v params List of graphic rendition aspects
+ */
+static void efi_handle_sgr ( unsigned int count, int params[] ) {
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *conout = efi_systab->ConOut;
+ static const uint8_t efi_attr_fcols[10] = {
+ ATTR_FCOL_BLACK, ATTR_FCOL_RED, ATTR_FCOL_GREEN,
+ ATTR_FCOL_YELLOW, ATTR_FCOL_BLUE, ATTR_FCOL_MAGENTA,
+ ATTR_FCOL_CYAN, ATTR_FCOL_WHITE,
+ ATTR_FCOL_WHITE, ATTR_FCOL_WHITE /* defaults */
+ };
+ static const uint8_t efi_attr_bcols[10] = {
+ ATTR_BCOL_BLACK, ATTR_BCOL_RED, ATTR_BCOL_GREEN,
+ ATTR_BCOL_YELLOW, ATTR_BCOL_BLUE, ATTR_BCOL_MAGENTA,
+ ATTR_BCOL_CYAN, ATTR_BCOL_WHITE,
+ ATTR_BCOL_BLACK, ATTR_BCOL_BLACK /* defaults */
+ };
+ unsigned int i;
+ int aspect;
+
+ for ( i = 0 ; i < count ; i++ ) {
+ aspect = params[i];
+ if ( aspect == 0 ) {
+ efi_attr = ATTR_DEFAULT;
+ } else if ( aspect == 1 ) {
+ efi_attr |= ATTR_BOLD;
+ } else if ( aspect == 22 ) {
+ efi_attr &= ~ATTR_BOLD;
+ } else if ( ( aspect >= 30 ) && ( aspect <= 39 ) ) {
+ efi_attr &= ~ATTR_FCOL_MASK;
+ efi_attr |= efi_attr_fcols[ aspect - 30 ];
+ } else if ( ( aspect >= 40 ) && ( aspect <= 49 ) ) {
+ efi_attr &= ~ATTR_BCOL_MASK;
+ efi_attr |= efi_attr_bcols[ aspect - 40 ];
+ }
+ }
+
+ conout->SetAttribute ( conout, efi_attr );
+}
+
+/** EFI console ANSI escape sequence handlers */
+static struct ansiesc_handler efi_ansiesc_handlers[] = {
+ { ANSIESC_CUP, efi_handle_cup },
+ { ANSIESC_ED, efi_handle_ed },
+ { ANSIESC_SGR, efi_handle_sgr },
+ { 0, NULL }
+};
+
+/** EFI console ANSI escape sequence context */
+static struct ansiesc_context efi_ansiesc_ctx = {
+ .handlers = efi_ansiesc_handlers,
+};
+
+/**
+ * Print a character to EFI console
+ *
+ * @v character Character to be printed
+ */
+static void efi_putchar ( int character ) {
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *conout = efi_systab->ConOut;
+ wchar_t wstr[] = { character, 0 };
+
+ /* Intercept ANSI escape sequences */
+ character = ansiesc_process ( &efi_ansiesc_ctx, character );
+ if ( character < 0 )
+ return;
+
+ conout->OutputString ( conout, wstr );
+}
+
+/**
+ * Pointer to current ANSI output sequence
+ *
+ * While we are in the middle of returning an ANSI sequence for a
+ * special key, this will point to the next character to return. When
+ * not in the middle of such a sequence, this will point to a NUL
+ * (note: not "will be NULL").
+ */
+static const char *ansi_input = "";
+
+/** Mapping from EFI scan codes to ANSI escape sequences */
+static const char *ansi_sequences[] = {
+ [SCAN_UP] = "[A",
+ [SCAN_DOWN] = "[B",
+ [SCAN_RIGHT] = "[C",
+ [SCAN_LEFT] = "[D",
+ [SCAN_HOME] = "[H",
+ [SCAN_END] = "[F",
+ [SCAN_INSERT] = "[2~",
+ /* EFI translates an incoming backspace via the serial console
+ * into a SCAN_DELETE. There's not much we can do about this.
+ */
+ [SCAN_DELETE] = "[3~",
+ [SCAN_PAGE_UP] = "[5~",
+ [SCAN_PAGE_DOWN] = "[6~",
+ /* EFI translates some (but not all) incoming escape sequences
+ * via the serial console into equivalent scancodes. When it
+ * doesn't recognise a sequence, it helpfully(!) translates
+ * the initial ESC and passes the remainder through verbatim.
+ * Treating SCAN_ESC as equivalent to an empty escape sequence
+ * works around this bug.
+ */
+ [SCAN_ESC] = "",
+};
+
+/**
+ * Get ANSI escape sequence corresponding to EFI scancode
+ *
+ * @v scancode EFI scancode
+ * @ret ansi_seq ANSI escape sequence, if any, otherwise NULL
+ */
+static const char * scancode_to_ansi_seq ( unsigned int scancode ) {
+ if ( scancode < ( sizeof ( ansi_sequences ) /
+ sizeof ( ansi_sequences[0] ) ) ) {
+ return ansi_sequences[scancode];
+ }
+ return NULL;
+}
+
+/**
+ * Get character from EFI console
+ *
+ * @ret character Character read from console
+ */
+static int efi_getchar ( void ) {
+ EFI_SIMPLE_TEXT_INPUT_PROTOCOL *conin = efi_systab->ConIn;
+ const char *ansi_seq;
+ EFI_INPUT_KEY key;
+ EFI_STATUS efirc;
+
+ /* If we are mid-sequence, pass out the next byte */
+ if ( *ansi_input )
+ return *(ansi_input++);
+
+ /* Read key from real EFI console */
+ if ( ( efirc = conin->ReadKeyStroke ( conin, &key ) ) != 0 ) {
+ DBG ( "EFI could not read keystroke: %s\n",
+ efi_strerror ( efirc ) );
+ return 0;
+ }
+ DBG2 ( "EFI read key stroke with unicode %04x scancode %04x\n",
+ key.UnicodeChar, key.ScanCode );
+
+ /* If key has a Unicode representation, return it */
+ if ( key.UnicodeChar )
+ return key.UnicodeChar;
+
+ /* Otherwise, check for a special key that we know about */
+ if ( ( ansi_seq = scancode_to_ansi_seq ( key.ScanCode ) ) ) {
+ /* Start of escape sequence: return ESC (0x1b) */
+ ansi_input = ansi_seq;
+ return 0x1b;
+ }
+
+ return 0;
+}
+
+/**
+ * Check for character ready to read from EFI console
+ *
+ * @ret True Character available to read
+ * @ret False No character available to read
+ */
+static int efi_iskey ( void ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_SIMPLE_TEXT_INPUT_PROTOCOL *conin = efi_systab->ConIn;
+ EFI_STATUS efirc;
+
+ /* If we are mid-sequence, we are always ready */
+ if ( *ansi_input )
+ return 1;
+
+ /* Check to see if the WaitForKey event has fired */
+ if ( ( efirc = bs->CheckEvent ( conin->WaitForKey ) ) == 0 )
+ return 1;
+
+ return 0;
+}
+
+struct console_driver efi_console __console_driver = {
+ .putchar = efi_putchar,
+ .getchar = efi_getchar,
+ .iskey = efi_iskey,
+};
diff --git a/gpxe/src/interface/efi/efi_init.c b/gpxe/src/interface/efi/efi_init.c
new file mode 100644
index 00000000..6e54cf7e
--- /dev/null
+++ b/gpxe/src/interface/efi/efi_init.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <string.h>
+#include <gpxe/efi/efi.h>
+#include <gpxe/uuid.h>
+
+/** Image handle passed to entry point */
+EFI_HANDLE efi_image_handle;
+
+/** System table passed to entry point */
+EFI_SYSTEM_TABLE *efi_systab;
+
+/** Declared used EFI protocols */
+static struct efi_protocol efi_protocols[0] \
+ __table_start ( struct efi_protocol, efi_protocols );
+static struct efi_protocol efi_protocols_end[0] \
+ __table_end ( struct efi_protocol, efi_protocols );
+
+/** Declared used EFI configuration tables */
+static struct efi_config_table efi_config_tables[0] \
+ __table_start ( struct efi_config_table, efi_config_tables );
+static struct efi_config_table efi_config_tables_end[0] \
+ __table_end ( struct efi_config_table, efi_config_tables );
+
+/**
+ * Look up EFI configuration table
+ *
+ * @v guid Configuration table GUID
+ * @ret table Configuration table, or NULL
+ */
+static void * efi_find_table ( EFI_GUID *guid ) {
+ unsigned int i;
+
+ for ( i = 0 ; i < efi_systab->NumberOfTableEntries ; i++ ) {
+ if ( memcmp ( &efi_systab->ConfigurationTable[i].VendorGuid,
+ guid, sizeof ( *guid ) ) == 0 )
+ return efi_systab->ConfigurationTable[i].VendorTable;
+ }
+
+ return NULL;
+}
+
+/**
+ * Initialise EFI environment
+ *
+ * @v image_handle Image handle
+ * @v systab System table
+ * @ret efirc EFI return status code
+ */
+EFI_STATUS efi_init ( EFI_HANDLE image_handle,
+ EFI_SYSTEM_TABLE *systab ) {
+ EFI_BOOT_SERVICES *bs;
+ struct efi_protocol *prot;
+ struct efi_config_table *tab;
+ EFI_STATUS efirc;
+
+ /* Store image handle and system table pointer for future use */
+ efi_image_handle = image_handle;
+ efi_systab = systab;
+
+ /* Sanity checks */
+ if ( ! systab )
+ return EFI_NOT_AVAILABLE_YET;
+ if ( ! systab->ConOut )
+ return EFI_NOT_AVAILABLE_YET;
+ if ( ! systab->BootServices ) {
+ DBGC ( systab, "EFI provided no BootServices entry point\n" );
+ return EFI_NOT_AVAILABLE_YET;
+ }
+ if ( ! systab->RuntimeServices ) {
+ DBGC ( systab, "EFI provided no RuntimeServices entry "
+ "point\n" );
+ return EFI_NOT_AVAILABLE_YET;
+ }
+ DBGC ( systab, "EFI handle %p systab %p\n", image_handle, systab );
+
+ /* Look up used protocols */
+ bs = systab->BootServices;
+ for ( prot = efi_protocols ; prot < efi_protocols_end ; prot++ ) {
+ if ( ( efirc = bs->LocateProtocol ( &prot->u.guid, NULL,
+ prot->protocol ) ) == 0 ) {
+ DBGC ( systab, "EFI protocol %s is at %p\n",
+ uuid_ntoa ( &prot->u.uuid ), *(prot->protocol));
+ } else {
+ DBGC ( systab, "EFI does not provide protocol %s\n",
+ uuid_ntoa ( &prot->u.uuid ) );
+ /* All protocols are required */
+ return efirc;
+ }
+ }
+
+ /* Look up used configuration tables */
+ for ( tab = efi_config_tables ; tab < efi_config_tables_end ; tab++ ) {
+ if ( ( *(tab->table) = efi_find_table ( &tab->u.guid ) ) ) {
+ DBGC ( systab, "EFI configuration table %s is at %p\n",
+ uuid_ntoa ( &tab->u.uuid ), *(tab->table) );
+ } else {
+ DBGC ( systab, "EFI does not provide configuration "
+ "table %s\n", uuid_ntoa ( &tab->u.uuid ) );
+ if ( tab->required )
+ return EFI_NOT_AVAILABLE_YET;
+ }
+ }
+
+ return 0;
+}
diff --git a/gpxe/src/interface/efi/efi_io.c b/gpxe/src/interface/efi/efi_io.c
new file mode 100644
index 00000000..e11f9bfd
--- /dev/null
+++ b/gpxe/src/interface/efi/efi_io.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <assert.h>
+#include <gpxe/io.h>
+#include <gpxe/efi/efi.h>
+#include <gpxe/efi/Protocol/CpuIo.h>
+#include <gpxe/efi/efi_io.h>
+
+/** @file
+ *
+ * gPXE I/O API for EFI
+ *
+ */
+
+/** CPU I/O protocol */
+static EFI_CPU_IO_PROTOCOL *cpu_io;
+EFI_REQUIRE_PROTOCOL ( EFI_CPU_IO_PROTOCOL, &cpu_io );
+
+/** Maximum address that can be used for port I/O */
+#define MAX_PORT_ADDRESS 0xffff
+
+/**
+ * Determine whether or not address is a port I/O address
+ *
+ * @v io_addr I/O address
+ * @v is_port I/O address is a port I/O address
+ */
+#define IS_PORT_ADDRESS(io_addr) \
+ ( ( ( intptr_t ) (io_addr) ) <= MAX_PORT_ADDRESS )
+
+/**
+ * Determine EFI CPU I/O width code
+ *
+ * @v size Size of value
+ * @ret width EFI width code
+ *
+ * Someone at Intel clearly gets paid by the number of lines of code
+ * they write. No-one should ever be able to make I/O this
+ * convoluted. The EFI_CPU_IO_PROTOCOL_WIDTH enum is my favourite
+ * idiocy.
+ */
+static EFI_CPU_IO_PROTOCOL_WIDTH efi_width ( size_t size ) {
+ switch ( size ) {
+ case 1 : return EfiCpuIoWidthFifoUint8;
+ case 2 : return EfiCpuIoWidthFifoUint16;
+ case 4 : return EfiCpuIoWidthFifoUint32;
+ case 8 : return EfiCpuIoWidthFifoUint64;
+ default :
+ assert ( 0 );
+ /* I wonder what this will actually do... */
+ return EfiCpuIoWidthMaximum;
+ }
+}
+
+/**
+ * Read from device
+ *
+ * @v io_addr I/O address
+ * @v size Size of value
+ * @ret data Value read
+ */
+unsigned long long efi_ioread ( volatile void *io_addr, size_t size ) {
+ EFI_CPU_IO_PROTOCOL_IO_MEM read;
+ unsigned long long data = 0;
+ EFI_STATUS efirc;
+
+ read = ( IS_PORT_ADDRESS ( io_addr ) ?
+ cpu_io->Io.Read : cpu_io->Mem.Read );
+
+ if ( ( efirc = read ( cpu_io, efi_width ( size ),
+ ( intptr_t ) io_addr, 1,
+ ( void * ) &data ) ) != 0 ) {
+ DBG ( "EFI I/O read at %p failed: %s\n",
+ io_addr, efi_strerror ( efirc ) );
+ return -1ULL;
+ }
+
+ return data;
+}
+
+/**
+ * Write to device
+ *
+ * @v data Value to write
+ * @v io_addr I/O address
+ * @v size Size of value
+ */
+void efi_iowrite ( unsigned long long data, volatile void *io_addr,
+ size_t size ) {
+ EFI_CPU_IO_PROTOCOL_IO_MEM write;
+ EFI_STATUS efirc;
+
+ write = ( IS_PORT_ADDRESS ( io_addr ) ?
+ cpu_io->Io.Write : cpu_io->Mem.Write );
+
+ if ( ( efirc = write ( cpu_io, efi_width ( size ),
+ ( intptr_t ) io_addr, 1,
+ ( void * ) &data ) ) != 0 ) {
+ DBG ( "EFI I/O write at %p failed: %s\n",
+ io_addr, efi_strerror ( efirc ) );
+ }
+}
+
+/**
+ * String read from device
+ *
+ * @v io_addr I/O address
+ * @v data Data buffer
+ * @v size Size of values
+ * @v count Number of values to read
+ */
+void efi_ioreads ( volatile void *io_addr, void *data,
+ size_t size, unsigned int count ) {
+ EFI_CPU_IO_PROTOCOL_IO_MEM read;
+ EFI_STATUS efirc;
+
+ read = ( IS_PORT_ADDRESS ( io_addr ) ?
+ cpu_io->Io.Read : cpu_io->Mem.Read );
+
+ if ( ( efirc = read ( cpu_io, efi_width ( size ),
+ ( intptr_t ) io_addr, count,
+ ( void * ) data ) ) != 0 ) {
+ DBG ( "EFI I/O string read at %p failed: %s\n",
+ io_addr, efi_strerror ( efirc ) );
+ }
+}
+
+/**
+ * String write to device
+ *
+ * @v io_addr I/O address
+ * @v data Data buffer
+ * @v size Size of values
+ * @v count Number of values to write
+ */
+void efi_iowrites ( volatile void *io_addr, const void *data,
+ size_t size, unsigned int count ) {
+ EFI_CPU_IO_PROTOCOL_IO_MEM write;
+ EFI_STATUS efirc;
+
+ write = ( IS_PORT_ADDRESS ( io_addr ) ?
+ cpu_io->Io.Write : cpu_io->Mem.Write );
+
+ if ( ( efirc = write ( cpu_io, efi_width ( size ),
+ ( intptr_t ) io_addr, count,
+ ( void * ) data ) ) != 0 ) {
+ DBG ( "EFI I/O write at %p failed: %s\n",
+ io_addr, efi_strerror ( efirc ) );
+ }
+}
+
+/**
+ * Wait for I/O-mapped operation to complete
+ *
+ */
+static void efi_iodelay ( void ) {
+ /* Write to non-existent port. Probably x86-only. */
+ outb ( 0, 0x80 );
+}
+
+PROVIDE_IOAPI_INLINE ( efi, phys_to_bus );
+PROVIDE_IOAPI_INLINE ( efi, bus_to_phys );
+PROVIDE_IOAPI_INLINE ( efi, ioremap );
+PROVIDE_IOAPI_INLINE ( efi, iounmap );
+PROVIDE_IOAPI_INLINE ( efi, io_to_bus );
+PROVIDE_IOAPI_INLINE ( efi, readb );
+PROVIDE_IOAPI_INLINE ( efi, readw );
+PROVIDE_IOAPI_INLINE ( efi, readl );
+PROVIDE_IOAPI_INLINE ( efi, readq );
+PROVIDE_IOAPI_INLINE ( efi, writeb );
+PROVIDE_IOAPI_INLINE ( efi, writew );
+PROVIDE_IOAPI_INLINE ( efi, writel );
+PROVIDE_IOAPI_INLINE ( efi, writeq );
+PROVIDE_IOAPI_INLINE ( efi, inb );
+PROVIDE_IOAPI_INLINE ( efi, inw );
+PROVIDE_IOAPI_INLINE ( efi, inl );
+PROVIDE_IOAPI_INLINE ( efi, outb );
+PROVIDE_IOAPI_INLINE ( efi, outw );
+PROVIDE_IOAPI_INLINE ( efi, outl );
+PROVIDE_IOAPI_INLINE ( efi, insb );
+PROVIDE_IOAPI_INLINE ( efi, insw );
+PROVIDE_IOAPI_INLINE ( efi, insl );
+PROVIDE_IOAPI_INLINE ( efi, outsb );
+PROVIDE_IOAPI_INLINE ( efi, outsw );
+PROVIDE_IOAPI_INLINE ( efi, outsl );
+PROVIDE_IOAPI ( efi, iodelay, efi_iodelay );
+PROVIDE_IOAPI_INLINE ( efi, mb );
diff --git a/gpxe/src/interface/efi/efi_pci.c b/gpxe/src/interface/efi/efi_pci.c
new file mode 100644
index 00000000..f87b5407
--- /dev/null
+++ b/gpxe/src/interface/efi/efi_pci.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <errno.h>
+#include <gpxe/pci.h>
+#include <gpxe/efi/efi.h>
+#include <gpxe/efi/Protocol/PciRootBridgeIo.h>
+
+/** @file
+ *
+ * gPXE PCI I/O API for EFI
+ *
+ */
+
+/** PCI root bridge I/O protocol */
+static EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *efipci;
+EFI_REQUIRE_PROTOCOL ( EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL, &efipci );
+
+static unsigned long efipci_address ( struct pci_device *pci,
+ unsigned long location ) {
+ return EFI_PCI_ADDRESS ( pci->bus, PCI_SLOT ( pci->devfn ),
+ PCI_FUNC ( pci->devfn ),
+ EFIPCI_OFFSET ( location ) );
+}
+
+int efipci_read ( struct pci_device *pci, unsigned long location,
+ void *value ) {
+ EFI_STATUS efirc;
+
+ if ( ( efirc = efipci->Pci.Read ( efipci, EFIPCI_WIDTH ( location ),
+ efipci_address ( pci, location ), 1,
+ value ) ) != 0 ) {
+ DBG ( "EFIPCI config read from %02x:%02x.%x offset %02lx "
+ "failed: %s\n", pci->bus, PCI_SLOT ( pci->devfn ),
+ PCI_FUNC ( pci->devfn ), EFIPCI_OFFSET ( location ),
+ efi_strerror ( efirc ) );
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int efipci_write ( struct pci_device *pci, unsigned long location,
+ unsigned long value ) {
+ EFI_STATUS efirc;
+
+ if ( ( efirc = efipci->Pci.Write ( efipci, EFIPCI_WIDTH ( location ),
+ efipci_address ( pci, location ), 1,
+ &value ) ) != 0 ) {
+ DBG ( "EFIPCI config write to %02x:%02x.%x offset %02lx "
+ "failed: %s\n", pci->bus, PCI_SLOT ( pci->devfn ),
+ PCI_FUNC ( pci->devfn ), EFIPCI_OFFSET ( location ),
+ efi_strerror ( efirc ) );
+ return -EIO;
+ }
+
+ return 0;
+}
+
+PROVIDE_PCIAPI_INLINE ( efi, pci_max_bus );
+PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_byte );
+PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_word );
+PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_dword );
+PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_byte );
+PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_word );
+PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_dword );
diff --git a/gpxe/src/interface/efi/efi_smbios.c b/gpxe/src/interface/efi/efi_smbios.c
new file mode 100644
index 00000000..5888f2f9
--- /dev/null
+++ b/gpxe/src/interface/efi/efi_smbios.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <errno.h>
+#include <gpxe/smbios.h>
+#include <gpxe/efi/efi.h>
+#include <gpxe/efi/Guid/SmBios.h>
+
+/** @file
+ *
+ * gPXE SMBIOS API for EFI
+ *
+ */
+
+/** SMBIOS configuration table */
+static struct smbios_entry *smbios_entry;
+EFI_USE_TABLE ( EFI_SMBIOS_TABLE, &smbios_entry, 0 );
+
+/**
+ * Find SMBIOS
+ *
+ * @v smbios SMBIOS entry point descriptor structure to fill in
+ * @ret rc Return status code
+ */
+static int efi_find_smbios ( struct smbios *smbios ) {
+
+ if ( ! smbios_entry ) {
+ DBG ( "No SMBIOS table provided\n" );
+ return -ENODEV;
+ }
+
+ if ( smbios_entry->signature != SMBIOS_SIGNATURE ) {
+ DBG ( "Invalid SMBIOS signature\n" );
+ return -ENODEV;
+ }
+
+ smbios->address = phys_to_user ( smbios_entry->smbios_address );
+ smbios->len = smbios_entry->smbios_len;
+ smbios->count = smbios_entry->smbios_count;
+ DBG ( "Found SMBIOS v%d.%d entry point at %p (%x+%zx)\n",
+ smbios_entry->major, smbios_entry->minor, smbios_entry,
+ smbios_entry->smbios_address, smbios->len );
+
+ return 0;
+}
+
+PROVIDE_SMBIOS ( efi, find_smbios, efi_find_smbios );
diff --git a/gpxe/src/interface/efi/efi_snp.c b/gpxe/src/interface/efi/efi_snp.c
new file mode 100644
index 00000000..771b9174
--- /dev/null
+++ b/gpxe/src/interface/efi/efi_snp.c
@@ -0,0 +1,1145 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <gpxe/netdevice.h>
+#include <gpxe/iobuf.h>
+#include <gpxe/in.h>
+#include <gpxe/pci.h>
+#include <gpxe/efi/efi.h>
+#include <gpxe/efi/Protocol/DriverBinding.h>
+#include <gpxe/efi/Protocol/PciIo.h>
+#include <gpxe/efi/Protocol/SimpleNetwork.h>
+#include <gpxe/efi/Protocol/ComponentName2.h>
+#include <gpxe/efi/Protocol/NetworkInterfaceIdentifier.h>
+#include <config/general.h>
+
+/** @file
+ *
+ * gPXE EFI SNP interface
+ *
+ */
+
+/** An SNP device */
+struct efi_snp_device {
+ /** The underlying gPXE network device */
+ struct net_device *netdev;
+ /** EFI device handle */
+ EFI_HANDLE handle;
+ /** The SNP structure itself */
+ EFI_SIMPLE_NETWORK_PROTOCOL snp;
+ /** The SNP "mode" (parameters) */
+ EFI_SIMPLE_NETWORK_MODE mode;
+ /** Outstanding TX packet count (via "interrupt status")
+ *
+ * Used in order to generate TX completions.
+ */
+ unsigned int tx_count_interrupts;
+ /** Outstanding TX packet count (via "recycled tx buffers")
+ *
+ * Used in order to generate TX completions.
+ */
+ unsigned int tx_count_txbufs;
+ /** Outstanding RX packet count (via "interrupt status") */
+ unsigned int rx_count_interrupts;
+ /** Outstanding RX packet count (via WaitForPacket event) */
+ unsigned int rx_count_events;
+ /** The network interface identifier */
+ EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL nii;
+ /** Device name */
+ wchar_t name[ sizeof ( ( ( struct net_device * ) NULL )->name ) ];
+ /** The device path
+ *
+ * This field is variable in size and must appear at the end
+ * of the structure.
+ */
+ EFI_DEVICE_PATH_PROTOCOL path;
+};
+
+/** EFI simple network protocol GUID */
+static EFI_GUID efi_simple_network_protocol_guid
+ = EFI_SIMPLE_NETWORK_PROTOCOL_GUID;
+
+/** EFI driver binding protocol GUID */
+static EFI_GUID efi_driver_binding_protocol_guid
+ = EFI_DRIVER_BINDING_PROTOCOL_GUID;
+
+/** EFI component name protocol GUID */
+static EFI_GUID efi_component_name2_protocol_guid
+ = EFI_COMPONENT_NAME2_PROTOCOL_GUID;
+
+/** EFI device path protocol GUID */
+static EFI_GUID efi_device_path_protocol_guid
+ = EFI_DEVICE_PATH_PROTOCOL_GUID;
+
+/** EFI network interface identifier GUID */
+static EFI_GUID efi_nii_protocol_guid
+ = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_GUID;
+
+/** EFI network interface identifier GUID (extra special version) */
+static EFI_GUID efi_nii31_protocol_guid = {
+ /* At some point, it seems that someone decided to change the
+ * GUID. Current EFI builds ignore the older GUID, older EFI
+ * builds ignore the newer GUID, so we have to expose both.
+ */
+ 0x1ACED566, 0x76ED, 0x4218,
+ { 0xBC, 0x81, 0x76, 0x7F, 0x1F, 0x97, 0x7A, 0x89 }
+};
+
+/** EFI PCI I/O protocol GUID */
+static EFI_GUID efi_pci_io_protocol_guid
+ = EFI_PCI_IO_PROTOCOL_GUID;
+
+/**
+ * Set EFI SNP mode based on gPXE net device parameters
+ *
+ * @v snp SNP interface
+ */
+static void efi_snp_set_mode ( struct efi_snp_device *snpdev ) {
+ struct net_device *netdev = snpdev->netdev;
+ EFI_SIMPLE_NETWORK_MODE *mode = &snpdev->mode;
+ unsigned int ll_addr_len = netdev->ll_protocol->ll_addr_len;
+
+ mode->HwAddressSize = ll_addr_len;
+ mode->MediaHeaderSize = netdev->ll_protocol->ll_header_len;
+ mode->MaxPacketSize = netdev->max_pkt_len;
+ mode->ReceiveFilterMask = ( EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
+ EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST |
+ EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST );
+ assert ( ll_addr_len <= sizeof ( mode->CurrentAddress ) );
+ memcpy ( &mode->CurrentAddress, netdev->ll_addr, ll_addr_len );
+ memcpy ( &mode->BroadcastAddress, netdev->ll_protocol->ll_broadcast,
+ ll_addr_len );
+ memcpy ( &mode->PermanentAddress, netdev->ll_addr, ll_addr_len );
+ mode->IfType = ntohs ( netdev->ll_protocol->ll_proto );
+ mode->MacAddressChangeable = TRUE;
+ mode->MediaPresentSupported = TRUE;
+ mode->MediaPresent = ( netdev_link_ok ( netdev ) ? TRUE : FALSE );
+}
+
+/**
+ * Poll net device and count received packets
+ *
+ * @v snpdev SNP device
+ */
+static void efi_snp_poll ( struct efi_snp_device *snpdev ) {
+ struct io_buffer *iobuf;
+ unsigned int before = 0;
+ unsigned int after = 0;
+ unsigned int arrived;
+
+ /* We have to report packet arrivals, and this is the easiest
+ * way to fake it.
+ */
+ list_for_each_entry ( iobuf, &snpdev->netdev->rx_queue, list )
+ before++;
+ netdev_poll ( snpdev->netdev );
+ list_for_each_entry ( iobuf, &snpdev->netdev->rx_queue, list )
+ after++;
+ arrived = ( after - before );
+
+ snpdev->rx_count_interrupts += arrived;
+ snpdev->rx_count_events += arrived;
+}
+
+/**
+ * Change SNP state from "stopped" to "started"
+ *
+ * @v snp SNP interface
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_start ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) {
+ struct efi_snp_device *snpdev =
+ container_of ( snp, struct efi_snp_device, snp );
+
+ DBGC2 ( snpdev, "SNPDEV %p START\n", snpdev );
+
+ snpdev->mode.State = EfiSimpleNetworkStarted;
+ return 0;
+}
+
+/**
+ * Change SNP state from "started" to "stopped"
+ *
+ * @v snp SNP interface
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_stop ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) {
+ struct efi_snp_device *snpdev =
+ container_of ( snp, struct efi_snp_device, snp );
+
+ DBGC2 ( snpdev, "SNPDEV %p STOP\n", snpdev );
+
+ snpdev->mode.State = EfiSimpleNetworkStopped;
+ return 0;
+}
+
+/**
+ * Open the network device
+ *
+ * @v snp SNP interface
+ * @v extra_rx_bufsize Extra RX buffer size, in bytes
+ * @v extra_tx_bufsize Extra TX buffer size, in bytes
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_initialize ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
+ UINTN extra_rx_bufsize, UINTN extra_tx_bufsize ) {
+ struct efi_snp_device *snpdev =
+ container_of ( snp, struct efi_snp_device, snp );
+ int rc;
+
+ DBGC2 ( snpdev, "SNPDEV %p INITIALIZE (%ld extra RX, %ld extra TX)\n",
+ snpdev, ( ( unsigned long ) extra_rx_bufsize ),
+ ( ( unsigned long ) extra_tx_bufsize ) );
+
+ if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) {
+ DBGC ( snpdev, "SNPDEV %p could not open %s: %s\n",
+ snpdev, snpdev->netdev->name, strerror ( rc ) );
+ return RC_TO_EFIRC ( rc );
+ }
+
+ snpdev->mode.State = EfiSimpleNetworkInitialized;
+ return 0;
+}
+
+/**
+ * Reset the network device
+ *
+ * @v snp SNP interface
+ * @v ext_verify Extended verification required
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_reset ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ext_verify ) {
+ struct efi_snp_device *snpdev =
+ container_of ( snp, struct efi_snp_device, snp );
+ int rc;
+
+ DBGC2 ( snpdev, "SNPDEV %p RESET (%s extended verification)\n",
+ snpdev, ( ext_verify ? "with" : "without" ) );
+
+ netdev_close ( snpdev->netdev );
+ snpdev->mode.State = EfiSimpleNetworkStarted;
+
+ if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) {
+ DBGC ( snpdev, "SNPDEV %p could not reopen %s: %s\n",
+ snpdev, snpdev->netdev->name, strerror ( rc ) );
+ return RC_TO_EFIRC ( rc );
+ }
+
+ snpdev->mode.State = EfiSimpleNetworkInitialized;
+ return 0;
+}
+
+/**
+ * Shut down the network device
+ *
+ * @v snp SNP interface
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_shutdown ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) {
+ struct efi_snp_device *snpdev =
+ container_of ( snp, struct efi_snp_device, snp );
+
+ DBGC2 ( snpdev, "SNPDEV %p SHUTDOWN\n", snpdev );
+
+ netdev_close ( snpdev->netdev );
+ snpdev->mode.State = EfiSimpleNetworkStarted;
+ return 0;
+}
+
+/**
+ * Manage receive filters
+ *
+ * @v snp SNP interface
+ * @v enable Receive filters to enable
+ * @v disable Receive filters to disable
+ * @v mcast_reset Reset multicast filters
+ * @v mcast_count Number of multicast filters
+ * @v mcast Multicast filters
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_receive_filters ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, UINT32 enable,
+ UINT32 disable, BOOLEAN mcast_reset,
+ UINTN mcast_count, EFI_MAC_ADDRESS *mcast ) {
+ struct efi_snp_device *snpdev =
+ container_of ( snp, struct efi_snp_device, snp );
+ unsigned int i;
+
+ DBGC2 ( snpdev, "SNPDEV %p RECEIVE_FILTERS %08x&~%08x%s %ld mcast\n",
+ snpdev, enable, disable, ( mcast_reset ? " reset" : "" ),
+ ( ( unsigned long ) mcast_count ) );
+ for ( i = 0 ; i < mcast_count ; i++ ) {
+ DBGC2_HDA ( snpdev, i, &mcast[i],
+ snpdev->netdev->ll_protocol->ll_addr_len );
+ }
+
+ /* Lie through our teeth, otherwise MNP refuses to accept us */
+ return 0;
+}
+
+/**
+ * Set station address
+ *
+ * @v snp SNP interface
+ * @v reset Reset to permanent address
+ * @v new New station address
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_station_address ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN reset,
+ EFI_MAC_ADDRESS *new ) {
+ struct efi_snp_device *snpdev =
+ container_of ( snp, struct efi_snp_device, snp );
+ struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
+
+ DBGC2 ( snpdev, "SNPDEV %p STATION_ADDRESS %s\n", snpdev,
+ ( reset ? "reset" : ll_protocol->ntoa ( new ) ) );
+
+ /* Set the MAC address */
+ if ( reset )
+ new = &snpdev->mode.PermanentAddress;
+ memcpy ( snpdev->netdev->ll_addr, new, ll_protocol->ll_addr_len );
+
+ /* MAC address changes take effect only on netdev_open() */
+ if ( snpdev->netdev->state & NETDEV_OPEN ) {
+ DBGC ( snpdev, "SNPDEV %p MAC address changed while net "
+ "devive open\n", snpdev );
+ }
+
+ return 0;
+}
+
+/**
+ * Get (or reset) statistics
+ *
+ * @v snp SNP interface
+ * @v reset Reset statistics
+ * @v stats_len Size of statistics table
+ * @v stats Statistics table
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_statistics ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN reset,
+ UINTN *stats_len, EFI_NETWORK_STATISTICS *stats ) {
+ struct efi_snp_device *snpdev =
+ container_of ( snp, struct efi_snp_device, snp );
+ EFI_NETWORK_STATISTICS stats_buf;
+
+ DBGC2 ( snpdev, "SNPDEV %p STATISTICS%s", snpdev,
+ ( reset ? " reset" : "" ) );
+
+ /* Gather statistics */
+ memset ( &stats_buf, 0, sizeof ( stats_buf ) );
+ stats_buf.TxGoodFrames = snpdev->netdev->tx_stats.good;
+ stats_buf.TxDroppedFrames = snpdev->netdev->tx_stats.bad;
+ stats_buf.TxTotalFrames = ( snpdev->netdev->tx_stats.good +
+ snpdev->netdev->tx_stats.bad );
+ stats_buf.RxGoodFrames = snpdev->netdev->rx_stats.good;
+ stats_buf.RxDroppedFrames = snpdev->netdev->rx_stats.bad;
+ stats_buf.RxTotalFrames = ( snpdev->netdev->rx_stats.good +
+ snpdev->netdev->rx_stats.bad );
+ if ( *stats_len > sizeof ( stats_buf ) )
+ *stats_len = sizeof ( stats_buf );
+ if ( stats )
+ memcpy ( stats, &stats_buf, *stats_len );
+
+ /* Reset statistics if requested to do so */
+ if ( reset ) {
+ memset ( &snpdev->netdev->tx_stats, 0,
+ sizeof ( snpdev->netdev->tx_stats ) );
+ memset ( &snpdev->netdev->rx_stats, 0,
+ sizeof ( snpdev->netdev->rx_stats ) );
+ }
+
+ return 0;
+}
+
+/**
+ * Convert multicast IP address to MAC address
+ *
+ * @v snp SNP interface
+ * @v ipv6 Address is IPv6
+ * @v ip IP address
+ * @v mac MAC address
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_mcast_ip_to_mac ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ipv6,
+ EFI_IP_ADDRESS *ip, EFI_MAC_ADDRESS *mac ) {
+ struct efi_snp_device *snpdev =
+ container_of ( snp, struct efi_snp_device, snp );
+ struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
+ const char *ip_str;
+ int rc;
+
+ ip_str = ( ipv6 ? "(IPv6)" /* FIXME when we have inet6_ntoa() */ :
+ inet_ntoa ( *( ( struct in_addr * ) ip ) ) );
+ DBGC2 ( snpdev, "SNPDEV %p MCAST_IP_TO_MAC %s\n", snpdev, ip_str );
+
+ /* Try to hash the address */
+ if ( ( rc = ll_protocol->mc_hash ( ( ipv6 ? AF_INET6 : AF_INET ),
+ ip, mac ) ) != 0 ) {
+ DBGC ( snpdev, "SNPDEV %p could not hash %s: %s\n",
+ snpdev, ip_str, strerror ( rc ) );
+ return RC_TO_EFIRC ( rc );
+ }
+
+ return 0;
+}
+
+/**
+ * Read or write non-volatile storage
+ *
+ * @v snp SNP interface
+ * @v read Operation is a read
+ * @v offset Starting offset within NVRAM
+ * @v len Length of data buffer
+ * @v data Data buffer
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_nvdata ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN read,
+ UINTN offset, UINTN len, VOID *data ) {
+ struct efi_snp_device *snpdev =
+ container_of ( snp, struct efi_snp_device, snp );
+
+ DBGC2 ( snpdev, "SNPDEV %p NVDATA %s %lx+%lx\n", snpdev,
+ ( read ? "read" : "write" ), ( ( unsigned long ) offset ),
+ ( ( unsigned long ) len ) );
+ if ( ! read )
+ DBGC2_HDA ( snpdev, offset, data, len );
+
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ * Read interrupt status and TX recycled buffer status
+ *
+ * @v snp SNP interface
+ * @v interrupts Interrupt status, or NULL
+ * @v txbufs Recycled transmit buffer address, or NULL
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_get_status ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
+ UINT32 *interrupts, VOID **txbufs ) {
+ struct efi_snp_device *snpdev =
+ container_of ( snp, struct efi_snp_device, snp );
+
+ DBGC2 ( snpdev, "SNPDEV %p GET_STATUS", snpdev );
+
+ /* Poll the network device */
+ efi_snp_poll ( snpdev );
+
+ /* Interrupt status. In practice, this seems to be used only
+ * to detect TX completions.
+ */
+ if ( interrupts ) {
+ *interrupts = 0;
+ /* Report TX completions once queue is empty; this
+ * avoids having to add hooks in the net device layer.
+ */
+ if ( snpdev->tx_count_interrupts &&
+ list_empty ( &snpdev->netdev->tx_queue ) ) {
+ *interrupts |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
+ snpdev->tx_count_interrupts--;
+ }
+ /* Report RX */
+ if ( snpdev->rx_count_interrupts ) {
+ *interrupts |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
+ snpdev->rx_count_interrupts--;
+ }
+ DBGC2 ( snpdev, " INTS:%02x", *interrupts );
+ }
+
+ /* TX completions. It would be possible to design a more
+ * idiotic scheme for this, but it would be a challenge.
+ * According to the UEFI header file, txbufs will be filled in
+ * with a list of "recycled transmit buffers" (i.e. completed
+ * TX buffers). Observant readers may care to note that
+ * *txbufs is a void pointer. Precisely how a list of
+ * completed transmit buffers is meant to be represented as an
+ * array of voids is left as an exercise for the reader.
+ *
+ * The only users of this interface (MnpDxe/MnpIo.c and
+ * PxeBcDxe/Bc.c within the EFI dev kit) both just poll until
+ * seeing a non-NULL result return in txbufs. This is valid
+ * provided that they do not ever attempt to transmit more
+ * than one packet concurrently (and that TX never times out).
+ */
+ if ( txbufs ) {
+ if ( snpdev->tx_count_txbufs &&
+ list_empty ( &snpdev->netdev->tx_queue ) ) {
+ *txbufs = "Which idiot designed this API?";
+ snpdev->tx_count_txbufs--;
+ } else {
+ *txbufs = NULL;
+ }
+ DBGC2 ( snpdev, " TX:%s", ( *txbufs ? "some" : "none" ) );
+ }
+
+ DBGC2 ( snpdev, "\n" );
+ return 0;
+}
+
+/**
+ * Start packet transmission
+ *
+ * @v snp SNP interface
+ * @v ll_header_len Link-layer header length, if to be filled in
+ * @v len Length of data buffer
+ * @v data Data buffer
+ * @v ll_src Link-layer source address, if specified
+ * @v ll_dest Link-layer destination address, if specified
+ * @v net_proto Network-layer protocol (in host order)
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_transmit ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
+ UINTN ll_header_len, UINTN len, VOID *data,
+ EFI_MAC_ADDRESS *ll_src, EFI_MAC_ADDRESS *ll_dest,
+ UINT16 *net_proto ) {
+ struct efi_snp_device *snpdev =
+ container_of ( snp, struct efi_snp_device, snp );
+ struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
+ struct io_buffer *iobuf;
+ int rc;
+ EFI_STATUS efirc;
+
+ DBGC2 ( snpdev, "SNPDEV %p TRANSMIT %p+%lx", snpdev, data,
+ ( ( unsigned long ) len ) );
+ if ( ll_header_len ) {
+ if ( ll_src ) {
+ DBGC2 ( snpdev, " src %s",
+ ll_protocol->ntoa ( ll_src ) );
+ }
+ if ( ll_dest ) {
+ DBGC2 ( snpdev, " dest %s",
+ ll_protocol->ntoa ( ll_dest ) );
+ }
+ if ( net_proto ) {
+ DBGC2 ( snpdev, " proto %04x", *net_proto );
+ }
+ }
+ DBGC2 ( snpdev, "\n" );
+
+ /* Sanity checks */
+ if ( ll_header_len ) {
+ if ( ll_header_len != ll_protocol->ll_header_len ) {
+ DBGC ( snpdev, "SNPDEV %p TX invalid header length "
+ "%ld\n", snpdev,
+ ( ( unsigned long ) ll_header_len ) );
+ efirc = EFI_INVALID_PARAMETER;
+ goto err_sanity;
+ }
+ if ( len < ll_header_len ) {
+ DBGC ( snpdev, "SNPDEV %p invalid packet length %ld\n",
+ snpdev, ( ( unsigned long ) len ) );
+ efirc = EFI_BUFFER_TOO_SMALL;
+ goto err_sanity;
+ }
+ if ( ! ll_dest ) {
+ DBGC ( snpdev, "SNPDEV %p TX missing destination "
+ "address\n", snpdev );
+ efirc = EFI_INVALID_PARAMETER;
+ goto err_sanity;
+ }
+ if ( ! net_proto ) {
+ DBGC ( snpdev, "SNPDEV %p TX missing network "
+ "protocol\n", snpdev );
+ efirc = EFI_INVALID_PARAMETER;
+ goto err_sanity;
+ }
+ if ( ! ll_src )
+ ll_src = &snpdev->mode.CurrentAddress;
+ }
+
+ /* Allocate buffer */
+ iobuf = alloc_iob ( len );
+ if ( ! iobuf ) {
+ DBGC ( snpdev, "SNPDEV %p TX could not allocate %ld-byte "
+ "buffer\n", snpdev, ( ( unsigned long ) len ) );
+ efirc = EFI_DEVICE_ERROR;
+ goto err_alloc_iob;
+ }
+ memcpy ( iob_put ( iobuf, len ), data, len );
+
+ /* Create link-layer header, if specified */
+ if ( ll_header_len ) {
+ iob_pull ( iobuf, ll_header_len );
+ if ( ( rc = ll_protocol->push ( iobuf, ll_dest, ll_src,
+ htons ( *net_proto ) )) != 0 ){
+ DBGC ( snpdev, "SNPDEV %p TX could not construct "
+ "header: %s\n", snpdev, strerror ( rc ) );
+ efirc = RC_TO_EFIRC ( rc );
+ goto err_ll_push;
+ }
+ }
+
+ /* Transmit packet */
+ if ( ( rc = netdev_tx ( snpdev->netdev, iob_disown ( iobuf ) ) ) != 0){
+ DBGC ( snpdev, "SNPDEV %p TX could not transmit: %s\n",
+ snpdev, strerror ( rc ) );
+ efirc = RC_TO_EFIRC ( rc );
+ goto err_tx;
+ }
+
+ /* Record transmission as outstanding */
+ snpdev->tx_count_interrupts++;
+ snpdev->tx_count_txbufs++;
+
+ return 0;
+
+ err_tx:
+ err_ll_push:
+ free_iob ( iobuf );
+ err_alloc_iob:
+ err_sanity:
+ return efirc;
+}
+
+/**
+ * Receive packet
+ *
+ * @v snp SNP interface
+ * @v ll_header_len Link-layer header length, if to be filled in
+ * @v len Length of data buffer
+ * @v data Data buffer
+ * @v ll_src Link-layer source address, if specified
+ * @v ll_dest Link-layer destination address, if specified
+ * @v net_proto Network-layer protocol (in host order)
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_receive ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
+ UINTN *ll_header_len, UINTN *len, VOID *data,
+ EFI_MAC_ADDRESS *ll_src, EFI_MAC_ADDRESS *ll_dest,
+ UINT16 *net_proto ) {
+ struct efi_snp_device *snpdev =
+ container_of ( snp, struct efi_snp_device, snp );
+ struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
+ struct io_buffer *iobuf;
+ const void *iob_ll_dest;
+ const void *iob_ll_src;
+ uint16_t iob_net_proto;
+ int rc;
+ EFI_STATUS efirc;
+
+ DBGC2 ( snpdev, "SNPDEV %p RECEIVE %p(+%lx)", snpdev, data,
+ ( ( unsigned long ) *len ) );
+
+ /* Poll the network device */
+ efi_snp_poll ( snpdev );
+
+ /* Dequeue a packet, if one is available */
+ iobuf = netdev_rx_dequeue ( snpdev->netdev );
+ if ( ! iobuf ) {
+ DBGC2 ( snpdev, "\n" );
+ efirc = EFI_NOT_READY;
+ goto out_no_packet;
+ }
+ DBGC2 ( snpdev, "+%zx\n", iob_len ( iobuf ) );
+
+ /* Return packet to caller */
+ memcpy ( data, iobuf->data, iob_len ( iobuf ) );
+ *len = iob_len ( iobuf );
+
+ /* Attempt to decode link-layer header */
+ if ( ( rc = ll_protocol->pull ( iobuf, &iob_ll_dest, &iob_ll_src,
+ &iob_net_proto ) ) != 0 ) {
+ DBGC ( snpdev, "SNPDEV %p could not parse header: %s\n",
+ snpdev, strerror ( rc ) );
+ efirc = RC_TO_EFIRC ( rc );
+ goto out_bad_ll_header;
+ }
+
+ /* Return link-layer header parameters to caller, if required */
+ if ( ll_header_len )
+ *ll_header_len = ll_protocol->ll_header_len;
+ if ( ll_src )
+ memcpy ( ll_src, iob_ll_src, ll_protocol->ll_addr_len );
+ if ( ll_dest )
+ memcpy ( ll_dest, iob_ll_dest, ll_protocol->ll_addr_len );
+ if ( net_proto )
+ *net_proto = ntohs ( iob_net_proto );
+
+ efirc = 0;
+
+ out_bad_ll_header:
+ free_iob ( iobuf );
+out_no_packet:
+ return efirc;
+}
+
+/**
+ * Poll event
+ *
+ * @v event Event
+ * @v context Event context
+ */
+static VOID EFIAPI efi_snp_wait_for_packet ( EFI_EVENT event,
+ VOID *context ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ struct efi_snp_device *snpdev = context;
+
+ DBGCP ( snpdev, "SNPDEV %p WAIT_FOR_PACKET\n", snpdev );
+
+ /* Do nothing unless the net device is open */
+ if ( ! ( snpdev->netdev->state & NETDEV_OPEN ) )
+ return;
+
+ /* Poll the network device */
+ efi_snp_poll ( snpdev );
+
+ /* Fire event if packets have been received */
+ if ( snpdev->rx_count_events != 0 ) {
+ DBGC2 ( snpdev, "SNPDEV %p firing WaitForPacket event\n",
+ snpdev );
+ bs->SignalEvent ( event );
+ snpdev->rx_count_events--;
+ }
+}
+
+/** SNP interface */
+static EFI_SIMPLE_NETWORK_PROTOCOL efi_snp_device_snp = {
+ .Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION,
+ .Start = efi_snp_start,
+ .Stop = efi_snp_stop,
+ .Initialize = efi_snp_initialize,
+ .Reset = efi_snp_reset,
+ .Shutdown = efi_snp_shutdown,
+ .ReceiveFilters = efi_snp_receive_filters,
+ .StationAddress = efi_snp_station_address,
+ .Statistics = efi_snp_statistics,
+ .MCastIpToMac = efi_snp_mcast_ip_to_mac,
+ .NvData = efi_snp_nvdata,
+ .GetStatus = efi_snp_get_status,
+ .Transmit = efi_snp_transmit,
+ .Receive = efi_snp_receive,
+};
+
+/**
+ * Locate net device corresponding to EFI device
+ *
+ * @v driver EFI driver
+ * @v device EFI device
+ * @ret netdev Net device, or NULL if not found
+ */
+static struct net_device *
+efi_snp_netdev ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ union {
+ EFI_PCI_IO_PROTOCOL *pci;
+ void *interface;
+ } u;
+ UINTN pci_segment, pci_bus, pci_dev, pci_fn;
+ unsigned int pci_busdevfn;
+ struct net_device *netdev = NULL;
+ EFI_STATUS efirc;
+
+ /* See if device is a PCI device */
+ if ( ( efirc = bs->OpenProtocol ( device,
+ &efi_pci_io_protocol_guid,
+ &u.interface,
+ driver->DriverBindingHandle,
+ device,
+ EFI_OPEN_PROTOCOL_BY_DRIVER )) !=0 ){
+ DBGCP ( driver, "SNPDRV %p device %p is not a PCI device\n",
+ driver, device );
+ goto out_no_pci_io;
+ }
+
+ /* Get PCI bus:dev.fn address */
+ if ( ( efirc = u.pci->GetLocation ( u.pci, &pci_segment, &pci_bus,
+ &pci_dev, &pci_fn ) ) != 0 ) {
+ DBGC ( driver, "SNPDRV %p device %p could not get PCI "
+ "location: %s\n",
+ driver, device, efi_strerror ( efirc ) );
+ goto out_no_pci_location;
+ }
+ DBGCP ( driver, "SNPDRV %p device %p is PCI %04lx:%02lx:%02lx.%lx\n",
+ driver, device, ( ( unsigned long ) pci_segment ),
+ ( ( unsigned long ) pci_bus ), ( ( unsigned long ) pci_dev ),
+ ( ( unsigned long ) pci_fn ) );
+
+ /* Look up corresponding network device */
+ pci_busdevfn = PCI_BUSDEVFN ( pci_bus, PCI_DEVFN ( pci_dev, pci_fn ) );
+ if ( ( netdev = find_netdev_by_location ( BUS_TYPE_PCI,
+ pci_busdevfn ) ) == NULL ) {
+ DBGCP ( driver, "SNPDRV %p device %p is not a gPXE network "
+ "device\n", driver, device );
+ goto out_no_netdev;
+ }
+ DBGC ( driver, "SNPDRV %p device %p is %s\n",
+ driver, device, netdev->name );
+
+ out_no_netdev:
+ out_no_pci_location:
+ bs->CloseProtocol ( device, &efi_pci_io_protocol_guid,
+ driver->DriverBindingHandle, device );
+ out_no_pci_io:
+ return netdev;
+}
+
+/**
+ * Locate SNP corresponding to EFI device
+ *
+ * @v driver EFI driver
+ * @v device EFI device
+ * @ret snp EFI SNP, or NULL if not found
+ */
+static struct efi_snp_device *
+efi_snp_snpdev ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ union {
+ EFI_SIMPLE_NETWORK_PROTOCOL *snp;
+ void *interface;
+ } u;
+ struct efi_snp_device *snpdev = NULL;
+ EFI_STATUS efirc;
+
+ if ( ( efirc = bs->OpenProtocol ( device,
+ &efi_simple_network_protocol_guid,
+ &u.interface,
+ driver->DriverBindingHandle,
+ device,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL))!=0){
+ DBGC ( driver, "SNPDRV %p device %p could not locate SNP: "
+ "%s\n", driver, device, efi_strerror ( efirc ) );
+ goto err_no_snp;
+ }
+
+ snpdev = container_of ( u.snp, struct efi_snp_device, snp );
+ DBGCP ( driver, "SNPDRV %p device %p is SNPDEV %p\n",
+ driver, device, snpdev );
+
+ bs->CloseProtocol ( device, &efi_simple_network_protocol_guid,
+ driver->DriverBindingHandle, device );
+ err_no_snp:
+ return snpdev;
+}
+
+/**
+ * Check to see if driver supports a device
+ *
+ * @v driver EFI driver
+ * @v device EFI device
+ * @v child Path to child device, if any
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_driver_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver,
+ EFI_HANDLE device,
+ EFI_DEVICE_PATH_PROTOCOL *child ) {
+ struct net_device *netdev;
+
+ DBGCP ( driver, "SNPDRV %p DRIVER_SUPPORTED %p (%p)\n",
+ driver, device, child );
+
+ netdev = efi_snp_netdev ( driver, device );
+ return ( netdev ? 0 : EFI_UNSUPPORTED );
+}
+
+/**
+ * Attach driver to device
+ *
+ * @v driver EFI driver
+ * @v device EFI device
+ * @v child Path to child device, if any
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_driver_start ( EFI_DRIVER_BINDING_PROTOCOL *driver,
+ EFI_HANDLE device,
+ EFI_DEVICE_PATH_PROTOCOL *child ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_DEVICE_PATH_PROTOCOL *path;
+ EFI_DEVICE_PATH_PROTOCOL *subpath;
+ MAC_ADDR_DEVICE_PATH *macpath;
+ struct efi_snp_device *snpdev;
+ struct net_device *netdev;
+ size_t subpath_len;
+ size_t path_prefix_len = 0;
+ unsigned int i;
+ EFI_STATUS efirc;
+
+ DBGCP ( driver, "SNPDRV %p DRIVER_START %p (%p)\n",
+ driver, device, child );
+
+ /* Determine device path prefix length */
+ if ( ( efirc = bs->OpenProtocol ( device,
+ &efi_device_path_protocol_guid,
+ ( void * ) &path,
+ driver->DriverBindingHandle,
+ device,
+ EFI_OPEN_PROTOCOL_BY_DRIVER )) !=0 ){
+ DBGCP ( driver, "SNPDRV %p device %p has no device path\n",
+ driver, device );
+ goto err_no_device_path;
+ }
+ subpath = path;
+ while ( subpath->Type != END_DEVICE_PATH_TYPE ) {
+ subpath_len = ( ( subpath->Length[1] << 8 ) |
+ subpath->Length[0] );
+ path_prefix_len += subpath_len;
+ subpath = ( ( ( void * ) subpath ) + subpath_len );
+ }
+
+ /* Allocate the SNP device */
+ snpdev = zalloc ( sizeof ( *snpdev ) + path_prefix_len +
+ sizeof ( *macpath ) );
+ if ( ! snpdev ) {
+ efirc = EFI_OUT_OF_RESOURCES;
+ goto err_alloc_snp;
+ }
+
+ /* Identify the net device */
+ netdev = efi_snp_netdev ( driver, device );
+ if ( ! netdev ) {
+ DBGC ( snpdev, "SNPDEV %p cannot find netdev for device %p\n",
+ snpdev, device );
+ efirc = EFI_UNSUPPORTED;
+ goto err_no_netdev;
+ }
+ snpdev->netdev = netdev_get ( netdev );
+
+ /* Sanity check */
+ if ( netdev->ll_protocol->ll_addr_len > sizeof ( EFI_MAC_ADDRESS ) ) {
+ DBGC ( snpdev, "SNPDEV %p cannot support link-layer address "
+ "length %d for %s\n", snpdev,
+ netdev->ll_protocol->ll_addr_len, netdev->name );
+ efirc = EFI_INVALID_PARAMETER;
+ goto err_ll_addr_len;
+ }
+
+ /* Populate the SNP structure */
+ memcpy ( &snpdev->snp, &efi_snp_device_snp, sizeof ( snpdev->snp ) );
+ snpdev->snp.Mode = &snpdev->mode;
+ if ( ( efirc = bs->CreateEvent ( EVT_NOTIFY_WAIT, TPL_NOTIFY,
+ efi_snp_wait_for_packet, snpdev,
+ &snpdev->snp.WaitForPacket ) ) != 0 ){
+ DBGC ( snpdev, "SNPDEV %p could not create event: %s\n",
+ snpdev, efi_strerror ( efirc ) );
+ goto err_create_event;
+ }
+
+ /* Populate the SNP mode structure */
+ snpdev->mode.State = EfiSimpleNetworkStopped;
+ efi_snp_set_mode ( snpdev );
+
+ /* Populate the NII structure */
+ snpdev->nii.Revision =
+ EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION;
+ strncpy ( snpdev->nii.StringId, "gPXE",
+ sizeof ( snpdev->nii.StringId ) );
+
+ /* Populate the device name */
+ for ( i = 0 ; i < sizeof ( netdev->name ) ; i++ ) {
+ /* Damn Unicode names */
+ assert ( i < ( sizeof ( snpdev->name ) /
+ sizeof ( snpdev->name[0] ) ) );
+ snpdev->name[i] = netdev->name[i];
+ }
+
+ /* Populate the device path */
+ memcpy ( &snpdev->path, path, path_prefix_len );
+ macpath = ( ( ( void * ) &snpdev->path ) + path_prefix_len );
+ subpath = ( ( void * ) ( macpath + 1 ) );
+ memset ( macpath, 0, sizeof ( *macpath ) );
+ macpath->Header.Type = MESSAGING_DEVICE_PATH;
+ macpath->Header.SubType = MSG_MAC_ADDR_DP;
+ macpath->Header.Length[0] = sizeof ( *macpath );
+ memcpy ( &macpath->MacAddress, netdev->ll_addr,
+ sizeof ( macpath->MacAddress ) );
+ macpath->IfType = ntohs ( netdev->ll_protocol->ll_proto );
+ memset ( subpath, 0, sizeof ( *subpath ) );
+ subpath->Type = END_DEVICE_PATH_TYPE;
+ subpath->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
+ subpath->Length[0] = sizeof ( *subpath );
+
+ /* Install the SNP */
+ if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
+ &snpdev->handle,
+ &efi_simple_network_protocol_guid, &snpdev->snp,
+ &efi_device_path_protocol_guid, &snpdev->path,
+ &efi_nii_protocol_guid, &snpdev->nii,
+ &efi_nii31_protocol_guid, &snpdev->nii,
+ NULL ) ) != 0 ) {
+ DBGC ( snpdev, "SNPDEV %p could not install protocols: "
+ "%s\n", snpdev, efi_strerror ( efirc ) );
+ goto err_install_protocol_interface;
+ }
+
+ DBGC ( snpdev, "SNPDEV %p installed for %s as device %p\n",
+ snpdev, netdev->name, snpdev->handle );
+ return 0;
+
+ bs->UninstallMultipleProtocolInterfaces (
+ snpdev->handle,
+ &efi_simple_network_protocol_guid, &snpdev->snp,
+ &efi_device_path_protocol_guid, &snpdev->path,
+ &efi_nii_protocol_guid, &snpdev->nii,
+ &efi_nii31_protocol_guid, &snpdev->nii,
+ NULL );
+ err_install_protocol_interface:
+ bs->CloseEvent ( snpdev->snp.WaitForPacket );
+ err_create_event:
+ err_ll_addr_len:
+ netdev_put ( netdev );
+ err_no_netdev:
+ free ( snpdev );
+ err_alloc_snp:
+ bs->CloseProtocol ( device, &efi_device_path_protocol_guid,
+ driver->DriverBindingHandle, device );
+ err_no_device_path:
+ return efirc;
+}
+
+/**
+ * Detach driver from device
+ *
+ * @v driver EFI driver
+ * @v device EFI device
+ * @v num_children Number of child devices
+ * @v children List of child devices
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_driver_stop ( EFI_DRIVER_BINDING_PROTOCOL *driver,
+ EFI_HANDLE device,
+ UINTN num_children,
+ EFI_HANDLE *children ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ struct efi_snp_device *snpdev;
+
+ DBGCP ( driver, "SNPDRV %p DRIVER_STOP %p (%ld %p)\n",
+ driver, device, ( ( unsigned long ) num_children ), children );
+
+ /* Locate SNP device */
+ snpdev = efi_snp_snpdev ( driver, device );
+ if ( ! snpdev ) {
+ DBGC ( driver, "SNPDRV %p device %p could not find SNPDEV\n",
+ driver, device );
+ return EFI_DEVICE_ERROR;
+ }
+
+ /* Uninstall the SNP */
+ bs->UninstallMultipleProtocolInterfaces (
+ snpdev->handle,
+ &efi_simple_network_protocol_guid, &snpdev->snp,
+ &efi_device_path_protocol_guid, &snpdev->path,
+ &efi_nii_protocol_guid, &snpdev->nii,
+ &efi_nii31_protocol_guid, &snpdev->nii,
+ NULL );
+ bs->CloseEvent ( snpdev->snp.WaitForPacket );
+ netdev_put ( snpdev->netdev );
+ free ( snpdev );
+ bs->CloseProtocol ( device, &efi_device_path_protocol_guid,
+ driver->DriverBindingHandle, device );
+ return 0;
+}
+
+/** EFI SNP driver binding */
+static EFI_DRIVER_BINDING_PROTOCOL efi_snp_binding = {
+ efi_snp_driver_supported,
+ efi_snp_driver_start,
+ efi_snp_driver_stop,
+ 0x10,
+ NULL,
+ NULL
+};
+
+/**
+ * Look up driver name
+ *
+ * @v wtf Component name protocol
+ * @v language Language to use
+ * @v driver_name Driver name to fill in
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_get_driver_name ( EFI_COMPONENT_NAME2_PROTOCOL *wtf __unused,
+ CHAR8 *language __unused, CHAR16 **driver_name ) {
+
+ *driver_name = L"" PRODUCT_SHORT_NAME " Driver";
+ return 0;
+}
+
+/**
+ * Look up controller name
+ *
+ * @v wtf Component name protocol
+ * @v device Device
+ * @v child Child device, or NULL
+ * @v language Language to use
+ * @v driver_name Device name to fill in
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_get_controller_name ( EFI_COMPONENT_NAME2_PROTOCOL *wtf __unused,
+ EFI_HANDLE device __unused,
+ EFI_HANDLE child __unused,
+ CHAR8 *language __unused,
+ CHAR16 **controller_name __unused ) {
+
+ /* Just let EFI use the default Device Path Name */
+ return EFI_UNSUPPORTED;
+}
+
+/** EFI SNP component name protocol */
+static EFI_COMPONENT_NAME2_PROTOCOL efi_snp_name = {
+ efi_snp_get_driver_name,
+ efi_snp_get_controller_name,
+ "en"
+};
+
+/**
+ * Install EFI SNP driver
+ *
+ * @ret rc Return status code
+ */
+int efi_snp_install ( void ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_DRIVER_BINDING_PROTOCOL *driver = &efi_snp_binding;
+ EFI_STATUS efirc;
+
+ driver->ImageHandle = efi_image_handle;
+ if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
+ &driver->DriverBindingHandle,
+ &efi_driver_binding_protocol_guid, driver,
+ &efi_component_name2_protocol_guid, &efi_snp_name,
+ NULL ) ) != 0 ) {
+ DBGC ( driver, "SNPDRV %p could not install protocols: "
+ "%s\n", driver, efi_strerror ( efirc ) );
+ return EFIRC_TO_RC ( efirc );
+ }
+
+ DBGC ( driver, "SNPDRV %p driver binding installed as %p\n",
+ driver, driver->DriverBindingHandle );
+ return 0;
+}
diff --git a/gpxe/src/interface/efi/efi_strerror.c b/gpxe/src/interface/efi/efi_strerror.c
new file mode 100644
index 00000000..adfeaed5
--- /dev/null
+++ b/gpxe/src/interface/efi/efi_strerror.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <gpxe/efi/efi.h>
+
+/** @file
+ *
+ * gPXE error message formatting for EFI
+ *
+ */
+
+/**
+ * Format EFI status code
+ *
+ * @v efirc EFI status code
+ * @v efi_strerror EFI status code string
+ */
+const char * efi_strerror ( EFI_STATUS efirc ) {
+ static char errbuf[32];
+
+ if ( ! efirc )
+ return "No error";
+
+ snprintf ( errbuf, sizeof ( errbuf ), "Error %lld",
+ ( unsigned long long ) ( efirc ^ MAX_BIT ) );
+ return errbuf;
+}
diff --git a/gpxe/src/interface/efi/efi_timer.c b/gpxe/src/interface/efi/efi_timer.c
new file mode 100644
index 00000000..d1ba43af
--- /dev/null
+++ b/gpxe/src/interface/efi/efi_timer.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <limits.h>
+#include <assert.h>
+#include <unistd.h>
+#include <gpxe/timer.h>
+#include <gpxe/efi/efi.h>
+#include <gpxe/efi/Protocol/Cpu.h>
+
+/** @file
+ *
+ * gPXE timer API for EFI
+ *
+ */
+
+/** Scale factor to apply to CPU timer 0
+ *
+ * The timer is scaled down in order to ensure that reasonable values
+ * for "number of ticks" don't exceed the size of an unsigned long.
+ */
+#define EFI_TIMER0_SHIFT 12
+
+/** Calibration time */
+#define EFI_CALIBRATE_DELAY_MS 1
+
+/** CPU protocol */
+static EFI_CPU_ARCH_PROTOCOL *cpu_arch;
+EFI_REQUIRE_PROTOCOL ( EFI_CPU_ARCH_PROTOCOL, &cpu_arch );
+
+/**
+ * Delay for a fixed number of microseconds
+ *
+ * @v usecs Number of microseconds for which to delay
+ */
+static void efi_udelay ( unsigned long usecs ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_STATUS efirc;
+
+ if ( ( efirc = bs->Stall ( usecs ) ) != 0 ) {
+ DBG ( "EFI could not delay for %ldus: %s\n",
+ usecs, efi_strerror ( efirc ) );
+ /* Probably screwed */
+ }
+}
+
+/**
+ * Get current system time in ticks
+ *
+ * @ret ticks Current time, in ticks
+ */
+static unsigned long efi_currticks ( void ) {
+ UINT64 time;
+ EFI_STATUS efirc;
+
+ /* Read CPU timer 0 (TSC) */
+ if ( ( efirc = cpu_arch->GetTimerValue ( cpu_arch, 0, &time,
+ NULL ) ) != 0 ) {
+ DBG ( "EFI could not read CPU timer: %s\n",
+ efi_strerror ( efirc ) );
+ /* Probably screwed */
+ return -1UL;
+ }
+
+ return ( time >> EFI_TIMER0_SHIFT );
+}
+
+/**
+ * Get number of ticks per second
+ *
+ * @ret ticks_per_sec Number of ticks per second
+ */
+static unsigned long efi_ticks_per_sec ( void ) {
+ static unsigned long ticks_per_sec = 0;
+
+ /* Calibrate timer, if necessary. EFI does nominally provide
+ * the timer speed via the (optional) TimerPeriod parameter to
+ * the GetTimerValue() call, but it gets the speed slightly
+ * wrong. By up to three orders of magnitude. Not helpful.
+ */
+ if ( ! ticks_per_sec ) {
+ unsigned long start;
+ unsigned long elapsed;
+
+ DBG ( "Calibrating EFI timer with a %d ms delay\n",
+ EFI_CALIBRATE_DELAY_MS );
+ start = currticks();
+ mdelay ( EFI_CALIBRATE_DELAY_MS );
+ elapsed = ( currticks() - start );
+ ticks_per_sec = ( elapsed * ( 1000 / EFI_CALIBRATE_DELAY_MS ));
+ DBG ( "EFI CPU timer calibrated at %ld ticks in %d ms (%ld "
+ "ticks/sec)\n", elapsed, EFI_CALIBRATE_DELAY_MS,
+ ticks_per_sec );
+ }
+
+ return ticks_per_sec;
+}
+
+PROVIDE_TIMER ( efi, udelay, efi_udelay );
+PROVIDE_TIMER ( efi, currticks, efi_currticks );
+PROVIDE_TIMER ( efi, ticks_per_sec, efi_ticks_per_sec );
diff --git a/gpxe/src/interface/efi/efi_uaccess.c b/gpxe/src/interface/efi/efi_uaccess.c
new file mode 100644
index 00000000..1c54c031
--- /dev/null
+++ b/gpxe/src/interface/efi/efi_uaccess.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <gpxe/uaccess.h>
+#include <gpxe/efi/efi.h>
+
+/** @file
+ *
+ * gPXE user access API for EFI
+ *
+ */
+
+PROVIDE_UACCESS_INLINE ( efi, phys_to_user );
+PROVIDE_UACCESS_INLINE ( efi, user_to_phys );
+PROVIDE_UACCESS_INLINE ( efi, virt_to_user );
+PROVIDE_UACCESS_INLINE ( efi, user_to_virt );
+PROVIDE_UACCESS_INLINE ( efi, userptr_add );
+PROVIDE_UACCESS_INLINE ( efi, memcpy_user );
+PROVIDE_UACCESS_INLINE ( efi, memmove_user );
+PROVIDE_UACCESS_INLINE ( efi, memset_user );
+PROVIDE_UACCESS_INLINE ( efi, strlen_user );
+PROVIDE_UACCESS_INLINE ( efi, memchr_user );
diff --git a/gpxe/src/interface/efi/efi_umalloc.c b/gpxe/src/interface/efi/efi_umalloc.c
new file mode 100644
index 00000000..4de3789d
--- /dev/null
+++ b/gpxe/src/interface/efi/efi_umalloc.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <assert.h>
+#include <gpxe/umalloc.h>
+#include <gpxe/efi/efi.h>
+
+/** @file
+ *
+ * gPXE user memory allocation API for EFI
+ *
+ */
+
+/** Equivalent of NOWHERE for user pointers */
+#define UNOWHERE ( ~UNULL )
+
+/**
+ * Reallocate external memory
+ *
+ * @v old_ptr Memory previously allocated by umalloc(), or UNULL
+ * @v new_size Requested size
+ * @ret new_ptr Allocated memory, or UNULL
+ *
+ * Calling realloc() with a new size of zero is a valid way to free a
+ * memory block.
+ */
+static userptr_t efi_urealloc ( userptr_t old_ptr, size_t new_size ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_PHYSICAL_ADDRESS phys_addr;
+ unsigned int new_pages, old_pages;
+ userptr_t new_ptr = UNOWHERE;
+ size_t old_size;
+ EFI_STATUS efirc;
+
+ /* Allocate new memory if necessary. If allocation fails,
+ * return without touching the old block.
+ */
+ if ( new_size ) {
+ new_pages = ( EFI_SIZE_TO_PAGES ( new_size ) + 1 );
+ if ( ( efirc = bs->AllocatePages ( AllocateAnyPages,
+ EfiBootServicesData,
+ new_pages,
+ &phys_addr ) ) != 0 ) {
+ DBG ( "EFI could not allocate %d pages: %s\n",
+ new_pages, efi_strerror ( efirc ) );
+ return UNULL;
+ }
+ assert ( phys_addr != 0 );
+ new_ptr = phys_to_user ( phys_addr + EFI_PAGE_SIZE );
+ copy_to_user ( new_ptr, -EFI_PAGE_SIZE,
+ &new_size, sizeof ( new_size ) );
+ DBG ( "EFI allocated %d pages at %llx\n",
+ new_pages, phys_addr );
+ }
+
+ /* Copy across relevant part of the old data region (if any),
+ * then free it. Note that at this point either (a) new_ptr
+ * is valid, or (b) new_size is 0; either way, the memcpy() is
+ * valid.
+ */
+ if ( old_ptr && ( old_ptr != UNOWHERE ) ) {
+ copy_from_user ( &old_size, old_ptr, -EFI_PAGE_SIZE,
+ sizeof ( old_size ) );
+ memcpy_user ( new_ptr, 0, old_ptr, 0,
+ ( (old_size < new_size) ? old_size : new_size ));
+ old_pages = ( EFI_SIZE_TO_PAGES ( old_size ) + 1 );
+ phys_addr = user_to_phys ( old_ptr, -EFI_PAGE_SIZE );
+ if ( ( efirc = bs->FreePages ( phys_addr, old_pages ) ) != 0 ){
+ DBG ( "EFI could not free %d pages at %llx: %s\n",
+ old_pages, phys_addr, efi_strerror ( efirc ) );
+ /* Not fatal; we have leaked memory but successfully
+ * allocated (if asked to do so).
+ */
+ }
+ DBG ( "EFI freed %d pages at %llx\n", old_pages, phys_addr );
+ }
+
+ return new_ptr;
+}
+
+PROVIDE_UMALLOC ( efi, urealloc, efi_urealloc );
diff --git a/gpxe/src/arch/i386/firmware/pcbios/smbios.c b/gpxe/src/interface/smbios/smbios.c
index a2cb3b88..8207c1fa 100644
--- a/gpxe/src/arch/i386/firmware/pcbios/smbios.c
+++ b/gpxe/src/interface/smbios/smbios.c
@@ -21,9 +21,7 @@
#include <errno.h>
#include <assert.h>
#include <gpxe/uaccess.h>
-#include <realmode.h>
-#include <pnpbios.h>
-#include <smbios.h>
+#include <gpxe/smbios.h>
/** @file
*
@@ -31,124 +29,12 @@
*
*/
-/** Signature for SMBIOS entry point */
-#define SMBIOS_SIGNATURE \
- ( ( '_' << 0 ) + ( 'S' << 8 ) + ( 'M' << 16 ) + ( '_' << 24 ) )
-
-/**
- * SMBIOS entry point
- *
- * This is the single table which describes the list of SMBIOS
- * structures. It is located by scanning through the BIOS segment.
- */
-struct smbios_entry {
- /** Signature
- *
- * Must be equal to SMBIOS_SIGNATURE
- */
- uint32_t signature;
- /** Checksum */
- uint8_t checksum;
- /** Length */
- uint8_t len;
- /** Major version */
- uint8_t major;
- /** Minor version */
- uint8_t minor;
- /** Maximum structure size */
- uint16_t max;
- /** Entry point revision */
- uint8_t revision;
- /** Formatted area */
- uint8_t formatted[5];
- /** DMI Signature */
- uint8_t dmi_signature[5];
- /** DMI checksum */
- uint8_t dmi_checksum;
- /** Structure table length */
- uint16_t smbios_len;
- /** Structure table address */
- physaddr_t smbios_address;
- /** Number of SMBIOS structures */
- uint16_t smbios_count;
- /** BCD revision */
- uint8_t bcd_revision;
-} __attribute__ (( packed ));
-
-/**
- * SMBIOS entry point descriptor
- *
- * This contains the information from the SMBIOS entry point that we
- * care about.
- */
-struct smbios {
- /** Start of SMBIOS structures */
- userptr_t address;
- /** Length of SMBIOS structures */
- size_t len;
- /** Number of SMBIOS structures */
- unsigned int count;
-};
-
/** SMBIOS entry point descriptor */
static struct smbios smbios = {
.address = UNULL,
};
/**
- * Find SMBIOS
- *
- * @ret rc Return status code
- */
-static int find_smbios ( void ) {
- union {
- struct smbios_entry entry;
- uint8_t bytes[256]; /* 256 is maximum length possible */
- } u;
- static unsigned int offset = 0;
- size_t len;
- unsigned int i;
- uint8_t sum;
-
- /* Return cached result if avaiable */
- if ( smbios.address != UNULL )
- return 0;
-
- /* Try to find SMBIOS */
- for ( ; offset < 0x10000 ; offset += 0x10 ) {
-
- /* Read start of header and verify signature */
- copy_from_real ( &u.entry, BIOS_SEG, offset,
- sizeof ( u.entry ));
- if ( u.entry.signature != SMBIOS_SIGNATURE )
- continue;
-
- /* Read whole header and verify checksum */
- len = u.entry.len;
- copy_from_real ( &u.bytes, BIOS_SEG, offset, len );
- for ( i = 0 , sum = 0 ; i < len ; i++ ) {
- sum += u.bytes[i];
- }
- if ( sum != 0 ) {
- DBG ( "SMBIOS at %04x:%04x has bad checksum %02x\n",
- BIOS_SEG, offset, sum );
- continue;
- }
-
- /* Fill result structure */
- DBG ( "Found SMBIOS v%d.%d entry point at %04x:%04x\n",
- u.entry.major, u.entry.minor, BIOS_SEG, offset );
- smbios.address = phys_to_user ( u.entry.smbios_address );
- smbios.len = u.entry.smbios_len;
- smbios.count = u.entry.smbios_count;
- return 0;
- }
-
- DBG ( "No SMBIOS found\n" );
- return -ENODEV;
-}
-
-/**
* Find SMBIOS strings terminator
*
* @v offset Offset to start of strings
@@ -182,8 +68,10 @@ int find_smbios_structure ( unsigned int type,
int rc;
/* Find SMBIOS */
- if ( ( rc = find_smbios() ) != 0 )
+ if ( ( smbios.address == UNULL ) &&
+ ( ( rc = find_smbios ( &smbios ) ) != 0 ) )
return rc;
+ assert ( smbios.address != UNULL );
/* Scan through list of structures */
while ( ( ( offset + sizeof ( structure->header ) ) < smbios.len )
diff --git a/gpxe/src/arch/i386/firmware/pcbios/smbios_settings.c b/gpxe/src/interface/smbios/smbios_settings.c
index b088e51d..61c2d919 100644
--- a/gpxe/src/arch/i386/firmware/pcbios/smbios_settings.c
+++ b/gpxe/src/interface/smbios/smbios_settings.c
@@ -22,7 +22,17 @@
#include <gpxe/settings.h>
#include <gpxe/init.h>
#include <gpxe/uuid.h>
-#include <smbios.h>
+#include <gpxe/smbios.h>
+
+/** SMBIOS settings tag magic number */
+#define SMBIOS_TAG_MAGIC 0x5B /* "SmBios" */
+
+/**
+ * Construct SMBIOS empty tag
+ *
+ * @ret tag SMBIOS setting tag
+ */
+#define SMBIOS_EMPTY_TAG ( SMBIOS_TAG_MAGIC << 24 )
/**
* Construct SMBIOS raw-data tag
@@ -33,7 +43,8 @@
* @ret tag SMBIOS setting tag
*/
#define SMBIOS_RAW_TAG( _type, _structure, _field ) \
- ( ( (_type) << 16 ) | \
+ ( ( SMBIOS_TAG_MAGIC << 24 ) | \
+ ( (_type) << 16 ) | \
( offsetof ( _structure, _field ) << 8 ) | \
( sizeof ( ( ( _structure * ) 0 )->_field ) ) )
@@ -46,7 +57,8 @@
* @ret tag SMBIOS setting tag
*/
#define SMBIOS_STRING_TAG( _type, _structure, _field ) \
- ( ( (_type) << 16 ) | \
+ ( ( SMBIOS_TAG_MAGIC << 24 ) | \
+ ( (_type) << 16 ) | \
( offsetof ( _structure, _field ) << 8 ) )
/**
@@ -78,16 +90,18 @@ static int smbios_fetch ( struct settings *settings __unused,
struct setting *setting,
void *data, size_t len ) {
struct smbios_structure structure;
+ unsigned int tag_magic;
unsigned int tag_type;
unsigned int tag_offset;
unsigned int tag_len;
int rc;
/* Split tag into type, offset and length */
- tag_type = ( setting->tag >> 16 );
+ tag_magic = ( setting->tag >> 24 );
+ tag_type = ( ( setting->tag >> 16 ) & 0xff );
tag_offset = ( ( setting->tag >> 8 ) & 0xff );
tag_len = ( setting->tag & 0xff );
- if ( ! tag_type )
+ if ( tag_magic != SMBIOS_TAG_MAGIC )
return -ENOENT;
/* Find SMBIOS structure */
@@ -127,6 +141,7 @@ static struct settings_operations smbios_settings_operations = {
static struct settings smbios_settings = {
.refcnt = NULL,
.name = "smbios",
+ .tag_magic = SMBIOS_EMPTY_TAG,
.siblings = LIST_HEAD_INIT ( smbios_settings.siblings ),
.children = LIST_HEAD_INIT ( smbios_settings.children ),
.op = &smbios_settings_operations,
diff --git a/gpxe/src/libgcc/__divdi3.c b/gpxe/src/libgcc/__divdi3.c
index 36f0b37f..7097b11e 100644
--- a/gpxe/src/libgcc/__divdi3.c
+++ b/gpxe/src/libgcc/__divdi3.c
@@ -4,7 +4,7 @@
#include "libgcc.h"
-LIBGCC int64_t __divdi3(int64_t num, int64_t den)
+__libgcc int64_t __divdi3(int64_t num, int64_t den)
{
int minus = 0;
int64_t v;
diff --git a/gpxe/src/libgcc/__moddi3.c b/gpxe/src/libgcc/__moddi3.c
index eb7784b7..d671bbc4 100644
--- a/gpxe/src/libgcc/__moddi3.c
+++ b/gpxe/src/libgcc/__moddi3.c
@@ -4,7 +4,7 @@
#include "libgcc.h"
-LIBGCC int64_t __moddi3(int64_t num, int64_t den)
+__libgcc int64_t __moddi3(int64_t num, int64_t den)
{
int minus = 0;
int64_t v;
diff --git a/gpxe/src/libgcc/__udivdi3.c b/gpxe/src/libgcc/__udivdi3.c
index 9ae0c3dc..f5a14de2 100644
--- a/gpxe/src/libgcc/__udivdi3.c
+++ b/gpxe/src/libgcc/__udivdi3.c
@@ -4,7 +4,7 @@
#include "libgcc.h"
-LIBGCC uint64_t __udivdi3(uint64_t num, uint64_t den)
+__libgcc uint64_t __udivdi3(uint64_t num, uint64_t den)
{
return __udivmoddi4(num, den, NULL);
}
diff --git a/gpxe/src/libgcc/__udivmoddi4.c b/gpxe/src/libgcc/__udivmoddi4.c
index 59966edb..21e0d51f 100644
--- a/gpxe/src/libgcc/__udivmoddi4.c
+++ b/gpxe/src/libgcc/__udivmoddi4.c
@@ -1,6 +1,6 @@
#include "libgcc.h"
-LIBGCC uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t *rem_p)
+__libgcc uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t *rem_p)
{
uint64_t quot = 0, qbit = 1;
diff --git a/gpxe/src/libgcc/__umoddi3.c b/gpxe/src/libgcc/__umoddi3.c
index f6c76cb6..fb4da991 100644
--- a/gpxe/src/libgcc/__umoddi3.c
+++ b/gpxe/src/libgcc/__umoddi3.c
@@ -4,7 +4,7 @@
#include "libgcc.h"
-LIBGCC uint64_t __umoddi3(uint64_t num, uint64_t den)
+__libgcc uint64_t __umoddi3(uint64_t num, uint64_t den)
{
uint64_t v;
diff --git a/gpxe/src/libgcc/libgcc.h b/gpxe/src/libgcc/libgcc.h
index 5b4a6244..d3e9bdd7 100644
--- a/gpxe/src/libgcc/libgcc.h
+++ b/gpxe/src/libgcc/libgcc.h
@@ -4,23 +4,11 @@
#include <stdint.h>
#include <stddef.h>
-/*
- * It seems as though gcc expects its implicit arithmetic functions to
- * be cdecl, even if -mrtd is specified. This is somewhat
- * inconsistent; for example, if -mregparm=3 is used then the implicit
- * functions do become regparm(3).
- *
- * The implicit calls to memcpy() and memset() which gcc can generate
- * do not seem to have this inconsistency; -mregparm and -mrtd affect
- * them in the same way as any other function.
- *
- */
-#define LIBGCC __attribute__ (( cdecl ))
-
-extern LIBGCC uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t *rem);
-extern LIBGCC uint64_t __udivdi3(uint64_t num, uint64_t den);
-extern LIBGCC uint64_t __umoddi3(uint64_t num, uint64_t den);
-extern LIBGCC int64_t __divdi3(int64_t num, int64_t den);
-extern LIBGCC int64_t __moddi3(int64_t num, int64_t den);
+extern __libgcc uint64_t __udivmoddi4 ( uint64_t num, uint64_t den,
+ uint64_t *rem );
+extern __libgcc uint64_t __udivdi3 (uint64_t num, uint64_t den );
+extern __libgcc uint64_t __umoddi3 ( uint64_t num, uint64_t den );
+extern __libgcc int64_t __divdi3 ( int64_t num, int64_t den );
+extern __libgcc int64_t __moddi3 ( int64_t num, int64_t den );
#endif /* _LIBGCC_H */
diff --git a/gpxe/src/net/aoe.c b/gpxe/src/net/aoe.c
index e3f84e5a..08887fe0 100644
--- a/gpxe/src/net/aoe.c
+++ b/gpxe/src/net/aoe.c
@@ -64,8 +64,13 @@ static void aoe_free ( struct refcnt *refcnt ) {
static void aoe_done ( struct aoe_session *aoe, int rc ) {
/* Record overall command status */
- aoe->command->cb.cmd_stat = aoe->status;
- aoe->command = NULL;
+ if ( aoe->command ) {
+ aoe->command->cb.cmd_stat = aoe->status;
+ aoe->command = NULL;
+ }
+
+ /* Stop retransmission timer */
+ stop_timer ( &aoe->timer );
/* Mark operation as complete */
aoe->rc = rc;
@@ -84,9 +89,11 @@ static int aoe_send_command ( struct aoe_session *aoe ) {
struct ata_command *command = aoe->command;
struct io_buffer *iobuf;
struct aoehdr *aoehdr;
- struct aoecmd *aoecmd;
+ union aoecmd *aoecmd;
+ struct aoeata *aoeata;
unsigned int count;
unsigned int data_out_len;
+ unsigned int aoecmdlen;
/* Fail immediately if we have no netdev to send on */
if ( ! aoe->netdev ) {
@@ -94,46 +101,81 @@ static int aoe_send_command ( struct aoe_session *aoe ) {
return -ENETUNREACH;
}
+ /* If we are transmitting anything that requires a response,
+ * start the retransmission timer. Do this before attempting
+ * to allocate the I/O buffer, in case allocation itself
+ * fails.
+ */
+ start_timer ( &aoe->timer );
+
/* Calculate count and data_out_len for this subcommand */
- count = command->cb.count.native;
- if ( count > AOE_MAX_COUNT )
- count = AOE_MAX_COUNT;
- data_out_len = ( command->data_out ? ( count * ATA_SECTOR_SIZE ) : 0 );
+ switch ( aoe->aoe_cmd_type ) {
+ case AOE_CMD_ATA:
+ count = command->cb.count.native;
+ if ( count > AOE_MAX_COUNT )
+ count = AOE_MAX_COUNT;
+ data_out_len = ( command->data_out ?
+ ( count * ATA_SECTOR_SIZE ) : 0 );
+ aoecmdlen = sizeof ( aoecmd->ata );
+ break;
+ case AOE_CMD_CONFIG:
+ count = 0;
+ data_out_len = 0;
+ aoecmdlen = sizeof ( aoecmd->cfg );
+ break;
+ default:
+ return -ENOTSUP;
+ }
/* Create outgoing I/O buffer */
- iobuf = alloc_iob ( ETH_HLEN + sizeof ( *aoehdr ) + sizeof ( *aoecmd ) +
- data_out_len );
+ iobuf = alloc_iob ( ETH_HLEN + sizeof ( *aoehdr ) +
+ aoecmdlen + data_out_len );
+
if ( ! iobuf )
return -ENOMEM;
iob_reserve ( iobuf, ETH_HLEN );
aoehdr = iob_put ( iobuf, sizeof ( *aoehdr ) );
- aoecmd = iob_put ( iobuf, sizeof ( *aoecmd ) );
- memset ( aoehdr, 0, ( sizeof ( *aoehdr ) + sizeof ( *aoecmd ) ) );
+ aoecmd = iob_put ( iobuf, aoecmdlen );
+ memset ( aoehdr, 0, ( sizeof ( *aoehdr ) + aoecmdlen ) );
/* Fill AoE header */
aoehdr->ver_flags = AOE_VERSION;
aoehdr->major = htons ( aoe->major );
aoehdr->minor = aoe->minor;
+ aoehdr->command = aoe->aoe_cmd_type;
aoehdr->tag = htonl ( ++aoe->tag );
- /* Fill AoE command */
- linker_assert ( AOE_FL_DEV_HEAD == ATA_DEV_SLAVE, __fix_ata_h__ );
- aoecmd->aflags = ( ( command->cb.lba48 ? AOE_FL_EXTENDED : 0 ) |
- ( command->cb.device & ATA_DEV_SLAVE ) |
- ( data_out_len ? AOE_FL_WRITE : 0 ) );
- aoecmd->err_feat = command->cb.err_feat.bytes.cur;
- aoecmd->count = count;
- aoecmd->cmd_stat = command->cb.cmd_stat;
- aoecmd->lba.u64 = cpu_to_le64 ( command->cb.lba.native );
- if ( ! command->cb.lba48 )
- aoecmd->lba.bytes[3] |= ( command->cb.device & ATA_DEV_MASK );
-
- /* Fill data payload */
- copy_from_user ( iob_put ( iobuf, data_out_len ), command->data_out,
- aoe->command_offset, data_out_len );
+ /* Fill AoE payload */
+ switch ( aoe->aoe_cmd_type ) {
+ case AOE_CMD_ATA:
+ /* Fill AoE command */
+ aoeata = &aoecmd->ata;
+ linker_assert ( AOE_FL_DEV_HEAD == ATA_DEV_SLAVE,
+ __fix_ata_h__ );
+ aoeata->aflags = ( ( command->cb.lba48 ? AOE_FL_EXTENDED : 0 )|
+ ( command->cb.device & ATA_DEV_SLAVE ) |
+ ( data_out_len ? AOE_FL_WRITE : 0 ) );
+ aoeata->err_feat = command->cb.err_feat.bytes.cur;
+ aoeata->count = count;
+ aoeata->cmd_stat = command->cb.cmd_stat;
+ aoeata->lba.u64 = cpu_to_le64 ( command->cb.lba.native );
+ if ( ! command->cb.lba48 )
+ aoeata->lba.bytes[3] |=
+ ( command->cb.device & ATA_DEV_MASK );
+
+ /* Fill data payload */
+ copy_from_user ( iob_put ( iobuf, data_out_len ),
+ command->data_out, aoe->command_offset,
+ data_out_len );
+ break;
+ case AOE_CMD_CONFIG:
+ /* Nothing to do */
+ break;
+ default:
+ assert ( 0 );
+ }
/* Send packet */
- start_timer ( &aoe->timer );
return net_tx ( iobuf, aoe->netdev, &aoe_protocol, aoe->target );
}
@@ -155,38 +197,46 @@ static void aoe_timer_expired ( struct retry_timer *timer, int fail ) {
}
/**
- * Handle AoE response
+ * Handle AoE configuration command response
*
* @v aoe AoE session
- * @v aoehdr AoE header
+ * @v ll_source Link-layer source address
* @ret rc Return status code
*/
-static int aoe_rx_response ( struct aoe_session *aoe, struct aoehdr *aoehdr,
- unsigned int len ) {
- struct aoecmd *aoecmd = aoehdr->arg.command;
+static int aoe_rx_cfg ( struct aoe_session *aoe, const void *ll_source ) {
+
+ /* Record target MAC address */
+ memcpy ( aoe->target, ll_source, sizeof ( aoe->target ) );
+ DBGC ( aoe, "AoE %p target MAC address %s\n",
+ aoe, eth_ntoa ( aoe->target ) );
+
+ /* Mark config request as complete */
+ aoe_done ( aoe, 0 );
+
+ return 0;
+}
+
+/**
+ * Handle AoE ATA command response
+ *
+ * @v aoe AoE session
+ * @v aoeata AoE ATA command
+ * @v len Length of AoE ATA command
+ * @ret rc Return status code
+ */
+static int aoe_rx_ata ( struct aoe_session *aoe, struct aoeata *aoeata,
+ size_t len ) {
struct ata_command *command = aoe->command;
unsigned int rx_data_len;
unsigned int count;
unsigned int data_len;
-
+
/* Sanity check */
- if ( len < ( sizeof ( *aoehdr ) + sizeof ( *aoecmd ) ) ) {
+ if ( len < sizeof ( *aoeata ) ) {
/* Ignore packet; allow timer to trigger retransmit */
return -EINVAL;
}
- rx_data_len = ( len - sizeof ( *aoehdr ) - sizeof ( *aoecmd ) );
-
- /* Stop retry timer. After this point, every code path must
- * either terminate the AoE operation via aoe_done(), or
- * transmit a new packet.
- */
- stop_timer ( &aoe->timer );
-
- /* Check for fatal errors */
- if ( aoehdr->ver_flags & AOE_FL_ERROR ) {
- aoe_done ( aoe, -EIO );
- return 0;
- }
+ rx_data_len = ( len - sizeof ( *aoeata ) );
/* Calculate count and data_len for this subcommand */
count = command->cb.count.native;
@@ -195,14 +245,14 @@ static int aoe_rx_response ( struct aoe_session *aoe, struct aoehdr *aoehdr,
data_len = count * ATA_SECTOR_SIZE;
/* Merge into overall ATA status */
- aoe->status |= aoecmd->cmd_stat;
+ aoe->status |= aoeata->cmd_stat;
/* Copy data payload */
if ( command->data_in ) {
if ( rx_data_len > data_len )
rx_data_len = data_len;
copy_to_user ( command->data_in, aoe->command_offset,
- aoecmd->data, rx_data_len );
+ aoeata->data, rx_data_len );
}
/* Update ATA command and offset */
@@ -217,6 +267,7 @@ static int aoe_rx_response ( struct aoe_session *aoe, struct aoehdr *aoehdr,
}
/* Transmit next portion of request */
+ stop_timer ( &aoe->timer );
aoe_send_command ( aoe );
return 0;
@@ -231,15 +282,15 @@ static int aoe_rx_response ( struct aoe_session *aoe, struct aoehdr *aoehdr,
* @ret rc Return status code
*
*/
-static int aoe_rx ( struct io_buffer *iobuf, struct net_device *netdev __unused,
+static int aoe_rx ( struct io_buffer *iobuf,
+ struct net_device *netdev __unused,
const void *ll_source ) {
struct aoehdr *aoehdr = iobuf->data;
- unsigned int len = iob_len ( iobuf );
struct aoe_session *aoe;
int rc = 0;
/* Sanity checks */
- if ( len < sizeof ( *aoehdr ) ) {
+ if ( iob_len ( iobuf ) < sizeof ( *aoehdr ) ) {
rc = -EINVAL;
goto done;
}
@@ -251,6 +302,7 @@ static int aoe_rx ( struct io_buffer *iobuf, struct net_device *netdev __unused,
/* Ignore AoE requests that we happen to see */
goto done;
}
+ iob_pull ( iobuf, sizeof ( *aoehdr ) );
/* Demultiplex amongst active AoE sessions */
list_for_each_entry ( aoe, &aoe_sessions, list ) {
@@ -260,8 +312,22 @@ static int aoe_rx ( struct io_buffer *iobuf, struct net_device *netdev __unused,
continue;
if ( ntohl ( aoehdr->tag ) != aoe->tag )
continue;
- memcpy ( aoe->target, ll_source, sizeof ( aoe->target ) );
- rc = aoe_rx_response ( aoe, aoehdr, len );
+ if ( aoehdr->ver_flags & AOE_FL_ERROR ) {
+ aoe_done ( aoe, -EIO );
+ break;
+ }
+ switch ( aoehdr->command ) {
+ case AOE_CMD_ATA:
+ rc = aoe_rx_ata ( aoe, iobuf->data, iob_len ( iobuf ));
+ break;
+ case AOE_CMD_CONFIG:
+ rc = aoe_rx_cfg ( aoe, ll_source );
+ break;
+ default:
+ DBGC ( aoe, "AoE %p ignoring command %02x\n",
+ aoe, aoehdr->command );
+ break;
+ }
break;
}
@@ -293,6 +359,32 @@ static int aoe_command ( struct ata_device *ata,
aoe->command = command;
aoe->status = 0;
aoe->command_offset = 0;
+ aoe->aoe_cmd_type = AOE_CMD_ATA;
+
+ aoe_send_command ( aoe );
+
+ aoe->rc = -EINPROGRESS;
+ while ( aoe->rc == -EINPROGRESS )
+ step();
+ rc = aoe->rc;
+
+ return rc;
+}
+
+
+/**
+ * Issue AoE config query for AoE target discovery
+ *
+ * @v aoe AoE session
+ * @ret rc Return status code
+ */
+static int aoe_discover ( struct aoe_session *aoe ) {
+ int rc;
+
+ aoe->status = 0;
+ aoe->aoe_cmd_type = AOE_CMD_CONFIG;
+ aoe->command = NULL;
+
aoe_send_command ( aoe );
aoe->rc = -EINPROGRESS;
@@ -367,6 +459,15 @@ int aoe_attach ( struct ata_device *ata, struct net_device *netdev,
ata->backend = ref_get ( &aoe->refcnt );
ata->command = aoe_command;
list_add ( &aoe->list, &aoe_sessions );
+
+ /* Send discovery packet to find the target MAC address.
+ * Ideally, this ought to be done asynchronously, but the
+ * block device interface does not yet support asynchronous
+ * operation.
+ */
+ if ( ( rc = aoe_discover( aoe ) ) != 0 )
+ goto err;
+
return 0;
err:
diff --git a/gpxe/src/net/arp.c b/gpxe/src/net/arp.c
index 011d4fef..ba9ebf48 100644
--- a/gpxe/src/net/arp.c
+++ b/gpxe/src/net/arp.c
@@ -265,8 +265,8 @@ static int arp_rx ( struct io_buffer *iobuf, struct net_device *netdev,
memcpy ( arp_sender_ha ( arphdr ), netdev->ll_addr, arphdr->ar_hln );
/* Send reply */
- net_tx ( iobuf, netdev, &arp_protocol, arp_target_ha (arphdr ) );
- iobuf = NULL;
+ net_tx ( iob_disown ( iobuf ), netdev, &arp_protocol,
+ arp_target_ha ( arphdr ) );
done:
free_iob ( iobuf );
diff --git a/gpxe/src/net/dhcppkt.c b/gpxe/src/net/dhcppkt.c
index c8bf215b..1f2d373c 100644
--- a/gpxe/src/net/dhcppkt.c
+++ b/gpxe/src/net/dhcppkt.c
@@ -32,6 +32,12 @@
*
*/
+/****************************************************************************
+ *
+ * DHCP packet raw interface
+ *
+ */
+
/**
* Calculate used length of an IPv4 field within a DHCP packet
*
@@ -193,21 +199,79 @@ int dhcppkt_fetch ( struct dhcp_packet *dhcppkt, unsigned int tag,
return dhcpopt_fetch ( &dhcppkt->options, tag, data, len );
}
+/****************************************************************************
+ *
+ * DHCP packet settings interface
+ *
+ */
+
+/**
+ * Store value of DHCP setting
+ *
+ * @v settings Settings block
+ * @v setting Setting to store
+ * @v data Setting data, or NULL to clear setting
+ * @v len Length of setting data
+ * @ret rc Return status code
+ */
+static int dhcppkt_settings_store ( struct settings *settings,
+ struct setting *setting,
+ const void *data, size_t len ) {
+ struct dhcp_packet *dhcppkt =
+ container_of ( settings, struct dhcp_packet, settings );
+
+ return dhcppkt_store ( dhcppkt, setting->tag, data, len );
+}
+
+/**
+ * Fetch value of DHCP setting
+ *
+ * @v settings Settings block, or NULL to search all blocks
+ * @v setting Setting to fetch
+ * @v data Buffer to fill with setting data
+ * @v len Length of buffer
+ * @ret len Length of setting data, or negative error
+ */
+static int dhcppkt_settings_fetch ( struct settings *settings,
+ struct setting *setting,
+ void *data, size_t len ) {
+ struct dhcp_packet *dhcppkt =
+ container_of ( settings, struct dhcp_packet, settings );
+
+ return dhcppkt_fetch ( dhcppkt, setting->tag, data, len );
+}
+
+/** DHCP settings operations */
+static struct settings_operations dhcppkt_settings_operations = {
+ .store = dhcppkt_settings_store,
+ .fetch = dhcppkt_settings_fetch,
+};
+
+/****************************************************************************
+ *
+ * Constructor
+ *
+ */
+
/**
- * Initialise prepopulated DHCP packet
+ * Initialise DHCP packet
*
- * @v dhcppkt Uninitialised DHCP packet
- * @v data Memory for DHCP packet data
- * @v max_len Length of memory for DHCP packet data
+ * @v dhcppkt DHCP packet structure to fill in
+ * @v data DHCP packet raw data
+ * @v max_len Length of raw data buffer
*
- * The memory content must already be filled with valid DHCP options.
- * A zeroed block counts as a block of valid DHCP options.
+ * Initialise a DHCP packet structure from a data buffer containing a
+ * DHCP packet.
*/
-void dhcppkt_init ( struct dhcp_packet *dhcppkt, void *data, size_t len ) {
+void dhcppkt_init ( struct dhcp_packet *dhcppkt, struct dhcphdr *data,
+ size_t len ) {
dhcppkt->dhcphdr = data;
dhcppkt->max_len = len;
dhcpopt_init ( &dhcppkt->options, &dhcppkt->dhcphdr->options,
( len - offsetof ( struct dhcphdr, options ) ) );
dhcppkt->len = ( offsetof ( struct dhcphdr, options ) +
dhcppkt->options.len );
+ settings_init ( &dhcppkt->settings,
+ &dhcppkt_settings_operations, &dhcppkt->refcnt,
+ DHCP_SETTINGS_NAME, 0 );
}
diff --git a/gpxe/src/net/ethernet.c b/gpxe/src/net/ethernet.c
index 7b1c496f..b16135a9 100644
--- a/gpxe/src/net/ethernet.c
+++ b/gpxe/src/net/ethernet.c
@@ -24,6 +24,7 @@
#include <assert.h>
#include <gpxe/if_arp.h>
#include <gpxe/if_ether.h>
+#include <gpxe/in.h>
#include <gpxe/netdevice.h>
#include <gpxe/iobuf.h>
#include <gpxe/ethernet.h>
@@ -41,19 +42,19 @@ static uint8_t eth_broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
* Add Ethernet link-layer header
*
* @v iobuf I/O buffer
- * @v netdev Network device
- * @v net_protocol Network-layer protocol
* @v ll_dest Link-layer destination address
+ * @v ll_source Source link-layer address
+ * @v net_proto Network-layer protocol, in network-byte order
+ * @ret rc Return status code
*/
-static int eth_push ( struct io_buffer *iobuf, struct net_device *netdev,
- struct net_protocol *net_protocol,
- const void *ll_dest ) {
+static int eth_push ( struct io_buffer *iobuf, const void *ll_dest,
+ const void *ll_source, uint16_t net_proto ) {
struct ethhdr *ethhdr = iob_push ( iobuf, sizeof ( *ethhdr ) );
/* Build Ethernet header */
memcpy ( ethhdr->h_dest, ll_dest, ETH_ALEN );
- memcpy ( ethhdr->h_source, netdev->ll_addr, ETH_ALEN );
- ethhdr->h_protocol = net_protocol->net_proto;
+ memcpy ( ethhdr->h_source, ll_source, ETH_ALEN );
+ ethhdr->h_protocol = net_proto;
return 0;
}
@@ -62,14 +63,13 @@ static int eth_push ( struct io_buffer *iobuf, struct net_device *netdev,
* Remove Ethernet link-layer header
*
* @v iobuf I/O buffer
- * @v netdev Network device
- * @v net_proto Network-layer protocol, in network-byte order
- * @v ll_source Source link-layer address
+ * @ret ll_dest Link-layer destination address
+ * @ret ll_source Source link-layer address
+ * @ret net_proto Network-layer protocol, in network-byte order
* @ret rc Return status code
*/
-static int eth_pull ( struct io_buffer *iobuf,
- struct net_device *netdev __unused,
- uint16_t *net_proto, const void **ll_source ) {
+static int eth_pull ( struct io_buffer *iobuf, const void **ll_dest,
+ const void **ll_source, uint16_t *net_proto ) {
struct ethhdr *ethhdr = iobuf->data;
/* Sanity check */
@@ -83,8 +83,9 @@ static int eth_pull ( struct io_buffer *iobuf,
iob_pull ( iobuf, sizeof ( *ethhdr ) );
/* Fill in required fields */
- *net_proto = ethhdr->h_protocol;
+ *ll_dest = ethhdr->h_dest;
*ll_source = ethhdr->h_source;
+ *net_proto = ethhdr->h_protocol;
return 0;
}
@@ -92,8 +93,8 @@ static int eth_pull ( struct io_buffer *iobuf,
/**
* Transcribe Ethernet address
*
- * @v ll_addr Link-layer address
- * @ret string Link-layer address in human-readable format
+ * @v ll_addr Link-layer address
+ * @ret string Link-layer address in human-readable format
*/
const char * eth_ntoa ( const void *ll_addr ) {
static char buf[18]; /* "00:00:00:00:00:00" */
@@ -105,6 +106,33 @@ const char * eth_ntoa ( const void *ll_addr ) {
return buf;
}
+/**
+ * Hash multicast address
+ *
+ * @v af Address family
+ * @v net_addr Network-layer address
+ * @v ll_addr Link-layer address to fill in
+ * @ret rc Return status code
+ */
+static int eth_mc_hash ( unsigned int af, const void *net_addr,
+ void *ll_addr ) {
+ const uint8_t *net_addr_bytes = net_addr;
+ uint8_t *ll_addr_bytes = ll_addr;
+
+ switch ( af ) {
+ case AF_INET:
+ ll_addr_bytes[0] = 0x01;
+ ll_addr_bytes[1] = 0x00;
+ ll_addr_bytes[2] = 0x5e;
+ ll_addr_bytes[3] = net_addr_bytes[1] & 0x7f;
+ ll_addr_bytes[4] = net_addr_bytes[2];
+ ll_addr_bytes[5] = net_addr_bytes[3];
+ return 0;
+ default:
+ return -ENOTSUP;
+ }
+}
+
/** Ethernet protocol */
struct ll_protocol ethernet_protocol __ll_protocol = {
.name = "Ethernet",
@@ -115,4 +143,5 @@ struct ll_protocol ethernet_protocol __ll_protocol = {
.push = eth_push,
.pull = eth_pull,
.ntoa = eth_ntoa,
+ .mc_hash = eth_mc_hash,
};
diff --git a/gpxe/src/net/fakedhcp.c b/gpxe/src/net/fakedhcp.c
index 60264756..0518789c 100644
--- a/gpxe/src/net/fakedhcp.c
+++ b/gpxe/src/net/fakedhcp.c
@@ -111,8 +111,8 @@ int create_fakedhcpdiscover ( struct net_device *netdev,
struct in_addr ciaddr = { 0 };
int rc;
- if ( ( rc = dhcp_create_request ( &dhcppkt, netdev, ciaddr, NULL, data,
- max_len ) ) != 0 ) {
+ if ( ( rc = dhcp_create_request ( &dhcppkt, netdev, DHCPDISCOVER,
+ ciaddr, data, max_len ) ) != 0 ) {
DBG ( "Could not create DHCPDISCOVER: %s\n",
strerror ( rc ) );
return rc;
@@ -137,7 +137,7 @@ int create_fakedhcpack ( struct net_device *netdev,
int rc;
/* Create base DHCPACK packet */
- if ( ( rc = dhcp_create_packet ( &dhcppkt, netdev, DHCPACK, NULL,
+ if ( ( rc = dhcp_create_packet ( &dhcppkt, netdev, DHCPACK, NULL, 0,
data, max_len ) ) != 0 ) {
DBG ( "Could not create DHCPACK: %s\n", strerror ( rc ) );
return rc;
@@ -163,7 +163,7 @@ int create_fakedhcpack ( struct net_device *netdev,
}
/**
- * Create ProxyDHCPACK packet
+ * Create fake PXE Boot Server ACK packet
*
* @v netdev Network device
* @v data Buffer for DHCP packet
@@ -172,30 +172,41 @@ int create_fakedhcpack ( struct net_device *netdev,
*
* Used by external code.
*/
-int create_fakeproxydhcpack ( struct net_device *netdev,
- void *data, size_t max_len ) {
+int create_fakepxebsack ( struct net_device *netdev,
+ void *data, size_t max_len ) {
struct dhcp_packet dhcppkt;
- struct settings *settings;
+ struct settings *proxy_settings;
+ struct settings *pxebs_settings;
int rc;
- /* Identify ProxyDHCP settings */
- settings = find_settings ( PROXYDHCP_SETTINGS_NAME );
-
- /* No ProxyDHCP settings => use normal DHCPACK */
- if ( ! settings )
+ /* Identify available settings */
+ proxy_settings = find_settings ( PROXYDHCP_SETTINGS_NAME );
+ pxebs_settings = find_settings ( PXEBS_SETTINGS_NAME );
+ if ( ( ! proxy_settings ) && ( ! pxebs_settings ) ) {
+ /* No PXE boot server; return the regular DHCPACK */
return create_fakedhcpack ( netdev, data, max_len );
+ }
/* Create base DHCPACK packet */
- if ( ( rc = dhcp_create_packet ( &dhcppkt, netdev, DHCPACK, NULL,
+ if ( ( rc = dhcp_create_packet ( &dhcppkt, netdev, DHCPACK, NULL, 0,
data, max_len ) ) != 0 ) {
- DBG ( "Could not create ProxyDHCPACK: %s\n",
+ DBG ( "Could not create PXE BS ACK: %s\n",
strerror ( rc ) );
return rc;
}
/* Merge in ProxyDHCP options */
- if ( ( rc = copy_settings ( &dhcppkt, settings ) ) != 0 ) {
- DBG ( "Could not set ProxyDHCPACK settings: %s\n",
+ if ( proxy_settings &&
+ ( ( rc = copy_settings ( &dhcppkt, proxy_settings ) ) != 0 ) ) {
+ DBG ( "Could not copy ProxyDHCP settings: %s\n",
+ strerror ( rc ) );
+ return rc;
+ }
+
+ /* Merge in BootServerDHCP options, if present */
+ if ( pxebs_settings &&
+ ( ( rc = copy_settings ( &dhcppkt, pxebs_settings ) ) != 0 ) ) {
+ DBG ( "Could not copy PXE BS settings: %s\n",
strerror ( rc ) );
return rc;
}
diff --git a/gpxe/src/net/icmp.c b/gpxe/src/net/icmp.c
new file mode 100644
index 00000000..3e45c1f6
--- /dev/null
+++ b/gpxe/src/net/icmp.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <string.h>
+#include <errno.h>
+#include <gpxe/iobuf.h>
+#include <gpxe/in.h>
+#include <gpxe/tcpip.h>
+#include <gpxe/icmp.h>
+
+/** @file
+ *
+ * ICMP protocol
+ *
+ */
+
+struct tcpip_protocol icmp_protocol __tcpip_protocol;
+
+/**
+ * Process a received packet
+ *
+ * @v iobuf I/O buffer
+ * @v st_src Partially-filled source address
+ * @v st_dest Partially-filled destination address
+ * @v pshdr_csum Pseudo-header checksum
+ * @ret rc Return status code
+ */
+static int icmp_rx ( struct io_buffer *iobuf, struct sockaddr_tcpip *st_src,
+ struct sockaddr_tcpip *st_dest,
+ uint16_t pshdr_csum __unused ) {
+ struct icmp_header *icmp = iobuf->data;
+ size_t len = iob_len ( iobuf );
+ unsigned int csum;
+ int rc;
+
+ /* Sanity check */
+ if ( len < sizeof ( *icmp ) ) {
+ DBG ( "ICMP packet too short at %zd bytes (min %zd bytes)\n",
+ len, sizeof ( *icmp ) );
+ rc = -EINVAL;
+ goto done;
+ }
+
+ /* Verify checksum */
+ csum = tcpip_chksum ( icmp, len );
+ if ( csum != 0 ) {
+ DBG ( "ICMP checksum incorrect (is %04x, should be 0000)\n",
+ csum );
+ DBG_HD ( icmp, len );
+ rc = -EINVAL;
+ goto done;
+ }
+
+ /* We respond only to pings */
+ if ( icmp->type != ICMP_ECHO_REQUEST ) {
+ DBG ( "ICMP ignoring type %d\n", icmp->type );
+ rc = 0;
+ goto done;
+ }
+
+ DBG ( "ICMP responding to ping\n" );
+
+ /* Change type to response and recalculate checksum */
+ icmp->type = ICMP_ECHO_RESPONSE;
+ icmp->chksum = 0;
+ icmp->chksum = tcpip_chksum ( icmp, len );
+
+ /* Transmit the response */
+ if ( ( rc = tcpip_tx ( iob_disown ( iobuf ), &icmp_protocol, st_dest,
+ st_src, NULL, NULL ) ) != 0 ) {
+ DBG ( "ICMP could not transmit ping response: %s\n",
+ strerror ( rc ) );
+ goto done;
+ }
+
+ done:
+ free_iob ( iobuf );
+ return rc;
+}
+
+/** ICMP TCP/IP protocol */
+struct tcpip_protocol icmp_protocol __tcpip_protocol = {
+ .name = "ICMP",
+ .rx = icmp_rx,
+ .tcpip_proto = IP_ICMP,
+};
diff --git a/gpxe/src/net/icmpv6.c b/gpxe/src/net/icmpv6.c
index 7b7146c2..237fc4a6 100644
--- a/gpxe/src/net/icmpv6.c
+++ b/gpxe/src/net/icmpv6.c
@@ -60,7 +60,7 @@ int icmp6_send_solicit ( struct net_device *netdev, struct in6_addr *src __unuse
st_dest.sin6.sin6_addr.in6_u.u6_addr8[13] = 0xff;
/* Send packet over IP6 */
- return tcpip_tx ( iobuf, &icmp6_protocol, &st_dest.st,
+ return tcpip_tx ( iobuf, &icmp6_protocol, NULL, &st_dest.st,
NULL, &nsolicit->csum );
}
diff --git a/gpxe/src/net/infiniband.c b/gpxe/src/net/infiniband.c
index ab76742e..d79bdc2c 100644
--- a/gpxe/src/net/infiniband.c
+++ b/gpxe/src/net/infiniband.c
@@ -46,10 +46,12 @@ struct list_head ib_devices = LIST_HEAD_INIT ( ib_devices );
*
* @v ibdev Infiniband device
* @v num_cqes Number of completion queue entries
+ * @v op Completion queue operations
* @ret cq New completion queue
*/
-struct ib_completion_queue * ib_create_cq ( struct ib_device *ibdev,
- unsigned int num_cqes ) {
+struct ib_completion_queue *
+ib_create_cq ( struct ib_device *ibdev, unsigned int num_cqes,
+ struct ib_completion_queue_operations *op ) {
struct ib_completion_queue *cq;
int rc;
@@ -58,22 +60,28 @@ struct ib_completion_queue * ib_create_cq ( struct ib_device *ibdev,
/* Allocate and initialise data structure */
cq = zalloc ( sizeof ( *cq ) );
if ( ! cq )
- return NULL;
+ goto err_alloc_cq;
cq->num_cqes = num_cqes;
INIT_LIST_HEAD ( &cq->work_queues );
+ cq->op = op;
/* Perform device-specific initialisation and get CQN */
if ( ( rc = ibdev->op->create_cq ( ibdev, cq ) ) != 0 ) {
DBGC ( ibdev, "IBDEV %p could not initialise completion "
"queue: %s\n", ibdev, strerror ( rc ) );
- free ( cq );
- return NULL;
+ goto err_dev_create_cq;
}
DBGC ( ibdev, "IBDEV %p created %d-entry completion queue %p (%p) "
"with CQN %#lx\n", ibdev, num_cqes, cq,
ib_cq_get_drvdata ( cq ), cq->cqn );
return cq;
+
+ ibdev->op->destroy_cq ( ibdev, cq );
+ err_dev_create_cq:
+ free ( cq );
+ err_alloc_cq:
+ return NULL;
}
/**
@@ -120,7 +128,9 @@ struct ib_queue_pair * ib_create_qp ( struct ib_device *ibdev,
( num_recv_wqes * sizeof ( qp->recv.iobufs[0] ) ) );
qp = zalloc ( total_size );
if ( ! qp )
- return NULL;
+ goto err_alloc_qp;
+ qp->ibdev = ibdev;
+ list_add ( &qp->list, &ibdev->qps );
qp->qkey = qkey;
qp->send.qp = qp;
qp->send.is_send = 1;
@@ -134,15 +144,13 @@ struct ib_queue_pair * ib_create_qp ( struct ib_device *ibdev,
qp->recv.num_wqes = num_recv_wqes;
qp->recv.iobufs = ( ( ( void * ) qp ) + sizeof ( *qp ) +
( num_send_wqes * sizeof ( qp->send.iobufs[0] ) ));
+ INIT_LIST_HEAD ( &qp->mgids );
/* Perform device-specific initialisation and get QPN */
if ( ( rc = ibdev->op->create_qp ( ibdev, qp ) ) != 0 ) {
DBGC ( ibdev, "IBDEV %p could not initialise queue pair: "
"%s\n", ibdev, strerror ( rc ) );
- list_del ( &qp->send.list );
- list_del ( &qp->recv.list );
- free ( qp );
- return NULL;
+ goto err_dev_create_qp;
}
DBGC ( ibdev, "IBDEV %p created queue pair %p (%p) with QPN %#lx\n",
@@ -154,6 +162,15 @@ struct ib_queue_pair * ib_create_qp ( struct ib_device *ibdev,
ibdev, qp->qpn, num_recv_wqes, qp->recv.iobufs,
( ( ( void * ) qp ) + total_size ) );
return qp;
+
+ ibdev->op->destroy_qp ( ibdev, qp );
+ err_dev_create_qp:
+ list_del ( &qp->send.list );
+ list_del ( &qp->recv.list );
+ list_del ( &qp->list );
+ free ( qp );
+ err_alloc_qp:
+ return NULL;
}
/**
@@ -190,15 +207,80 @@ int ib_modify_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp,
* @v qp Queue pair
*/
void ib_destroy_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp ) {
+ struct io_buffer *iobuf;
+ unsigned int i;
+
DBGC ( ibdev, "IBDEV %p destroying QPN %#lx\n",
ibdev, qp->qpn );
+
+ assert ( list_empty ( &qp->mgids ) );
+
+ /* Perform device-specific destruction */
ibdev->op->destroy_qp ( ibdev, qp );
+
+ /* Complete any remaining I/O buffers with errors */
+ for ( i = 0 ; i < qp->send.num_wqes ; i++ ) {
+ if ( ( iobuf = qp->send.iobufs[i] ) != NULL )
+ ib_complete_send ( ibdev, qp, iobuf, -ECANCELED );
+ }
+ for ( i = 0 ; i < qp->recv.num_wqes ; i++ ) {
+ if ( ( iobuf = qp->recv.iobufs[i] ) != NULL ) {
+ ib_complete_recv ( ibdev, qp, NULL, iobuf,
+ -ECANCELED );
+ }
+ }
+
+ /* Remove work queues from completion queue */
list_del ( &qp->send.list );
list_del ( &qp->recv.list );
+
+ /* Free QP */
+ list_del ( &qp->list );
free ( qp );
}
/**
+ * Find queue pair by QPN
+ *
+ * @v ibdev Infiniband device
+ * @v qpn Queue pair number
+ * @ret qp Queue pair, or NULL
+ */
+struct ib_queue_pair * ib_find_qp_qpn ( struct ib_device *ibdev,
+ unsigned long qpn ) {
+ struct ib_queue_pair *qp;
+
+ list_for_each_entry ( qp, &ibdev->qps, list ) {
+ if ( qp->qpn == qpn )
+ return qp;
+ }
+ return NULL;
+}
+
+/**
+ * Find queue pair by multicast GID
+ *
+ * @v ibdev Infiniband device
+ * @v gid Multicast GID
+ * @ret qp Queue pair, or NULL
+ */
+struct ib_queue_pair * ib_find_qp_mgid ( struct ib_device *ibdev,
+ struct ib_gid *gid ) {
+ struct ib_queue_pair *qp;
+ struct ib_multicast_gid *mgid;
+
+ list_for_each_entry ( qp, &ibdev->qps, list ) {
+ list_for_each_entry ( mgid, &qp->mgids, list ) {
+ if ( memcmp ( &mgid->gid, gid,
+ sizeof ( mgid->gid ) ) == 0 ) {
+ return qp;
+ }
+ }
+ }
+ return NULL;
+}
+
+/**
* Find work queue belonging to completion queue
*
* @v cq Completion queue
@@ -217,142 +299,194 @@ struct ib_work_queue * ib_find_wq ( struct ib_completion_queue *cq,
return NULL;
}
-/***************************************************************************
- *
- * Management datagram operations
- *
- ***************************************************************************
- */
-
/**
- * Get port information
+ * Post send work queue entry
*
* @v ibdev Infiniband device
- * @v port_info Port information datagram to fill in
+ * @v qp Queue pair
+ * @v av Address vector
+ * @v iobuf I/O buffer
* @ret rc Return status code
*/
-static int ib_get_port_info ( struct ib_device *ibdev,
- struct ib_mad_port_info *port_info ) {
- struct ib_mad_hdr *hdr = &port_info->mad_hdr;
+int ib_post_send ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+ struct ib_address_vector *av,
+ struct io_buffer *iobuf ) {
int rc;
- /* Construct MAD */
- memset ( port_info, 0, sizeof ( *port_info ) );
- hdr->base_version = IB_MGMT_BASE_VERSION;
- hdr->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED;
- hdr->class_version = 1;
- hdr->method = IB_MGMT_METHOD_GET;
- hdr->attr_id = htons ( IB_SMP_ATTR_PORT_INFO );
- hdr->attr_mod = htonl ( ibdev->port );
-
- if ( ( rc = ib_mad ( ibdev, hdr, sizeof ( *port_info ) ) ) != 0 ) {
- DBGC ( ibdev, "IBDEV %p could not get port info: %s\n",
- ibdev, strerror ( rc ) );
+ /* Check queue fill level */
+ if ( qp->send.fill >= qp->send.num_wqes ) {
+ DBGC ( ibdev, "IBDEV %p QPN %#lx send queue full\n",
+ ibdev, qp->qpn );
+ return -ENOBUFS;
+ }
+
+ /* Post to hardware */
+ if ( ( rc = ibdev->op->post_send ( ibdev, qp, av, iobuf ) ) != 0 ) {
+ DBGC ( ibdev, "IBDEV %p QPN %#lx could not post send WQE: "
+ "%s\n", ibdev, qp->qpn, strerror ( rc ) );
return rc;
}
+
+ qp->send.fill++;
return 0;
}
/**
- * Get GUID information
+ * Post receive work queue entry
*
* @v ibdev Infiniband device
- * @v guid_info GUID information datagram to fill in
+ * @v qp Queue pair
+ * @v iobuf I/O buffer
* @ret rc Return status code
*/
-static int ib_get_guid_info ( struct ib_device *ibdev,
- struct ib_mad_guid_info *guid_info ) {
- struct ib_mad_hdr *hdr = &guid_info->mad_hdr;
+int ib_post_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+ struct io_buffer *iobuf ) {
int rc;
- /* Construct MAD */
- memset ( guid_info, 0, sizeof ( *guid_info ) );
- hdr->base_version = IB_MGMT_BASE_VERSION;
- hdr->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED;
- hdr->class_version = 1;
- hdr->method = IB_MGMT_METHOD_GET;
- hdr->attr_id = htons ( IB_SMP_ATTR_GUID_INFO );
+ /* Check queue fill level */
+ if ( qp->recv.fill >= qp->recv.num_wqes ) {
+ DBGC ( ibdev, "IBDEV %p QPN %#lx receive queue full\n",
+ ibdev, qp->qpn );
+ return -ENOBUFS;
+ }
- if ( ( rc = ib_mad ( ibdev, hdr, sizeof ( *guid_info ) ) ) != 0 ) {
- DBGC ( ibdev, "IBDEV %p could not get GUID info: %s\n",
- ibdev, strerror ( rc ) );
+ /* Post to hardware */
+ if ( ( rc = ibdev->op->post_recv ( ibdev, qp, iobuf ) ) != 0 ) {
+ DBGC ( ibdev, "IBDEV %p QPN %#lx could not post receive WQE: "
+ "%s\n", ibdev, qp->qpn, strerror ( rc ) );
return rc;
}
+
+ qp->recv.fill++;
return 0;
}
/**
- * Get partition key table
+ * Complete send work queue entry
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ * @v iobuf I/O buffer
+ * @v rc Completion status code
+ */
+void ib_complete_send ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+ struct io_buffer *iobuf, int rc ) {
+ qp->send.cq->op->complete_send ( ibdev, qp, iobuf, rc );
+ qp->send.fill--;
+}
+
+/**
+ * Complete receive work queue entry
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ * @v av Address vector
+ * @v iobuf I/O buffer
+ * @v rc Completion status code
+ */
+void ib_complete_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+ struct ib_address_vector *av,
+ struct io_buffer *iobuf, int rc ) {
+ qp->recv.cq->op->complete_recv ( ibdev, qp, av, iobuf, rc );
+ qp->recv.fill--;
+}
+
+/**
+ * Open port
*
* @v ibdev Infiniband device
- * @v guid_info Partition key table datagram to fill in
* @ret rc Return status code
*/
-static int ib_get_pkey_table ( struct ib_device *ibdev,
- struct ib_mad_pkey_table *pkey_table ) {
- struct ib_mad_hdr *hdr = &pkey_table->mad_hdr;
+int ib_open ( struct ib_device *ibdev ) {
int rc;
- /* Construct MAD */
- memset ( pkey_table, 0, sizeof ( *pkey_table ) );
- hdr->base_version = IB_MGMT_BASE_VERSION;
- hdr->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED;
- hdr->class_version = 1;
- hdr->method = IB_MGMT_METHOD_GET;
- hdr->attr_id = htons ( IB_SMP_ATTR_PKEY_TABLE );
-
- if ( ( rc = ib_mad ( ibdev, hdr, sizeof ( *pkey_table ) ) ) != 0 ) {
- DBGC ( ibdev, "IBDEV %p could not get pkey table: %s\n",
- ibdev, strerror ( rc ) );
- return rc;
+ /* Open device if this is the first requested opening */
+ if ( ibdev->open_count == 0 ) {
+ if ( ( rc = ibdev->op->open ( ibdev ) ) != 0 )
+ return rc;
}
+
+ /* Increment device open request counter */
+ ibdev->open_count++;
+
return 0;
}
/**
- * Get MAD parameters
+ * Close port
*
* @v ibdev Infiniband device
+ */
+void ib_close ( struct ib_device *ibdev ) {
+
+ /* Decrement device open request counter */
+ ibdev->open_count--;
+
+ /* Close device if this was the last remaining requested opening */
+ if ( ibdev->open_count == 0 )
+ ibdev->op->close ( ibdev );
+}
+
+/**
+ * Attach to multicast group
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ * @v gid Multicast GID
* @ret rc Return status code
*/
-static int ib_get_mad_params ( struct ib_device *ibdev ) {
- union {
- /* This union exists just to save stack space */
- struct ib_mad_port_info port_info;
- struct ib_mad_guid_info guid_info;
- struct ib_mad_pkey_table pkey_table;
- } u;
+int ib_mcast_attach ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+ struct ib_gid *gid ) {
+ struct ib_multicast_gid *mgid;
int rc;
- /* Port info gives us the link state, the first half of the
- * port GID and the SM LID.
- */
- if ( ( rc = ib_get_port_info ( ibdev, &u.port_info ) ) != 0 )
- return rc;
- ibdev->link_up = ( ( u.port_info.port_state__link_speed_supported
- & 0xf ) == 4 );
- memcpy ( &ibdev->port_gid.u.bytes[0], u.port_info.gid_prefix, 8 );
- ibdev->sm_lid = ntohs ( u.port_info.mastersm_lid );
+ /* Add to software multicast GID list */
+ mgid = zalloc ( sizeof ( *mgid ) );
+ if ( ! mgid ) {
+ rc = -ENOMEM;
+ goto err_alloc_mgid;
+ }
+ memcpy ( &mgid->gid, gid, sizeof ( mgid->gid ) );
+ list_add ( &mgid->list, &qp->mgids );
- /* GUID info gives us the second half of the port GID */
- if ( ( rc = ib_get_guid_info ( ibdev, &u.guid_info ) ) != 0 )
- return rc;
- memcpy ( &ibdev->port_gid.u.bytes[8], u.guid_info.gid_local, 8 );
+ /* Add to hardware multicast GID list */
+ if ( ( rc = ibdev->op->mcast_attach ( ibdev, qp, gid ) ) != 0 )
+ goto err_dev_mcast_attach;
- /* Get partition key */
- if ( ( rc = ib_get_pkey_table ( ibdev, &u.pkey_table ) ) != 0 )
- return rc;
- ibdev->pkey = ntohs ( u.pkey_table.pkey[0][0] );
+ return 0;
- DBGC ( ibdev, "IBDEV %p port GID is %08lx:%08lx:%08lx:%08lx\n",
- ibdev, htonl ( ibdev->port_gid.u.dwords[0] ),
- htonl ( ibdev->port_gid.u.dwords[1] ),
- htonl ( ibdev->port_gid.u.dwords[2] ),
- htonl ( ibdev->port_gid.u.dwords[3] ) );
+ err_dev_mcast_attach:
+ list_del ( &mgid->list );
+ free ( mgid );
+ err_alloc_mgid:
+ return rc;
+}
- return 0;
+/**
+ * Detach from multicast group
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ * @v gid Multicast GID
+ */
+void ib_mcast_detach ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+ struct ib_gid *gid ) {
+ struct ib_multicast_gid *mgid;
+
+ /* Remove from hardware multicast GID list */
+ ibdev->op->mcast_detach ( ibdev, qp, gid );
+
+ /* Remove from software multicast GID list */
+ list_for_each_entry ( mgid, &qp->mgids, list ) {
+ if ( memcmp ( &mgid->gid, gid, sizeof ( mgid->gid ) ) == 0 ) {
+ list_del ( &mgid->list );
+ free ( mgid );
+ break;
+ }
+ }
}
+
/***************************************************************************
*
* Event queues
@@ -366,14 +500,6 @@ static int ib_get_mad_params ( struct ib_device *ibdev ) {
* @v ibdev Infiniband device
*/
void ib_link_state_changed ( struct ib_device *ibdev ) {
- int rc;
-
- /* Update MAD parameters */
- if ( ( rc = ib_get_mad_params ( ibdev ) ) != 0 ) {
- DBGC ( ibdev, "IBDEV %p could not update MAD parameters: %s\n",
- ibdev, strerror ( rc ) );
- return;
- }
/* Notify IPoIB of link state change */
ipoib_link_state_changed ( ibdev );
@@ -420,6 +546,9 @@ struct ib_device * alloc_ibdev ( size_t priv_size ) {
if ( ibdev ) {
drv_priv = ( ( ( void * ) ibdev ) + sizeof ( *ibdev ) );
ib_set_drvdata ( ibdev, drv_priv );
+ INIT_LIST_HEAD ( &ibdev->qps );
+ ibdev->lid = IB_LID_NONE;
+ ibdev->pkey = IB_PKEY_NONE;
}
return ibdev;
}
@@ -437,14 +566,6 @@ int register_ibdev ( struct ib_device *ibdev ) {
ibdev_get ( ibdev );
list_add_tail ( &ibdev->list, &ib_devices );
- /* Open link */
- if ( ( rc = ib_open ( ibdev ) ) != 0 )
- goto err_open;
-
- /* Get MAD parameters */
- if ( ( rc = ib_get_mad_params ( ibdev ) ) != 0 )
- goto err_get_mad_params;
-
/* Add IPoIB device */
if ( ( rc = ipoib_probe ( ibdev ) ) != 0 ) {
DBGC ( ibdev, "IBDEV %p could not add IPoIB device: %s\n",
@@ -457,9 +578,6 @@ int register_ibdev ( struct ib_device *ibdev ) {
return 0;
err_ipoib_probe:
- err_get_mad_params:
- ib_close ( ibdev );
- err_open:
list_del ( &ibdev->list );
ibdev_put ( ibdev );
return rc;
@@ -474,7 +592,6 @@ void unregister_ibdev ( struct ib_device *ibdev ) {
/* Close device */
ipoib_remove ( ibdev );
- ib_close ( ibdev );
/* Remove from device list */
list_del ( &ibdev->list );
diff --git a/gpxe/src/net/ipv4.c b/gpxe/src/net/ipv4.c
index 82a13c33..8668d44b 100644
--- a/gpxe/src/net/ipv4.c
+++ b/gpxe/src/net/ipv4.c
@@ -188,7 +188,7 @@ static struct io_buffer * ipv4_reassemble ( struct io_buffer * iobuf ) {
free_iob ( iobuf );
/** Check if the fragment series is over */
- if ( !iphdr->frags & IP_MASK_MOREFRAGS ) {
+ if ( ! ( iphdr->frags & IP_MASK_MOREFRAGS ) ) {
iobuf = fragbuf->frag_iob;
free_fragbuf ( fragbuf );
return iobuf;
@@ -266,7 +266,6 @@ static uint16_t ipv4_pshdr_chksum ( struct io_buffer *iobuf, uint16_t csum ) {
static int ipv4_ll_addr ( struct in_addr dest, struct in_addr src,
struct net_device *netdev, uint8_t *ll_dest ) {
struct ll_protocol *ll_protocol = netdev->ll_protocol;
- uint8_t *dest_bytes = ( ( uint8_t * ) &dest );
if ( dest.s_addr == INADDR_BROADCAST ) {
/* Broadcast address */
@@ -274,17 +273,7 @@ static int ipv4_ll_addr ( struct in_addr dest, struct in_addr src,
ll_protocol->ll_addr_len );
return 0;
} else if ( IN_MULTICAST ( ntohl ( dest.s_addr ) ) ) {
- /* Special case: IPv4 multicast over Ethernet. This
- * code may need to be generalised once we find out
- * what happens for other link layers.
- */
- ll_dest[0] = 0x01;
- ll_dest[1] = 0x00;
- ll_dest[2] = 0x5e;
- ll_dest[3] = dest_bytes[1] & 0x7f;
- ll_dest[4] = dest_bytes[2];
- ll_dest[5] = dest_bytes[3];
- return 0;
+ return ll_protocol->mc_hash ( AF_INET, &dest, ll_dest );
} else {
/* Unicast address: resolve via ARP */
return arp_resolve ( netdev, &ipv4_protocol, &dest,
@@ -297,6 +286,7 @@ static int ipv4_ll_addr ( struct in_addr dest, struct in_addr src,
*
* @v iobuf I/O buffer
* @v tcpip Transport-layer protocol
+ * @v st_src Source network-layer address
* @v st_dest Destination network-layer address
* @v netdev Network device to use if no route found, or NULL
* @v trans_csum Transport-layer checksum to complete, or NULL
@@ -306,10 +296,12 @@ static int ipv4_ll_addr ( struct in_addr dest, struct in_addr src,
*/
static int ipv4_tx ( struct io_buffer *iobuf,
struct tcpip_protocol *tcpip_protocol,
+ struct sockaddr_tcpip *st_src,
struct sockaddr_tcpip *st_dest,
struct net_device *netdev,
uint16_t *trans_csum ) {
struct iphdr *iphdr = iob_push ( iobuf, sizeof ( *iphdr ) );
+ struct sockaddr_in *sin_src = ( ( struct sockaddr_in * ) st_src );
struct sockaddr_in *sin_dest = ( ( struct sockaddr_in * ) st_dest );
struct ipv4_miniroute *miniroute;
struct in_addr next_hop;
@@ -328,7 +320,11 @@ static int ipv4_tx ( struct io_buffer *iobuf,
/* Use routing table to identify next hop and transmitting netdev */
next_hop = iphdr->dest;
- if ( ( miniroute = ipv4_route ( &next_hop ) ) ) {
+ if ( sin_src )
+ iphdr->src = sin_src->sin_addr;
+ if ( ( next_hop.s_addr != INADDR_BROADCAST ) &&
+ ( ! IN_MULTICAST ( ntohl ( next_hop.s_addr ) ) ) &&
+ ( ( miniroute = ipv4_route ( &next_hop ) ) != NULL ) ) {
iphdr->src = miniroute->address;
netdev = miniroute->netdev;
}
@@ -631,3 +627,6 @@ static int ipv4_create_routes ( void ) {
struct settings_applicator ipv4_settings_applicator __settings_applicator = {
.apply = ipv4_create_routes,
};
+
+/* Drag in ICMP */
+REQUIRE_OBJECT ( icmp );
diff --git a/gpxe/src/net/ipv6.c b/gpxe/src/net/ipv6.c
index 3407d538..f7308bb4 100644
--- a/gpxe/src/net/ipv6.c
+++ b/gpxe/src/net/ipv6.c
@@ -176,6 +176,7 @@ void ipv6_dump ( struct ip6_header *ip6hdr ) {
*/
static int ipv6_tx ( struct io_buffer *iobuf,
struct tcpip_protocol *tcpip,
+ struct sockaddr_tcpip *st_src __unused,
struct sockaddr_tcpip *st_dest,
struct net_device *netdev,
uint16_t *trans_csum ) {
diff --git a/gpxe/src/net/netdevice.c b/gpxe/src/net/netdevice.c
index 3721b334..9e142d27 100644
--- a/gpxe/src/net/netdevice.c
+++ b/gpxe/src/net/netdevice.c
@@ -45,6 +45,48 @@ static struct net_protocol net_protocols_end[0]
/** List of network devices */
struct list_head net_devices = LIST_HEAD_INIT ( net_devices );
+/** List of open network devices, in reverse order of opening */
+struct list_head open_net_devices = LIST_HEAD_INIT ( open_net_devices );
+
+/**
+ * Record network device statistic
+ *
+ * @v stats Network device statistics
+ * @v rc Status code
+ */
+static void netdev_record_stat ( struct net_device_stats *stats, int rc ) {
+ struct net_device_error *error;
+ struct net_device_error *least_common_error;
+ unsigned int i;
+
+ /* If this is not an error, just update the good counter */
+ if ( rc == 0 ) {
+ stats->good++;
+ return;
+ }
+
+ /* Update the bad counter */
+ stats->bad++;
+
+ /* Locate the appropriate error record */
+ least_common_error = &stats->errors[0];
+ for ( i = 0 ; i < ( sizeof ( stats->errors ) /
+ sizeof ( stats->errors[0] ) ) ; i++ ) {
+ error = &stats->errors[i];
+ /* Update matching record, if found */
+ if ( error->rc == rc ) {
+ error->count++;
+ return;
+ }
+ if ( error->count < least_common_error->count )
+ least_common_error = error;
+ }
+
+ /* Overwrite the least common error record */
+ least_common_error->rc = rc;
+ least_common_error->count = 1;
+}
+
/**
* Transmit raw packet via network device
*
@@ -91,12 +133,11 @@ void netdev_tx_complete_err ( struct net_device *netdev,
struct io_buffer *iobuf, int rc ) {
/* Update statistics counter */
+ netdev_record_stat ( &netdev->tx_stats, rc );
if ( rc == 0 ) {
- netdev->stats.tx_ok++;
DBGC ( netdev, "NETDEV %p transmission %p complete\n",
netdev, iobuf );
} else {
- netdev->stats.tx_err++;
DBGC ( netdev, "NETDEV %p transmission %p failed: %s\n",
netdev, iobuf, strerror ( rc ) );
}
@@ -158,7 +199,7 @@ void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ) {
list_add_tail ( &iobuf->list, &netdev->rx_queue );
/* Update statistics counter */
- netdev->stats.rx_ok++;
+ netdev_record_stat ( &netdev->rx_stats, 0 );
}
/**
@@ -183,7 +224,7 @@ void netdev_rx_err ( struct net_device *netdev,
free_iob ( iobuf );
/* Update statistics counter */
- netdev->stats.rx_err++;
+ netdev_record_stat ( &netdev->rx_stats, rc );
}
/**
@@ -268,7 +309,7 @@ struct net_device * alloc_netdev ( size_t priv_size ) {
INIT_LIST_HEAD ( &netdev->rx_queue );
settings_init ( netdev_settings ( netdev ),
&netdev_settings_operations, &netdev->refcnt,
- netdev->name );
+ netdev->name, 0 );
netdev->priv = ( ( ( void * ) netdev ) + sizeof ( *netdev ) );
}
return netdev;
@@ -330,6 +371,10 @@ int netdev_open ( struct net_device *netdev ) {
/* Mark as opened */
netdev->state |= NETDEV_OPEN;
+
+ /* Add to head of open devices list */
+ list_add ( &netdev->open_list, &open_net_devices );
+
return 0;
}
@@ -355,6 +400,9 @@ void netdev_close ( struct net_device *netdev ) {
/* Mark as closed */
netdev->state &= ~NETDEV_OPEN;
+
+ /* Remove from open devices list */
+ list_del ( &netdev->open_list );
}
/**
@@ -425,6 +473,22 @@ struct net_device * find_netdev_by_location ( unsigned int bus_type,
}
/**
+ * Get most recently opened network device
+ *
+ * @ret netdev Most recently opened network device, or NULL
+ */
+struct net_device * last_opened_netdev ( void ) {
+ struct net_device *netdev;
+
+ list_for_each_entry ( netdev, &open_net_devices, open_list ) {
+ assert ( netdev->state & NETDEV_OPEN );
+ return netdev;
+ }
+
+ return NULL;
+}
+
+/**
* Transmit network-layer packet
*
* @v iobuf I/O buffer
@@ -439,6 +503,7 @@ struct net_device * find_netdev_by_location ( unsigned int bus_type,
*/
int net_tx ( struct io_buffer *iobuf, struct net_device *netdev,
struct net_protocol *net_protocol, const void *ll_dest ) {
+ struct ll_protocol *ll_protocol = netdev->ll_protocol;
int rc;
/* Force a poll on the netdevice to (potentially) clear any
@@ -449,8 +514,8 @@ int net_tx ( struct io_buffer *iobuf, struct net_device *netdev,
netdev_poll ( netdev );
/* Add link-layer header */
- if ( ( rc = netdev->ll_protocol->push ( iobuf, netdev, net_protocol,
- ll_dest ) ) != 0 ) {
+ if ( ( rc = ll_protocol->push ( iobuf, ll_dest, netdev->ll_addr,
+ net_protocol->net_proto ) ) != 0 ) {
free_iob ( iobuf );
return rc;
}
@@ -495,8 +560,9 @@ static void net_step ( struct process *process __unused ) {
struct net_device *netdev;
struct io_buffer *iobuf;
struct ll_protocol *ll_protocol;
- uint16_t net_proto;
+ const void *ll_dest;
const void *ll_source;
+ uint16_t net_proto;
int rc;
/* Poll and process each network device */
@@ -519,9 +585,9 @@ static void net_step ( struct process *process __unused ) {
/* Remove link-layer header */
ll_protocol = netdev->ll_protocol;
- if ( ( rc = ll_protocol->pull ( iobuf, netdev,
- &net_proto,
- &ll_source ) ) != 0 ) {
+ if ( ( rc = ll_protocol->pull ( iobuf, &ll_dest,
+ &ll_source,
+ &net_proto ) ) != 0 ) {
free_iob ( iobuf );
continue;
}
diff --git a/gpxe/src/net/retry.c b/gpxe/src/net/retry.c
index 2a645c97..cd793a7f 100644
--- a/gpxe/src/net/retry.c
+++ b/gpxe/src/net/retry.c
@@ -55,9 +55,10 @@ static LIST_HEAD ( timers );
* be stopped and the timer's callback function will be called.
*/
void start_timer ( struct retry_timer *timer ) {
- if ( ! timer_running ( timer ) )
+ if ( ! timer->running )
list_add ( &timer->list, &timers );
timer->start = currticks();
+ timer->running = 1;
/* 0 means "use default timeout" */
if ( timer->min_timeout == 0 )
@@ -82,6 +83,8 @@ void start_timer ( struct retry_timer *timer ) {
void start_timer_fixed ( struct retry_timer *timer, unsigned long timeout ) {
start_timer ( timer );
timer->timeout = timeout;
+ DBG2 ( "Timer %p expiry time changed to %ld\n",
+ timer, ( timer->start + timer->timeout ) );
}
/**
@@ -97,12 +100,12 @@ void stop_timer ( struct retry_timer *timer ) {
unsigned long runtime;
/* If timer was already stopped, do nothing */
- if ( ! timer_running ( timer ) )
+ if ( ! timer->running )
return;
list_del ( &timer->list );
runtime = ( now - timer->start );
- timer->start = 0;
+ timer->running = 0;
DBG2 ( "Timer %p stopped at time %ld (ran for %ld)\n",
timer, now, runtime );
@@ -144,8 +147,9 @@ static void timer_expired ( struct retry_timer *timer ) {
/* Stop timer without performing RTT calculations */
DBG2 ( "Timer %p stopped at time %ld on expiry\n",
timer, currticks() );
+ assert ( timer->running );
list_del ( &timer->list );
- timer->start = 0;
+ timer->running = 0;
timer->count++;
/* Back off the timeout value */
diff --git a/gpxe/src/net/tcp.c b/gpxe/src/net/tcp.c
index df87fc14..6bcd193c 100644
--- a/gpxe/src/net/tcp.c
+++ b/gpxe/src/net/tcp.c
@@ -478,12 +478,12 @@ static int tcp_xmit ( struct tcp_connection *tcp, int force_send ) {
tcphdr->seq = htonl ( tcp->snd_seq );
tcphdr->ack = htonl ( tcp->rcv_ack );
tcphdr->hlen = ( ( payload - iobuf->data ) << 2 );
- tcphdr->flags = flags;
+ tcphdr->flags = ( flags | TCP_PSH );
tcphdr->win = htons ( tcp->rcv_win );
tcphdr->csum = tcpip_chksum ( iobuf->data, iob_len ( iobuf ) );
/* Dump header */
- DBGC ( tcp, "TCP %p TX %d->%d %08lx..%08lx %08lx %4zd",
+ DBGC ( tcp, "TCP %p TX %d->%d %08x..%08zx %08x %4zd",
tcp, ntohs ( tcphdr->src ), ntohs ( tcphdr->dest ),
ntohl ( tcphdr->seq ), ( ntohl ( tcphdr->seq ) + seq_len ),
ntohl ( tcphdr->ack ), len );
@@ -491,7 +491,7 @@ static int tcp_xmit ( struct tcp_connection *tcp, int force_send ) {
DBGC ( tcp, "\n" );
/* Transmit packet */
- return tcpip_tx ( iobuf, &tcp_protocol, &tcp->peer, NULL,
+ return tcpip_tx ( iobuf, &tcp_protocol, NULL, &tcp->peer, NULL,
&tcphdr->csum );
}
@@ -564,7 +564,7 @@ static int tcp_xmit_reset ( struct tcp_connection *tcp,
tcphdr->csum = tcpip_chksum ( iobuf->data, iob_len ( iobuf ) );
/* Dump header */
- DBGC ( tcp, "TCP %p TX %d->%d %08lx..%08lx %08lx %4d",
+ DBGC ( tcp, "TCP %p TX %d->%d %08x..%08x %08x %4d",
tcp, ntohs ( tcphdr->src ), ntohs ( tcphdr->dest ),
ntohl ( tcphdr->seq ), ( ntohl ( tcphdr->seq ) ),
ntohl ( tcphdr->ack ), 0 );
@@ -572,7 +572,7 @@ static int tcp_xmit_reset ( struct tcp_connection *tcp,
DBGC ( tcp, "\n" );
/* Transmit packet */
- return tcpip_tx ( iobuf, &tcp_protocol, st_dest,
+ return tcpip_tx ( iobuf, &tcp_protocol, NULL, st_dest,
NULL, &tcphdr->csum );
}
@@ -702,8 +702,8 @@ static int tcp_rx_ack ( struct tcp_connection *tcp, uint32_t ack,
/* Ignore duplicate or out-of-range ACK */
if ( ack_len > tcp->snd_sent ) {
- DBGC ( tcp, "TCP %p received ACK for [%08lx,%08lx), "
- "sent only [%08lx,%08lx)\n", tcp, tcp->snd_seq,
+ DBGC ( tcp, "TCP %p received ACK for [%08x,%08zx), "
+ "sent only [%08x,%08x)\n", tcp, tcp->snd_seq,
( tcp->snd_seq + ack_len ), tcp->snd_seq,
( tcp->snd_seq + tcp->snd_sent ) );
return -EINVAL;
@@ -894,7 +894,7 @@ static int tcp_rx ( struct io_buffer *iobuf,
len = iob_len ( iobuf );
/* Dump header */
- DBGC ( tcp, "TCP %p RX %d<-%d %08lx %08lx..%08lx %4zd",
+ DBGC ( tcp, "TCP %p RX %d<-%d %08x %08x..%08zx %4zd",
tcp, ntohs ( tcphdr->dest ), ntohs ( tcphdr->src ),
ntohl ( tcphdr->ack ), ntohl ( tcphdr->seq ),
( ntohl ( tcphdr->seq ) + len +
@@ -1033,7 +1033,7 @@ static size_t tcp_xfer_window ( struct xfer_interface *xfer ) {
*
* @v xfer Data transfer interface
* @v iobuf Datagram I/O buffer
- * @v meta Data transfer metadata, or NULL
+ * @v meta Data transfer metadata
* @ret rc Return status code
*/
static int tcp_xfer_deliver_iob ( struct xfer_interface *xfer,
@@ -1070,12 +1070,13 @@ static struct xfer_interface_operations tcp_xfer_operations = {
/** TCP socket opener */
struct socket_opener tcp_socket_opener __socket_opener = {
- .semantics = SOCK_STREAM,
+ .semantics = TCP_SOCK_STREAM,
.family = AF_INET,
.open = tcp_open,
};
-char TCP_SOCK_STREAM[1];
+/** Linkage hack */
+int tcp_sock_stream = TCP_SOCK_STREAM;
/**
* Open TCP URI
diff --git a/gpxe/src/net/tcp/ftp.c b/gpxe/src/net/tcp/ftp.c
index 3b88f7b6..445e32bb 100644
--- a/gpxe/src/net/tcp/ftp.c
+++ b/gpxe/src/net/tcp/ftp.c
@@ -109,23 +109,39 @@ static void ftp_done ( struct ftp_request *ftp, int rc ) {
*
*/
+/** An FTP control channel string */
+struct ftp_control_string {
+ /** Literal portion */
+ const char *literal;
+ /** Variable portion
+ *
+ * @v ftp FTP request
+ * @ret string Variable portion of string
+ */
+ const char * ( *variable ) ( struct ftp_request *ftp );
+};
+
/**
- * FTP control channel strings
+ * Retrieve FTP pathname
*
- * These are used as printf() format strings. Since only one of them
- * (RETR) takes an argument, we always supply that argument to the
- * snprintf() call.
+ * @v ftp FTP request
+ * @ret path FTP pathname
*/
-static const char * ftp_strings[] = {
- [FTP_CONNECT] = NULL,
- [FTP_USER] = "USER anonymous\r\n",
- [FTP_PASS] = "PASS etherboot@etherboot.org\r\n",
- [FTP_TYPE] = "TYPE I\r\n",
- [FTP_PASV] = "PASV\r\n",
- [FTP_RETR] = "RETR %s\r\n",
- [FTP_WAIT] = NULL,
- [FTP_QUIT] = "QUIT\r\n",
- [FTP_DONE] = NULL,
+static const char * ftp_uri_path ( struct ftp_request *ftp ) {
+ return ftp->uri->path;
+}
+
+/** FTP control channel strings */
+static struct ftp_control_string ftp_strings[] = {
+ [FTP_CONNECT] = { NULL, NULL },
+ [FTP_USER] = { "USER anonymous", NULL },
+ [FTP_PASS] = { "PASS etherboot@etherboot.org", NULL },
+ [FTP_TYPE] = { "TYPE I", NULL },
+ [FTP_PASV] = { "PASV", NULL },
+ [FTP_RETR] = { "RETR ", ftp_uri_path },
+ [FTP_WAIT] = { NULL, NULL },
+ [FTP_QUIT] = { "QUIT", NULL },
+ [FTP_DONE] = { NULL, NULL },
};
/**
@@ -178,18 +194,23 @@ static void ftp_parse_value ( char **text, uint8_t *value, size_t len ) {
*
*/
static void ftp_next_state ( struct ftp_request *ftp ) {
+ struct ftp_control_string *ftp_string;
+ const char *literal;
+ const char *variable;
/* Move to next state */
if ( ftp->state < FTP_DONE )
ftp->state++;
/* Send control string if needed */
- if ( ftp_strings[ftp->state] != NULL ) {
- DBGC ( ftp, "FTP %p sending ", ftp );
- DBGC ( ftp, ftp_strings[ftp->state], ftp->uri->path );
- xfer_printf ( &ftp->control, ftp_strings[ftp->state],
- ftp->uri->path );
- }
+ ftp_string = &ftp_strings[ftp->state];
+ literal = ftp_string->literal;
+ variable = ( ftp_string->variable ?
+ ftp_string->variable ( ftp ) : "" );
+ if ( literal ) {
+ DBGC ( ftp, "FTP %p sending %s%s\n", ftp, literal, variable );
+ xfer_printf ( &ftp->control, "%s%s\r\n", literal, variable );
+ }
}
/**
@@ -359,7 +380,7 @@ static void ftp_data_closed ( struct xfer_interface *data, int rc ) {
*
* @v xfer FTP data channel interface
* @v iobuf I/O buffer
- * @v meta Data transfer metadata, or NULL
+ * @v meta Data transfer metadata
* @ret rc Return status code
*/
static int ftp_data_deliver_iob ( struct xfer_interface *data,
diff --git a/gpxe/src/net/tcp/http.c b/gpxe/src/net/tcp/http.c
index 4dc1ab73..93ccfd3b 100644
--- a/gpxe/src/net/tcp/http.c
+++ b/gpxe/src/net/tcp/http.c
@@ -41,6 +41,7 @@
#include <gpxe/process.h>
#include <gpxe/linebuf.h>
#include <gpxe/features.h>
+#include <gpxe/base64.h>
#include <gpxe/http.h>
FEATURE ( FEATURE_PROTOCOL, "HTTP", DHCP_EB_FEATURE_HTTP, 1 );
@@ -142,6 +143,8 @@ static int http_response_to_rc ( unsigned int response ) {
return -ENOENT;
case 403:
return -EPERM;
+ case 401:
+ return -EACCES;
default:
return -EIO;
}
@@ -318,7 +321,7 @@ static int http_rx_data ( struct http_request *http,
*
* @v socket Transport layer interface
* @v iobuf I/O buffer
- * @v meta Data transfer metadata, or NULL
+ * @v meta Data transfer metadata
* @ret rc Return status code
*/
static int http_socket_deliver_iob ( struct xfer_interface *socket,
@@ -340,8 +343,7 @@ static int http_socket_deliver_iob ( struct xfer_interface *socket,
/* Once we're into the data phase, just fill
* the data buffer
*/
- rc = http_rx_data ( http, iobuf );
- iobuf = NULL;
+ rc = http_rx_data ( http, iob_disown ( iobuf ) );
goto done;
case HTTP_RX_RESPONSE:
case HTTP_RX_HEADER:
@@ -388,18 +390,55 @@ static void http_step ( struct process *process ) {
const char *path = http->uri->path;
const char *host = http->uri->host;
const char *query = http->uri->query;
+ const char *user = http->uri->user;
+ const char *password =
+ ( http->uri->password ? http->uri->password : "" );
+ size_t user_pw_len = ( user ? ( strlen ( user ) + 1 /* ":" */ +
+ strlen ( password ) ) : 0 );
+ size_t user_pw_base64_len = base64_encoded_len ( user_pw_len );
+ char user_pw[ user_pw_len + 1 /* NUL */ ];
+ char user_pw_base64[ user_pw_base64_len + 1 /* NUL */ ];
int rc;
if ( xfer_window ( &http->socket ) ) {
+
+ /* We want to execute only once */
process_del ( &http->process );
+
+ /* Construct authorisation, if applicable */
+ if ( user ) {
+ char *buf = user_pw;
+ ssize_t remaining = sizeof ( user_pw );
+ size_t len;
+
+ /* URI-decode the username and password */
+ len = uri_decode ( user, buf, remaining );
+ buf += len;
+ remaining -= len;
+ *(remaining--, buf++) = ':';
+ len = uri_decode ( password, buf, remaining );
+ buf += len;
+ remaining -= len;
+ assert ( remaining >= 0 );
+
+ /* Base64-encode the "user:password" string */
+ base64_encode ( user_pw, user_pw_base64 );
+ }
+
+ /* Send GET request */
if ( ( rc = xfer_printf ( &http->socket,
"GET %s%s%s HTTP/1.0\r\n"
"User-Agent: gPXE/" VERSION "\r\n"
+ "%s%s%s"
"Host: %s\r\n"
"\r\n",
( path ? path : "/" ),
( query ? "?" : "" ),
( query ? query : "" ),
+ ( user ?
+ "Authorization: Basic " : "" ),
+ ( user ? user_pw_base64 : "" ),
+ ( user ? "\r\n" : "" ),
host ) ) != 0 ) {
http_done ( http, rc );
}
diff --git a/gpxe/src/net/tcp/iscsi.c b/gpxe/src/net/tcp/iscsi.c
index e9e36449..aa99db71 100644
--- a/gpxe/src/net/tcp/iscsi.c
+++ b/gpxe/src/net/tcp/iscsi.c
@@ -1305,7 +1305,7 @@ static int iscsi_rx_bhs ( struct iscsi_session *iscsi, const void *data,
size_t len, size_t remaining __unused ) {
memcpy ( &iscsi->rx_bhs.bytes[iscsi->rx_offset], data, len );
if ( ( iscsi->rx_offset + len ) >= sizeof ( iscsi->rx_bhs ) ) {
- DBGC2 ( iscsi, "iSCSI %p received PDU opcode %#x len %#lx\n",
+ DBGC2 ( iscsi, "iSCSI %p received PDU opcode %#x len %#x\n",
iscsi, iscsi->rx_bhs.common.opcode,
ISCSI_DATA_LEN ( iscsi->rx_bhs.common.lengths ) );
}
diff --git a/gpxe/src/net/tcpip.c b/gpxe/src/net/tcpip.c
index 1bc8d1a3..d4542b05 100644
--- a/gpxe/src/net/tcpip.c
+++ b/gpxe/src/net/tcpip.c
@@ -64,14 +64,15 @@ int tcpip_rx ( struct io_buffer *iobuf, uint8_t tcpip_proto,
*
* @v iobuf I/O buffer
* @v tcpip_protocol Transport-layer protocol
+ * @v st_src Source address, or NULL to use route default
* @v st_dest Destination address
* @v netdev Network device to use if no route found, or NULL
* @v trans_csum Transport-layer checksum to complete, or NULL
* @ret rc Return status code
*/
int tcpip_tx ( struct io_buffer *iobuf, struct tcpip_protocol *tcpip_protocol,
- struct sockaddr_tcpip *st_dest, struct net_device *netdev,
- uint16_t *trans_csum ) {
+ struct sockaddr_tcpip *st_src, struct sockaddr_tcpip *st_dest,
+ struct net_device *netdev, uint16_t *trans_csum ) {
struct tcpip_net_protocol *tcpip_net;
/* Hand off packet to the appropriate network-layer protocol */
@@ -79,8 +80,8 @@ int tcpip_tx ( struct io_buffer *iobuf, struct tcpip_protocol *tcpip_protocol,
tcpip_net < tcpip_net_protocols_end ; tcpip_net++ ) {
if ( tcpip_net->sa_family == st_dest->st_family ) {
DBG ( "TCP/IP sending %s packet\n", tcpip_net->name );
- return tcpip_net->tx ( iobuf, tcpip_protocol, st_dest,
- netdev, trans_csum );
+ return tcpip_net->tx ( iobuf, tcpip_protocol, st_src,
+ st_dest, netdev, trans_csum );
}
}
diff --git a/gpxe/src/net/tls.c b/gpxe/src/net/tls.c
index 834686fb..f5bff7a4 100644
--- a/gpxe/src/net/tls.c
+++ b/gpxe/src/net/tls.c
@@ -36,6 +36,8 @@
#include <gpxe/xfer.h>
#include <gpxe/open.h>
#include <gpxe/filter.h>
+#include <gpxe/asn1.h>
+#include <gpxe/x509.h>
#include <gpxe/tls.h>
static int tls_send_plaintext ( struct tls_session *tls, unsigned int type,
@@ -43,6 +45,33 @@ static int tls_send_plaintext ( struct tls_session *tls, unsigned int type,
static void tls_clear_cipher ( struct tls_session *tls,
struct tls_cipherspec *cipherspec );
+/******************************************************************************
+ *
+ * Utility functions
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Extract 24-bit field value
+ *
+ * @v field24 24-bit field
+ * @ret value Field value
+ *
+ * TLS uses 24-bit integers in several places, which are awkward to
+ * parse in C.
+ */
+static unsigned long tls_uint24 ( uint8_t field24[3] ) {
+ return ( ( field24[0] << 16 ) + ( field24[1] << 8 ) + field24[2] );
+}
+
+/******************************************************************************
+ *
+ * Cleanup functions
+ *
+ ******************************************************************************
+ */
+
/**
* Free TLS session
*
@@ -57,8 +86,7 @@ static void free_tls ( struct refcnt *refcnt ) {
tls_clear_cipher ( tls, &tls->tx_cipherspec_pending );
tls_clear_cipher ( tls, &tls->rx_cipherspec );
tls_clear_cipher ( tls, &tls->rx_cipherspec_pending );
- free ( tls->rsa_mod );
- free ( tls->rsa_pub_exp );
+ x509_free_rsa_public_key ( &tls->rsa );
free ( tls->rx_data );
/* Free TLS structure itself */
@@ -270,16 +298,16 @@ static void tls_generate_master_secret ( struct tls_session *tls ) {
DBGC_HD ( tls, &tls->pre_master_secret,
sizeof ( tls->pre_master_secret ) );
DBGC ( tls, "TLS %p client random bytes:\n", tls );
- DBGC_HD ( tls, &tls->client_random, sizeof ( tls->server_random ) );
+ DBGC_HD ( tls, &tls->client_random, sizeof ( tls->client_random ) );
DBGC ( tls, "TLS %p server random bytes:\n", tls );
DBGC_HD ( tls, &tls->server_random, sizeof ( tls->server_random ) );
- tls_prf_label ( tls, tls->pre_master_secret,
+ tls_prf_label ( tls, &tls->pre_master_secret,
sizeof ( tls->pre_master_secret ),
- tls->master_secret, sizeof ( tls->master_secret ),
+ &tls->master_secret, sizeof ( tls->master_secret ),
"master secret",
- tls->client_random, sizeof ( tls->client_random ),
- tls->server_random, sizeof ( tls->server_random ) );
+ &tls->client_random, sizeof ( tls->client_random ),
+ &tls->server_random, sizeof ( tls->server_random ) );
DBGC ( tls, "TLS %p generated master secret:\n", tls );
DBGC_HD ( tls, &tls->master_secret, sizeof ( tls->master_secret ) );
@@ -304,10 +332,10 @@ static int tls_generate_keys ( struct tls_session *tls ) {
int rc;
/* Generate key block */
- tls_prf_label ( tls, tls->master_secret, sizeof ( tls->master_secret ),
+ tls_prf_label ( tls, &tls->master_secret, sizeof ( tls->master_secret ),
key_block, sizeof ( key_block ), "key expansion",
- tls->server_random, sizeof ( tls->server_random ),
- tls->client_random, sizeof ( tls->client_random ) );
+ &tls->server_random, sizeof ( tls->server_random ),
+ &tls->client_random, sizeof ( tls->client_random ) );
/* Split key block into portions */
key = key_block;
@@ -604,7 +632,7 @@ static int tls_send_client_hello ( struct tls_session *tls ) {
htonl ( sizeof ( hello ) -
sizeof ( hello.type_length ) ) );
hello.version = htons ( TLS_VERSION_TLS_1_0 );
- memcpy ( &hello.random, tls->client_random, sizeof ( hello.random ) );
+ memcpy ( &hello.random, &tls->client_random, sizeof ( hello.random ) );
hello.cipher_suite_len = htons ( sizeof ( hello.cipher_suites ) );
hello.cipher_suites[0] = htons ( TLS_RSA_WITH_AES_128_CBC_SHA );
hello.cipher_suites[1] = htons ( TLS_RSA_WITH_AES_256_CBC_SHA );
@@ -622,8 +650,8 @@ static int tls_send_client_hello ( struct tls_session *tls ) {
static int tls_send_client_key_exchange ( struct tls_session *tls ) {
/* FIXME: Hack alert */
RSA_CTX *rsa_ctx;
- RSA_pub_key_new ( &rsa_ctx, tls->rsa_mod, tls->rsa_mod_len,
- tls->rsa_pub_exp, tls->rsa_pub_exp_len );
+ RSA_pub_key_new ( &rsa_ctx, tls->rsa.modulus, tls->rsa.modulus_len,
+ tls->rsa.exponent, tls->rsa.exponent_len );
struct {
uint32_t type_length;
uint16_t encrypted_pre_master_secret_len;
@@ -641,9 +669,9 @@ static int tls_send_client_key_exchange ( struct tls_session *tls ) {
DBGC ( tls, "RSA encrypting plaintext, modulus, exponent:\n" );
DBGC_HD ( tls, &tls->pre_master_secret,
sizeof ( tls->pre_master_secret ) );
- DBGC_HD ( tls, tls->rsa_mod, tls->rsa_mod_len );
- DBGC_HD ( tls, tls->rsa_pub_exp, tls->rsa_pub_exp_len );
- RSA_encrypt ( rsa_ctx, tls->pre_master_secret,
+ DBGC_HD ( tls, tls->rsa.modulus, tls->rsa.modulus_len );
+ DBGC_HD ( tls, tls->rsa.exponent, tls->rsa.exponent_len );
+ RSA_encrypt ( rsa_ctx, ( const uint8_t * ) &tls->pre_master_secret,
sizeof ( tls->pre_master_secret ),
key_xchg.encrypted_pre_master_secret, 0 );
DBGC ( tls, "RSA encrypt done. Ciphertext:\n" );
@@ -685,7 +713,7 @@ static int tls_send_finished ( struct tls_session *tls ) {
htonl ( sizeof ( finished ) -
sizeof ( finished.type_length ) ) );
tls_verify_handshake ( tls, digest );
- tls_prf_label ( tls, tls->master_secret, sizeof ( tls->master_secret ),
+ tls_prf_label ( tls, &tls->master_secret, sizeof ( tls->master_secret ),
finished.verify_data, sizeof ( finished.verify_data ),
"client finished", digest, sizeof ( digest ) );
@@ -761,17 +789,16 @@ static int tls_new_alert ( struct tls_session *tls, void *data, size_t len ) {
}
/**
- * Receive new Server Hello record
+ * Receive new Server Hello handshake record
*
* @v tls TLS session
- * @v data Plaintext record
- * @v len Length of plaintext record
+ * @v data Plaintext handshake record
+ * @v len Length of plaintext handshake record
* @ret rc Return status code
*/
static int tls_new_server_hello ( struct tls_session *tls,
void *data, size_t len ) {
struct {
- uint32_t type_length;
uint16_t version;
uint8_t random[32];
uint8_t session_id_len;
@@ -802,7 +829,7 @@ static int tls_new_server_hello ( struct tls_session *tls,
}
/* Copy out server random bytes */
- memcpy ( tls->server_random, hello_a->random,
+ memcpy ( &tls->server_random, &hello_a->random,
sizeof ( tls->server_random ) );
/* Select cipher suite */
@@ -818,72 +845,74 @@ static int tls_new_server_hello ( struct tls_session *tls,
}
/**
- * Receive new Certificate record
+ * Receive new Certificate handshake record
*
* @v tls TLS session
- * @v data Plaintext record
- * @v len Length of plaintext record
+ * @v data Plaintext handshake record
+ * @v len Length of plaintext handshake record
* @ret rc Return status code
*/
static int tls_new_certificate ( struct tls_session *tls,
void *data, size_t len ) {
struct {
- uint32_t type_length;
uint8_t length[3];
- uint8_t first_cert_length[3];
- uint8_t asn1_start[0];
+ uint8_t certificates[0];
} __attribute__ (( packed )) *certificate = data;
- uint8_t *cert = certificate->asn1_start;
- int offset = 0;
-
- /* FIXME */
- (void) len;
-
- if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0 ||
- asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0 ||
- asn1_skip_obj(cert, &offset, ASN1_EXPLICIT_TAG) ||
- asn1_skip_obj(cert, &offset, ASN1_INTEGER) ||
- asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) ||
- asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) ||
- asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) ||
- asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) ||
- asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0 ||
- asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) ||
- asn1_next_obj(cert, &offset, ASN1_BIT_STRING) < 0) {
- DBGC ( tls, "TLS %p invalid certificate\n", tls );
- DBGC_HD ( tls, cert + offset, 64 );
- return -EPERM;
- }
-
- offset++;
-
- if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0) {
- DBGC ( tls, "TLS %p invalid certificate\n", tls );
- DBGC_HD ( tls, cert + offset, 64 );
- return -EPERM;
+ struct {
+ uint8_t length[3];
+ uint8_t certificate[0];
+ } __attribute__ (( packed )) *element =
+ ( ( void * ) certificate->certificates );
+ size_t elements_len = tls_uint24 ( certificate->length );
+ void *end = ( certificate->certificates + elements_len );
+ struct asn1_cursor cursor;
+ int rc;
+
+ /* Sanity check */
+ if ( end != ( data + len ) ) {
+ DBGC ( tls, "TLS %p received overlength Server Certificate\n",
+ tls );
+ DBGC_HD ( tls, data, len );
+ return -EINVAL;
}
-
- tls->rsa_mod_len = asn1_get_int(cert, &offset, &tls->rsa_mod);
- tls->rsa_pub_exp_len = asn1_get_int(cert, &offset, &tls->rsa_pub_exp);
-
- DBGC_HD ( tls, tls->rsa_mod, tls->rsa_mod_len );
- DBGC_HD ( tls, tls->rsa_pub_exp, tls->rsa_pub_exp_len );
- return 0;
+ /* Traverse certificate chain */
+ do {
+ cursor.data = element->certificate;
+ cursor.len = tls_uint24 ( element->length );
+ if ( ( cursor.data + cursor.len ) > end ) {
+ DBGC ( tls, "TLS %p received corrupt Server "
+ "Certificate\n", tls );
+ DBGC_HD ( tls, data, len );
+ return -EINVAL;
+ }
+
+ // HACK
+ if ( ( rc = x509_rsa_public_key ( &cursor,
+ &tls->rsa ) ) != 0 ) {
+ DBGC ( tls, "TLS %p cannot determine RSA public key: "
+ "%s\n", tls, strerror ( rc ) );
+ return rc;
+ }
+ return 0;
+
+ element = ( cursor.data + cursor.len );
+ } while ( element != end );
+
+ return -EINVAL;
}
/**
- * Receive new Server Hello Done record
+ * Receive new Server Hello Done handshake record
*
* @v tls TLS session
- * @v data Plaintext record
- * @v len Length of plaintext record
+ * @v data Plaintext handshake record
+ * @v len Length of plaintext handshake record
* @ret rc Return status code
*/
static int tls_new_server_hello_done ( struct tls_session *tls,
void *data, size_t len ) {
struct {
- uint32_t type_length;
char next[0];
} __attribute__ (( packed )) *hello_done = data;
void *end = hello_done->next;
@@ -910,11 +939,11 @@ static int tls_new_server_hello_done ( struct tls_session *tls,
}
/**
- * Receive new Finished record
+ * Receive new Finished handshake record
*
* @v tls TLS session
- * @v data Plaintext record
- * @v len Length of plaintext record
+ * @v data Plaintext handshake record
+ * @v len Length of plaintext handshake record
* @ret rc Return status code
*/
static int tls_new_finished ( struct tls_session *tls,
@@ -937,33 +966,47 @@ static int tls_new_finished ( struct tls_session *tls,
*/
static int tls_new_handshake ( struct tls_session *tls,
void *data, size_t len ) {
- uint8_t *type = data;
+ struct {
+ uint8_t type;
+ uint8_t length[3];
+ uint8_t payload[0];
+ } __attribute__ (( packed )) *handshake = data;
+ void *payload = &handshake->payload;
+ size_t payload_len = tls_uint24 ( handshake->length );
+ void *end = ( payload + payload_len );
int rc;
- switch ( *type ) {
+ /* Sanity check */
+ if ( end != ( data + len ) ) {
+ DBGC ( tls, "TLS %p received overlength Handshake\n", tls );
+ DBGC_HD ( tls, data, len );
+ return -EINVAL;
+ }
+
+ switch ( handshake->type ) {
case TLS_SERVER_HELLO:
- rc = tls_new_server_hello ( tls, data, len );
+ rc = tls_new_server_hello ( tls, payload, payload_len );
break;
case TLS_CERTIFICATE:
- rc = tls_new_certificate ( tls, data, len );
+ rc = tls_new_certificate ( tls, payload, payload_len );
break;
case TLS_SERVER_HELLO_DONE:
- rc = tls_new_server_hello_done ( tls, data, len );
+ rc = tls_new_server_hello_done ( tls, payload, payload_len );
break;
case TLS_FINISHED:
- rc = tls_new_finished ( tls, data, len );
+ rc = tls_new_finished ( tls, payload, payload_len );
break;
default:
DBGC ( tls, "TLS %p ignoring handshake type %d\n",
- tls, *type );
+ tls, handshake->type );
rc = 0;
break;
}
/* Add to handshake digest (except for Hello Requests, which
- * are explicitly excludede).
+ * are explicitly excluded).
*/
- if ( *type != TLS_HELLO_REQUEST )
+ if ( handshake->type != TLS_HELLO_REQUEST )
tls_add_handshake ( tls, data, len );
return rc;
@@ -1710,13 +1753,12 @@ int add_tls ( struct xfer_interface *xfer, struct xfer_interface **next ) {
tls_clear_cipher ( tls, &tls->tx_cipherspec_pending );
tls_clear_cipher ( tls, &tls->rx_cipherspec );
tls_clear_cipher ( tls, &tls->rx_cipherspec_pending );
- *( ( uint32_t * ) tls->client_random ) = 0; /* GMT Unix time */
- tls_generate_random ( ( tls->client_random + 4 ),
- ( sizeof ( tls->client_random ) - 4 ) );
- *( ( uint16_t * ) tls->pre_master_secret )
- = htons ( TLS_VERSION_TLS_1_0 );
- tls_generate_random ( ( tls->pre_master_secret + 2 ),
- ( sizeof ( tls->pre_master_secret ) - 2 ) );
+ tls->client_random.gmt_unix_time = 0;
+ tls_generate_random ( &tls->client_random.random,
+ ( sizeof ( tls->client_random.random ) ) );
+ tls->pre_master_secret.version = htons ( TLS_VERSION_TLS_1_0 );
+ tls_generate_random ( &tls->pre_master_secret.random,
+ ( sizeof ( tls->pre_master_secret.random ) ) );
digest_init ( &md5_algorithm, tls->handshake_md5_ctx );
digest_init ( &sha1_algorithm, tls->handshake_sha1_ctx );
tls->tx_state = TLS_TX_CLIENT_HELLO;
diff --git a/gpxe/src/net/udp.c b/gpxe/src/net/udp.c
index 407ea14d..c3a1eba3 100644
--- a/gpxe/src/net/udp.c
+++ b/gpxe/src/net/udp.c
@@ -182,13 +182,13 @@ static void udp_close ( struct udp_connection *udp, int rc ) {
*
* @v udp UDP connection
* @v iobuf I/O buffer
- * @v src_port Source port, or 0 to use default
+ * @v src Source address, or NULL to use default
* @v dest Destination address, or NULL to use default
* @v netdev Network device, or NULL to use default
* @ret rc Return status code
*/
static int udp_tx ( struct udp_connection *udp, struct io_buffer *iobuf,
- unsigned int src_port, struct sockaddr_tcpip *dest,
+ struct sockaddr_tcpip *src, struct sockaddr_tcpip *dest,
struct net_device *netdev ) {
struct udp_header *udphdr;
size_t len;
@@ -201,8 +201,8 @@ static int udp_tx ( struct udp_connection *udp, struct io_buffer *iobuf,
}
/* Fill in default values if not explicitly provided */
- if ( ! src_port )
- src_port = udp->local.st_port;
+ if ( ! src )
+ src = &udp->local;
if ( ! dest )
dest = &udp->peer;
@@ -210,7 +210,7 @@ static int udp_tx ( struct udp_connection *udp, struct io_buffer *iobuf,
udphdr = iob_push ( iobuf, sizeof ( *udphdr ) );
len = iob_len ( iobuf );
udphdr->dest = dest->st_port;
- udphdr->src = src_port;
+ udphdr->src = src->st_port;
udphdr->len = htons ( len );
udphdr->chksum = 0;
udphdr->chksum = tcpip_chksum ( udphdr, len );
@@ -221,7 +221,7 @@ static int udp_tx ( struct udp_connection *udp, struct io_buffer *iobuf,
ntohs ( udphdr->len ) );
/* Send it to the next layer for processing */
- if ( ( rc = tcpip_tx ( iobuf, &udp_protocol, dest, netdev,
+ if ( ( rc = tcpip_tx ( iobuf, &udp_protocol, src, dest, netdev,
&udphdr->chksum ) ) != 0 ) {
DBGC ( udp, "UDP %p could not transmit packet: %s\n",
udp, strerror ( rc ) );
@@ -328,8 +328,7 @@ static int udp_rx ( struct io_buffer *iobuf, struct sockaddr_tcpip *st_src,
memset ( &meta, 0, sizeof ( meta ) );
meta.src = ( struct sockaddr * ) st_src;
meta.dest = ( struct sockaddr * ) st_dest;
- rc = xfer_deliver_iob_meta ( &udp->xfer, iobuf, &meta );
- iobuf = NULL;
+ rc = xfer_deliver_iob_meta ( &udp->xfer, iob_disown ( iobuf ), &meta );
done:
free_iob ( iobuf );
@@ -391,7 +390,7 @@ static struct io_buffer * udp_alloc_iob ( struct xfer_interface *xfer,
*
* @v xfer Data transfer interface
* @v iobuf Datagram I/O buffer
- * @v meta Data transfer metadata, or NULL
+ * @v meta Data transfer metadata
* @ret rc Return status code
*/
static int udp_xfer_deliver_iob ( struct xfer_interface *xfer,
@@ -399,22 +398,10 @@ static int udp_xfer_deliver_iob ( struct xfer_interface *xfer,
struct xfer_metadata *meta ) {
struct udp_connection *udp =
container_of ( xfer, struct udp_connection, xfer );
- struct sockaddr_tcpip *src;
- struct sockaddr_tcpip *dest = NULL;
- struct net_device *netdev = NULL;
- unsigned int src_port = 0;
-
- /* Apply xfer metadata */
- if ( meta ) {
- src = ( struct sockaddr_tcpip * ) meta->src;
- if ( src )
- src_port = src->st_port;
- dest = ( struct sockaddr_tcpip * ) meta->dest;
- netdev = meta->netdev;
- }
/* Transmit data, if possible */
- udp_tx ( udp, iobuf, src_port, dest, netdev );
+ udp_tx ( udp, iobuf, ( ( struct sockaddr_tcpip * ) meta->src ),
+ ( ( struct sockaddr_tcpip * ) meta->dest ), meta->netdev );
return 0;
}
@@ -438,12 +425,13 @@ static struct xfer_interface_operations udp_xfer_operations = {
/** UDP socket opener */
struct socket_opener udp_socket_opener __socket_opener = {
- .semantics = SOCK_DGRAM,
+ .semantics = UDP_SOCK_DGRAM,
.family = AF_INET,
.open = udp_open,
};
-char UDP_SOCK_DGRAM[1];
+/** Linkage hack */
+int udp_sock_dgram = UDP_SOCK_DGRAM;
/**
* Open UDP URI
diff --git a/gpxe/src/net/udp/dhcp.c b/gpxe/src/net/udp/dhcp.c
index ab751cd5..ab843ce1 100644
--- a/gpxe/src/net/udp/dhcp.c
+++ b/gpxe/src/net/udp/dhcp.c
@@ -19,6 +19,7 @@
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
+#include <ctype.h>
#include <errno.h>
#include <assert.h>
#include <byteswap.h>
@@ -32,12 +33,12 @@
#include <gpxe/tcpip.h>
#include <gpxe/ip.h>
#include <gpxe/uuid.h>
-#include <gpxe/dhcp.h>
#include <gpxe/timer.h>
#include <gpxe/settings.h>
#include <gpxe/dhcp.h>
#include <gpxe/dhcpopts.h>
#include <gpxe/dhcppkt.h>
+#include <gpxe/features.h>
/** @file
*
@@ -45,6 +46,9 @@
*
*/
+struct dhcp_session;
+static int dhcp_tx ( struct dhcp_session *dhcp );
+
/**
* DHCP operation types
*
@@ -73,6 +77,8 @@ static uint8_t dhcp_request_options_data[] = {
DHCP_STRING ( 'P', 'X', 'E', 'C', 'l', 'i', 'e', 'n', 't', ':',
'A', 'r', 'c', 'h', ':', '0', '0', '0', '0', '0', ':',
'U', 'N', 'D', 'I', ':', '0', '0', '2', '0', '0', '1' ),
+ DHCP_USER_CLASS_ID,
+ DHCP_STRING ( 'g', 'P', 'X', 'E' ),
DHCP_PARAMETER_REQUEST_LIST,
DHCP_OPTION ( DHCP_SUBNET_MASK, DHCP_ROUTERS, DHCP_DNS_SERVERS,
DHCP_LOG_SERVERS, DHCP_HOST_NAME, DHCP_DOMAIN_NAME,
@@ -82,44 +88,28 @@ static uint8_t dhcp_request_options_data[] = {
DHCP_END
};
-/** Options common to all DHCP requests */
-static struct dhcp_options dhcp_request_options = {
- .data = dhcp_request_options_data,
- .max_len = sizeof ( dhcp_request_options_data ),
- .len = sizeof ( dhcp_request_options_data ),
-};
-
/** DHCP feature codes */
static uint8_t dhcp_features[0] __table_start ( uint8_t, dhcp_features );
static uint8_t dhcp_features_end[0] __table_end ( uint8_t, dhcp_features );
-/** DHCP network device descriptor */
-struct dhcp_netdev_desc {
- /** Bus type ID */
- uint8_t type;
- /** Vendor ID */
- uint16_t vendor;
- /** Device ID */
- uint16_t device;
-} __attribute__ (( packed ));
-
-/** DHCP client identifier */
-struct dhcp_client_id {
- /** Link-layer protocol */
- uint8_t ll_proto;
- /** Link-layer address */
- uint8_t ll_addr[MAX_LL_ADDR_LEN];
-} __attribute__ (( packed ));
-
-/** DHCP client UUID */
-struct dhcp_client_uuid {
- /** Identifier type */
- uint8_t type;
- /** UUID */
- union uuid uuid;
-} __attribute__ (( packed ));
-
-#define DHCP_CLIENT_UUID_TYPE 0
+/** Version number feature */
+FEATURE_VERSION ( VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH );
+
+/** DHCP server address setting */
+struct setting dhcp_server_setting __setting = {
+ .name = "dhcp-server",
+ .description = "DHCP server address",
+ .tag = DHCP_SERVER_IDENTIFIER,
+ .type = &setting_type_ipv4,
+};
+
+/** DHCP user class setting */
+struct setting user_class_setting __setting = {
+ .name = "user-class",
+ .description = "User class identifier",
+ .tag = DHCP_USER_CLASS_ID,
+ .type = &setting_type_string,
+};
/**
* Name a DHCP packet type
@@ -161,211 +151,658 @@ static uint32_t dhcp_xid ( struct net_device *netdev ) {
/****************************************************************************
*
- * DHCP settings
+ * DHCP session
*
*/
-/** A DHCP settings block */
-struct dhcp_settings {
+struct dhcp_session;
+
+/** DHCP session state operations */
+struct dhcp_session_state {
+ /** State name */
+ const char *name;
+ /**
+ * Construct transmitted packet
+ *
+ * @v dhcp DHCP session
+ * @v dhcppkt DHCP packet
+ * @v peer Destination address
+ */
+ int ( * tx ) ( struct dhcp_session *dhcp,
+ struct dhcp_packet *dhcppkt,
+ struct sockaddr_in *peer );
+ /** Handle received packet
+ *
+ * @v dhcp DHCP session
+ * @v dhcppkt DHCP packet
+ * @v peer DHCP server address
+ * @v msgtype DHCP message type
+ * @v server_id DHCP server ID
+ */
+ void ( * rx ) ( struct dhcp_session *dhcp,
+ struct dhcp_packet *dhcppkt,
+ struct sockaddr_in *peer,
+ uint8_t msgtype, struct in_addr server_id );
+ /** Handle timer expiry
+ *
+ * @v dhcp DHCP session
+ */
+ void ( * expired ) ( struct dhcp_session *dhcp );
+ /** Transmitted message type */
+ uint8_t tx_msgtype;
+ /** Apply minimum timeout */
+ uint8_t apply_min_timeout;
+};
+
+static struct dhcp_session_state dhcp_state_discover;
+static struct dhcp_session_state dhcp_state_request;
+static struct dhcp_session_state dhcp_state_proxy;
+static struct dhcp_session_state dhcp_state_pxebs;
+
+/** A DHCP session */
+struct dhcp_session {
/** Reference counter */
struct refcnt refcnt;
- /** DHCP packet */
- struct dhcp_packet dhcppkt;
- /** Setting interface */
- struct settings settings;
+ /** Job control interface */
+ struct job_interface job;
+ /** Data transfer interface */
+ struct xfer_interface xfer;
+
+ /** Network device being configured */
+ struct net_device *netdev;
+ /** Local socket address */
+ struct sockaddr_in local;
+ /** State of the session */
+ struct dhcp_session_state *state;
+
+ /** Offered IP address */
+ struct in_addr offer;
+ /** DHCP server */
+ struct in_addr server;
+ /** DHCP offer priority */
+ int priority;
+
+ /** ProxyDHCP protocol extensions should be ignored */
+ int no_pxedhcp;
+ /** ProxyDHCP server */
+ struct in_addr proxy_server;
+ /** ProxyDHCP server priority */
+ int proxy_priority;
+
+ /** PXE Boot Server type */
+ uint16_t pxe_type;
+ /** List of PXE Boot Servers to attempt */
+ struct in_addr *pxe_attempt;
+ /** List of PXE Boot Servers to accept */
+ struct in_addr *pxe_accept;
+
+ /** Retransmission timer */
+ struct retry_timer timer;
+ /** Start time of the current state (in ticks) */
+ unsigned long start;
};
/**
- * Increment reference count on DHCP settings block
+ * Free DHCP session
*
- * @v dhcpset DHCP settings block
- * @ret dhcpset DHCP settings block
+ * @v refcnt Reference counter
*/
-static inline __attribute__ (( always_inline )) struct dhcp_settings *
-dhcpset_get ( struct dhcp_settings *dhcpset ) {
- ref_get ( &dhcpset->refcnt );
- return dhcpset;
+static void dhcp_free ( struct refcnt *refcnt ) {
+ struct dhcp_session *dhcp =
+ container_of ( refcnt, struct dhcp_session, refcnt );
+
+ netdev_put ( dhcp->netdev );
+ free ( dhcp );
}
/**
- * Decrement reference count on DHCP settings block
+ * Mark DHCP session as complete
*
- * @v dhcpset DHCP settings block
+ * @v dhcp DHCP session
+ * @v rc Return status code
*/
-static inline __attribute__ (( always_inline )) void
-dhcpset_put ( struct dhcp_settings *dhcpset ) {
- ref_put ( &dhcpset->refcnt );
+static void dhcp_finished ( struct dhcp_session *dhcp, int rc ) {
+
+ /* Block futher incoming messages */
+ job_nullify ( &dhcp->job );
+ xfer_nullify ( &dhcp->xfer );
+
+ /* Stop retry timer */
+ stop_timer ( &dhcp->timer );
+
+ /* Free resources and close interfaces */
+ xfer_close ( &dhcp->xfer, rc );
+ job_done ( &dhcp->job, rc );
}
/**
- * Store value of DHCP setting
+ * Transition to new DHCP session state
*
- * @v settings Settings block
- * @v setting Setting to store
- * @v data Setting data, or NULL to clear setting
- * @v len Length of setting data
- * @ret rc Return status code
+ * @v dhcp DHCP session
+ * @v state New session state
*/
-static int dhcpset_store ( struct settings *settings, struct setting *setting,
- const void *data, size_t len ) {
- struct dhcp_settings *dhcpset =
- container_of ( settings, struct dhcp_settings, settings );
+static void dhcp_set_state ( struct dhcp_session *dhcp,
+ struct dhcp_session_state *state ) {
- return dhcppkt_store ( &dhcpset->dhcppkt, setting->tag, data, len );
+ DBGC ( dhcp, "DHCP %p entering %s state\n", dhcp, state->name );
+ dhcp->state = state;
+ dhcp->start = currticks();
+ stop_timer ( &dhcp->timer );
+ dhcp->timer.min_timeout =
+ ( state->apply_min_timeout ? DHCP_MIN_TIMEOUT : 0 );
+ dhcp->timer.max_timeout = DHCP_MAX_TIMEOUT;
+ start_timer_nodelay ( &dhcp->timer );
}
+/****************************************************************************
+ *
+ * DHCP state machine
+ *
+ */
+
/**
- * Fetch value of DHCP setting
+ * Construct transmitted packet for DHCP discovery
*
- * @v settings Settings block, or NULL to search all blocks
- * @v setting Setting to fetch
- * @v data Buffer to fill with setting data
- * @v len Length of buffer
- * @ret len Length of setting data, or negative error
+ * @v dhcp DHCP session
+ * @v dhcppkt DHCP packet
+ * @v peer Destination address
*/
-static int dhcpset_fetch ( struct settings *settings, struct setting *setting,
- void *data, size_t len ) {
- struct dhcp_settings *dhcpset =
- container_of ( settings, struct dhcp_settings, settings );
+static int dhcp_discovery_tx ( struct dhcp_session *dhcp,
+ struct dhcp_packet *dhcppkt __unused,
+ struct sockaddr_in *peer ) {
+
+ DBGC ( dhcp, "DHCP %p DHCPDISCOVER\n", dhcp );
+
+ /* Set server address */
+ peer->sin_addr.s_addr = INADDR_BROADCAST;
+ peer->sin_port = htons ( BOOTPS_PORT );
- return dhcppkt_fetch ( &dhcpset->dhcppkt, setting->tag, data, len );
+ return 0;
}
-/** DHCP settings operations */
-static struct settings_operations dhcpset_settings_operations = {
- .store = dhcpset_store,
- .fetch = dhcpset_fetch,
-};
+/**
+ * Handle received packet during DHCP discovery
+ *
+ * @v dhcp DHCP session
+ * @v dhcppkt DHCP packet
+ * @v peer DHCP server address
+ * @v msgtype DHCP message type
+ * @v server_id DHCP server ID
+ */
+static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
+ struct dhcp_packet *dhcppkt,
+ struct sockaddr_in *peer, uint8_t msgtype,
+ struct in_addr server_id ) {
+ struct in_addr ip;
+ char vci[9]; /* "PXEClient" */
+ int vci_len;
+ int has_pxeclient;
+ int8_t priority = 0;
+ uint8_t no_pxedhcp = 0;
+ unsigned long elapsed;
+
+ DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
+ dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
+ ntohs ( peer->sin_port ) );
+ if ( server_id.s_addr != peer->sin_addr.s_addr )
+ DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
+
+ /* Identify offered IP address */
+ ip = dhcppkt->dhcphdr->yiaddr;
+ if ( ip.s_addr )
+ DBGC ( dhcp, " for %s", inet_ntoa ( ip ) );
+
+ /* Identify "PXEClient" vendor class */
+ vci_len = dhcppkt_fetch ( dhcppkt, DHCP_VENDOR_CLASS_ID,
+ vci, sizeof ( vci ) );
+ has_pxeclient = ( ( vci_len >= ( int ) sizeof ( vci ) ) &&
+ ( strncmp ( "PXEClient", vci, sizeof (vci) ) == 0 ));
+ if ( has_pxeclient )
+ DBGC ( dhcp, " pxe" );
+
+ /* Identify priority */
+ dhcppkt_fetch ( dhcppkt, DHCP_EB_PRIORITY, &priority,
+ sizeof ( priority ) );
+ if ( priority )
+ DBGC ( dhcp, " pri %d", priority );
+
+ /* Identify ignore-PXE flag */
+ dhcppkt_fetch ( dhcppkt, DHCP_EB_NO_PXEDHCP, &no_pxedhcp,
+ sizeof ( no_pxedhcp ) );
+ if ( no_pxedhcp )
+ DBGC ( dhcp, " nopxe" );
+ DBGC ( dhcp, "\n" );
+
+ /* Select as DHCP offer, if applicable */
+ if ( ip.s_addr && ( peer->sin_port == htons ( BOOTPS_PORT ) ) &&
+ ( ( msgtype == DHCPOFFER ) || ( ! msgtype /* BOOTP */ ) ) &&
+ ( priority >= dhcp->priority ) ) {
+ dhcp->offer = ip;
+ dhcp->server = server_id;
+ dhcp->priority = priority;
+ dhcp->no_pxedhcp = no_pxedhcp;
+ }
+
+ /* Select as ProxyDHCP offer, if applicable */
+ if ( has_pxeclient && ( msgtype == DHCPOFFER ) &&
+ ( priority >= dhcp->proxy_priority ) ) {
+ dhcp->proxy_server = server_id;
+ dhcp->proxy_priority = priority;
+ }
+
+ /* We can exit the discovery state when we have a valid
+ * DHCPOFFER, and either:
+ *
+ * o The DHCPOFFER instructs us to ignore ProxyDHCPOFFERs, or
+ * o We have a valid ProxyDHCPOFFER, or
+ * o We have allowed sufficient time for ProxyDHCPOFFERs.
+ */
+
+ /* If we don't yet have a DHCPOFFER, do nothing */
+ if ( ! dhcp->offer.s_addr )
+ return;
+
+ /* If we can't yet transition to DHCPREQUEST, do nothing */
+ elapsed = ( currticks() - dhcp->start );
+ if ( ! ( dhcp->no_pxedhcp || dhcp->proxy_server.s_addr ||
+ ( elapsed > PROXYDHCP_MAX_TIMEOUT ) ) )
+ return;
+
+ /* Transition to DHCPREQUEST */
+ dhcp_set_state ( dhcp, &dhcp_state_request );
+}
/**
- * Create DHCP setting block
+ * Handle timer expiry during DHCP discovery
*
- * @v dhcphdr DHCP packet
- * @v len Length of DHCP packet
- * @ret dhcpset DHCP settings block
+ * @v dhcp DHCP session
*/
-static struct dhcp_settings * dhcpset_create ( const struct dhcphdr *dhcphdr,
- size_t len ) {
- struct dhcp_settings *dhcpset;
- void *data;
-
- dhcpset = zalloc ( sizeof ( *dhcpset ) + len );
- if ( dhcpset ) {
- data = ( ( ( void * ) dhcpset ) + sizeof ( *dhcpset ) );
- memcpy ( data, dhcphdr, len );
- dhcppkt_init ( &dhcpset->dhcppkt, data, len );
- settings_init ( &dhcpset->settings,
- &dhcpset_settings_operations, &dhcpset->refcnt,
- DHCP_SETTINGS_NAME );
+static void dhcp_discovery_expired ( struct dhcp_session *dhcp ) {
+ unsigned long elapsed = ( currticks() - dhcp->start );
+
+ /* Give up waiting for ProxyDHCP before we reach the failure point */
+ if ( dhcp->offer.s_addr && ( elapsed > PROXYDHCP_MAX_TIMEOUT ) ) {
+ dhcp_set_state ( dhcp, &dhcp_state_request );
+ return;
}
- return dhcpset;
+
+ /* Otherwise, retransmit current packet */
+ dhcp_tx ( dhcp );
}
-/** DHCP server address setting */
-struct setting dhcp_server_setting __setting = {
- .name = "dhcp-server",
- .description = "DHCP server address",
- .tag = DHCP_SERVER_IDENTIFIER,
- .type = &setting_type_ipv4,
+/** DHCP discovery state operations */
+static struct dhcp_session_state dhcp_state_discover = {
+ .name = "discovery",
+ .tx = dhcp_discovery_tx,
+ .rx = dhcp_discovery_rx,
+ .expired = dhcp_discovery_expired,
+ .tx_msgtype = DHCPDISCOVER,
+ .apply_min_timeout = 1,
};
-/****************************************************************************
+/**
+ * Construct transmitted packet for DHCP request
*
- * DHCP session
+ * @v dhcp DHCP session
+ * @v dhcppkt DHCP packet
+ * @v peer Destination address
+ */
+static int dhcp_request_tx ( struct dhcp_session *dhcp,
+ struct dhcp_packet *dhcppkt,
+ struct sockaddr_in *peer ) {
+ int rc;
+
+ DBGC ( dhcp, "DHCP %p DHCPREQUEST to %s:%d",
+ dhcp, inet_ntoa ( dhcp->server ), BOOTPS_PORT );
+ DBGC ( dhcp, " for %s\n", inet_ntoa ( dhcp->offer ) );
+
+ /* Set server ID */
+ if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_SERVER_IDENTIFIER,
+ &dhcp->server,
+ sizeof ( dhcp->server ) ) ) != 0 )
+ return rc;
+
+ /* Set requested IP address */
+ if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_REQUESTED_ADDRESS,
+ &dhcp->offer,
+ sizeof ( dhcp->offer ) ) ) != 0 )
+ return rc;
+
+ /* Set server address */
+ peer->sin_addr.s_addr = INADDR_BROADCAST;
+ peer->sin_port = htons ( BOOTPS_PORT );
+
+ return 0;
+}
+
+/**
+ * Handle received packet during DHCP request
+ *
+ * @v dhcp DHCP session
+ * @v dhcppkt DHCP packet
+ * @v peer DHCP server address
+ * @v msgtype DHCP message type
+ * @v server_id DHCP server ID
+ */
+static void dhcp_request_rx ( struct dhcp_session *dhcp,
+ struct dhcp_packet *dhcppkt,
+ struct sockaddr_in *peer, uint8_t msgtype,
+ struct in_addr server_id ) {
+ struct in_addr ip;
+ struct settings *parent;
+ int rc;
+
+ DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
+ dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
+ ntohs ( peer->sin_port ) );
+ if ( server_id.s_addr != peer->sin_addr.s_addr )
+ DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
+
+ /* Identify leased IP address */
+ ip = dhcppkt->dhcphdr->yiaddr;
+ if ( ip.s_addr )
+ DBGC ( dhcp, " for %s", inet_ntoa ( ip ) );
+ DBGC ( dhcp, "\n" );
+
+ /* Filter out unacceptable responses */
+ if ( peer->sin_port != htons ( BOOTPS_PORT ) )
+ return;
+ if ( msgtype /* BOOTP */ && ( msgtype != DHCPACK ) )
+ return;
+ if ( server_id.s_addr != dhcp->server.s_addr )
+ return;
+
+ /* Record assigned address */
+ dhcp->local.sin_addr = ip;
+
+ /* Register settings */
+ parent = netdev_settings ( dhcp->netdev );
+ if ( ( rc = register_settings ( &dhcppkt->settings, parent ) ) != 0 ){
+ DBGC ( dhcp, "DHCP %p could not register settings: %s\n",
+ dhcp, strerror ( rc ) );
+ dhcp_finished ( dhcp, rc );
+ return;
+ }
+
+ /* Start ProxyDHCPREQUEST if applicable */
+ if ( dhcp->proxy_server.s_addr && ( ! dhcp->no_pxedhcp ) ) {
+ dhcp_set_state ( dhcp, &dhcp_state_proxy );
+ return;
+ }
+
+ /* Terminate DHCP */
+ dhcp_finished ( dhcp, 0 );
+}
+
+/**
+ * Handle timer expiry during DHCP discovery
*
+ * @v dhcp DHCP session
*/
+static void dhcp_request_expired ( struct dhcp_session *dhcp ) {
+
+ /* Retransmit current packet */
+ dhcp_tx ( dhcp );
+}
-/** DHCP session states */
-enum dhcp_session_state {
- /** Sending DHCPDISCOVERs, collecting DHCPOFFERs and ProxyDHCPOFFERs */
- DHCP_STATE_DISCOVER = 0,
- /** Sending DHCPREQUESTs, waiting for DHCPACK */
- DHCP_STATE_REQUEST,
- /** Sending ProxyDHCPREQUESTs, waiting for ProxyDHCPACK */
- DHCP_STATE_PROXYREQUEST,
+/** DHCP request state operations */
+static struct dhcp_session_state dhcp_state_request = {
+ .name = "request",
+ .tx = dhcp_request_tx,
+ .rx = dhcp_request_rx,
+ .expired = dhcp_request_expired,
+ .tx_msgtype = DHCPREQUEST,
+ .apply_min_timeout = 0,
};
/**
- * Name a DHCP session state
+ * Construct transmitted packet for ProxyDHCP request
+ *
+ * @v dhcp DHCP session
+ * @v dhcppkt DHCP packet
+ * @v peer Destination address
+ */
+static int dhcp_proxy_tx ( struct dhcp_session *dhcp,
+ struct dhcp_packet *dhcppkt,
+ struct sockaddr_in *peer ) {
+ int rc;
+
+ DBGC ( dhcp, "DHCP %p ProxyDHCP REQUEST to %s:%d\n",
+ dhcp, inet_ntoa ( dhcp->proxy_server ), PXE_PORT );
+
+ /* Set server ID */
+ if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_SERVER_IDENTIFIER,
+ &dhcp->proxy_server,
+ sizeof ( dhcp->proxy_server ) ) ) != 0 )
+ return rc;
+
+ /* Set server address */
+ peer->sin_addr = dhcp->proxy_server;
+ peer->sin_port = htons ( PXE_PORT );
+
+ return 0;
+}
+
+/**
+ * Handle received packet during ProxyDHCP request
*
- * @v state DHCP session state
- * @ret string DHCP session state name
+ * @v dhcp DHCP session
+ * @v dhcppkt DHCP packet
+ * @v peer DHCP server address
+ * @v msgtype DHCP message type
+ * @v server_id DHCP server ID
*/
-static inline const char * dhcp_state_name ( enum dhcp_session_state state ) {
- switch ( state ) {
- case DHCP_STATE_DISCOVER: return "DHCPDISCOVER";
- case DHCP_STATE_REQUEST: return "DHCPREQUEST";
- case DHCP_STATE_PROXYREQUEST: return "ProxyDHCPREQUEST";
- default: return "<invalid>";
+static void dhcp_proxy_rx ( struct dhcp_session *dhcp,
+ struct dhcp_packet *dhcppkt,
+ struct sockaddr_in *peer, uint8_t msgtype,
+ struct in_addr server_id ) {
+ int rc;
+
+ DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
+ dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
+ ntohs ( peer->sin_port ) );
+ if ( server_id.s_addr != peer->sin_addr.s_addr )
+ DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
+ DBGC ( dhcp, "\n" );
+
+ /* Filter out unacceptable responses */
+ if ( peer->sin_port != htons ( PXE_PORT ) )
+ return;
+ if ( msgtype != DHCPACK )
+ return;
+ if ( server_id.s_addr /* Linux PXE server omits server ID */ &&
+ ( server_id.s_addr != dhcp->proxy_server.s_addr ) )
+ return;
+
+ /* Register settings */
+ dhcppkt->settings.name = PROXYDHCP_SETTINGS_NAME;
+ if ( ( rc = register_settings ( &dhcppkt->settings, NULL ) ) != 0 ) {
+ DBGC ( dhcp, "DHCP %p could not register settings: %s\n",
+ dhcp, strerror ( rc ) );
+ dhcp_finished ( dhcp, rc );
+ return;
}
+
+ /* Terminate DHCP */
+ dhcp_finished ( dhcp, 0 );
}
-/** A DHCP session */
-struct dhcp_session {
- /** Reference counter */
- struct refcnt refcnt;
- /** Job control interface */
- struct job_interface job;
- /** Data transfer interface */
- struct xfer_interface xfer;
+/**
+ * Handle timer expiry during ProxyDHCP request
+ *
+ * @v dhcp DHCP session
+ */
+static void dhcp_proxy_expired ( struct dhcp_session *dhcp ) {
+ unsigned long elapsed = ( currticks() - dhcp->start );
- /** Network device being configured */
- struct net_device *netdev;
+ /* Give up waiting for ProxyDHCP before we reach the failure point */
+ if ( elapsed > PROXYDHCP_MAX_TIMEOUT ) {
+ dhcp_finished ( dhcp, 0 );
+ return;
+ }
- /** State of the session
- *
- * This is a value for the @c DHCP_MESSAGE_TYPE option
- * (e.g. @c DHCPDISCOVER).
- */
- enum dhcp_session_state state;
- /** DHCPOFFER obtained during DHCPDISCOVER */
- struct dhcp_settings *dhcpoffer;
- /** ProxyDHCPOFFER obtained during DHCPDISCOVER */
- struct dhcp_settings *proxydhcpoffer;
- /** Retransmission timer */
- struct retry_timer timer;
- /** Start time of the current state (in ticks) */
- unsigned long start;
+ /* Retransmit current packet */
+ dhcp_tx ( dhcp );
+}
+
+/** ProxyDHCP request state operations */
+static struct dhcp_session_state dhcp_state_proxy = {
+ .name = "ProxyDHCP",
+ .tx = dhcp_proxy_tx,
+ .rx = dhcp_proxy_rx,
+ .expired = dhcp_proxy_expired,
+ .tx_msgtype = DHCPREQUEST,
+ .apply_min_timeout = 0,
};
/**
- * Free DHCP session
+ * Construct transmitted packet for PXE Boot Server Discovery
*
- * @v refcnt Reference counter
+ * @v dhcp DHCP session
+ * @v dhcppkt DHCP packet
+ * @v peer Destination address
*/
-static void dhcp_free ( struct refcnt *refcnt ) {
- struct dhcp_session *dhcp =
- container_of ( refcnt, struct dhcp_session, refcnt );
+static int dhcp_pxebs_tx ( struct dhcp_session *dhcp,
+ struct dhcp_packet *dhcppkt,
+ struct sockaddr_in *peer ) {
+ struct dhcp_pxe_boot_menu_item menu_item = { 0, 0 };
+ int rc;
- netdev_put ( dhcp->netdev );
- dhcpset_put ( dhcp->dhcpoffer );
- dhcpset_put ( dhcp->proxydhcpoffer );
- free ( dhcp );
+ DBGC ( dhcp, "DHCP %p PXEBS REQUEST to %s:%d for type %d\n",
+ dhcp, inet_ntoa ( *(dhcp->pxe_attempt) ), PXE_PORT,
+ ntohs ( dhcp->pxe_type ) );
+
+ /* Set boot menu item */
+ menu_item.type = dhcp->pxe_type;
+ if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_PXE_BOOT_MENU_ITEM,
+ &menu_item, sizeof ( menu_item ) ) ) != 0 )
+ return rc;
+
+ /* Set server address */
+ peer->sin_addr = *(dhcp->pxe_attempt);
+ peer->sin_port = htons ( PXE_PORT );
+
+ return 0;
}
/**
- * Mark DHCP session as complete
+ * Check to see if PXE Boot Server address is acceptable
*
* @v dhcp DHCP session
- * @v rc Return status code
+ * @v bs Boot Server address
+ * @ret accept Boot Server is acceptable
*/
-static void dhcp_finished ( struct dhcp_session *dhcp, int rc ) {
+static int dhcp_pxebs_accept ( struct dhcp_session *dhcp,
+ struct in_addr bs ) {
+ struct in_addr *accept;
+
+ /* Accept if we have no acceptance filter */
+ if ( ! dhcp->pxe_accept )
+ return 1;
+
+ /* Scan through acceptance list */
+ for ( accept = dhcp->pxe_accept ; accept->s_addr ; accept++ ) {
+ if ( accept->s_addr == bs.s_addr )
+ return 1;
+ }
- /* Block futher incoming messages */
- job_nullify ( &dhcp->job );
- xfer_nullify ( &dhcp->xfer );
+ DBGC ( dhcp, "DHCP %p rejecting server %s\n",
+ dhcp, inet_ntoa ( bs ) );
+ return 0;
+}
- /* Stop retry timer */
- stop_timer ( &dhcp->timer );
+/**
+ * Handle received packet during PXE Boot Server Discovery
+ *
+ * @v dhcp DHCP session
+ * @v dhcppkt DHCP packet
+ * @v peer DHCP server address
+ * @v msgtype DHCP message type
+ * @v server_id DHCP server ID
+ */
+static void dhcp_pxebs_rx ( struct dhcp_session *dhcp,
+ struct dhcp_packet *dhcppkt,
+ struct sockaddr_in *peer, uint8_t msgtype,
+ struct in_addr server_id ) {
+ struct dhcp_pxe_boot_menu_item menu_item = { 0, 0 };
+ int rc;
- /* Free resources and close interfaces */
- xfer_close ( &dhcp->xfer, rc );
- job_done ( &dhcp->job, rc );
+ DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
+ dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
+ ntohs ( peer->sin_port ) );
+ if ( server_id.s_addr != peer->sin_addr.s_addr )
+ DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
+
+ /* Identify boot menu item */
+ dhcppkt_fetch ( dhcppkt, DHCP_PXE_BOOT_MENU_ITEM,
+ &menu_item, sizeof ( menu_item ) );
+ if ( menu_item.type )
+ DBGC ( dhcp, " for type %d", ntohs ( menu_item.type ) );
+ DBGC ( dhcp, "\n" );
+
+ /* Filter out unacceptable responses */
+ if ( peer->sin_port != htons ( PXE_PORT ) )
+ return;
+ if ( msgtype != DHCPACK )
+ return;
+ if ( menu_item.type != dhcp->pxe_type )
+ return;
+ if ( ! dhcp_pxebs_accept ( dhcp, ( server_id.s_addr ?
+ server_id : peer->sin_addr ) ) )
+ return;
+
+ /* Register settings */
+ dhcppkt->settings.name = PXEBS_SETTINGS_NAME;
+ if ( ( rc = register_settings ( &dhcppkt->settings, NULL ) ) != 0 ) {
+ DBGC ( dhcp, "DHCP %p could not register settings: %s\n",
+ dhcp, strerror ( rc ) );
+ dhcp_finished ( dhcp, rc );
+ return;
+ }
+
+ /* Terminate DHCP */
+ dhcp_finished ( dhcp, 0 );
}
+/**
+ * Handle timer expiry during PXE Boot Server Discovery
+ *
+ * @v dhcp DHCP session
+ */
+static void dhcp_pxebs_expired ( struct dhcp_session *dhcp ) {
+ unsigned long elapsed = ( currticks() - dhcp->start );
+
+ /* Give up waiting before we reach the failure point, and fail
+ * over to the next server in the attempt list
+ */
+ if ( elapsed > PXEBS_MAX_TIMEOUT ) {
+ dhcp->pxe_attempt++;
+ if ( dhcp->pxe_attempt->s_addr ) {
+ dhcp_set_state ( dhcp, &dhcp_state_pxebs );
+ return;
+ } else {
+ dhcp_finished ( dhcp, -ETIMEDOUT );
+ return;
+ }
+ }
+
+ /* Retransmit current packet */
+ dhcp_tx ( dhcp );
+}
+
+/** PXE Boot Server Discovery state operations */
+static struct dhcp_session_state dhcp_state_pxebs = {
+ .name = "PXEBS",
+ .tx = dhcp_pxebs_tx,
+ .rx = dhcp_pxebs_rx,
+ .expired = dhcp_pxebs_expired,
+ .tx_msgtype = DHCPREQUEST,
+ .apply_min_timeout = 1,
+};
+
/****************************************************************************
*
- * Data transfer interface
+ * Packet construction
*
*/
@@ -376,24 +813,23 @@ static void dhcp_finished ( struct dhcp_session *dhcp, int rc ) {
* @v netdev Network device
* @v msgtype DHCP message type
* @v options Initial options to include (or NULL)
+ * @v options_len Length of initial options
* @v data Buffer for DHCP packet
* @v max_len Size of DHCP packet buffer
* @ret rc Return status code
*
- * Creates a DHCP packet in the specified buffer, and fills out a @c
- * dhcp_packet structure.
+ * Creates a DHCP packet in the specified buffer, and initialise a
+ * DHCP packet structure.
*/
int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
struct net_device *netdev, uint8_t msgtype,
- struct dhcp_options *options,
+ const void *options, size_t options_len,
void *data, size_t max_len ) {
struct dhcphdr *dhcphdr = data;
- size_t options_len;
unsigned int hlen;
int rc;
/* Sanity check */
- options_len = ( options ? options->len : 0 );
if ( max_len < ( sizeof ( *dhcphdr ) + options_len ) )
return -ENOSPC;
@@ -413,7 +849,7 @@ int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
}
dhcphdr->hlen = hlen;
memcpy ( dhcphdr->chaddr, netdev->ll_addr, hlen );
- memcpy ( dhcphdr->options, options->data, options_len );
+ memcpy ( dhcphdr->options, options, options_len );
/* Initialise DHCP packet structure */
memset ( dhcppkt, 0, sizeof ( *dhcppkt ) );
@@ -432,30 +868,32 @@ int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
*
* @v dhcppkt DHCP packet structure to fill in
* @v netdev Network device
+ * @v msgtype DHCP message type
* @v ciaddr Client IP address
- * @v offer DHCP offer, if applicable
* @v data Buffer for DHCP packet
* @v max_len Size of DHCP packet buffer
* @ret rc Return status code
+ *
+ * Creates a DHCP request packet in the specified buffer, and
+ * initialise a DHCP packet structure.
*/
int dhcp_create_request ( struct dhcp_packet *dhcppkt,
- struct net_device *netdev, struct in_addr ciaddr,
- struct dhcp_packet *offer,
- void *data, size_t max_len ) {
+ struct net_device *netdev, unsigned int msgtype,
+ struct in_addr ciaddr, void *data, size_t max_len ) {
struct device_description *desc = &netdev->dev->desc;
struct dhcp_netdev_desc dhcp_desc;
struct dhcp_client_id client_id;
struct dhcp_client_uuid client_uuid;
- unsigned int msgtype;
size_t dhcp_features_len;
size_t ll_addr_len;
+ ssize_t len;
int rc;
/* Create DHCP packet */
- msgtype = ( offer ? DHCPREQUEST : DHCPDISCOVER );
if ( ( rc = dhcp_create_packet ( dhcppkt, netdev, msgtype,
- &dhcp_request_options, data,
- max_len ) ) != 0 ) {
+ dhcp_request_options_data,
+ sizeof ( dhcp_request_options_data ),
+ data, max_len ) ) != 0 ) {
DBG ( "DHCP could not create DHCP packet: %s\n",
strerror ( rc ) );
return rc;
@@ -464,32 +902,6 @@ int dhcp_create_request ( struct dhcp_packet *dhcppkt,
/* Set client IP address */
dhcppkt->dhcphdr->ciaddr = ciaddr;
- /* Copy any required options from previous server repsonse */
- if ( offer ) {
- struct in_addr server = { 0 };
- struct in_addr *ip = &offer->dhcphdr->yiaddr;
-
- /* Copy server identifier, if present */
- if ( ( dhcppkt_fetch ( offer, DHCP_SERVER_IDENTIFIER, &server,
- sizeof ( server ) ) >= 0 ) &&
- ( ( rc = dhcppkt_store ( dhcppkt, DHCP_SERVER_IDENTIFIER,
- &server,
- sizeof ( server ) ) ) != 0 ) ) {
- DBG ( "DHCP could not set server ID: %s\n",
- strerror ( rc ) );
- return rc;
- }
-
- /* Copy requested IP address, if present */
- if ( ( ip->s_addr != 0 ) &&
- ( ( rc = dhcppkt_store ( dhcppkt, DHCP_REQUESTED_ADDRESS,
- ip, sizeof ( *ip ) ) ) != 0 ) ) {
- DBG ( "DHCP could not set requested address: %s\n",
- strerror ( rc ) );
- return rc;
- }
- }
-
/* Add options to identify the feature list */
dhcp_features_len = ( dhcp_features_end - dhcp_features );
if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_EB_ENCAP, dhcp_features,
@@ -526,8 +938,8 @@ int dhcp_create_request ( struct dhcp_packet *dhcppkt,
/* Add client UUID, if we have one. Required for PXE. */
client_uuid.type = DHCP_CLIENT_UUID_TYPE;
- if ( ( rc = fetch_uuid_setting ( NULL, &uuid_setting,
- &client_uuid.uuid ) ) >= 0 ) {
+ if ( ( len = fetch_uuid_setting ( NULL, &uuid_setting,
+ &client_uuid.uuid ) ) >= 0 ) {
if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_CLIENT_UUID,
&client_uuid,
sizeof ( client_uuid ) ) ) != 0 ) {
@@ -537,9 +949,29 @@ int dhcp_create_request ( struct dhcp_packet *dhcppkt,
}
}
+ /* Add user class, if we have one. */
+ if ( ( len = fetch_setting_len ( NULL, &user_class_setting ) ) >= 0 ) {
+ char user_class[len];
+ fetch_setting ( NULL, &user_class_setting, user_class,
+ sizeof ( user_class ) );
+ if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_USER_CLASS_ID,
+ &user_class,
+ sizeof ( user_class ) ) ) != 0 ) {
+ DBG ( "DHCP could not set user class: %s\n",
+ strerror ( rc ) );
+ return rc;
+ }
+ }
+
return 0;
}
+/****************************************************************************
+ *
+ * Data transfer interface
+ *
+ */
+
/**
* Transmit DHCP request
*
@@ -547,18 +979,17 @@ int dhcp_create_request ( struct dhcp_packet *dhcppkt,
* @ret rc Return status code
*/
static int dhcp_tx ( struct dhcp_session *dhcp ) {
- static struct sockaddr_in proxydhcp_server = {
+ static struct sockaddr_in peer = {
.sin_family = AF_INET,
- .sin_port = htons ( PROXYDHCP_PORT ),
};
struct xfer_metadata meta = {
.netdev = dhcp->netdev,
+ .src = ( struct sockaddr * ) &dhcp->local,
+ .dest = ( struct sockaddr * ) &peer,
};
struct io_buffer *iobuf;
+ uint8_t msgtype = dhcp->state->tx_msgtype;
struct dhcp_packet dhcppkt;
- struct dhcp_packet *offer = NULL;
- struct in_addr ciaddr = { 0 };
- int check_len;
int rc;
/* Start retry timer. Do this first so that failures to
@@ -566,54 +997,31 @@ static int dhcp_tx ( struct dhcp_session *dhcp ) {
*/
start_timer ( &dhcp->timer );
- /* Determine packet contents based on current state */
- switch ( dhcp->state ) {
- case DHCP_STATE_DISCOVER:
- DBGC ( dhcp, "DHCP %p transmitting DHCPDISCOVER\n", dhcp );
- break;
- case DHCP_STATE_REQUEST:
- DBGC ( dhcp, "DHCP %p transmitting DHCPREQUEST\n", dhcp );
- assert ( dhcp->dhcpoffer );
- offer = &dhcp->dhcpoffer->dhcppkt;
- break;
- case DHCP_STATE_PROXYREQUEST:
- DBGC ( dhcp, "DHCP %p transmitting ProxyDHCPREQUEST\n", dhcp );
- assert ( dhcp->dhcpoffer );
- assert ( dhcp->proxydhcpoffer );
- offer = &dhcp->proxydhcpoffer->dhcppkt;
- ciaddr = dhcp->dhcpoffer->dhcppkt.dhcphdr->yiaddr;
- check_len = dhcppkt_fetch ( offer, DHCP_SERVER_IDENTIFIER,
- &proxydhcp_server.sin_addr,
- sizeof(proxydhcp_server.sin_addr));
- meta.dest = ( struct sockaddr * ) &proxydhcp_server;
- assert ( ciaddr.s_addr != 0 );
- assert ( proxydhcp_server.sin_addr.s_addr != 0 );
- assert ( check_len == sizeof ( proxydhcp_server.sin_addr ) );
- break;
- default:
- assert ( 0 );
- break;
- }
-
/* Allocate buffer for packet */
iobuf = xfer_alloc_iob ( &dhcp->xfer, DHCP_MIN_LEN );
if ( ! iobuf )
return -ENOMEM;
- /* Create DHCP packet in temporary buffer */
- if ( ( rc = dhcp_create_request ( &dhcppkt, dhcp->netdev,
- ciaddr, offer, iobuf->data,
+ /* Create basic DHCP packet in temporary buffer */
+ if ( ( rc = dhcp_create_request ( &dhcppkt, dhcp->netdev, msgtype,
+ dhcp->local.sin_addr, iobuf->data,
iob_tailroom ( iobuf ) ) ) != 0 ) {
DBGC ( dhcp, "DHCP %p could not construct DHCP request: %s\n",
dhcp, strerror ( rc ) );
goto done;
}
+ /* Fill in packet based on current state */
+ if ( ( rc = dhcp->state->tx ( dhcp, &dhcppkt, &peer ) ) != 0 ) {
+ DBGC ( dhcp, "DHCP %p could not fill DHCP request: %s\n",
+ dhcp, strerror ( rc ) );
+ goto done;
+ }
+
/* Transmit the packet */
iob_put ( iobuf, dhcppkt.len );
- rc = xfer_deliver_iob_meta ( &dhcp->xfer, iobuf, &meta );
- iobuf = NULL;
- if ( rc != 0 ) {
+ if ( ( rc = xfer_deliver_iob_meta ( &dhcp->xfer, iob_disown ( iobuf ),
+ &meta ) ) != 0 ) {
DBGC ( dhcp, "DHCP %p could not transmit UDP packet: %s\n",
dhcp, strerror ( rc ) );
goto done;
@@ -625,246 +1033,6 @@ static int dhcp_tx ( struct dhcp_session *dhcp ) {
}
/**
- * Transition to new DHCP session state
- *
- * @v dhcp DHCP session
- * @v state New session state
- */
-static void dhcp_set_state ( struct dhcp_session *dhcp,
- enum dhcp_session_state state ) {
- DBGC ( dhcp, "DHCP %p entering %s state\n",
- dhcp, dhcp_state_name ( state ) );
- dhcp->state = state;
- dhcp->start = currticks();
- start_timer_nodelay ( &dhcp->timer );
-}
-
-/**
- * Store received DHCPOFFER
- *
- * @v dhcp DHCP session
- * @v dhcpoffer Received DHCPOFFER
- * @v stored_dhcpoffer Location to store DHCPOFFER
- *
- * The DHCPOFFER will be stored in place of the existing stored
- * DHCPOFFER if its priority is equal to or greater than the stored
- * DHCPOFFER.
- */
-static void dhcp_store_dhcpoffer ( struct dhcp_session *dhcp,
- struct dhcp_settings *dhcpoffer,
- struct dhcp_settings **stored_dhcpoffer ) {
- uint8_t stored_priority = 0;
- uint8_t priority = 0;
-
- /* Get priorities of the two DHCPOFFERs */
- if ( *stored_dhcpoffer ) {
- dhcppkt_fetch ( &(*stored_dhcpoffer)->dhcppkt,
- DHCP_EB_PRIORITY, &stored_priority,
- sizeof ( stored_priority ) );
- }
- dhcppkt_fetch ( &dhcpoffer->dhcppkt, DHCP_EB_PRIORITY, &priority,
- sizeof ( priority ) );
-
- /* Replace stored offer only if priority is equal or greater */
- if ( priority >= stored_priority ) {
- if ( *stored_dhcpoffer ) {
- DBGC ( dhcp, "DHCP %p stored DHCPOFFER %p discarded\n",
- dhcp, *stored_dhcpoffer );
- }
- DBGC ( dhcp, "DHCP %p received DHCPOFFER %p stored\n",
- dhcp, dhcpoffer );
- dhcpset_put ( *stored_dhcpoffer );
- *stored_dhcpoffer = dhcpset_get ( dhcpoffer );
- }
-}
-
-/**
- * Handle received DHCPOFFER
- *
- * @v dhcp DHCP session
- * @v dhcpoffer Received DHCPOFFER
- */
-static void dhcp_rx_dhcpoffer ( struct dhcp_session *dhcp,
- struct dhcp_settings *dhcpoffer ) {
- struct in_addr server_id = { 0 };
- char vci[9]; /* "PXEClient" */
- int len;
- uint8_t ignore_proxy = 0;
- unsigned long elapsed;
-
- /* Check for presence of DHCP server ID */
- if ( dhcppkt_fetch ( &dhcpoffer->dhcppkt, DHCP_SERVER_IDENTIFIER,
- &server_id, sizeof ( server_id ) )
- != sizeof ( server_id ) ) {
- DBGC ( dhcp, "DHCP %p received DHCPOFFER %p missing server "
- "identifier\n", dhcp, dhcpoffer );
- /* Could be a valid BOOTP offer; do not abort processing */
- }
-
- /* If there is an IP address, it's a normal DHCPOFFER */
- if ( dhcpoffer->dhcppkt.dhcphdr->yiaddr.s_addr != 0 ) {
- DBGC ( dhcp, "DHCP %p received DHCPOFFER %p from %s has IP "
- "address\n",
- dhcp, dhcpoffer, inet_ntoa ( server_id ) );
- dhcp_store_dhcpoffer ( dhcp, dhcpoffer, &dhcp->dhcpoffer );
- }
-
- /* If there is a "PXEClient" vendor class ID, it's a
- * ProxyDHCPOFFER. Note that it could be both a normal
- * DHCPOFFER and a ProxyDHCPOFFER.
- */
- len = dhcppkt_fetch ( &dhcpoffer->dhcppkt, DHCP_VENDOR_CLASS_ID,
- vci, sizeof ( vci ) );
- if ( ( server_id.s_addr != 0 ) &&
- ( len >= ( int ) sizeof ( vci ) ) &&
- ( strncmp ( "PXEClient", vci, sizeof ( vci ) ) == 0 ) ) {
- DBGC ( dhcp, "DHCP %p received DHCPOFFER %p from %s is a "
- "ProxyDHCPOFFER\n",
- dhcp, dhcpoffer, inet_ntoa ( server_id ) );
- dhcp_store_dhcpoffer ( dhcp, dhcpoffer,
- &dhcp->proxydhcpoffer );
- }
-
- /* We can transition to making the DHCPREQUEST when we have a
- * valid DHCPOFFER, and either:
- *
- * o The DHCPOFFER instructs us to not wait for ProxyDHCP, or
- * o We have a valid ProxyDHCPOFFER, or
- * o We have allowed sufficient time for ProxyDHCPOFFERs.
- */
-
- /* If we don't yet have a DHCPOFFER, do nothing */
- if ( ! dhcp->dhcpoffer )
- return;
-
- /* If the DHCPOFFER instructs us to ignore ProxyDHCP, discard
- * any ProxyDHCPOFFER
- */
- dhcppkt_fetch ( &dhcp->dhcpoffer->dhcppkt, DHCP_EB_NO_PROXYDHCP,
- &ignore_proxy, sizeof ( ignore_proxy ) );
- if ( ignore_proxy && dhcp->proxydhcpoffer ) {
- DBGC ( dhcp, "DHCP %p discarding ProxyDHCPOFFER\n", dhcp );
- dhcpset_put ( dhcp->proxydhcpoffer );
- dhcp->proxydhcpoffer = NULL;
- }
-
- /* If we can't yet transition to DHCPREQUEST, do nothing */
- elapsed = ( currticks() - dhcp->start );
- if ( ! ( ignore_proxy || dhcp->proxydhcpoffer ||
- ( elapsed > PROXYDHCP_WAIT_TIME ) ) )
- return;
-
- /* Transition to DHCPREQUEST */
- dhcp_set_state ( dhcp, DHCP_STATE_REQUEST );
-}
-
-/**
- * Store received DHCPACK
- *
- * @v dhcp DHCP session
- * @v dhcpack Received DHCPACK
- *
- * The DHCPACK will be registered as a settings block.
- */
-static int dhcp_store_dhcpack ( struct dhcp_session *dhcp,
- struct dhcp_settings *dhcpack,
- struct settings *parent ) {
- struct settings *settings = &dhcpack->settings;
- struct settings *old_settings;
- int rc;
-
- /* Unregister any old settings obtained via DHCP */
- if ( ( old_settings = find_child_settings ( parent, settings->name ) ))
- unregister_settings ( old_settings );
-
- /* Register new settings */
- if ( ( rc = register_settings ( settings, parent ) ) != 0 ) {
- DBGC ( dhcp, "DHCP %p could not register settings: %s\n",
- dhcp, strerror ( rc ) );
- dhcp_finished ( dhcp, rc ); /* This is a fatal error */
- return rc;
- }
-
- return 0;
-}
-
-/**
- * Handle received DHCPACK
- *
- * @v dhcp DHCP session
- * @v dhcpack Received DHCPACK
- */
-static void dhcp_rx_dhcpack ( struct dhcp_session *dhcp,
- struct dhcp_settings *dhcpack ) {
- struct settings *parent;
- struct in_addr offer_server_id = { 0 };
- struct in_addr ack_server_id = { 0 };
- int rc;
-
- /* Verify server ID matches */
- assert ( dhcp->dhcpoffer != NULL );
- dhcppkt_fetch ( &dhcp->dhcpoffer->dhcppkt, DHCP_SERVER_IDENTIFIER,
- &offer_server_id, sizeof ( offer_server_id ) );
- dhcppkt_fetch ( &dhcpack->dhcppkt, DHCP_SERVER_IDENTIFIER,
- &ack_server_id, sizeof ( ack_server_id ) );
- if ( offer_server_id.s_addr != ack_server_id.s_addr ) {
- DBGC ( dhcp, "DHCP %p ignoring DHCPACK with wrong server ID "
- "%s\n", dhcp, inet_ntoa ( ack_server_id ) );
- return;
- }
-
- /* Register settings */
- parent = netdev_settings ( dhcp->netdev );
- if ( ( rc = dhcp_store_dhcpack ( dhcp, dhcpack, parent ) ) !=0 )
- return;
-
- /* If we have a ProxyDHCPOFFER, transition to PROXYDHCPREQUEST */
- if ( dhcp->proxydhcpoffer ) {
- dhcp->timer.min_timeout = 0;
- dhcp_set_state ( dhcp, DHCP_STATE_PROXYREQUEST );
- return;
- }
-
- /* Terminate DHCP */
- dhcp_finished ( dhcp, 0 );
-}
-
-/**
- * Handle received ProxyDHCPACK
- *
- * @v dhcp DHCP session
- * @v proxydhcpack Received ProxyDHCPACK
- */
-static void dhcp_rx_proxydhcpack ( struct dhcp_session *dhcp,
- struct dhcp_settings *proxydhcpack ) {
- struct in_addr offer_server_id = { 0 };
- struct in_addr ack_server_id = { 0 };
- int rc;
-
- /* Verify server ID matches */
- assert ( dhcp->proxydhcpoffer != NULL );
- dhcppkt_fetch ( &dhcp->proxydhcpoffer->dhcppkt, DHCP_SERVER_IDENTIFIER,
- &offer_server_id, sizeof ( offer_server_id ) );
- dhcppkt_fetch ( &proxydhcpack->dhcppkt, DHCP_SERVER_IDENTIFIER,
- &ack_server_id, sizeof ( ack_server_id ) );
- if ( offer_server_id.s_addr != ack_server_id.s_addr ) {
- DBGC ( dhcp, "DHCP %p ignoring ProxyDHCPACK with wrong server "
- "ID %s\n", dhcp, inet_ntoa ( ack_server_id ) );
- return;
- }
-
- /* Rename settings */
- proxydhcpack->settings.name = PROXYDHCP_SETTINGS_NAME;
-
- /* Register settings */
- if ( ( rc = dhcp_store_dhcpack ( dhcp, proxydhcpack, NULL ) ) != 0 )
- return;
-
- /* Terminate DHCP */
- dhcp_finished ( dhcp, 0 );
-}
-
-/**
* Receive new data
*
* @v xfer Data transfer interface
@@ -877,79 +1045,63 @@ static int dhcp_deliver_iob ( struct xfer_interface *xfer,
struct xfer_metadata *meta ) {
struct dhcp_session *dhcp =
container_of ( xfer, struct dhcp_session, xfer );
- struct sockaddr_tcpip *st_src;
- unsigned int src_port;
- struct dhcp_settings *dhcpset;
+ struct sockaddr_in *peer;
+ size_t data_len;
+ struct dhcp_packet *dhcppkt;
struct dhcphdr *dhcphdr;
uint8_t msgtype = 0;
+ struct in_addr server_id = { 0 };
int rc = 0;
/* Sanity checks */
- if ( ! meta ) {
- DBGC ( dhcp, "DHCP %p received packet without metadata\n",
- dhcp );
- rc = -EINVAL;
- goto err_no_meta;
- }
if ( ! meta->src ) {
DBGC ( dhcp, "DHCP %p received packet without source port\n",
dhcp );
rc = -EINVAL;
goto err_no_src;
}
- st_src = ( struct sockaddr_tcpip * ) meta->src;
- src_port = st_src->st_port;
+ peer = ( struct sockaddr_in * ) meta->src;
- /* Convert packet into a DHCP settings block */
- dhcpset = dhcpset_create ( iobuf->data, iob_len ( iobuf ) );
- if ( ! dhcpset ) {
- DBGC ( dhcp, "DHCP %p could not store DHCP packet\n", dhcp );
+ /* Create a DHCP packet containing the I/O buffer contents.
+ * Whilst we could just use the original buffer in situ, that
+ * would waste the unused space in the packet buffer, and also
+ * waste a relatively scarce fully-aligned I/O buffer.
+ */
+ data_len = iob_len ( iobuf );
+ dhcppkt = zalloc ( sizeof ( *dhcppkt ) + data_len );
+ if ( ! dhcppkt ) {
rc = -ENOMEM;
- goto err_dhcpset_create;
+ goto err_alloc_dhcppkt;
}
- dhcphdr = dhcpset->dhcppkt.dhcphdr;
+ dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) );
+ memcpy ( dhcphdr, iobuf->data, data_len );
+ dhcppkt_init ( dhcppkt, dhcphdr, data_len );
/* Identify message type */
- dhcppkt_fetch ( &dhcpset->dhcppkt, DHCP_MESSAGE_TYPE, &msgtype,
+ dhcppkt_fetch ( dhcppkt, DHCP_MESSAGE_TYPE, &msgtype,
sizeof ( msgtype ) );
- DBGC ( dhcp, "DHCP %p received %s %p from port %d\n", dhcp,
- dhcp_msgtype_name ( msgtype ), dhcpset, ntohs ( src_port ) );
+
+ /* Identify server ID */
+ dhcppkt_fetch ( dhcppkt, DHCP_SERVER_IDENTIFIER,
+ &server_id, sizeof ( server_id ) );
/* Check for matching transaction ID */
if ( dhcphdr->xid != dhcp_xid ( dhcp->netdev ) ) {
- DBGC ( dhcp, "DHCP %p received %s %p has bad transaction ID\n",
- dhcp, dhcp_msgtype_name ( msgtype ), dhcpset );
+ DBGC ( dhcp, "DHCP %p %s from %s:%d has bad transaction "
+ "ID\n", dhcp, dhcp_msgtype_name ( msgtype ),
+ inet_ntoa ( peer->sin_addr ),
+ ntohs ( peer->sin_port ) );
rc = -EINVAL;
goto err_xid;
};
/* Handle packet based on current state */
- switch ( dhcp->state ) {
- case DHCP_STATE_DISCOVER:
- if ( ( ( msgtype == DHCPOFFER ) || ( msgtype == DHCPNONE ) ) &&
- ( src_port == htons ( BOOTPS_PORT ) ) )
- dhcp_rx_dhcpoffer ( dhcp, dhcpset );
- break;
- case DHCP_STATE_REQUEST:
- if ( ( ( msgtype == DHCPACK ) || ( msgtype == DHCPNONE ) ) &&
- ( src_port == htons ( BOOTPS_PORT ) ) )
- dhcp_rx_dhcpack ( dhcp, dhcpset );
- break;
- case DHCP_STATE_PROXYREQUEST:
- if ( ( msgtype == DHCPACK ) &&
- ( src_port == htons ( PROXYDHCP_PORT ) ) )
- dhcp_rx_proxydhcpack ( dhcp, dhcpset );
- break;
- default:
- assert ( 0 );
- break;
- }
+ dhcp->state->rx ( dhcp, dhcppkt, peer, msgtype, server_id );
err_xid:
- dhcpset_put ( dhcpset );
- err_dhcpset_create:
+ dhcppkt_put ( dhcppkt );
+ err_alloc_dhcppkt:
err_no_src:
- err_no_meta:
free_iob ( iobuf );
return rc;
}
@@ -973,7 +1125,6 @@ static struct xfer_interface_operations dhcp_xfer_operations = {
static void dhcp_timer_expired ( struct retry_timer *timer, int fail ) {
struct dhcp_session *dhcp =
container_of ( timer, struct dhcp_session, timer );
- unsigned long elapsed = ( currticks() - dhcp->start );
/* If we have failed, terminate DHCP */
if ( fail ) {
@@ -981,19 +1132,8 @@ static void dhcp_timer_expired ( struct retry_timer *timer, int fail ) {
return;
}
- /* Give up waiting for ProxyDHCP before we reach the failure point */
- if ( dhcp->dhcpoffer && ( elapsed > PROXYDHCP_WAIT_TIME ) ) {
- if ( dhcp->state == DHCP_STATE_DISCOVER ) {
- dhcp_set_state ( dhcp, DHCP_STATE_REQUEST );
- return;
- } else if ( dhcp->state == DHCP_STATE_PROXYREQUEST ) {
- dhcp_finished ( dhcp, 0 );
- return;
- }
- }
-
- /* Otherwise, retransmit current packet */
- dhcp_tx ( dhcp );
+ /* Handle timer expiry based on current state */
+ dhcp->state->expired ( dhcp );
}
/****************************************************************************
@@ -1024,32 +1164,33 @@ static struct job_interface_operations dhcp_job_operations = {
/****************************************************************************
*
- * Instantiator
+ * Instantiators
+ *
+ */
+
+/**
+ * DHCP peer address for socket opening
*
+ * This is a dummy address; the only useful portion is the socket
+ * family (so that we get a UDP connection). The DHCP client will set
+ * the IP address and source port explicitly on each transmission.
*/
+static struct sockaddr dhcp_peer = {
+ .sa_family = AF_INET,
+};
/**
- * Start DHCP on a network device
+ * Start DHCP state machine on a network device
*
* @v job Job control interface
* @v netdev Network device
- * @v register_options DHCP option block registration routine
* @ret rc Return status code
*
- * Starts DHCP on the specified network device. If successful, the @c
- * register_options() routine will be called with the acquired
- * options.
+ * Starts DHCP on the specified network device. If successful, the
+ * DHCPACK (and ProxyDHCPACK, if applicable) will be registered as
+ * option sources.
*/
int start_dhcp ( struct job_interface *job, struct net_device *netdev ) {
- static struct sockaddr_in server = {
- .sin_family = AF_INET,
- .sin_addr.s_addr = INADDR_BROADCAST,
- .sin_port = htons ( BOOTPS_PORT ),
- };
- static struct sockaddr_in client = {
- .sin_family = AF_INET,
- .sin_port = htons ( BOOTPC_PORT ),
- };
struct dhcp_session *dhcp;
int rc;
@@ -1061,19 +1202,163 @@ int start_dhcp ( struct job_interface *job, struct net_device *netdev ) {
job_init ( &dhcp->job, &dhcp_job_operations, &dhcp->refcnt );
xfer_init ( &dhcp->xfer, &dhcp_xfer_operations, &dhcp->refcnt );
dhcp->netdev = netdev_get ( netdev );
+ dhcp->local.sin_family = AF_INET;
+ dhcp->local.sin_port = htons ( BOOTPC_PORT );
dhcp->timer.expired = dhcp_timer_expired;
- dhcp->timer.min_timeout = DHCP_MIN_TIMEOUT;
- dhcp->timer.max_timeout = DHCP_MAX_TIMEOUT;
- dhcp->start = currticks();
/* Instantiate child objects and attach to our interfaces */
- if ( ( rc = xfer_open_socket ( &dhcp->xfer, SOCK_DGRAM,
- ( struct sockaddr * ) &server,
- ( struct sockaddr * ) &client ) ) != 0 )
+ if ( ( rc = xfer_open_socket ( &dhcp->xfer, SOCK_DGRAM, &dhcp_peer,
+ ( struct sockaddr * ) &dhcp->local ) ) != 0 )
goto err;
- /* Start timer to initiate initial DHCPREQUEST */
- start_timer_nodelay ( &dhcp->timer );
+ /* Enter DHCPDISCOVER state */
+ dhcp_set_state ( dhcp, &dhcp_state_discover );
+
+ /* Attach parent interface, mortalise self, and return */
+ job_plug_plug ( &dhcp->job, job );
+ ref_put ( &dhcp->refcnt );
+ return 0;
+
+ err:
+ dhcp_finished ( dhcp, rc );
+ ref_put ( &dhcp->refcnt );
+ return rc;
+}
+
+/**
+ * Retrieve list of PXE boot servers for a given server type
+ *
+ * @v dhcp DHCP session
+ * @v raw DHCP PXE boot server list
+ * @v raw_len Length of DHCP PXE boot server list
+ * @v ip IP address list to fill in
+ *
+ * The caller must ensure that the IP address list has sufficient
+ * space.
+ */
+static void pxebs_list ( struct dhcp_session *dhcp, void *raw,
+ size_t raw_len, struct in_addr *ip ) {
+ struct dhcp_pxe_boot_server *server = raw;
+ size_t server_len;
+ unsigned int i;
+
+ while ( raw_len ) {
+ if ( raw_len < sizeof ( *server ) ) {
+ DBGC ( dhcp, "DHCP %p malformed PXE server list\n",
+ dhcp );
+ break;
+ }
+ server_len = offsetof ( typeof ( *server ),
+ ip[ server->num_ip ] );
+ if ( raw_len < server_len ) {
+ DBGC ( dhcp, "DHCP %p malformed PXE server list\n",
+ dhcp );
+ break;
+ }
+ if ( server->type == dhcp->pxe_type ) {
+ for ( i = 0 ; i < server->num_ip ; i++ )
+ *(ip++) = server->ip[i];
+ }
+ server = ( ( ( void * ) server ) + server_len );
+ raw_len -= server_len;
+ }
+}
+
+/**
+ * Start PXE Boot Server Discovery on a network device
+ *
+ * @v job Job control interface
+ * @v netdev Network device
+ * @v pxe_type PXE server type
+ * @ret rc Return status code
+ *
+ * Starts PXE Boot Server Discovery on the specified network device.
+ * If successful, the Boot Server ACK will be registered as an option
+ * source.
+ */
+int start_pxebs ( struct job_interface *job, struct net_device *netdev,
+ unsigned int pxe_type ) {
+ struct setting pxe_discovery_control_setting =
+ { .tag = DHCP_PXE_DISCOVERY_CONTROL };
+ struct setting pxe_boot_servers_setting =
+ { .tag = DHCP_PXE_BOOT_SERVERS };
+ struct setting pxe_boot_server_mcast_setting =
+ { .tag = DHCP_PXE_BOOT_SERVER_MCAST };
+ ssize_t pxebs_list_len;
+ struct dhcp_session *dhcp;
+ struct in_addr *ip;
+ unsigned int pxe_discovery_control;
+ int rc;
+
+ /* Get upper bound for PXE boot server IP address list */
+ pxebs_list_len = fetch_setting_len ( NULL, &pxe_boot_servers_setting );
+ if ( pxebs_list_len < 0 )
+ pxebs_list_len = 0;
+
+ /* Allocate and initialise structure */
+ dhcp = zalloc ( sizeof ( *dhcp ) + sizeof ( *ip ) /* mcast */ +
+ sizeof ( *ip ) /* bcast */ + pxebs_list_len +
+ sizeof ( *ip ) /* terminator */ );
+ if ( ! dhcp )
+ return -ENOMEM;
+ dhcp->refcnt.free = dhcp_free;
+ job_init ( &dhcp->job, &dhcp_job_operations, &dhcp->refcnt );
+ xfer_init ( &dhcp->xfer, &dhcp_xfer_operations, &dhcp->refcnt );
+ dhcp->netdev = netdev_get ( netdev );
+ dhcp->local.sin_family = AF_INET;
+ fetch_ipv4_setting ( netdev_settings ( netdev ), &ip_setting,
+ &dhcp->local.sin_addr );
+ dhcp->local.sin_port = htons ( BOOTPC_PORT );
+ dhcp->pxe_type = htons ( pxe_type );
+ dhcp->timer.expired = dhcp_timer_expired;
+
+ /* Construct PXE boot server IP address lists */
+ pxe_discovery_control =
+ fetch_uintz_setting ( NULL, &pxe_discovery_control_setting );
+ ip = ( ( ( void * ) dhcp ) + sizeof ( *dhcp ) );
+ dhcp->pxe_attempt = ip;
+ if ( ! ( pxe_discovery_control & PXEBS_NO_MULTICAST ) ) {
+ fetch_ipv4_setting ( NULL, &pxe_boot_server_mcast_setting, ip);
+ if ( ip->s_addr )
+ ip++;
+ }
+ if ( ! ( pxe_discovery_control & PXEBS_NO_BROADCAST ) )
+ (ip++)->s_addr = INADDR_BROADCAST;
+ if ( pxe_discovery_control & PXEBS_NO_UNKNOWN_SERVERS )
+ dhcp->pxe_accept = ip;
+ if ( pxebs_list_len ) {
+ uint8_t buf[pxebs_list_len];
+
+ fetch_setting ( NULL, &pxe_boot_servers_setting,
+ buf, sizeof ( buf ) );
+ pxebs_list ( dhcp, buf, sizeof ( buf ), ip );
+ }
+ if ( ! dhcp->pxe_attempt->s_addr ) {
+ DBGC ( dhcp, "DHCP %p has no PXE boot servers for type %04x\n",
+ dhcp, pxe_type );
+ rc = -EINVAL;
+ goto err;
+ }
+
+ /* Dump out PXE server lists */
+ DBGC ( dhcp, "DHCP %p attempting", dhcp );
+ for ( ip = dhcp->pxe_attempt ; ip->s_addr ; ip++ )
+ DBGC ( dhcp, " %s", inet_ntoa ( *ip ) );
+ DBGC ( dhcp, "\n" );
+ if ( dhcp->pxe_accept ) {
+ DBGC ( dhcp, "DHCP %p accepting", dhcp );
+ for ( ip = dhcp->pxe_accept ; ip->s_addr ; ip++ )
+ DBGC ( dhcp, " %s", inet_ntoa ( *ip ) );
+ DBGC ( dhcp, "\n" );
+ }
+
+ /* Instantiate child objects and attach to our interfaces */
+ if ( ( rc = xfer_open_socket ( &dhcp->xfer, SOCK_DGRAM, &dhcp_peer,
+ ( struct sockaddr * ) &dhcp->local ) ) != 0 )
+ goto err;
+
+ /* Enter PXEBS state */
+ dhcp_set_state ( dhcp, &dhcp_state_pxebs );
/* Attach parent interface, mortalise self, and return */
job_plug_plug ( &dhcp->job, job );
diff --git a/gpxe/src/net/udp/dns.c b/gpxe/src/net/udp/dns.c
index 1bcdbc7e..a498aefc 100644
--- a/gpxe/src/net/udp/dns.c
+++ b/gpxe/src/net/udp/dns.c
@@ -22,6 +22,7 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
+#include <stdio.h>
#include <errno.h>
#include <byteswap.h>
#include <gpxe/refcnt.h>
@@ -47,6 +48,9 @@ static struct sockaddr_tcpip nameserver = {
.st_port = htons ( DNS_PORT ),
};
+/** The local domain */
+static char *localdomain;
+
/** A DNS request */
struct dns_request {
/** Reference counter */
@@ -180,6 +184,27 @@ static union dns_rr_info * dns_find_rr ( struct dns_request *dns,
}
/**
+ * Append DHCP domain name if available and name is not fully qualified
+ *
+ * @v string Name as a NUL-terminated string
+ * @ret fqdn Fully-qualified domain name, malloc'd copy
+ *
+ * The caller must free fqdn which is allocated even if the name is already
+ * fully qualified.
+ */
+static char * dns_qualify_name ( const char *string ) {
+ char *fqdn;
+
+ /* Leave unchanged if already fully-qualified or no local domain */
+ if ( ( ! localdomain ) || ( strchr ( string, '.' ) != 0 ) )
+ return strdup ( string );
+
+ /* Append local domain to name */
+ asprintf ( &fqdn, "%s.%s", string, localdomain );
+ return fqdn;
+}
+
+/**
* Convert a standard NUL-terminated string to a DNS name
*
* @v string Name as a NUL-terminated string
@@ -452,19 +477,30 @@ static struct xfer_interface_operations dns_socket_operations = {
static int dns_resolv ( struct resolv_interface *resolv,
const char *name, struct sockaddr *sa ) {
struct dns_request *dns;
+ char *fqdn;
int rc;
/* Fail immediately if no DNS servers */
if ( ! nameserver.st_family ) {
DBG ( "DNS not attempting to resolve \"%s\": "
"no DNS servers\n", name );
- return -ENXIO;
+ rc = -ENXIO;
+ goto err_no_nameserver;
+ }
+
+ /* Ensure fully-qualified domain name if DHCP option was given */
+ fqdn = dns_qualify_name ( name );
+ if ( ! fqdn ) {
+ rc = -ENOMEM;
+ goto err_qualify_name;
}
/* Allocate DNS structure */
dns = zalloc ( sizeof ( *dns ) );
- if ( ! dns )
- return -ENOMEM;
+ if ( ! dns ) {
+ rc = -ENOMEM;
+ goto err_alloc_dns;
+ }
resolv_init ( &dns->resolv, &null_resolv_ops, &dns->refcnt );
xfer_init ( &dns->socket, &dns_socket_operations, &dns->refcnt );
dns->timer.expired = dns_timer_expired;
@@ -474,7 +510,7 @@ static int dns_resolv ( struct resolv_interface *resolv,
dns->query.dns.flags = htons ( DNS_FLAG_QUERY | DNS_FLAG_OPCODE_QUERY |
DNS_FLAG_RD );
dns->query.dns.qdcount = htons ( 1 );
- dns->qinfo = ( void * ) dns_make_name ( name, dns->query.payload );
+ dns->qinfo = ( void * ) dns_make_name ( fqdn, dns->query.payload );
dns->qinfo->qtype = htons ( DNS_TYPE_A );
dns->qinfo->qclass = htons ( DNS_CLASS_IN );
@@ -484,7 +520,7 @@ static int dns_resolv ( struct resolv_interface *resolv,
NULL ) ) != 0 ) {
DBGC ( dns, "DNS %p could not open socket: %s\n",
dns, strerror ( rc ) );
- goto err;
+ goto err_open_socket;
}
/* Send first DNS packet */
@@ -493,10 +529,15 @@ static int dns_resolv ( struct resolv_interface *resolv,
/* Attach parent interface, mortalise self, and return */
resolv_plug_plug ( &dns->resolv, resolv );
ref_put ( &dns->refcnt );
+ free ( fqdn );
return 0;
- err:
+ err_open_socket:
+ err_alloc_dns:
ref_put ( &dns->refcnt );
+ err_qualify_name:
+ free ( fqdn );
+ err_no_nameserver:
return rc;
}
@@ -521,12 +562,20 @@ struct setting dns_setting __setting = {
.type = &setting_type_ipv4,
};
+/** Domain name setting */
+struct setting domain_setting __setting = {
+ .name = "domain",
+ .description = "Local domain",
+ .tag = DHCP_DOMAIN_NAME,
+ .type = &setting_type_string,
+};
+
/**
- * Apply nameserver setting
+ * Apply DNS settings
*
* @ret rc Return status code
*/
-static int apply_nameserver_setting ( void ) {
+static int apply_dns_settings ( void ) {
struct sockaddr_in *sin_nameserver =
( struct sockaddr_in * ) &nameserver;
int len;
@@ -538,10 +587,15 @@ static int apply_nameserver_setting ( void ) {
inet_ntoa ( sin_nameserver->sin_addr ) );
}
+ /* Get local domain DHCP option */
+ if ( ( len = fetch_string_setting_copy ( NULL, &domain_setting,
+ &localdomain ) ) >= 0 )
+ DBG ( "DNS local domain %s\n", localdomain );
+
return 0;
}
-/** Nameserver setting applicator */
-struct settings_applicator nameserver_applicator __settings_applicator = {
- .apply = apply_nameserver_setting,
+/** DNS settings applicator */
+struct settings_applicator dns_applicator __settings_applicator = {
+ .apply = apply_dns_settings,
};
diff --git a/gpxe/src/net/udp/slam.c b/gpxe/src/net/udp/slam.c
index cb0dfa5c..6add99bc 100644
--- a/gpxe/src/net/udp/slam.c
+++ b/gpxe/src/net/udp/slam.c
@@ -219,7 +219,7 @@ static int slam_put_value ( struct slam_request *slam,
*/
len = ( ( flsl ( value ) + 10 ) / 8 );
if ( len >= iob_tailroom ( iobuf ) ) {
- DBGC2 ( slam, "SLAM %p cannot add %d-byte value\n",
+ DBGC2 ( slam, "SLAM %p cannot add %zd-byte value\n",
slam, len );
return -ENOBUFS;
}
@@ -380,7 +380,7 @@ static int slam_pull_value ( struct slam_request *slam,
len = ( *data >> 5 );
if ( ( len == 0 ) ||
( value && ( len > sizeof ( *value ) ) ) ) {
- DBGC ( slam, "SLAM %p invalid value length %d bytes\n",
+ DBGC ( slam, "SLAM %p invalid value length %zd bytes\n",
slam, len );
return -EINVAL;
}
diff --git a/gpxe/src/net/udp/tftp.c b/gpxe/src/net/udp/tftp.c
index 8fdb3714..19525f79 100644
--- a/gpxe/src/net/udp/tftp.c
+++ b/gpxe/src/net/udp/tftp.c
@@ -45,6 +45,15 @@
FEATURE ( FEATURE_PROTOCOL, "TFTP", DHCP_EB_FEATURE_TFTP, 1 );
+/* TFTP-specific error codes */
+#define ETFTP_INVALID_BLKSIZE EUNIQ_01
+#define ETFTP_INVALID_TSIZE EUNIQ_02
+#define ETFTP_MC_NO_PORT EUNIQ_03
+#define ETFTP_MC_NO_MC EUNIQ_04
+#define ETFTP_MC_INVALID_MC EUNIQ_05
+#define ETFTP_MC_INVALID_IP EUNIQ_06
+#define ETFTP_MC_INVALID_PORT EUNIQ_07
+
/**
* A TFTP request
*
@@ -504,7 +513,7 @@ static int tftp_process_blksize ( struct tftp_request *tftp,
if ( *end ) {
DBGC ( tftp, "TFTP %p got invalid blksize \"%s\"\n",
tftp, value );
- return -EINVAL;
+ return -( EINVAL | ETFTP_INVALID_BLKSIZE );
}
DBGC ( tftp, "TFTP %p blksize=%d\n", tftp, tftp->blksize );
@@ -526,7 +535,7 @@ static int tftp_process_tsize ( struct tftp_request *tftp,
if ( *end ) {
DBGC ( tftp, "TFTP %p got invalid tsize \"%s\"\n",
tftp, value );
- return -EINVAL;
+ return -( EINVAL | ETFTP_INVALID_TSIZE );
}
DBGC ( tftp, "TFTP %p tsize=%ld\n", tftp, tftp->tsize );
@@ -560,13 +569,13 @@ static int tftp_process_multicast ( struct tftp_request *tftp,
port = strchr ( addr, ',' );
if ( ! port ) {
DBGC ( tftp, "TFTP %p multicast missing port,mc\n", tftp );
- return -EINVAL;
+ return -( EINVAL | ETFTP_MC_NO_PORT );
}
*(port++) = '\0';
mc = strchr ( port, ',' );
if ( ! mc ) {
DBGC ( tftp, "TFTP %p multicast missing mc\n", tftp );
- return -EINVAL;
+ return -( EINVAL | ETFTP_MC_NO_MC );
}
*(mc++) = '\0';
@@ -575,7 +584,7 @@ static int tftp_process_multicast ( struct tftp_request *tftp,
tftp->flags &= ~TFTP_FL_SEND_ACK;
if ( *mc_end ) {
DBGC ( tftp, "TFTP %p multicast invalid mc %s\n", tftp, mc );
- return -EINVAL;
+ return -( EINVAL | ETFTP_MC_INVALID_MC );
}
DBGC ( tftp, "TFTP %p is%s the master client\n",
tftp, ( ( tftp->flags & TFTP_FL_SEND_ACK ) ? "" : " not" ) );
@@ -584,7 +593,7 @@ static int tftp_process_multicast ( struct tftp_request *tftp,
if ( inet_aton ( addr, &socket.sin.sin_addr ) == 0 ) {
DBGC ( tftp, "TFTP %p multicast invalid IP address "
"%s\n", tftp, addr );
- return -EINVAL;
+ return -( EINVAL | ETFTP_MC_INVALID_IP );
}
DBGC ( tftp, "TFTP %p multicast IP address %s\n",
tftp, inet_ntoa ( socket.sin.sin_addr ) );
@@ -592,7 +601,7 @@ static int tftp_process_multicast ( struct tftp_request *tftp,
if ( *port_end ) {
DBGC ( tftp, "TFTP %p multicast invalid port %s\n",
tftp, port );
- return -EINVAL;
+ return -( EINVAL | ETFTP_MC_INVALID_PORT );
}
DBGC ( tftp, "TFTP %p multicast port %d\n",
tftp, ntohs ( socket.sin.sin_port ) );
@@ -732,6 +741,11 @@ static int tftp_rx_data ( struct tftp_request *tftp,
rc = -EINVAL;
goto done;
}
+ if ( data->block == 0 ) {
+ DBGC ( tftp, "TFTP %p received data block 0\n", tftp );
+ rc = -EINVAL;
+ goto done;
+ }
/* Extract data */
block = ( ntohs ( data->block ) - 1 );
@@ -749,9 +763,8 @@ static int tftp_rx_data ( struct tftp_request *tftp,
memset ( &meta, 0, sizeof ( meta ) );
meta.whence = SEEK_SET;
meta.offset = offset;
- rc = xfer_deliver_iob_meta ( &tftp->xfer, iobuf, &meta );
- iobuf = NULL;
- if ( rc != 0 ) {
+ if ( ( rc = xfer_deliver_iob_meta ( &tftp->xfer, iob_disown ( iobuf ),
+ &meta ) ) != 0 ) {
DBGC ( tftp, "TFTP %p could not deliver data: %s\n",
tftp, strerror ( rc ) );
goto done;
@@ -826,7 +839,7 @@ static int tftp_rx_error ( struct tftp_request *tftp, void *buf, size_t len ) {
*
* @v tftp TFTP connection
* @v iobuf I/O buffer
- * @v meta Transfer metadata, or NULL
+ * @v meta Transfer metadata
* @ret rc Return status code
*/
static int tftp_rx ( struct tftp_request *tftp,
@@ -843,11 +856,6 @@ static int tftp_rx ( struct tftp_request *tftp,
"%zd\n", tftp, len );
goto done;
}
- if ( ! meta ) {
- DBGC ( tftp, "TFTP %p received packet without metadata\n",
- tftp );
- goto done;
- }
if ( ! meta->src ) {
DBGC ( tftp, "TFTP %p received packet without source port\n",
tftp );
@@ -873,8 +881,7 @@ static int tftp_rx ( struct tftp_request *tftp,
rc = tftp_rx_oack ( tftp, iobuf->data, len );
break;
case htons ( TFTP_DATA ):
- rc = tftp_rx_data ( tftp, iobuf );
- iobuf = NULL;
+ rc = tftp_rx_data ( tftp, iob_disown ( iobuf ) );
break;
case htons ( TFTP_ERROR ):
rc = tftp_rx_error ( tftp, iobuf->data, len );
@@ -895,7 +902,7 @@ static int tftp_rx ( struct tftp_request *tftp,
*
* @v socket Transport layer interface
* @v iobuf I/O buffer
- * @v meta Transfer metadata, or NULL
+ * @v meta Transfer metadata
* @ret rc Return status code
*/
static int tftp_socket_deliver_iob ( struct xfer_interface *socket,
@@ -939,7 +946,7 @@ static struct xfer_interface_operations tftp_socket_operations = {
*
* @v mc_socket Multicast transport layer interface
* @v iobuf I/O buffer
- * @v meta Transfer metadata, or NULL
+ * @v meta Transfer metadata
* @ret rc Return status code
*/
static int tftp_mc_socket_deliver_iob ( struct xfer_interface *mc_socket,
@@ -977,11 +984,29 @@ static void tftp_xfer_close ( struct xfer_interface *xfer, int rc ) {
tftp_done ( tftp, rc );
}
+/**
+ * Check flow control window
+ *
+ * @v xfer Data transfer interface
+ * @ret len Length of window
+ */
+static size_t tftp_xfer_window ( struct xfer_interface *xfer ) {
+ struct tftp_request *tftp =
+ container_of ( xfer, struct tftp_request, xfer );
+
+ /* We abuse this data-xfer method to convey the blocksize to
+ * the caller. This really should be done using some kind of
+ * stat() method, but we don't yet have the facility to do
+ * that.
+ */
+ return tftp->blksize;
+}
+
/** TFTP data transfer interface operations */
static struct xfer_interface_operations tftp_xfer_operations = {
.close = tftp_xfer_close,
.vredirect = ignore_xfer_vredirect,
- .window = unlimited_xfer_window,
+ .window = tftp_xfer_window,
.alloc_iob = default_xfer_alloc_iob,
.deliver_iob = xfer_deliver_as_raw,
.deliver_raw = ignore_xfer_deliver_raw,
diff --git a/gpxe/src/netboot.gpxe b/gpxe/src/netboot.gpxe
new file mode 100644
index 00000000..dd3f01a3
--- /dev/null
+++ b/gpxe/src/netboot.gpxe
@@ -0,0 +1,4 @@
+#!gpxe
+kernel http://www.zytor.com/netboot/pxelinux.0
+set filename http://www.zytor.com/netboot/pxelinux.0
+boot
diff --git a/gpxe/src/tests/gdbstub_test.S b/gpxe/src/tests/gdbstub_test.S
index bd293836..739b0527 100644
--- a/gpxe/src/tests/gdbstub_test.S
+++ b/gpxe/src/tests/gdbstub_test.S
@@ -1,10 +1,10 @@
.arch i386
- .section ".data"
+ .section ".data", "aw", @progbits
watch_me:
.long 0xfeedbeef
- .section ".text"
+ .section ".text", "ax", @progbits
.code32
gdbstub_test:
/* 1. Read registers test */
diff --git a/gpxe/src/tests/gdbstub_test.gdb b/gpxe/src/tests/gdbstub_test.gdb
index 52aa693f..52aa693f 100644..100755
--- a/gpxe/src/tests/gdbstub_test.gdb
+++ b/gpxe/src/tests/gdbstub_test.gdb
diff --git a/gpxe/src/usr/autoboot.c b/gpxe/src/usr/autoboot.c
index 326292b4..98e79a7f 100644
--- a/gpxe/src/usr/autoboot.c
+++ b/gpxe/src/usr/autoboot.c
@@ -23,14 +23,12 @@
#include <gpxe/dhcp.h>
#include <gpxe/settings.h>
#include <gpxe/image.h>
-#include <gpxe/embedded.h>
+#include <gpxe/sanboot.h>
#include <gpxe/uri.h>
#include <usr/ifmgmt.h>
#include <usr/route.h>
#include <usr/dhcpmgmt.h>
#include <usr/imgmgmt.h>
-#include <usr/iscsiboot.h>
-#include <usr/aoeboot.h>
#include <usr/autoboot.h>
/** @file
@@ -45,6 +43,12 @@
/** Shutdown flags for exit */
int shutdown_exit_flags = 0;
+/* SAN boot protocols */
+static struct sanboot_protocol sanboot_protocols[0] \
+ __table_start ( struct sanboot_protocol, sanboot_protocols );
+static struct sanboot_protocol sanboot_protocols_end[0] \
+ __table_end ( struct sanboot_protocol, sanboot_protocols );
+
/**
* Identify the boot network device
*
@@ -55,37 +59,13 @@ static struct net_device * find_boot_netdev ( void ) {
}
/**
- * Boot embedded image
- *
- * @ret rc Return status code
- */
-static int boot_embedded_image ( void ) {
- struct image *image;
- int rc;
-
- image = embedded_image();
- if ( !image )
- return ENOENT;
-
- if ( ( rc = imgload ( image ) ) != 0 ) {
- printf ( "Could not load embedded image: %s\n",
- strerror ( rc ) );
- } else if ( ( rc = imgexec ( image ) ) != 0 ) {
- printf ( "Could not boot embedded image: %s\n",
- strerror ( rc ) );
- }
- image_put ( image );
- return rc;
-}
-
-/**
* Boot using next-server and filename
*
* @v filename Boot filename
* @ret rc Return status code
*/
-static int boot_next_server_and_filename ( struct in_addr next_server,
- const char *filename ) {
+int boot_next_server_and_filename ( struct in_addr next_server,
+ const char *filename ) {
struct uri *uri;
struct image *image;
char buf[ 23 /* tftp://xxx.xxx.xxx.xxx/ */ + strlen(filename) + 1 ];
@@ -141,12 +121,15 @@ static int boot_next_server_and_filename ( struct in_addr next_server,
* @ret rc Return status code
*/
int boot_root_path ( const char *root_path ) {
+ struct sanboot_protocol *sanboot;
/* Quick hack */
- if ( strncmp ( root_path, "iscsi:", 6 ) == 0 ) {
- return iscsiboot ( root_path );
- } else if ( strncmp ( root_path, "aoe:", 4 ) == 0 ) {
- return aoeboot ( root_path );
+ for ( sanboot = sanboot_protocols ;
+ sanboot < sanboot_protocols_end ; sanboot++ ) {
+ if ( strncmp ( root_path, sanboot->prefix,
+ strlen ( sanboot->prefix ) ) == 0 ) {
+ return sanboot->boot ( root_path );
+ }
}
return -ENOTSUP;
@@ -159,8 +142,15 @@ int boot_root_path ( const char *root_path ) {
* @ret rc Return status code
*/
static int netboot ( struct net_device *netdev ) {
+ struct setting vendor_class_id_setting
+ = { .tag = DHCP_VENDOR_CLASS_ID };
+ struct setting pxe_discovery_control_setting
+ = { .tag = DHCP_PXE_DISCOVERY_CONTROL };
+ struct setting pxe_boot_menu_setting
+ = { .tag = DHCP_PXE_BOOT_MENU };
char buf[256];
struct in_addr next_server;
+ unsigned int pxe_discovery_control;
int rc;
/* Open device and display device status */
@@ -181,10 +171,18 @@ static int netboot ( struct net_device *netdev ) {
return rc;
route();
- /* Try to boot an embedded image if we have one */
- rc = boot_embedded_image ();
- if ( rc != ENOENT )
- return rc;
+ /* Try PXE menu boot, if applicable */
+ fetch_string_setting ( NULL, &vendor_class_id_setting,
+ buf, sizeof ( buf ) );
+ pxe_discovery_control =
+ fetch_uintz_setting ( NULL, &pxe_discovery_control_setting );
+ if ( ( strcmp ( buf, "PXEClient" ) == 0 ) &&
+ setting_exists ( NULL, &pxe_boot_menu_setting ) &&
+ ( ! ( ( pxe_discovery_control & PXEBS_SKIP ) &&
+ setting_exists ( NULL, &filename_setting ) ) ) ) {
+ printf ( "Booting from PXE menu\n" );
+ return pxe_menu_boot ( netdev );
+ }
/* Try to download and boot whatever we are given as a filename */
fetch_ipv4_setting ( NULL, &next_server_setting, &next_server );
diff --git a/gpxe/src/usr/dhcpmgmt.c b/gpxe/src/usr/dhcpmgmt.c
index 2e429cd6..6acf7f6d 100644
--- a/gpxe/src/usr/dhcpmgmt.c
+++ b/gpxe/src/usr/dhcpmgmt.c
@@ -46,3 +46,14 @@ int dhcp ( struct net_device *netdev ) {
return rc;
}
+
+int pxebs ( struct net_device *netdev, unsigned int pxe_type ) {
+ int rc;
+
+ /* Perform PXE Boot Server Discovery */
+ printf ( "PXEBS (%s type %d)", netdev->name, pxe_type );
+ if ( ( rc = start_pxebs ( &monojob, netdev, pxe_type ) ) == 0 )
+ rc = monojob_wait ( "" );
+
+ return rc;
+}
diff --git a/gpxe/src/usr/ifmgmt.c b/gpxe/src/usr/ifmgmt.c
index 9c88ab53..0ebf5615 100644
--- a/gpxe/src/usr/ifmgmt.c
+++ b/gpxe/src/usr/ifmgmt.c
@@ -20,9 +20,11 @@
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
+#include <console.h>
#include <gpxe/netdevice.h>
#include <gpxe/device.h>
#include <gpxe/process.h>
+#include <gpxe/keys.h>
#include <usr/ifmgmt.h>
/** @file
@@ -59,6 +61,25 @@ void ifclose ( struct net_device *netdev ) {
}
/**
+ * Print network device error breakdown
+ *
+ * @v stats Network device statistics
+ * @v prefix Message prefix
+ */
+static void ifstat_errors ( struct net_device_stats *stats,
+ const char *prefix ) {
+ unsigned int i;
+
+ for ( i = 0 ; i < ( sizeof ( stats->errors ) /
+ sizeof ( stats->errors[0] ) ) ; i++ ) {
+ if ( stats->errors[i].count )
+ printf ( " [%s: %d x \"%s\"]\n", prefix,
+ stats->errors[i].count,
+ strerror ( stats->errors[i].rc ) );
+ }
+}
+
+/**
* Print status of network device
*
* @v netdev Network device
@@ -69,8 +90,10 @@ void ifstat ( struct net_device *netdev ) {
netdev->name, netdev_hwaddr ( netdev ), netdev->dev->name,
( ( netdev->state & NETDEV_OPEN ) ? "open" : "closed" ),
( netdev_link_ok ( netdev ) ? "up" : "down" ),
- netdev->stats.tx_ok, netdev->stats.tx_err,
- netdev->stats.rx_ok, netdev->stats.rx_err );
+ netdev->tx_stats.good, netdev->tx_stats.bad,
+ netdev->rx_stats.good, netdev->rx_stats.bad );
+ ifstat_errors ( &netdev->tx_stats, "TXE" );
+ ifstat_errors ( &netdev->rx_stats, "RXE" );
}
/**
@@ -80,12 +103,19 @@ void ifstat ( struct net_device *netdev ) {
* @v max_wait_ms Maximum time to wait, in ms
*/
int iflinkwait ( struct net_device *netdev, unsigned int max_wait_ms ) {
+ int key;
+
while ( 1 ) {
if ( netdev_link_ok ( netdev ) )
return 0;
if ( max_wait_ms-- == 0 )
return -ETIMEDOUT;
step();
+ if ( iskey() ) {
+ key = getchar();
+ if ( key == CTRL_C )
+ return -ECANCELED;
+ }
mdelay ( 1 );
}
}
diff --git a/gpxe/src/usr/imgmgmt.c b/gpxe/src/usr/imgmgmt.c
index be153f87..bd53d824 100644
--- a/gpxe/src/usr/imgmgmt.c
+++ b/gpxe/src/usr/imgmgmt.c
@@ -43,7 +43,10 @@
*/
int imgfetch ( struct image *image, const char *uri_string,
int ( * image_register ) ( struct image *image ) ) {
+ char uri_string_redacted[ strlen ( uri_string ) + 3 /* "***" */
+ + 1 /* NUL */ ];
struct uri *uri;
+ const char *password;
int rc;
if ( ! ( uri = parse_uri ( uri_string ) ) )
@@ -51,9 +54,17 @@ int imgfetch ( struct image *image, const char *uri_string,
image_set_uri ( image, uri );
+ /* Redact password portion of URI, if necessary */
+ password = uri->password;
+ if ( password )
+ uri->password = "***";
+ unparse_uri ( uri_string_redacted, sizeof ( uri_string_redacted ),
+ uri );
+ uri->password = password;
+
if ( ( rc = create_downloader ( &monojob, image, image_register,
LOCATION_URI, uri ) ) == 0 )
- rc = monojob_wait ( uri_string );
+ rc = monojob_wait ( uri_string_redacted );
uri_put ( uri );
return rc;
diff --git a/gpxe/src/usr/pxemenu.c b/gpxe/src/usr/pxemenu.c
new file mode 100644
index 00000000..793cb624
--- /dev/null
+++ b/gpxe/src/usr/pxemenu.c
@@ -0,0 +1,381 @@
+/*
+ * Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <byteswap.h>
+#include <curses.h>
+#include <console.h>
+#include <gpxe/dhcp.h>
+#include <gpxe/keys.h>
+#include <gpxe/timer.h>
+#include <gpxe/process.h>
+#include <usr/dhcpmgmt.h>
+#include <usr/autoboot.h>
+
+/** @file
+ *
+ * PXE Boot Menus
+ *
+ */
+
+/* Colour pairs */
+#define CPAIR_NORMAL 1
+#define CPAIR_SELECT 2
+
+/** A PXE boot menu item */
+struct pxe_menu_item {
+ /** Boot Server type */
+ unsigned int type;
+ /** Description */
+ char *desc;
+};
+
+/**
+ * A PXE boot menu
+ *
+ * This structure encapsulates the menu information provided via DHCP
+ * options.
+ */
+struct pxe_menu {
+ /** Prompt string (optional) */
+ const char *prompt;
+ /** Timeout (in seconds)
+ *
+ * Negative indicates no timeout (i.e. wait indefinitely)
+ */
+ int timeout;
+ /** Number of menu items */
+ unsigned int num_items;
+ /** Selected menu item */
+ unsigned int selection;
+ /** Menu items */
+ struct pxe_menu_item items[0];
+};
+
+/**
+ * Parse and allocate PXE boot menu
+ *
+ * @v menu PXE boot menu to fill in
+ * @ret rc Return status code
+ *
+ * It is the callers responsibility to eventually free the allocated
+ * boot menu.
+ */
+static int pxe_menu_parse ( struct pxe_menu **menu ) {
+ struct setting pxe_boot_menu_prompt_setting =
+ { .tag = DHCP_PXE_BOOT_MENU_PROMPT };
+ struct setting pxe_boot_menu_setting =
+ { .tag = DHCP_PXE_BOOT_MENU };
+ uint8_t raw_menu[256];
+ int raw_prompt_len;
+ int raw_menu_len;
+ struct dhcp_pxe_boot_menu *raw_menu_item;
+ struct dhcp_pxe_boot_menu_prompt *raw_menu_prompt;
+ void *raw_menu_end;
+ unsigned int num_menu_items;
+ unsigned int i;
+ int rc;
+
+ /* Fetch raw menu */
+ memset ( raw_menu, 0, sizeof ( raw_menu ) );
+ if ( ( raw_menu_len = fetch_setting ( NULL, &pxe_boot_menu_setting,
+ raw_menu,
+ sizeof ( raw_menu ) ) ) < 0 ) {
+ rc = raw_menu_len;
+ DBG ( "Could not retrieve raw PXE boot menu: %s\n",
+ strerror ( rc ) );
+ return rc;
+ }
+ if ( raw_menu_len >= ( int ) sizeof ( raw_menu ) ) {
+ DBG ( "Raw PXE boot menu too large for buffer\n" );
+ return -ENOSPC;
+ }
+ raw_menu_end = ( raw_menu + raw_menu_len );
+
+ /* Fetch raw prompt length */
+ raw_prompt_len = fetch_setting_len ( NULL,
+ &pxe_boot_menu_prompt_setting );
+ if ( raw_prompt_len < 0 )
+ raw_prompt_len = 0;
+
+ /* Count menu items */
+ num_menu_items = 0;
+ raw_menu_item = ( ( void * ) raw_menu );
+ while ( 1 ) {
+ if ( ( ( ( void * ) raw_menu_item ) +
+ sizeof ( *raw_menu_item ) ) > raw_menu_end )
+ break;
+ if ( ( ( ( void * ) raw_menu_item ) +
+ sizeof ( *raw_menu_item ) +
+ raw_menu_item->desc_len ) > raw_menu_end )
+ break;
+ num_menu_items++;
+ raw_menu_item = ( ( ( void * ) raw_menu_item ) +
+ sizeof ( *raw_menu_item ) +
+ raw_menu_item->desc_len );
+ }
+
+ /* Allocate space for parsed menu */
+ *menu = zalloc ( sizeof ( **menu ) +
+ ( num_menu_items * sizeof ( (*menu)->items[0] ) ) +
+ raw_menu_len + 1 /* NUL */ +
+ raw_prompt_len + 1 /* NUL */ );
+ if ( ! *menu ) {
+ DBG ( "Could not allocate PXE boot menu\n" );
+ return -ENOMEM;
+ }
+
+ /* Fill in parsed menu */
+ (*menu)->num_items = num_menu_items;
+ raw_menu_item = ( ( ( void * ) (*menu) ) + sizeof ( **menu ) +
+ ( num_menu_items * sizeof ( (*menu)->items[0] ) ) );
+ memcpy ( raw_menu_item, raw_menu, raw_menu_len );
+ for ( i = 0 ; i < num_menu_items ; i++ ) {
+ (*menu)->items[i].type = ntohs ( raw_menu_item->type );
+ (*menu)->items[i].desc = raw_menu_item->desc;
+ /* Set type to 0; this ensures that the description
+ * for the previous menu item is NUL-terminated.
+ * (Final item is NUL-terminated anyway.)
+ */
+ raw_menu_item->type = 0;
+ raw_menu_item = ( ( ( void * ) raw_menu_item ) +
+ sizeof ( *raw_menu_item ) +
+ raw_menu_item->desc_len );
+ }
+ if ( raw_prompt_len ) {
+ raw_menu_prompt = ( ( ( void * ) raw_menu_item ) +
+ 1 /* NUL */ );
+ fetch_setting ( NULL, &pxe_boot_menu_prompt_setting,
+ raw_menu_prompt, raw_prompt_len );
+ (*menu)->timeout =
+ ( ( raw_menu_prompt->timeout == 0xff ) ?
+ -1 : raw_menu_prompt->timeout );
+ (*menu)->prompt = raw_menu_prompt->prompt;
+ } else {
+ (*menu)->timeout = -1;
+ }
+
+ return 0;
+}
+
+/**
+ * Draw PXE boot menu item
+ *
+ * @v menu PXE boot menu
+ * @v index Index of item to draw
+ * @v selected Item is selected
+ */
+static void pxe_menu_draw_item ( struct pxe_menu *menu,
+ unsigned int index, int selected ) {
+ char buf[COLS+1];
+ size_t len;
+ unsigned int row;
+
+ /* Prepare space-padded row content */
+ len = snprintf ( buf, sizeof ( buf ), " %c. %s",
+ ( 'A' + index ), menu->items[index].desc );
+ while ( len < ( sizeof ( buf ) - 1 ) )
+ buf[len++] = ' ';
+ buf[ sizeof ( buf ) - 1 ] = '\0';
+
+ /* Draw row */
+ row = ( LINES - menu->num_items + index );
+ color_set ( ( selected ? CPAIR_SELECT : CPAIR_NORMAL ), NULL );
+ mvprintw ( row, 0, "%s", buf );
+ move ( row, 1 );
+}
+
+/**
+ * Make selection from PXE boot menu
+ *
+ * @v menu PXE boot menu
+ * @ret rc Return status code
+ */
+static int pxe_menu_select ( struct pxe_menu *menu ) {
+ int key;
+ unsigned int key_selection;
+ unsigned int i;
+ int rc = 0;
+
+ /* Initialise UI */
+ initscr();
+ start_color();
+ init_pair ( CPAIR_NORMAL, COLOR_WHITE, COLOR_BLACK );
+ init_pair ( CPAIR_SELECT, COLOR_BLACK, COLOR_WHITE );
+ color_set ( CPAIR_NORMAL, NULL );
+
+ /* Draw initial menu */
+ for ( i = 0 ; i < menu->num_items ; i++ )
+ printf ( "\n" );
+ for ( i = 0 ; i < menu->num_items ; i++ )
+ pxe_menu_draw_item ( menu, ( menu->num_items - i - 1 ), 0 );
+
+ while ( 1 ) {
+
+ /* Highlight currently selected item */
+ pxe_menu_draw_item ( menu, menu->selection, 1 );
+
+ /* Wait for keyboard input */
+ while ( ! iskey() )
+ step();
+ key = getkey();
+
+ /* Unhighlight currently selected item */
+ pxe_menu_draw_item ( menu, menu->selection, 0 );
+
+ /* Act upon key */
+ if ( ( key == CR ) || ( key == LF ) ) {
+ pxe_menu_draw_item ( menu, menu->selection, 1 );
+ break;
+ } else if ( ( key == CTRL_C ) || ( key == ESC ) ) {
+ rc = -ECANCELED;
+ break;
+ } else if ( key == KEY_UP ) {
+ if ( menu->selection > 0 )
+ menu->selection--;
+ } else if ( key == KEY_DOWN ) {
+ if ( menu->selection < ( menu->num_items - 1 ) )
+ menu->selection++;
+ } else if ( ( key < KEY_MIN ) &&
+ ( ( key_selection = ( toupper ( key ) - 'A' ) )
+ < menu->num_items ) ) {
+ menu->selection = key_selection;
+ pxe_menu_draw_item ( menu, menu->selection, 1 );
+ break;
+ }
+ }
+
+ /* Shut down UI */
+ endwin();
+
+ return rc;
+}
+
+/**
+ * Prompt for (and make selection from) PXE boot menu
+ *
+ * @v menu PXE boot menu
+ * @ret rc Return status code
+ */
+static int pxe_menu_prompt_and_select ( struct pxe_menu *menu ) {
+ unsigned long start = currticks();
+ unsigned long now;
+ unsigned long elapsed;
+ size_t len = 0;
+ int key;
+ int rc = 0;
+
+ /* Display menu immediately, if specified to do so */
+ if ( menu->timeout < 0 ) {
+ if ( menu->prompt )
+ printf ( "%s\n", menu->prompt );
+ return pxe_menu_select ( menu );
+ }
+
+ /* Display prompt, if specified */
+ if ( menu->prompt )
+ printf ( "%s", menu->prompt );
+
+ /* Wait for timeout, if specified */
+ while ( menu->timeout > 0 ) {
+ if ( ! len )
+ len = printf ( " (%d)", menu->timeout );
+ if ( iskey() ) {
+ key = getkey();
+ if ( key == KEY_F8 ) {
+ /* Display menu */
+ printf ( "\n" );
+ return pxe_menu_select ( menu );
+ } else if ( ( key == CTRL_C ) || ( key == ESC ) ) {
+ /* Abort */
+ rc = -ECANCELED;
+ break;
+ } else {
+ /* Stop waiting */
+ break;
+ }
+ }
+ now = currticks();
+ elapsed = ( now - start );
+ if ( elapsed >= TICKS_PER_SEC ) {
+ menu->timeout -= 1;
+ do {
+ printf ( "\b \b" );
+ } while ( --len );
+ start = now;
+ }
+ }
+
+ /* Return with default option selected */
+ printf ( "\n" );
+ return rc;
+}
+
+/**
+ * Boot using PXE boot menu
+ *
+ * @ret rc Return status code
+ *
+ * Note that a success return status indicates that a PXE boot menu
+ * item has been selected, and that the DHCP session should perform a
+ * boot server request/ack.
+ */
+int pxe_menu_boot ( struct net_device *netdev ) {
+ struct pxe_menu *menu;
+ unsigned int pxe_type;
+ struct settings *pxebs_settings;
+ struct in_addr next_server;
+ char filename[256];
+ int rc;
+
+ /* Parse and allocate boot menu */
+ if ( ( rc = pxe_menu_parse ( &menu ) ) != 0 )
+ return rc;
+
+ /* Make selection from boot menu */
+ if ( ( rc = pxe_menu_prompt_and_select ( menu ) ) != 0 ) {
+ free ( menu );
+ return rc;
+ }
+ pxe_type = menu->items[menu->selection].type;
+
+ /* Free boot menu */
+ free ( menu );
+
+ /* Return immediately if local boot selected */
+ if ( ! pxe_type )
+ return 0;
+
+ /* Attempt PXE Boot Server Discovery */
+ if ( ( rc = pxebs ( netdev, pxe_type ) ) != 0 )
+ return rc;
+
+ /* Attempt boot */
+ pxebs_settings = find_settings ( PXEBS_SETTINGS_NAME );
+ assert ( pxebs_settings );
+ fetch_ipv4_setting ( pxebs_settings, &next_server_setting,
+ &next_server );
+ fetch_string_setting ( pxebs_settings, &filename_setting,
+ filename, sizeof ( filename ) );
+ return boot_next_server_and_filename ( next_server, filename );
+}
diff --git a/gpxe/src/util/.gitignore b/gpxe/src/util/.gitignore
index 98adc2df..c2567012 100644
--- a/gpxe/src/util/.gitignore
+++ b/gpxe/src/util/.gitignore
@@ -2,3 +2,6 @@ nrv2b
zbin
hijack
prototester
+elf2efi32
+elf2efi64
+efirom
diff --git a/gpxe/src/util/disrom.pl b/gpxe/src/util/disrom.pl
index 80ac4af8..1fb4cc3c 100755
--- a/gpxe/src/util/disrom.pl
+++ b/gpxe/src/util/disrom.pl
@@ -36,41 +36,46 @@ die "ROM image truncated (is $filelength, should be $romlength)\n"
if $filelength < $romlength;
printf "ROM header:\n\n";
-printf " Length:\t0x%02x (%d)\n", $rom->{length}, ( $rom->{length} * 512 );
-printf " Checksum:\t0x%02x (0x%02x)\n", $rom->{checksum}, $rom->checksum;
-printf " Init:\t\t0x%04x\n", $rom->{init};
-printf " UNDI header:\t0x%04x\n", $rom->{undi_header};
-printf " PCI header:\t0x%04x\n", $rom->{pci_header};
-printf " PnP header:\t0x%04x\n", $rom->{pnp_header};
+printf " %-16s 0x%02x (%d)\n", "Length:", $rom->{length}, ( $rom->{length} * 512 );
+printf " %-16s 0x%02x (%s0x%02x)\n", "Checksum:", $rom->{checksum},
+ ( ( $rom->checksum == 0 ) ? "" : "INCORRECT: " ), $rom->checksum;
+printf " %-16s 0x%04x\n", "Init:", $rom->{init};
+printf " %-16s 0x%04x\n", "UNDI header:", $rom->{undi_header};
+printf " %-16s 0x%04x\n", "PCI header:", $rom->{pci_header};
+printf " %-16s 0x%04x\n", "PnP header:", $rom->{pnp_header};
printf "\n";
my $pci = $rom->pci_header();
if ( $pci ) {
printf "PCI header:\n\n";
- printf " Signature:\t%s\n", $pci->{signature};
- printf " Vendor id:\t0x%04x\n", $pci->{vendor_id};
- printf " Device id:\t0x%04x\n", $pci->{device_id};
- printf " Device class:\t0x%02x%02x%02x\n",
+ printf " %-16s %s\n", "Signature:", $pci->{signature};
+ printf " %-16s 0x%04x\n", "Vendor ID:", $pci->{vendor_id};
+ printf " %-16s 0x%04x\n", "Device ID:", $pci->{device_id};
+ printf " %-16s 0x%02x%02x%02x\n", "Device class:",
$pci->{base_class}, $pci->{sub_class}, $pci->{prog_intf};
- printf " Image length:\t0x%04x (%d)\n",
+ printf " %-16s 0x%04x (%d)\n", "Image length:",
$pci->{image_length}, ( $pci->{image_length} * 512 );
- printf " Runtime length:\t0x%04x (%d)\n",
+ printf " %-16s 0x%04x (%d)\n", "Runtime length:",
$pci->{runtime_length}, ( $pci->{runtime_length} * 512 );
- printf " Config header:\t0x%04x\n", $pci->{conf_header};
- printf " CLP entry:\t0x%04x\n", $pci->{clp_entry};
+ if ( exists $pci->{conf_header} ) {
+ printf " %-16s 0x%04x\n", "Config header:", $pci->{conf_header};
+ printf " %-16s 0x%04x\n", "CLP entry:", $pci->{clp_entry};
+ }
printf "\n";
}
my $pnp = $rom->pnp_header();
if ( $pnp ) {
printf "PnP header:\n\n";
- printf " Signature:\t%s\n", $pnp->{signature};
- printf " Checksum:\t0x%02x (0x%02x)\n", $pnp->{checksum}, $pnp->checksum;
- printf " Manufacturer:\t0x%04x \"%s\"\n",
+ printf " %-16s %s\n", "Signature:", $pnp->{signature};
+ printf " %-16s 0x%02x (%s0x%02x)\n", "Checksum:", $pnp->{checksum},
+ ( ( $pnp->checksum == 0 ) ? "" : "INCORRECT: " ), $pnp->checksum;
+ printf " %-16s 0x%04x \"%s\"\n", "Manufacturer:",
$pnp->{manufacturer}, $pnp->manufacturer;
- printf " Product:\t0x%04x \"%s\"\n", $pnp->{product}, $pnp->product;
- printf " BCV:\t\t0x%04x\n", $pnp->{bcv};
- printf " BDV:\t\t0x%04x\n", $pnp->{bdv};
- printf " BEV:\t\t0x%04x\n", $pnp->{bev};
+ printf " %-16s 0x%04x \"%s\"\n", "Product:",
+ $pnp->{product}, $pnp->product;
+ printf " %-16s 0x%04x\n", "BCV:", $pnp->{bcv};
+ printf " %-16s 0x%04x\n", "BDV:", $pnp->{bdv};
+ printf " %-16s 0x%04x\n", "BEV:", $pnp->{bev};
printf "\n";
}
diff --git a/gpxe/src/util/efirom.c b/gpxe/src/util/efirom.c
new file mode 100644
index 00000000..9369db87
--- /dev/null
+++ b/gpxe/src/util/efirom.c
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <getopt.h>
+#include <gpxe/efi/efi.h>
+#include <gpxe/efi/IndustryStandard/PeImage.h>
+#include <gpxe/efi/IndustryStandard/Pci22.h>
+
+#define eprintf(...) fprintf ( stderr, __VA_ARGS__ )
+
+/** Command-line options */
+struct options {
+ uint16_t vendor;
+ uint16_t device;
+};
+
+/**
+ * Allocate memory
+ *
+ * @v len Length of memory to allocate
+ * @ret ptr Pointer to allocated memory
+ */
+static void * xmalloc ( size_t len ) {
+ void *ptr;
+
+ ptr = malloc ( len );
+ if ( ! ptr ) {
+ eprintf ( "Could not allocate %zd bytes\n", len );
+ exit ( 1 );
+ }
+
+ return ptr;
+}
+
+/**
+ * Get file size
+ *
+ * @v file File
+ * @v len File size
+ */
+static size_t file_size ( FILE *file ) {
+ ssize_t len;
+
+ return len;
+}
+
+/**
+ * Read information from PE headers
+ *
+ * @v pe PE file
+ * @ret machine Machine type
+ * @ret subsystem EFI subsystem
+ */
+static void read_pe_info ( void *pe, uint16_t *machine,
+ uint16_t *subsystem ) {
+ EFI_IMAGE_DOS_HEADER *dos;
+ union {
+ EFI_IMAGE_NT_HEADERS32 nt32;
+ EFI_IMAGE_NT_HEADERS64 nt64;
+ } *nt;
+
+ /* Locate NT header */
+ dos = pe;
+ nt = ( pe + dos->e_lfanew );
+
+ /* Parse out PE information */
+ *machine = nt->nt32.FileHeader.Machine;
+ switch ( *machine ) {
+ case EFI_IMAGE_MACHINE_IA32:
+ *subsystem = nt->nt32.OptionalHeader.Subsystem;
+ break;
+ case EFI_IMAGE_MACHINE_X64:
+ *subsystem = nt->nt64.OptionalHeader.Subsystem;
+ break;
+ default:
+ eprintf ( "Unrecognised machine type %04x\n", *machine );
+ exit ( 1 );
+ }
+}
+
+/**
+ * Convert EFI image to ROM image
+ *
+ * @v pe EFI file
+ * @v rom ROM file
+ */
+static void make_efi_rom ( FILE *pe, FILE *rom, struct options *opts ) {
+ struct {
+ EFI_PCI_EXPANSION_ROM_HEADER rom;
+ PCI_DATA_STRUCTURE pci __attribute__ (( aligned ( 4 ) ));
+ uint8_t checksum;
+ } *headers;
+ struct stat pe_stat;
+ size_t pe_size;
+ size_t rom_size;
+ void *buf;
+ void *payload;
+ unsigned int i;
+ uint8_t checksum;
+
+ /* Determine PE file size */
+ if ( fstat ( fileno ( pe ), &pe_stat ) != 0 ) {
+ eprintf ( "Could not stat PE file: %s\n",
+ strerror ( errno ) );
+ exit ( 1 );
+ }
+ pe_size = pe_stat.st_size;
+
+ /* Determine ROM file size */
+ rom_size = ( ( pe_size + sizeof ( *headers ) + 511 ) & ~511 );
+
+ /* Allocate ROM buffer and read in PE file */
+ buf = xmalloc ( rom_size );
+ memset ( buf, 0, rom_size );
+ headers = buf;
+ payload = ( buf + sizeof ( *headers ) );
+ if ( fread ( payload, pe_size, 1, pe ) != 1 ) {
+ eprintf ( "Could not read PE file: %s\n",
+ strerror ( errno ) );
+ exit ( 1 );
+ }
+
+ /* Construct ROM header */
+ headers->rom.Signature = PCI_EXPANSION_ROM_HEADER_SIGNATURE;
+ headers->rom.InitializationSize = ( rom_size / 512 );
+ headers->rom.EfiSignature = EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE;
+ read_pe_info ( payload, &headers->rom.EfiMachineType,
+ &headers->rom.EfiSubsystem );
+ headers->rom.EfiImageHeaderOffset = sizeof ( *headers );
+ headers->rom.PcirOffset =
+ offsetof ( typeof ( *headers ), pci );
+ headers->pci.Signature = PCI_DATA_STRUCTURE_SIGNATURE;
+ headers->pci.VendorId = opts->vendor;
+ headers->pci.DeviceId = opts->device;
+ headers->pci.Length = sizeof ( headers->pci );
+ headers->pci.ClassCode[0] = PCI_CLASS_NETWORK;
+ headers->pci.ImageLength = ( rom_size / 512 );
+ headers->pci.CodeType = 0x03; /* No constant in EFI headers? */
+ headers->pci.Indicator = 0x80; /* No constant in EFI headers? */
+
+ /* Fix image checksum */
+ for ( i = 0, checksum = 0 ; i < rom_size ; i++ )
+ checksum += *( ( uint8_t * ) buf + i );
+ headers->checksum -= checksum;
+
+ /* Write out ROM */
+ if ( fwrite ( buf, rom_size, 1, rom ) != 1 ) {
+ eprintf ( "Could not write ROM file: %s\n",
+ strerror ( errno ) );
+ exit ( 1 );
+ }
+}
+
+/**
+ * Print help
+ *
+ * @v program_name Program name
+ */
+static void print_help ( const char *program_name ) {
+ eprintf ( "Syntax: %s [--vendor=VVVV] [--device=DDDD] "
+ "infile outfile\n", program_name );
+}
+
+/**
+ * Parse command-line options
+ *
+ * @v argc Argument count
+ * @v argv Argument list
+ * @v opts Options structure to populate
+ */
+static int parse_options ( const int argc, char **argv,
+ struct options *opts ) {
+ char *end;
+ int c;
+
+ while (1) {
+ int option_index = 0;
+ static struct option long_options[] = {
+ { "vendor", required_argument, NULL, 'v' },
+ { "device", required_argument, NULL, 'd' },
+ { "help", 0, NULL, 'h' },
+ { 0, 0, 0, 0 }
+ };
+
+ if ( ( c = getopt_long ( argc, argv, "v:d:h",
+ long_options,
+ &option_index ) ) == -1 ) {
+ break;
+ }
+
+ switch ( c ) {
+ case 'v':
+ opts->vendor = strtoul ( optarg, &end, 16 );
+ if ( *end ) {
+ eprintf ( "Invalid vendor \"%s\"\n", optarg );
+ exit ( 2 );
+ }
+ break;
+ case 'd':
+ opts->device = strtoul ( optarg, &end, 16 );
+ if ( *end ) {
+ eprintf ( "Invalid device \"%s\"\n", optarg );
+ exit ( 2 );
+ }
+ break;
+ case 'h':
+ print_help ( argv[0] );
+ exit ( 0 );
+ case '?':
+ default:
+ exit ( 2 );
+ }
+ }
+ return optind;
+}
+
+int main ( int argc, char **argv ) {
+ struct options opts = {
+ };
+ unsigned int infile_index;
+ const char *infile_name;
+ const char *outfile_name;
+ FILE *infile;
+ FILE *outfile;
+
+ /* Parse command-line arguments */
+ infile_index = parse_options ( argc, argv, &opts );
+ if ( argc != ( infile_index + 2 ) ) {
+ print_help ( argv[0] );
+ exit ( 2 );
+ }
+ infile_name = argv[infile_index];
+ outfile_name = argv[infile_index + 1];
+
+ /* Open input and output files */
+ infile = fopen ( infile_name, "r" );
+ if ( ! infile ) {
+ eprintf ( "Could not open %s for reading: %s\n",
+ infile_name, strerror ( errno ) );
+ exit ( 1 );
+ }
+ outfile = fopen ( outfile_name, "w" );
+ if ( ! outfile ) {
+ eprintf ( "Could not open %s for writing: %s\n",
+ outfile_name, strerror ( errno ) );
+ exit ( 1 );
+ }
+
+ /* Convert file */
+ make_efi_rom ( infile, outfile, &opts );
+
+ fclose ( outfile );
+ fclose ( infile );
+
+ return 0;
+}
diff --git a/gpxe/src/util/elf2efi.c b/gpxe/src/util/elf2efi.c
new file mode 100644
index 00000000..886777d9
--- /dev/null
+++ b/gpxe/src/util/elf2efi.c
@@ -0,0 +1,803 @@
+/*
+ * Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define _GNU_SOURCE
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <getopt.h>
+#include <bfd.h>
+#include <gpxe/efi/efi.h>
+#include <gpxe/efi/IndustryStandard/PeImage.h>
+
+#define eprintf(...) fprintf ( stderr, __VA_ARGS__ )
+
+#define EFI_FILE_ALIGN 0x20
+
+struct pe_section {
+ struct pe_section *next;
+ EFI_IMAGE_SECTION_HEADER hdr;
+ uint8_t contents[0];
+};
+
+struct pe_relocs {
+ struct pe_relocs *next;
+ unsigned long start_rva;
+ unsigned int used_relocs;
+ unsigned int total_relocs;
+ uint16_t *relocs;
+};
+
+struct pe_header {
+ EFI_IMAGE_DOS_HEADER dos;
+ uint8_t padding[128];
+#if defined(MDE_CPU_IA32)
+ EFI_IMAGE_NT_HEADERS32 nt;
+#elif defined(MDE_CPU_X64)
+ EFI_IMAGE_NT_HEADERS64 nt;
+#endif
+};
+
+static struct pe_header efi_pe_header = {
+ .dos = {
+ .e_magic = EFI_IMAGE_DOS_SIGNATURE,
+ .e_lfanew = offsetof ( typeof ( efi_pe_header ), nt ),
+ },
+ .nt = {
+ .Signature = EFI_IMAGE_NT_SIGNATURE,
+ .FileHeader = {
+#if defined(MDE_CPU_IA32)
+ .Machine = EFI_IMAGE_MACHINE_IA32,
+#elif defined(MDE_CPU_X64)
+ .Machine = EFI_IMAGE_MACHINE_X64,
+#endif
+ .TimeDateStamp = 0x10d1a884,
+ .SizeOfOptionalHeader =
+ sizeof ( efi_pe_header.nt.OptionalHeader ),
+ .Characteristics = ( EFI_IMAGE_FILE_DLL |
+#if defined(MDE_CPU_IA32)
+ EFI_IMAGE_FILE_32BIT_MACHINE |
+#endif
+ EFI_IMAGE_FILE_EXECUTABLE_IMAGE ),
+ },
+ .OptionalHeader = {
+#if defined(MDE_CPU_IA32)
+ .Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC,
+#elif defined(MDE_CPU_X64)
+ .Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC,
+#endif
+ .SectionAlignment = EFI_FILE_ALIGN,
+ .FileAlignment = EFI_FILE_ALIGN,
+ .SizeOfImage = sizeof ( efi_pe_header ),
+ .SizeOfHeaders = sizeof ( efi_pe_header ),
+ .NumberOfRvaAndSizes =
+ EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES,
+ },
+ },
+};
+
+/** Command-line options */
+struct options {
+ unsigned int subsystem;
+};
+
+/**
+ * Allocate memory
+ *
+ * @v len Length of memory to allocate
+ * @ret ptr Pointer to allocated memory
+ */
+static void * xmalloc ( size_t len ) {
+ void *ptr;
+
+ ptr = malloc ( len );
+ if ( ! ptr ) {
+ eprintf ( "Could not allocate %zd bytes\n", len );
+ exit ( 1 );
+ }
+
+ return ptr;
+}
+
+/**
+ * Align section within PE file
+ *
+ * @v offset Unaligned offset
+ * @ret aligned_offset Aligned offset
+ */
+static unsigned long efi_file_align ( unsigned long offset ) {
+ return ( ( offset + EFI_FILE_ALIGN - 1 ) & ~( EFI_FILE_ALIGN - 1 ) );
+}
+
+/**
+ * Generate entry in PE relocation table
+ *
+ * @v pe_reltab PE relocation table
+ * @v rva RVA
+ * @v size Size of relocation entry
+ */
+static void generate_pe_reloc ( struct pe_relocs **pe_reltab,
+ unsigned long rva, size_t size ) {
+ unsigned long start_rva;
+ uint16_t reloc;
+ struct pe_relocs *pe_rel;
+ uint16_t *relocs;
+
+ /* Construct */
+ start_rva = ( rva & ~0xfff );
+ reloc = ( rva & 0xfff );
+ switch ( size ) {
+ case 8:
+ reloc |= 0xa000;
+ break;
+ case 4:
+ reloc |= 0x3000;
+ break;
+ case 2:
+ reloc |= 0x2000;
+ break;
+ default:
+ eprintf ( "Unsupported relocation size %zd\n", size );
+ exit ( 1 );
+ }
+
+ /* Locate or create PE relocation table */
+ for ( pe_rel = *pe_reltab ; pe_rel ; pe_rel = pe_rel->next ) {
+ if ( pe_rel->start_rva == start_rva )
+ break;
+ }
+ if ( ! pe_rel ) {
+ pe_rel = xmalloc ( sizeof ( *pe_rel ) );
+ memset ( pe_rel, 0, sizeof ( *pe_rel ) );
+ pe_rel->next = *pe_reltab;
+ *pe_reltab = pe_rel;
+ pe_rel->start_rva = start_rva;
+ }
+
+ /* Expand relocation list if necessary */
+ if ( pe_rel->used_relocs < pe_rel->total_relocs ) {
+ relocs = pe_rel->relocs;
+ } else {
+ pe_rel->total_relocs = ( pe_rel->total_relocs ?
+ ( pe_rel->total_relocs * 2 ) : 256 );
+ relocs = xmalloc ( pe_rel->total_relocs *
+ sizeof ( pe_rel->relocs[0] ) );
+ memset ( relocs, 0,
+ pe_rel->total_relocs * sizeof ( pe_rel->relocs[0] ) );
+ memcpy ( relocs, pe_rel->relocs,
+ pe_rel->used_relocs * sizeof ( pe_rel->relocs[0] ) );
+ free ( pe_rel->relocs );
+ pe_rel->relocs = relocs;
+ }
+
+ /* Store relocation */
+ pe_rel->relocs[ pe_rel->used_relocs++ ] = reloc;
+}
+
+/**
+ * Calculate size of binary PE relocation table
+ *
+ * @v pe_reltab PE relocation table
+ * @v buffer Buffer to contain binary table, or NULL
+ * @ret size Size of binary table
+ */
+static size_t output_pe_reltab ( struct pe_relocs *pe_reltab,
+ void *buffer ) {
+ struct pe_relocs *pe_rel;
+ unsigned int num_relocs;
+ size_t size;
+ size_t total_size = 0;
+
+ for ( pe_rel = pe_reltab ; pe_rel ; pe_rel = pe_rel->next ) {
+ num_relocs = ( ( pe_rel->used_relocs + 1 ) & ~1 );
+ size = ( sizeof ( uint32_t ) /* VirtualAddress */ +
+ sizeof ( uint32_t ) /* SizeOfBlock */ +
+ ( num_relocs * sizeof ( uint16_t ) ) );
+ if ( buffer ) {
+ *( (uint32_t *) ( buffer + total_size + 0 ) )
+ = pe_rel->start_rva;
+ *( (uint32_t *) ( buffer + total_size + 4 ) ) = size;
+ memcpy ( ( buffer + total_size + 8 ), pe_rel->relocs,
+ ( num_relocs * sizeof ( uint16_t ) ) );
+ }
+ total_size += size;
+ }
+
+ return total_size;
+}
+
+/**
+ * Open input BFD file
+ *
+ * @v filename File name
+ * @ret ibfd BFD file
+ */
+static bfd * open_input_bfd ( const char *filename ) {
+ bfd *bfd;
+
+ /* Open the file */
+ bfd = bfd_openr ( filename, NULL );
+ if ( ! bfd ) {
+ eprintf ( "Cannot open %s: ", filename );
+ bfd_perror ( NULL );
+ exit ( 1 );
+ }
+
+ /* The call to bfd_check_format() must be present, otherwise
+ * we get a segfault from later BFD calls.
+ */
+ if ( bfd_check_format ( bfd, bfd_object ) < 0 ) {
+ eprintf ( "%s is not an object file\n", filename );
+ exit ( 1 );
+ }
+
+ return bfd;
+}
+
+/**
+ * Read symbol table
+ *
+ * @v bfd BFD file
+ */
+static asymbol ** read_symtab ( bfd *bfd ) {
+ long symtab_size;
+ asymbol **symtab;
+ long symcount;
+
+ /* Get symbol table size */
+ symtab_size = bfd_get_symtab_upper_bound ( bfd );
+ if ( symtab_size < 0 ) {
+ bfd_perror ( "Could not get symbol table upper bound" );
+ exit ( 1 );
+ }
+
+ /* Allocate and read symbol table */
+ symtab = xmalloc ( symtab_size );
+ symcount = bfd_canonicalize_symtab ( bfd, symtab );
+ if ( symcount < 0 ) {
+ bfd_perror ( "Cannot read symbol table" );
+ exit ( 1 );
+ }
+
+ return symtab;
+}
+
+/**
+ * Read relocation table
+ *
+ * @v bfd BFD file
+ * @v symtab Symbol table
+ * @v section Section
+ * @v symtab Symbol table
+ * @ret reltab Relocation table
+ */
+static arelent ** read_reltab ( bfd *bfd, asymbol **symtab,
+ asection *section ) {
+ long reltab_size;
+ arelent **reltab;
+ long numrels;
+
+ /* Get relocation table size */
+ reltab_size = bfd_get_reloc_upper_bound ( bfd, section );
+ if ( reltab_size < 0 ) {
+ bfd_perror ( "Could not get relocation table upper bound" );
+ exit ( 1 );
+ }
+
+ /* Allocate and read relocation table */
+ reltab = xmalloc ( reltab_size );
+ numrels = bfd_canonicalize_reloc ( bfd, section, reltab, symtab );
+ if ( numrels < 0 ) {
+ bfd_perror ( "Cannot read relocation table" );
+ exit ( 1 );
+ }
+
+ return reltab;
+}
+
+/**
+ * Process section
+ *
+ * @v bfd BFD file
+ * @v pe_header PE file header
+ * @v section Section
+ * @ret new New PE section
+ */
+static struct pe_section * process_section ( bfd *bfd,
+ struct pe_header *pe_header,
+ asection *section ) {
+ struct pe_section *new;
+ size_t section_memsz;
+ size_t section_filesz;
+ unsigned long flags = bfd_get_section_flags ( bfd, section );
+ unsigned long code_start;
+ unsigned long code_end;
+ unsigned long data_start;
+ unsigned long data_mid;
+ unsigned long data_end;
+ unsigned long start;
+ unsigned long end;
+ unsigned long *applicable_start;
+ unsigned long *applicable_end;
+
+ /* Extract current RVA limits from file header */
+ code_start = pe_header->nt.OptionalHeader.BaseOfCode;
+ code_end = ( code_start + pe_header->nt.OptionalHeader.SizeOfCode );
+#if defined(MDE_CPU_IA32)
+ data_start = pe_header->nt.OptionalHeader.BaseOfData;
+#elif defined(MDE_CPU_X64)
+ data_start = code_end;
+#endif
+ data_mid = ( data_start +
+ pe_header->nt.OptionalHeader.SizeOfInitializedData );
+ data_end = ( data_mid +
+ pe_header->nt.OptionalHeader.SizeOfUninitializedData );
+
+ /* Allocate PE section */
+ section_memsz = bfd_section_size ( bfd, section );
+ section_filesz = ( ( flags & SEC_LOAD ) ?
+ efi_file_align ( section_memsz ) : 0 );
+ new = xmalloc ( sizeof ( *new ) + section_filesz );
+ memset ( new, 0, sizeof ( *new ) + section_filesz );
+
+ /* Fill in section header details */
+ strncpy ( ( char * ) new->hdr.Name, section->name,
+ sizeof ( new->hdr.Name ) );
+ new->hdr.Misc.VirtualSize = section_memsz;
+ new->hdr.VirtualAddress = bfd_get_section_vma ( bfd, section );
+ new->hdr.SizeOfRawData = section_filesz;
+
+ /* Fill in section characteristics and update RVA limits */
+ if ( flags & SEC_CODE ) {
+ /* .text-type section */
+ new->hdr.Characteristics =
+ ( EFI_IMAGE_SCN_CNT_CODE |
+ EFI_IMAGE_SCN_MEM_NOT_PAGED |
+ EFI_IMAGE_SCN_MEM_EXECUTE |
+ EFI_IMAGE_SCN_MEM_READ );
+ applicable_start = &code_start;
+ applicable_end = &code_end;
+ } else if ( flags & SEC_DATA ) {
+ /* .data-type section */
+ new->hdr.Characteristics =
+ ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
+ EFI_IMAGE_SCN_MEM_NOT_PAGED |
+ EFI_IMAGE_SCN_MEM_READ |
+ EFI_IMAGE_SCN_MEM_WRITE );
+ applicable_start = &data_start;
+ applicable_end = &data_mid;
+ } else if ( flags & SEC_READONLY ) {
+ /* .rodata-type section */
+ new->hdr.Characteristics =
+ ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
+ EFI_IMAGE_SCN_MEM_NOT_PAGED |
+ EFI_IMAGE_SCN_MEM_READ );
+ applicable_start = &data_start;
+ applicable_end = &data_mid;
+ } else if ( ! ( flags & SEC_LOAD ) ) {
+ /* .bss-type section */
+ new->hdr.Characteristics =
+ ( EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA |
+ EFI_IMAGE_SCN_MEM_NOT_PAGED |
+ EFI_IMAGE_SCN_MEM_READ |
+ EFI_IMAGE_SCN_MEM_WRITE );
+ applicable_start = &data_mid;
+ applicable_end = &data_end;
+ }
+
+ /* Copy in section contents */
+ if ( flags & SEC_LOAD ) {
+ if ( ! bfd_get_section_contents ( bfd, section, new->contents,
+ 0, section_memsz ) ) {
+ eprintf ( "Cannot read section %s: ", section->name );
+ bfd_perror ( NULL );
+ exit ( 1 );
+ }
+ }
+
+ /* Update RVA limits */
+ start = new->hdr.VirtualAddress;
+ end = ( start + new->hdr.Misc.VirtualSize );
+ if ( ( ! *applicable_start ) || ( *applicable_start >= start ) )
+ *applicable_start = start;
+ if ( *applicable_end < end )
+ *applicable_end = end;
+ if ( data_start < code_end )
+ data_start = code_end;
+ if ( data_mid < data_start )
+ data_mid = data_start;
+ if ( data_end < data_mid )
+ data_end = data_mid;
+
+ /* Write RVA limits back to file header */
+ pe_header->nt.OptionalHeader.BaseOfCode = code_start;
+ pe_header->nt.OptionalHeader.SizeOfCode = ( code_end - code_start );
+#if defined(MDE_CPU_IA32)
+ pe_header->nt.OptionalHeader.BaseOfData = data_start;
+#endif
+ pe_header->nt.OptionalHeader.SizeOfInitializedData =
+ ( data_mid - data_start );
+ pe_header->nt.OptionalHeader.SizeOfUninitializedData =
+ ( data_end - data_mid );
+
+ /* Update remaining file header fields */
+ pe_header->nt.FileHeader.NumberOfSections++;
+ pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( new->hdr );
+ pe_header->nt.OptionalHeader.SizeOfImage =
+ efi_file_align ( data_end );
+
+ return new;
+}
+
+/**
+ * Process relocation record
+ *
+ * @v bfd BFD file
+ * @v section Section
+ * @v rel Relocation entry
+ * @v pe_reltab PE relocation table to fill in
+ */
+static void process_reloc ( bfd *bfd, asection *section, arelent *rel,
+ struct pe_relocs **pe_reltab ) {
+ reloc_howto_type *howto = rel->howto;
+ asymbol *sym = *(rel->sym_ptr_ptr);
+ unsigned long offset = ( bfd_get_section_vma ( bfd, section ) +
+ rel->address );
+
+ if ( bfd_is_abs_section ( sym->section ) ) {
+ /* Skip absolute symbols; the symbol value won't
+ * change when the object is loaded.
+ */
+ } else if ( strcmp ( howto->name, "R_X86_64_64" ) == 0 ) {
+ /* Generate an 8-byte PE relocation */
+ generate_pe_reloc ( pe_reltab, offset, 8 );
+ } else if ( ( strcmp ( howto->name, "R_386_32" ) == 0 ) ||
+ ( strcmp ( howto->name, "R_X86_64_32" ) == 0 ) ) {
+ /* Generate a 4-byte PE relocation */
+ generate_pe_reloc ( pe_reltab, offset, 4 );
+ } else if ( strcmp ( howto->name, "R_386_16" ) == 0 ) {
+ /* Generate a 2-byte PE relocation */
+ generate_pe_reloc ( pe_reltab, offset, 2 );
+ } else if ( ( strcmp ( howto->name, "R_386_PC32" ) == 0 ) ||
+ ( strcmp ( howto->name, "R_X86_64_PC32" ) == 0 ) ) {
+ /* Skip PC-relative relocations; all relative offsets
+ * remain unaltered when the object is loaded.
+ */
+ } else {
+ eprintf ( "Unrecognised relocation type %s\n", howto->name );
+ exit ( 1 );
+ }
+}
+
+/**
+ * Create relocations section
+ *
+ * @v pe_header PE file header
+ * @v pe_reltab PE relocation table
+ * @ret section Relocation section
+ */
+static struct pe_section *
+create_reloc_section ( struct pe_header *pe_header,
+ struct pe_relocs *pe_reltab ) {
+ struct pe_section *reloc;
+ size_t section_memsz;
+ size_t section_filesz;
+ EFI_IMAGE_DATA_DIRECTORY *relocdir;
+
+ /* Allocate PE section */
+ section_memsz = output_pe_reltab ( pe_reltab, NULL );
+ section_filesz = efi_file_align ( section_memsz );
+ reloc = xmalloc ( sizeof ( *reloc ) + section_filesz );
+ memset ( reloc, 0, sizeof ( *reloc ) + section_filesz );
+
+ /* Fill in section header details */
+ strncpy ( ( char * ) reloc->hdr.Name, ".reloc",
+ sizeof ( reloc->hdr.Name ) );
+ reloc->hdr.Misc.VirtualSize = section_memsz;
+ reloc->hdr.VirtualAddress = pe_header->nt.OptionalHeader.SizeOfImage;
+ reloc->hdr.SizeOfRawData = section_filesz;
+ reloc->hdr.Characteristics = ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
+ EFI_IMAGE_SCN_MEM_NOT_PAGED |
+ EFI_IMAGE_SCN_MEM_READ );
+
+ /* Copy in section contents */
+ output_pe_reltab ( pe_reltab, reloc->contents );
+
+ /* Update file header details */
+ pe_header->nt.FileHeader.NumberOfSections++;
+ pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( reloc->hdr );
+ pe_header->nt.OptionalHeader.SizeOfImage += section_filesz;
+ relocdir = &(pe_header->nt.OptionalHeader.DataDirectory
+ [EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]);
+ relocdir->VirtualAddress = reloc->hdr.VirtualAddress;
+ relocdir->Size = reloc->hdr.Misc.VirtualSize;
+
+ return reloc;
+}
+
+/**
+ * Create debug section
+ *
+ * @v pe_header PE file header
+ * @ret section Debug section
+ */
+static struct pe_section *
+create_debug_section ( struct pe_header *pe_header, const char *filename ) {
+ struct pe_section *debug;
+ size_t section_memsz;
+ size_t section_filesz;
+ EFI_IMAGE_DATA_DIRECTORY *debugdir;
+ struct {
+ EFI_IMAGE_DEBUG_DIRECTORY_ENTRY debug;
+ EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY rsds;
+ char name[ strlen ( filename ) + 1 ];
+ } *contents;
+
+ /* Allocate PE section */
+ section_memsz = sizeof ( *contents );
+ section_filesz = efi_file_align ( section_memsz );
+ debug = xmalloc ( sizeof ( *debug ) + section_filesz );
+ memset ( debug, 0, sizeof ( *debug ) + section_filesz );
+ contents = ( void * ) debug->contents;
+
+ /* Fill in section header details */
+ strncpy ( ( char * ) debug->hdr.Name, ".debug",
+ sizeof ( debug->hdr.Name ) );
+ debug->hdr.Misc.VirtualSize = section_memsz;
+ debug->hdr.VirtualAddress = pe_header->nt.OptionalHeader.SizeOfImage;
+ debug->hdr.SizeOfRawData = section_filesz;
+ debug->hdr.Characteristics = ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
+ EFI_IMAGE_SCN_MEM_NOT_PAGED |
+ EFI_IMAGE_SCN_MEM_READ );
+
+ /* Create section contents */
+ contents->debug.TimeDateStamp = 0x10d1a884;
+ contents->debug.Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;
+ contents->debug.SizeOfData =
+ ( sizeof ( *contents ) - sizeof ( contents->debug ) );
+ contents->debug.RVA = ( debug->hdr.VirtualAddress +
+ offsetof ( typeof ( *contents ), rsds ) );
+ contents->rsds.Signature = CODEVIEW_SIGNATURE_RSDS;
+ snprintf ( contents->name, sizeof ( contents->name ), "%s",
+ filename );
+
+ /* Update file header details */
+ pe_header->nt.FileHeader.NumberOfSections++;
+ pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( debug->hdr );
+ pe_header->nt.OptionalHeader.SizeOfImage += section_filesz;
+ debugdir = &(pe_header->nt.OptionalHeader.DataDirectory
+ [EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
+ debugdir->VirtualAddress = debug->hdr.VirtualAddress;
+ debugdir->Size = debug->hdr.Misc.VirtualSize;
+
+ return debug;
+}
+
+/**
+ * Write out PE file
+ *
+ * @v pe_header PE file header
+ * @v pe_sections List of PE sections
+ * @v pe Output file
+ */
+static void write_pe_file ( struct pe_header *pe_header,
+ struct pe_section *pe_sections,
+ FILE *pe ) {
+ struct pe_section *section;
+ unsigned long fpos = 0;
+
+ /* Assign raw data pointers */
+ fpos = efi_file_align ( pe_header->nt.OptionalHeader.SizeOfHeaders );
+ for ( section = pe_sections ; section ; section = section->next ) {
+ if ( section->hdr.SizeOfRawData ) {
+ section->hdr.PointerToRawData = fpos;
+ fpos += section->hdr.SizeOfRawData;
+ fpos = efi_file_align ( fpos );
+ }
+ }
+
+ /* Write file header */
+ if ( fwrite ( pe_header, sizeof ( *pe_header ), 1, pe ) != 1 ) {
+ perror ( "Could not write PE header" );
+ exit ( 1 );
+ }
+
+ /* Write section headers */
+ for ( section = pe_sections ; section ; section = section->next ) {
+ if ( fwrite ( &section->hdr, sizeof ( section->hdr ),
+ 1, pe ) != 1 ) {
+ perror ( "Could not write section header" );
+ exit ( 1 );
+ }
+ }
+
+ /* Write sections */
+ for ( section = pe_sections ; section ; section = section->next ) {
+ if ( fseek ( pe, section->hdr.PointerToRawData,
+ SEEK_SET ) != 0 ) {
+ eprintf ( "Could not seek to %lx: %s\n",
+ section->hdr.PointerToRawData,
+ strerror ( errno ) );
+ exit ( 1 );
+ }
+ if ( section->hdr.SizeOfRawData &&
+ ( fwrite ( section->contents, section->hdr.SizeOfRawData,
+ 1, pe ) != 1 ) ) {
+ eprintf ( "Could not write section %.8s: %s\n",
+ section->hdr.Name, strerror ( errno ) );
+ exit ( 1 );
+ }
+ }
+}
+
+/**
+ * Convert ELF to PE
+ *
+ * @v elf_name ELF file name
+ * @v pe_name PE file name
+ */
+static void elf2pe ( const char *elf_name, const char *pe_name,
+ struct options *opts ) {
+ bfd *bfd;
+ asymbol **symtab;
+ asection *section;
+ arelent **reltab;
+ arelent **rel;
+ struct pe_relocs *pe_reltab = NULL;
+ struct pe_section *pe_sections = NULL;
+ struct pe_section **next_pe_section = &pe_sections;
+ struct pe_header pe_header;
+ FILE *pe;
+
+ /* Open the file */
+ bfd = open_input_bfd ( elf_name );
+ symtab = read_symtab ( bfd );
+
+ /* Initialise the PE header */
+ memcpy ( &pe_header, &efi_pe_header, sizeof ( pe_header ) );
+ pe_header.nt.OptionalHeader.AddressOfEntryPoint =
+ bfd_get_start_address ( bfd );
+ pe_header.nt.OptionalHeader.Subsystem = opts->subsystem;
+
+ /* For each input section, build an output section and create
+ * the appropriate relocation records
+ */
+ for ( section = bfd->sections ; section ; section = section->next ) {
+ /* Discard non-allocatable sections */
+ if ( ! ( bfd_get_section_flags ( bfd, section ) & SEC_ALLOC ) )
+ continue;
+ /* Create output section */
+ *(next_pe_section) = process_section ( bfd, &pe_header,
+ section );
+ next_pe_section = &(*next_pe_section)->next;
+ /* Add relocations from this section */
+ reltab = read_reltab ( bfd, symtab, section );
+ for ( rel = reltab ; *rel ; rel++ )
+ process_reloc ( bfd, section, *rel, &pe_reltab );
+ free ( reltab );
+ }
+
+ /* Create the .reloc section */
+ *(next_pe_section) = create_reloc_section ( &pe_header, pe_reltab );
+ next_pe_section = &(*next_pe_section)->next;
+
+ /* Create the .reloc section */
+ *(next_pe_section) = create_debug_section ( &pe_header,
+ basename ( pe_name ) );
+ next_pe_section = &(*next_pe_section)->next;
+
+ /* Write out PE file */
+ pe = fopen ( pe_name, "w" );
+ if ( ! pe ) {
+ eprintf ( "Could not open %s for writing: %s\n",
+ pe_name, strerror ( errno ) );
+ exit ( 1 );
+ }
+ write_pe_file ( &pe_header, pe_sections, pe );
+ fclose ( pe );
+
+ /* Close BFD file */
+ bfd_close ( bfd );
+}
+
+/**
+ * Print help
+ *
+ * @v program_name Program name
+ */
+static void print_help ( const char *program_name ) {
+ eprintf ( "Syntax: %s [--subsystem=<number>] infile outfile\n",
+ program_name );
+}
+
+/**
+ * Parse command-line options
+ *
+ * @v argc Argument count
+ * @v argv Argument list
+ * @v opts Options structure to populate
+ */
+static int parse_options ( const int argc, char **argv,
+ struct options *opts ) {
+ char *end;
+ int c;
+
+ while (1) {
+ int option_index = 0;
+ static struct option long_options[] = {
+ { "subsystem", required_argument, NULL, 's' },
+ { "help", 0, NULL, 'h' },
+ { 0, 0, 0, 0 }
+ };
+
+ if ( ( c = getopt_long ( argc, argv, "s:h",
+ long_options,
+ &option_index ) ) == -1 ) {
+ break;
+ }
+
+ switch ( c ) {
+ case 's':
+ opts->subsystem = strtoul ( optarg, &end, 0 );
+ if ( *end ) {
+ eprintf ( "Invalid subsytem \"%s\"\n",
+ optarg );
+ exit ( 2 );
+ }
+ break;
+ case 'h':
+ print_help ( argv[0] );
+ exit ( 0 );
+ case '?':
+ default:
+ exit ( 2 );
+ }
+ }
+ return optind;
+}
+
+int main ( int argc, char **argv ) {
+ struct options opts = {
+ .subsystem = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION,
+ };
+ unsigned int infile_index;
+ const char *infile;
+ const char *outfile;
+
+ /* Initialise libbfd */
+ bfd_init();
+
+ /* Parse command-line arguments */
+ infile_index = parse_options ( argc, argv, &opts );
+ if ( argc != ( infile_index + 2 ) ) {
+ print_help ( argv[0] );
+ exit ( 2 );
+ }
+ infile = argv[infile_index];
+ outfile = argv[infile_index + 1];
+
+ /* Convert file */
+ elf2pe ( infile, outfile, &opts );
+
+ return 0;
+}
diff --git a/gpxe/src/util/geniso b/gpxe/src/util/geniso
index 7642ed36..d7ddbd2b 100755
--- a/gpxe/src/util/geniso
+++ b/gpxe/src/util/geniso
@@ -52,5 +52,5 @@ do
echo "" KERNEL $g
cp -p $f $dir/$g
done >> $cfg
-mkisofs -l -o $out -c boot.cat -b isolinux.bin -no-emul-boot -boot-load-size 4 -boot-info-table $dir
+mkisofs -q -l -o $out -c boot.cat -b isolinux.bin -no-emul-boot -boot-load-size 4 -boot-info-table $dir
rm -fr $dir
diff --git a/gpxe/src/util/mergerom.pl b/gpxe/src/util/mergerom.pl
index f9c52502..f9c52502 100644..100755
--- a/gpxe/src/util/mergerom.pl
+++ b/gpxe/src/util/mergerom.pl
diff --git a/gpxe/src/util/mkconfig.pl b/gpxe/src/util/mkconfig.pl
deleted file mode 100755
index e55c2ca8..00000000
--- a/gpxe/src/util/mkconfig.pl
+++ /dev/null
@@ -1,205 +0,0 @@
-#!/usr/bin/perl -w
-
-use File::Spec::Functions qw ( :ALL );
-use File::stat;
-use strict;
-use warnings;
-
-my $cfgdir = "config";
-my $config_h = shift || "config.h";
-my @input_files;
-
-# Read in a whole file
-#
-sub read_file {
- my $file = shift;
-
- open my $fh, "<$file" or die "Could not open file $file: $!\n";
- local $/;
- my $data = <$fh>;
- close $fh;
- return $data;
-}
-
-# Write out a whole file
-#
-sub write_file {
- my $file = shift;
- my $data = shift;
-
- open my $fh, ">$file" or die "Could not write $file: $!\n";
- print $fh $data;
- close $fh;
-}
-
-# Delete a file
-#
-sub delete_file {
- my $file = shift;
-
- unlink $file or die "Could not delete $file: $!\n";
-}
-
-# Get a file modification time
-#
-sub file_mtime {
- my $file = shift;
-
- my $stat = stat ( $file ) or die "Could not stat $file: $!\n";
- return $stat->mtime;
-}
-
-# Read all the .h files in a directory
-#
-sub read_dir {
- my $dir = shift;
-
- opendir my $dh, $dir or die "Could not open directory $dir: $!\n";
- my @entries = grep { /\.h$/ } readdir $dh;
- closedir $dh;
- return @entries;
-}
-
-# Get the current configuration by reading the configuration file
-# fragments
-#
-sub current_config {
- my $dir = shift;
-
- my $cfg = {};
- foreach my $file ( read_dir ( $dir ) ) {
- $cfg->{$file} = read_file ( catfile ( $dir, $file ) );
- }
- return $cfg;
-}
-
-# Calculate guard name for a header file
-#
-sub guard {
- my $name = shift;
-
- $name =~ s/\W/_/g;
- return "CONFIG_".( uc $name );
-}
-
-# Calculate preamble for a header file
-#
-sub preamble {
- my $name = shift;
- my $master = shift;
-
- my $guard = guard ( $name );
- my $preamble = <<"EOF";
-/*
- * This file is automatically generated from $master. Do not edit this
- * file; edit $master instead.
- *
- */
-
-#ifndef $guard
-#define $guard
-EOF
- return $preamble;
-}
-
-# Calculate postamble for a header file
-#
-sub postamble {
- my $name = shift;
-
- my $guard = guard ( $name );
- return "\n#endif /* $guard */\n";
-}
-
-# Parse one config.h file into an existing configuration
-#
-sub parse_config {
- my $file = shift;
- my $cfg = shift;
- my $cursor = "";
-
- push ( @input_files, $file );
-
- open my $fh, "<$file" or die "Could not open $file: $!\n";
- while ( <$fh> ) {
- if ( ( my $newcursor, my $suffix ) = /\@BEGIN\s+(\w+\.h)(.*)$/ ) {
- die "Missing \"\@END $cursor\" before \"\@BEGIN $1\""
- ." at $file line $.\n" if $cursor;
- $cursor = $newcursor;
- $cfg->{$cursor} = preamble ( $cursor, $file )
- unless exists $cfg->{$cursor};
- $cfg->{$cursor} .= "\n/*".$suffix."\n";
- } elsif ( ( my $prefix, my $oldcursor ) = /^(.*)\@END\s+(\w+\.h)/ ) {
- die "Missing \"\@BEGIN $oldcursor\" before \"\@END $oldcursor\""
- ." at $file line $.\n" unless $cursor eq $oldcursor;
- $cfg->{$cursor} .= $prefix."*/\n";
- $cursor = "";
- } elsif ( ( my $newfile ) = /\@TRYSOURCE\s+([\w\-]+\.h)/ ) {
- die "Missing \"\@END $cursor\" before \"\@TRYSOURCE $newfile\""
- ." at $file line $.\n" if $cursor;
- parse_config ( $newfile, $cfg ) if -e $newfile;
- } else {
- $cfg->{$cursor} .= $_ if $cursor;
- }
- }
- close $fh;
- die "Missing \"\@END $cursor\" in $file\n" if $cursor;
-}
-
-# Get the new configuration by splitting config.h file using the
-# @BEGIN/@END tags
-#
-sub new_config {
- my $file = shift;
- my $cfg = {};
-
- parse_config ( $file, $cfg );
-
- foreach my $cursor ( keys %$cfg ) {
- $cfg->{$cursor} .= postamble ( $cursor );
- }
-
- return $cfg;
-}
-
-#############################################################################
-#
-# Main program
-
-# Read in current config file fragments
-#
-my $current = current_config ( $cfgdir );
-
-# Read in config.h and split it into fragments
-#
-my $new = new_config ( $config_h );
-
-# Delete any no-longer-wanted config file fragments
-#
-foreach my $file ( keys %$current ) {
- unlink catfile ( $cfgdir, $file ) unless exists $new->{$file};
-}
-
-# Write out any modified fragments, and find the oldest timestamp of
-# any unmodified fragments.
-#
-my $oldest = time ();
-foreach my $file ( keys %$new ) {
- if ( $current->{$file} && $new->{$file} eq $current->{$file} ) {
- # Unmodified
- my $time = file_mtime ( catfile ( $cfgdir, $file ) );
- $oldest = $time if $time < $oldest;
- } else {
- write_file ( catfile ( $cfgdir, $file ), $new->{$file} );
- }
-}
-
-# If we now have fragments that are older than config.h, set the
-# timestamp on each input file to match the oldest fragment, to
-# prevent make from always attempting to rebuild the fragments.
-#
-foreach my $file ( @input_files ) {
- if ( $oldest < file_mtime ( $file ) ) {
- utime time(), $oldest, $file or die "Could not touch $file: $!\n";
- }
-}
diff --git a/gpxe/src/util/sortobjdump.pl b/gpxe/src/util/sortobjdump.pl
index 8ad7314b..1373a7ff 100755
--- a/gpxe/src/util/sortobjdump.pl
+++ b/gpxe/src/util/sortobjdump.pl
@@ -8,7 +8,7 @@ use warnings;
# linker maps produced by "make bin/%.map" by also showing the values
# of all non-global symbols.
-my %section_idx = ( "*ABS*" => "." );
+my %section_idx = ( "*ABS*" => ".", "*UND*" => "_" );
my %lines;
while ( <> ) {
if ( /^\s+(\d+)\s+([\.\*]\S+)\s+[0-9a-fA-F]+\s+[0-9a-fA-F]/ ) {
diff --git a/gpxe/src/util/zbin.c b/gpxe/src/util/zbin.c
index b24f401e..c1082b31 100644
--- a/gpxe/src/util/zbin.c
+++ b/gpxe/src/util/zbin.c
@@ -6,6 +6,8 @@
#include "nrv2b.c"
FILE *infile, *outfile;
+#define DEBUG 0
+
struct input_file {
void *buf;
size_t len;
@@ -151,6 +153,11 @@ static int process_zinfo_copy ( struct input_file *input,
return -1;
}
+ if ( DEBUG ) {
+ fprintf ( stderr, "COPY [%#zx,%#zx) to [%#zx,%#zx)\n", offset, ( offset + len ),
+ output->len, ( output->len + len ) );
+ }
+
memcpy ( ( output->buf + output->len ),
( input->buf + offset ), len );
output->len += len;
@@ -184,6 +191,11 @@ static int process_zinfo_pack ( struct input_file *input,
return -1;
}
+ if ( DEBUG ) {
+ fprintf ( stderr, "PACK [%#zx,%#zx) to [%#zx,%#zx)\n", offset, ( offset + len ),
+ output->len, ( output->len + packed_len ) );
+ }
+
output->len += packed_len;
if ( output->len > output->max_len ) {
fprintf ( stderr, "Output buffer overrun on pack\n" );
@@ -200,6 +212,8 @@ static int process_zinfo_subtract ( struct input_file *input,
size_t offset = subtract->offset;
void *target;
long delta;
+ unsigned long old;
+ unsigned long new;
if ( ( offset + datasize ) > output->len ) {
fprintf ( stderr, "Subtract at %#zx outside output buffer\n",
@@ -214,21 +228,34 @@ static int process_zinfo_subtract ( struct input_file *input,
switch ( datasize ) {
case 1: {
uint8_t *byte = target;
+ old = *byte;
*byte += delta;
+ new = *byte;
break; }
case 2: {
uint16_t *word = target;
+ old = *word;
*word += delta;
+ new = *word;
break; }
case 4: {
uint32_t *dword = target;
+ old = *dword;
*dword += delta;
+ new = *dword;
break; }
default:
fprintf ( stderr, "Unsupported subtract datasize %d\n",
datasize );
return -1;
}
+
+ if ( DEBUG ) {
+ fprintf ( stderr, "SUBx [%#zx,%#zx) (%#lx+(%#lx/%#lx)-(%#lx/%#lx)) = %#lx\n",
+ offset, ( offset + datasize ), old, output->len, subtract->divisor,
+ input->len, subtract->divisor, new );
+ }
+
return 0;
}