summaryrefslogtreecommitdiff
path: root/roms
diff options
context:
space:
mode:
authorYonghee Han <onstudy@samsung.com>2016-07-27 16:42:54 +0900
committerYonghee Han <onstudy@samsung.com>2016-07-27 00:56:08 -0700
commita03c4728275d119af5f66c4a69e8d9d5a1730031 (patch)
tree2b4ed9542884bf8b947076c55c4ef1814217cb69 /roms
parent3158f4a51894e46ecb593bffbfd12824e1d6534a (diff)
downloadqemu-a03c4728275d119af5f66c4a69e8d9d5a1730031.tar.gz
qemu-a03c4728275d119af5f66c4a69e8d9d5a1730031.tar.bz2
qemu-a03c4728275d119af5f66c4a69e8d9d5a1730031.zip
Imported Upstream version 2.5.1.1upstream/2.5.1.1
Change-Id: Ie290b0e68882590d8a64fab165a943940b7c98ed
Diffstat (limited to 'roms')
-rw-r--r--roms/Makefile11
-rw-r--r--roms/SLOF/README14
-rw-r--r--roms/SLOF/VERSION2
-rw-r--r--roms/SLOF/board-js2x/llfw/stage2.lds3
-rw-r--r--roms/SLOF/board-js2x/llfw/stage2_head.S2
-rw-r--r--roms/SLOF/board-js2x/slof/Makefile1
-rw-r--r--roms/SLOF/board-js2x/slof/helper.fs11
-rw-r--r--roms/SLOF/board-qemu/llfw/stage2.lds3
-rw-r--r--roms/SLOF/board-qemu/llfw/stage2_head.S2
-rw-r--r--roms/SLOF/board-qemu/slof/Makefile2
-rw-r--r--roms/SLOF/board-qemu/slof/helper.fs13
-rw-r--r--roms/SLOF/board-qemu/slof/pci-device_1234_1111.fs229
-rw-r--r--roms/SLOF/board-qemu/slof/pci-device_1af4_1050.fs15
-rw-r--r--roms/SLOF/board-qemu/slof/qemu-vga.fs198
-rw-r--r--roms/SLOF/clients/net-snk/client.lds4
-rw-r--r--roms/SLOF/clients/net-snk/kernel/entry.S2
-rw-r--r--roms/SLOF/clients/takeover/client.lds4
-rw-r--r--roms/SLOF/clients/takeover/entry.S2
-rw-r--r--roms/SLOF/clients/takeover/main.c2
-rw-r--r--roms/SLOF/include/ppc970/cache.h50
-rw-r--r--roms/SLOF/include/ppcp7/cache.h22
-rw-r--r--roms/SLOF/lib/libusb/usb-hid.c85
-rw-r--r--roms/SLOF/lib/libusb/usb-xhci.c232
-rw-r--r--roms/SLOF/lib/libusb/usb-xhci.h5
-rw-r--r--roms/SLOF/make.rules12
-rw-r--r--roms/SLOF/rtas/reloc.S2
-rw-r--r--roms/SLOF/rtas/rtas.lds3
-rw-r--r--roms/SLOF/rtas/rtas_entry.S2
-rw-r--r--roms/SLOF/slof/entry.S9
-rw-r--r--roms/SLOF/slof/fs/archsupport.fs6
-rw-r--r--roms/SLOF/slof/fs/base.fs2
-rw-r--r--roms/SLOF/slof/fs/boot.fs7
-rw-r--r--roms/SLOF/slof/fs/client.fs12
-rw-r--r--roms/SLOF/slof/fs/fbuffer.fs30
-rw-r--r--roms/SLOF/slof/fs/little-endian.fs6
-rw-r--r--roms/SLOF/slof/fs/packages/disk-label.fs162
-rw-r--r--roms/SLOF/slof/fs/pci-scan.fs19
-rw-r--r--roms/SLOF/slof/fs/rmove.fs53
-rw-r--r--roms/SLOF/slof/fs/terminal.fs3
-rw-r--r--roms/SLOF/slof/ppc64.c19
-rw-r--r--roms/SLOF/slof/prim.code13
-rw-r--r--roms/SLOF/slof/prim.in3
-rw-r--r--roms/config.ipxe.general.h4
-rw-r--r--roms/ipxe/COPYING345
-rw-r--r--roms/ipxe/COPYING.GPLv2339
-rw-r--r--roms/ipxe/COPYING.UBDL59
-rw-r--r--roms/ipxe/COPYRIGHTS12
-rw-r--r--roms/ipxe/src/Makefile4
-rw-r--r--roms/ipxe/src/Makefile.housekeeping131
-rw-r--r--roms/ipxe/src/arch/i386/Makefile11
-rw-r--r--roms/ipxe/src/arch/i386/core/basemem_packet.c6
-rw-r--r--roms/ipxe/src/arch/i386/core/cachedhcp.c6
-rw-r--r--roms/ipxe/src/arch/i386/core/gdbmach.c6
-rw-r--r--roms/ipxe/src/arch/i386/core/patch_cf.S6
-rw-r--r--roms/ipxe/src/arch/i386/core/pci_autoboot.c6
-rw-r--r--roms/ipxe/src/arch/i386/core/rdtsc_timer.c12
-rw-r--r--roms/ipxe/src/arch/i386/core/relocate.c2
-rw-r--r--roms/ipxe/src/arch/i386/core/runtime.c6
-rw-r--r--roms/ipxe/src/arch/i386/core/setjmp.S84
-rw-r--r--roms/ipxe/src/arch/i386/core/stack.S2
-rw-r--r--roms/ipxe/src/arch/i386/core/stack16.S2
-rw-r--r--roms/ipxe/src/arch/i386/core/timer2.c87
-rw-r--r--roms/ipxe/src/arch/i386/core/virtaddr.S2
-rw-r--r--roms/ipxe/src/arch/i386/drivers/net/undi.c7
-rw-r--r--roms/ipxe/src/arch/i386/drivers/net/undiload.c6
-rw-r--r--roms/ipxe/src/arch/i386/drivers/net/undionly.c6
-rw-r--r--roms/ipxe/src/arch/i386/drivers/net/undipreload.c6
-rw-r--r--roms/ipxe/src/arch/i386/firmware/pcbios/basemem.c6
-rw-r--r--roms/ipxe/src/arch/i386/firmware/pcbios/bios_console.c12
-rw-r--r--roms/ipxe/src/arch/i386/firmware/pcbios/e820mangler.S6
-rw-r--r--roms/ipxe/src/arch/i386/firmware/pcbios/fakee820.c6
-rw-r--r--roms/ipxe/src/arch/i386/firmware/pcbios/hidemem.c6
-rw-r--r--roms/ipxe/src/arch/i386/firmware/pcbios/memmap.c6
-rw-r--r--roms/ipxe/src/arch/i386/firmware/pcbios/pnpbios.c6
-rw-r--r--roms/ipxe/src/arch/i386/hci/commands/pxe_cmd.c6
-rw-r--r--roms/ipxe/src/arch/i386/image/bootsector.c6
-rw-r--r--roms/ipxe/src/arch/i386/image/bzimage.c6
-rw-r--r--roms/ipxe/src/arch/i386/image/elfboot.c39
-rw-r--r--roms/ipxe/src/arch/i386/image/initrd.c6
-rw-r--r--roms/ipxe/src/arch/i386/image/multiboot.c6
-rw-r--r--roms/ipxe/src/arch/i386/image/pxe_image.c52
-rw-r--r--roms/ipxe/src/arch/i386/image/sdi.c6
-rw-r--r--roms/ipxe/src/arch/i386/include/basemem.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/basemem_packet.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/bios.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/biosint.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/bits/byteswap.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/bits/compiler.h5
-rw-r--r--roms/ipxe/src/arch/i386/include/bits/endian.h8
-rw-r--r--roms/ipxe/src/arch/i386/include/bits/entropy.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/bits/hyperv.h72
-rw-r--r--roms/ipxe/src/arch/i386/include/bits/nap.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/bits/profile.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/bits/reboot.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/bits/sanboot.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/bits/smbios.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/bits/stdint.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/bits/strings.h48
-rw-r--r--roms/ipxe/src/arch/i386/include/bits/time.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/bits/timer.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/bits/uaccess.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/bits/umalloc.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/bootsector.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/bzimage.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/efi/ipxe/dhcp_arch.h11
-rw-r--r--roms/ipxe/src/arch/i386/include/fakee820.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/initrd.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/int13.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/ipxe/bios_nap.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/ipxe/bios_reboot.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/ipxe/bios_sanboot.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/ipxe/bios_smbios.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/ipxe/bios_timer.h8
-rw-r--r--roms/ipxe/src/arch/i386/include/ipxe/errno/pcbios.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/ipxe/guestrpc.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/ipxe/memtop_umalloc.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/ipxe/msr.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/ipxe/rdtsc_timer.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/ipxe/rtc_entropy.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/ipxe/rtc_time.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/ipxe/timer2.h14
-rw-r--r--roms/ipxe/src/arch/i386/include/ipxe/vesafb.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/ipxe/vmware.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/librm.h14
-rw-r--r--roms/ipxe/src/arch/i386/include/limits.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/memsizes.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/multiboot.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/pcbios/ipxe/dhcp_arch.h11
-rw-r--r--roms/ipxe/src/arch/i386/include/pnpbios.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/pxe.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/pxe_api.h6
-rw-r--r--roms/ipxe/src/arch/i386/include/pxe_call.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/pxe_error.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/pxe_types.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/realmode.h14
-rw-r--r--roms/ipxe/src/arch/i386/include/registers.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/rtc.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/sdi.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/setjmp.h46
-rw-r--r--roms/ipxe/src/arch/i386/include/undi.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/undiload.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/undinet.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/undipreload.h2
-rw-r--r--roms/ipxe/src/arch/i386/include/undirom.h2
-rw-r--r--roms/ipxe/src/arch/i386/interface/pcbios/apm.c6
-rw-r--r--roms/ipxe/src/arch/i386/interface/pcbios/bios_nap.c2
-rw-r--r--roms/ipxe/src/arch/i386/interface/pcbios/bios_reboot.c6
-rw-r--r--roms/ipxe/src/arch/i386/interface/pcbios/bios_smbios.c6
-rw-r--r--roms/ipxe/src/arch/i386/interface/pcbios/bios_timer.c6
-rw-r--r--roms/ipxe/src/arch/i386/interface/pcbios/biosint.c2
-rw-r--r--roms/ipxe/src/arch/i386/interface/pcbios/int13.c6
-rw-r--r--roms/ipxe/src/arch/i386/interface/pcbios/int13con.c284
-rw-r--r--roms/ipxe/src/arch/i386/interface/pcbios/memtop_umalloc.c6
-rw-r--r--roms/ipxe/src/arch/i386/interface/pcbios/pcibios.c12
-rw-r--r--roms/ipxe/src/arch/i386/interface/pcbios/rtc_entropy.c6
-rw-r--r--roms/ipxe/src/arch/i386/interface/pcbios/rtc_time.c6
-rw-r--r--roms/ipxe/src/arch/i386/interface/pcbios/vesafb.c6
-rw-r--r--roms/ipxe/src/arch/i386/interface/pxe/pxe_call.c7
-rw-r--r--roms/ipxe/src/arch/i386/interface/pxe/pxe_entry.S6
-rw-r--r--roms/ipxe/src/arch/i386/interface/pxe/pxe_exit_hook.c6
-rw-r--r--roms/ipxe/src/arch/i386/interface/pxe/pxe_file.c6
-rw-r--r--roms/ipxe/src/arch/i386/interface/pxe/pxe_loader.c6
-rw-r--r--roms/ipxe/src/arch/i386/interface/pxe/pxe_preboot.c24
-rw-r--r--roms/ipxe/src/arch/i386/interface/pxe/pxe_tftp.c43
-rw-r--r--roms/ipxe/src/arch/i386/interface/pxe/pxe_udp.c130
-rw-r--r--roms/ipxe/src/arch/i386/interface/pxe/pxe_undi.c6
-rw-r--r--roms/ipxe/src/arch/i386/interface/syslinux/comboot_call.c29
-rw-r--r--roms/ipxe/src/arch/i386/interface/vmware/guestrpc.c6
-rw-r--r--roms/ipxe/src/arch/i386/interface/vmware/vmconsole.c6
-rw-r--r--roms/ipxe/src/arch/i386/interface/vmware/vmware.c6
-rw-r--r--roms/ipxe/src/arch/i386/prefix/bootpart.S2
-rw-r--r--roms/ipxe/src/arch/i386/prefix/exeprefix.S6
-rw-r--r--roms/ipxe/src/arch/i386/prefix/hdprefix.S2
-rw-r--r--roms/ipxe/src/arch/i386/prefix/isaromprefix.S6
-rw-r--r--roms/ipxe/src/arch/i386/prefix/kkkpxeprefix.S6
-rw-r--r--roms/ipxe/src/arch/i386/prefix/kkpxeprefix.S5
-rw-r--r--roms/ipxe/src/arch/i386/prefix/kpxeprefix.S2
-rw-r--r--roms/ipxe/src/arch/i386/prefix/libprefix.S75
-rw-r--r--roms/ipxe/src/arch/i386/prefix/lkrnprefix.S2
-rw-r--r--roms/ipxe/src/arch/i386/prefix/mbr.S2
-rw-r--r--roms/ipxe/src/arch/i386/prefix/mromprefix.S7
-rw-r--r--roms/ipxe/src/arch/i386/prefix/nbiprefix.S2
-rw-r--r--roms/ipxe/src/arch/i386/prefix/nullprefix.S2
-rw-r--r--roms/ipxe/src/arch/i386/prefix/pciromprefix.S6
-rw-r--r--roms/ipxe/src/arch/i386/prefix/pxeprefix.S2
-rw-r--r--roms/ipxe/src/arch/i386/prefix/romprefix.S31
-rw-r--r--roms/ipxe/src/arch/i386/prefix/undiloader.S2
-rw-r--r--roms/ipxe/src/arch/i386/prefix/unlzma.S942
-rw-r--r--roms/ipxe/src/arch/i386/prefix/unlzma16.S (renamed from roms/ipxe/src/arch/i386/prefix/unnrv2b16.S)4
-rw-r--r--roms/ipxe/src/arch/i386/prefix/unnrv2b.S184
-rw-r--r--roms/ipxe/src/arch/i386/prefix/usbdisk.S23
-rw-r--r--roms/ipxe/src/arch/i386/scripts/i386.lds9
-rw-r--r--roms/ipxe/src/arch/i386/transitions/liba20.S6
-rw-r--r--roms/ipxe/src/arch/i386/transitions/libkir.S2
-rw-r--r--roms/ipxe/src/arch/i386/transitions/librm.S2
-rw-r--r--roms/ipxe/src/arch/i386/transitions/librm_mgmt.c4
-rw-r--r--roms/ipxe/src/arch/i386/transitions/librm_test.c7
-rw-r--r--roms/ipxe/src/arch/x86/Makefile5
-rw-r--r--roms/ipxe/src/arch/x86/Makefile.efi2
-rw-r--r--roms/ipxe/src/arch/x86/core/cpuid.c6
-rw-r--r--roms/ipxe/src/arch/x86/core/cpuid_settings.c6
-rw-r--r--roms/ipxe/src/arch/x86/core/debugcon.c6
-rw-r--r--roms/ipxe/src/arch/x86/core/pcidirect.c6
-rw-r--r--roms/ipxe/src/arch/x86/core/pic8259.c (renamed from roms/ipxe/src/arch/i386/core/pic8259.c)0
-rw-r--r--roms/ipxe/src/arch/x86/core/pit8254.c70
-rw-r--r--roms/ipxe/src/arch/x86/core/vram_settings.c72
-rw-r--r--roms/ipxe/src/arch/x86/core/x86_bigint.c6
-rw-r--r--roms/ipxe/src/arch/x86/core/x86_io.c6
-rw-r--r--roms/ipxe/src/arch/x86/core/x86_string.c90
-rw-r--r--roms/ipxe/src/arch/x86/core/x86_tcpip.c6
-rw-r--r--roms/ipxe/src/arch/x86/core/x86_uart.c69
-rw-r--r--roms/ipxe/src/arch/x86/drivers/hyperv/hyperv.c597
-rw-r--r--roms/ipxe/src/arch/x86/drivers/hyperv/hyperv.h57
-rw-r--r--roms/ipxe/src/arch/x86/drivers/xen/hvm.c9
-rw-r--r--roms/ipxe/src/arch/x86/drivers/xen/hvm.h2
-rw-r--r--roms/ipxe/src/arch/x86/hci/commands/cpuid_cmd.c6
-rw-r--r--roms/ipxe/src/arch/x86/include/bits/bigint.h2
-rw-r--r--roms/ipxe/src/arch/x86/include/bits/endian.h8
-rw-r--r--roms/ipxe/src/arch/x86/include/bits/errfile.h6
-rw-r--r--roms/ipxe/src/arch/x86/include/bits/io.h2
-rw-r--r--roms/ipxe/src/arch/x86/include/bits/pci_io.h2
-rw-r--r--roms/ipxe/src/arch/x86/include/bits/string.h140
-rw-r--r--roms/ipxe/src/arch/x86/include/bits/tcpip.h2
-rw-r--r--roms/ipxe/src/arch/x86/include/bits/uart.h41
-rw-r--r--roms/ipxe/src/arch/x86/include/bits/xen.h21
-rw-r--r--roms/ipxe/src/arch/x86/include/ipxe/cpuid.h5
-rw-r--r--roms/ipxe/src/arch/x86/include/ipxe/efi/efix86_nap.h2
-rw-r--r--roms/ipxe/src/arch/x86/include/ipxe/pcibios.h2
-rw-r--r--roms/ipxe/src/arch/x86/include/ipxe/pcidirect.h2
-rw-r--r--roms/ipxe/src/arch/x86/include/ipxe/pit8254.h81
-rw-r--r--roms/ipxe/src/arch/x86/include/ipxe/x86_io.h2
-rw-r--r--roms/ipxe/src/arch/x86/include/linux/ipxe/dhcp_arch.h11
-rw-r--r--roms/ipxe/src/arch/x86/include/pic8259.h (renamed from roms/ipxe/src/arch/i386/include/pic8259.h)5
-rw-r--r--roms/ipxe/src/arch/x86/interface/efi/efi_entropy.c223
-rw-r--r--roms/ipxe/src/arch/x86/interface/efi/efix86_nap.c6
-rw-r--r--roms/ipxe/src/arch/x86/prefix/efidrvprefix.c35
-rw-r--r--roms/ipxe/src/arch/x86/prefix/efiprefix.c5
-rw-r--r--roms/ipxe/src/arch/x86_64/Makefile1
-rw-r--r--roms/ipxe/src/arch/x86_64/core/setjmp.S65
-rw-r--r--roms/ipxe/src/arch/x86_64/include/bits/byteswap.h2
-rw-r--r--roms/ipxe/src/arch/x86_64/include/bits/compiler.h3
-rw-r--r--roms/ipxe/src/arch/x86_64/include/bits/endian.h6
-rw-r--r--roms/ipxe/src/arch/x86_64/include/bits/entropy.h2
-rw-r--r--roms/ipxe/src/arch/x86_64/include/bits/hyperv.h75
-rw-r--r--roms/ipxe/src/arch/x86_64/include/bits/profile.h2
-rw-r--r--roms/ipxe/src/arch/x86_64/include/bits/reboot.h2
-rw-r--r--roms/ipxe/src/arch/x86_64/include/bits/sanboot.h2
-rw-r--r--roms/ipxe/src/arch/x86_64/include/bits/strings.h40
-rw-r--r--roms/ipxe/src/arch/x86_64/include/bits/time.h2
-rw-r--r--roms/ipxe/src/arch/x86_64/include/efi/ipxe/dhcp_arch.h11
-rw-r--r--roms/ipxe/src/arch/x86_64/include/ipxe/msr.h2
-rw-r--r--roms/ipxe/src/arch/x86_64/include/setjmp.h34
-rw-r--r--roms/ipxe/src/config/.gitignore1
-rw-r--r--roms/ipxe/src/config/branding.h174
-rw-r--r--roms/ipxe/src/config/colour.h2
-rw-r--r--roms/ipxe/src/config/config.c59
-rw-r--r--roms/ipxe/src/config/config_crypto.c76
-rw-r--r--roms/ipxe/src/config/config_ethernet.c25
-rw-r--r--roms/ipxe/src/config/config_fc.c22
-rw-r--r--roms/ipxe/src/config/config_http.c45
-rw-r--r--roms/ipxe/src/config/config_infiniband.c22
-rw-r--r--roms/ipxe/src/config/config_net80211.c16
-rw-r--r--roms/ipxe/src/config/config_romprefix.c22
-rw-r--r--roms/ipxe/src/config/config_route.c22
-rw-r--r--roms/ipxe/src/config/config_usb.c52
-rw-r--r--roms/ipxe/src/config/console.h3
-rw-r--r--roms/ipxe/src/config/crypto.h35
-rw-r--r--roms/ipxe/src/config/defaults.h2
-rw-r--r--roms/ipxe/src/config/defaults/efi.h6
-rw-r--r--roms/ipxe/src/config/defaults/pcbios.h8
-rw-r--r--roms/ipxe/src/config/dhcp.h87
-rw-r--r--roms/ipxe/src/config/entropy.h2
-rw-r--r--roms/ipxe/src/config/fault.h34
-rw-r--r--roms/ipxe/src/config/general.h31
-rw-r--r--roms/ipxe/src/config/ioapi.h2
-rw-r--r--roms/ipxe/src/config/named.h2
-rw-r--r--roms/ipxe/src/config/nap.h2
-rw-r--r--roms/ipxe/src/config/qemu/colour.h0
-rw-r--r--roms/ipxe/src/config/qemu/console.h0
-rw-r--r--roms/ipxe/src/config/qemu/crypto.h0
-rw-r--r--roms/ipxe/src/config/qemu/general.h10
-rw-r--r--roms/ipxe/src/config/qemu/serial.h0
-rw-r--r--roms/ipxe/src/config/qemu/settings.h0
-rw-r--r--roms/ipxe/src/config/qemu/sideband.h0
-rw-r--r--roms/ipxe/src/config/qemu/usb.h0
-rw-r--r--roms/ipxe/src/config/reboot.h2
-rw-r--r--roms/ipxe/src/config/sanboot.h2
-rw-r--r--roms/ipxe/src/config/serial.h5
-rw-r--r--roms/ipxe/src/config/settings.h3
-rw-r--r--roms/ipxe/src/config/sideband.h2
-rw-r--r--roms/ipxe/src/config/time.h2
-rw-r--r--roms/ipxe/src/config/timer.h2
-rw-r--r--roms/ipxe/src/config/umalloc.h2
-rw-r--r--roms/ipxe/src/config/usb.h33
-rw-r--r--roms/ipxe/src/config/vbox/general.h8
-rw-r--r--roms/ipxe/src/config/vbox/usb.h0
-rw-r--r--roms/ipxe/src/core/acpi.c6
-rw-r--r--roms/ipxe/src/core/ansicol.c6
-rw-r--r--roms/ipxe/src/core/ansicoldef.c6
-rw-r--r--roms/ipxe/src/core/ansiesc.c6
-rw-r--r--roms/ipxe/src/core/asprintf.c2
-rw-r--r--roms/ipxe/src/core/assert.c6
-rw-r--r--roms/ipxe/src/core/base16.c96
-rw-r--r--roms/ipxe/src/core/base64.c106
-rw-r--r--roms/ipxe/src/core/basename.c6
-rw-r--r--roms/ipxe/src/core/bitmap.c6
-rw-r--r--roms/ipxe/src/core/blockdev.c6
-rw-r--r--roms/ipxe/src/core/blocktrans.c261
-rw-r--r--roms/ipxe/src/core/console.c2
-rw-r--r--roms/ipxe/src/core/cpio.c6
-rw-r--r--roms/ipxe/src/core/ctype.c13
-rw-r--r--roms/ipxe/src/core/cwuri.c6
-rw-r--r--roms/ipxe/src/core/debug.c6
-rw-r--r--roms/ipxe/src/core/debug_md5.c6
-rw-r--r--roms/ipxe/src/core/device.c6
-rw-r--r--roms/ipxe/src/core/downloader.c112
-rw-r--r--roms/ipxe/src/core/edd.c6
-rw-r--r--roms/ipxe/src/core/errno.c2
-rw-r--r--roms/ipxe/src/core/exec.c6
-rw-r--r--roms/ipxe/src/core/fault.c82
-rw-r--r--roms/ipxe/src/core/fbcon.c6
-rw-r--r--roms/ipxe/src/core/fnrec.c6
-rw-r--r--roms/ipxe/src/core/gdbserial.c80
-rw-r--r--roms/ipxe/src/core/gdbstub.c6
-rw-r--r--roms/ipxe/src/core/gdbudp.c6
-rw-r--r--roms/ipxe/src/core/getkey.c6
-rw-r--r--roms/ipxe/src/core/getopt.c6
-rw-r--r--roms/ipxe/src/core/image.c89
-rw-r--r--roms/ipxe/src/core/init.c6
-rw-r--r--roms/ipxe/src/core/interface.c31
-rw-r--r--roms/ipxe/src/core/iobuf.c36
-rw-r--r--roms/ipxe/src/core/isqrt.c6
-rw-r--r--roms/ipxe/src/core/job.c6
-rw-r--r--roms/ipxe/src/core/linebuf.c59
-rw-r--r--roms/ipxe/src/core/lineconsole.c6
-rw-r--r--roms/ipxe/src/core/list.c6
-rw-r--r--roms/ipxe/src/core/log.c6
-rw-r--r--roms/ipxe/src/core/main.c11
-rw-r--r--roms/ipxe/src/core/malloc.c63
-rw-r--r--roms/ipxe/src/core/memblock.c6
-rw-r--r--roms/ipxe/src/core/memmap_settings.c6
-rw-r--r--roms/ipxe/src/core/menu.c6
-rw-r--r--roms/ipxe/src/core/misc.c85
-rw-r--r--roms/ipxe/src/core/monojob.c6
-rw-r--r--roms/ipxe/src/core/null_reboot.c6
-rw-r--r--roms/ipxe/src/core/null_sanboot.c6
-rw-r--r--roms/ipxe/src/core/null_time.c6
-rw-r--r--roms/ipxe/src/core/nvo.c6
-rw-r--r--roms/ipxe/src/core/open.c6
-rw-r--r--roms/ipxe/src/core/params.c6
-rw-r--r--roms/ipxe/src/core/parseopt.c9
-rw-r--r--roms/ipxe/src/core/pending.c6
-rw-r--r--roms/ipxe/src/core/pinger.c6
-rw-r--r--roms/ipxe/src/core/pixbuf.c6
-rw-r--r--roms/ipxe/src/core/pool.c114
-rw-r--r--roms/ipxe/src/core/posix_io.c6
-rw-r--r--roms/ipxe/src/core/process.c6
-rw-r--r--roms/ipxe/src/core/profile.c6
-rw-r--r--roms/ipxe/src/core/random.c2
-rw-r--r--roms/ipxe/src/core/refcnt.c6
-rw-r--r--roms/ipxe/src/core/resolv.c6
-rw-r--r--roms/ipxe/src/core/serial.c349
-rw-r--r--roms/ipxe/src/core/serial_console.c42
-rw-r--r--roms/ipxe/src/core/settings.c102
-rw-r--r--roms/ipxe/src/core/string.c648
-rw-r--r--roms/ipxe/src/core/stringextra.c188
-rw-r--r--roms/ipxe/src/core/strtoull.c60
-rw-r--r--roms/ipxe/src/core/time.c6
-rw-r--r--roms/ipxe/src/core/timer.c6
-rw-r--r--roms/ipxe/src/core/uart.c153
-rw-r--r--roms/ipxe/src/core/uri.c15
-rw-r--r--roms/ipxe/src/core/uuid.c6
-rw-r--r--roms/ipxe/src/core/version.c7
-rw-r--r--roms/ipxe/src/core/vsprintf.c6
-rw-r--r--roms/ipxe/src/core/wchar.c6
-rw-r--r--roms/ipxe/src/core/xfer.c49
-rw-r--r--roms/ipxe/src/core/xferbuf.c262
-rw-r--r--roms/ipxe/src/crypto/aes.c808
-rw-r--r--roms/ipxe/src/crypto/asn1.c6
-rw-r--r--roms/ipxe/src/crypto/axtls/aes.c457
-rw-r--r--roms/ipxe/src/crypto/axtls/bigint.h99
-rw-r--r--roms/ipxe/src/crypto/axtls/bigint_impl.h131
-rw-r--r--roms/ipxe/src/crypto/axtls/config.h13
-rw-r--r--roms/ipxe/src/crypto/axtls/crypto.h229
-rw-r--r--roms/ipxe/src/crypto/axtls/os_port.h54
-rw-r--r--roms/ipxe/src/crypto/axtls_aes.c160
-rw-r--r--roms/ipxe/src/crypto/bigint.c6
-rw-r--r--roms/ipxe/src/crypto/cbc.c6
-rw-r--r--roms/ipxe/src/crypto/certstore.c6
-rw-r--r--roms/ipxe/src/crypto/chap.c6
-rw-r--r--roms/ipxe/src/crypto/cms.c6
-rw-r--r--roms/ipxe/src/crypto/crypto_null.c6
-rw-r--r--roms/ipxe/src/crypto/deflate.c6
-rw-r--r--roms/ipxe/src/crypto/drbg.c6
-rw-r--r--roms/ipxe/src/crypto/ecb.c80
-rw-r--r--roms/ipxe/src/crypto/entropy.c6
-rw-r--r--roms/ipxe/src/crypto/hash_df.c6
-rw-r--r--roms/ipxe/src/crypto/hmac.c6
-rw-r--r--roms/ipxe/src/crypto/hmac_drbg.c6
-rw-r--r--roms/ipxe/src/crypto/md5.c6
-rw-r--r--roms/ipxe/src/crypto/mishmash/rsa_aes_cbc_sha1.c48
-rw-r--r--roms/ipxe/src/crypto/mishmash/rsa_aes_cbc_sha256.c48
-rw-r--r--roms/ipxe/src/crypto/mishmash/rsa_md5.c51
-rw-r--r--roms/ipxe/src/crypto/mishmash/rsa_sha1.c62
-rw-r--r--roms/ipxe/src/crypto/mishmash/rsa_sha224.c62
-rw-r--r--roms/ipxe/src/crypto/mishmash/rsa_sha256.c62
-rw-r--r--roms/ipxe/src/crypto/mishmash/rsa_sha384.c62
-rw-r--r--roms/ipxe/src/crypto/mishmash/rsa_sha512.c62
-rw-r--r--roms/ipxe/src/crypto/null_entropy.c6
-rw-r--r--roms/ipxe/src/crypto/ocsp.c2
-rw-r--r--roms/ipxe/src/crypto/privkey.c6
-rw-r--r--roms/ipxe/src/crypto/random_nz.c6
-rw-r--r--roms/ipxe/src/crypto/rbg.c6
-rw-r--r--roms/ipxe/src/crypto/rootcert.c6
-rw-r--r--roms/ipxe/src/crypto/rsa.c78
-rw-r--r--roms/ipxe/src/crypto/sha1.c6
-rw-r--r--roms/ipxe/src/crypto/sha224.c82
-rw-r--r--roms/ipxe/src/crypto/sha256.c63
-rw-r--r--roms/ipxe/src/crypto/sha384.c82
-rw-r--r--roms/ipxe/src/crypto/sha512.c303
-rw-r--r--roms/ipxe/src/crypto/sha512_224.c83
-rw-r--r--roms/ipxe/src/crypto/sha512_256.c83
-rw-r--r--roms/ipxe/src/crypto/x509.c15
-rw-r--r--roms/ipxe/src/drivers/bitbash/bitbash.c6
-rw-r--r--roms/ipxe/src/drivers/bitbash/i2c_bit.c6
-rw-r--r--roms/ipxe/src/drivers/bitbash/spi_bit.c6
-rw-r--r--roms/ipxe/src/drivers/block/ata.c6
-rw-r--r--roms/ipxe/src/drivers/block/scsi.c6
-rw-r--r--roms/ipxe/src/drivers/bus/cdc.c54
-rw-r--r--roms/ipxe/src/drivers/bus/pci.c31
-rw-r--r--roms/ipxe/src/drivers/bus/pci_settings.c6
-rw-r--r--roms/ipxe/src/drivers/bus/pcibackup.c6
-rw-r--r--roms/ipxe/src/drivers/bus/pciextra.c12
-rw-r--r--roms/ipxe/src/drivers/bus/pcivpd.c6
-rw-r--r--roms/ipxe/src/drivers/bus/usb.c2128
-rw-r--r--roms/ipxe/src/drivers/infiniband/arbel.c6
-rw-r--r--roms/ipxe/src/drivers/infiniband/arbel.h2
-rw-r--r--roms/ipxe/src/drivers/infiniband/linda.c6
-rw-r--r--roms/ipxe/src/drivers/infiniband/linda.h6
-rw-r--r--roms/ipxe/src/drivers/infiniband/qib7322.c6
-rw-r--r--roms/ipxe/src/drivers/infiniband/qib7322.h6
-rw-r--r--roms/ipxe/src/drivers/net/amd8111e.h6
-rw-r--r--roms/ipxe/src/drivers/net/ath/ath9k/ani.h2
-rw-r--r--roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ani.c16
-rw-r--r--roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar5008_phy.c18
-rw-r--r--roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9003_phy.c12
-rw-r--r--roms/ipxe/src/drivers/net/atl1e.c2
-rw-r--r--roms/ipxe/src/drivers/net/davicom.c1
-rw-r--r--roms/ipxe/src/drivers/net/dm96xx.c671
-rw-r--r--roms/ipxe/src/drivers/net/dm96xx.h194
-rw-r--r--roms/ipxe/src/drivers/net/dmfe.c2
-rw-r--r--roms/ipxe/src/drivers/net/ecm.c520
-rw-r--r--roms/ipxe/src/drivers/net/ecm.h93
-rw-r--r--roms/ipxe/src/drivers/net/eepro.c20
-rw-r--r--roms/ipxe/src/drivers/net/eepro100.c1
-rw-r--r--roms/ipxe/src/drivers/net/efi/nii.c150
-rw-r--r--roms/ipxe/src/drivers/net/efi/nii.h2
-rw-r--r--roms/ipxe/src/drivers/net/efi/snp.c6
-rw-r--r--roms/ipxe/src/drivers/net/efi/snponly.c6
-rw-r--r--roms/ipxe/src/drivers/net/etherfabric.c2
-rw-r--r--roms/ipxe/src/drivers/net/forcedeth.c6
-rw-r--r--roms/ipxe/src/drivers/net/igbvf/igbvf_main.c2
-rw-r--r--roms/ipxe/src/drivers/net/intel.c148
-rw-r--r--roms/ipxe/src/drivers/net/intel.h123
-rw-r--r--roms/ipxe/src/drivers/net/intelvf.c340
-rw-r--r--roms/ipxe/src/drivers/net/intelvf.h109
-rw-r--r--roms/ipxe/src/drivers/net/intelx.c25
-rw-r--r--roms/ipxe/src/drivers/net/intelx.h2
-rw-r--r--roms/ipxe/src/drivers/net/intelxvf.c466
-rw-r--r--roms/ipxe/src/drivers/net/intelxvf.h104
-rw-r--r--roms/ipxe/src/drivers/net/ipoib.c90
-rw-r--r--roms/ipxe/src/drivers/net/legacy.c2
-rw-r--r--roms/ipxe/src/drivers/net/mii.c38
-rw-r--r--roms/ipxe/src/drivers/net/myson.c6
-rw-r--r--roms/ipxe/src/drivers/net/myson.h2
-rw-r--r--roms/ipxe/src/drivers/net/ncm.c672
-rw-r--r--roms/ipxe/src/drivers/net/ncm.h173
-rw-r--r--roms/ipxe/src/drivers/net/netfront.c16
-rw-r--r--roms/ipxe/src/drivers/net/netfront.h2
-rw-r--r--roms/ipxe/src/drivers/net/netvsc.c848
-rw-r--r--roms/ipxe/src/drivers/net/netvsc.h365
-rw-r--r--roms/ipxe/src/drivers/net/phantom/nx_bitops.h6
-rw-r--r--roms/ipxe/src/drivers/net/phantom/phantom.c6
-rw-r--r--roms/ipxe/src/drivers/net/phantom/phantom.h6
-rw-r--r--roms/ipxe/src/drivers/net/phantom/phantom_hw.h6
-rw-r--r--roms/ipxe/src/drivers/net/pnic.c14
-rw-r--r--roms/ipxe/src/drivers/net/prism2.c14
-rw-r--r--roms/ipxe/src/drivers/net/prism2_pci.c16
-rw-r--r--roms/ipxe/src/drivers/net/prism2_plx.c18
-rw-r--r--roms/ipxe/src/drivers/net/realtek.c11
-rw-r--r--roms/ipxe/src/drivers/net/realtek.h2
-rw-r--r--roms/ipxe/src/drivers/net/rtl818x/rtl8180.c20
-rw-r--r--roms/ipxe/src/drivers/net/rtl818x/rtl8185.c14
-rw-r--r--roms/ipxe/src/drivers/net/rtl818x/rtl818x.c26
-rw-r--r--roms/ipxe/src/drivers/net/rtl818x/rtl818x.h4
-rw-r--r--roms/ipxe/src/drivers/net/skeleton.c6
-rw-r--r--roms/ipxe/src/drivers/net/skeleton.h2
-rw-r--r--roms/ipxe/src/drivers/net/smsc75xx.c1057
-rw-r--r--roms/ipxe/src/drivers/net/smsc75xx.h309
-rw-r--r--roms/ipxe/src/drivers/net/sundance.c2
-rw-r--r--roms/ipxe/src/drivers/net/tg3/tg3.c1
-rw-r--r--roms/ipxe/src/drivers/net/tg3/tg3.h5
-rw-r--r--roms/ipxe/src/drivers/net/tg3/tg3_hw.c1
-rw-r--r--roms/ipxe/src/drivers/net/virtio-net.c14
-rw-r--r--roms/ipxe/src/drivers/net/vmxnet3.c6
-rw-r--r--roms/ipxe/src/drivers/net/vmxnet3.h6
-rw-r--r--roms/ipxe/src/drivers/net/vxge/vxge.c3
-rw-r--r--roms/ipxe/src/drivers/net/vxge/vxge_main.c2
-rw-r--r--roms/ipxe/src/drivers/net/w89c840.c2
-rw-r--r--roms/ipxe/src/drivers/nvs/nvs.c6
-rw-r--r--roms/ipxe/src/drivers/nvs/nvsvpd.c6
-rw-r--r--roms/ipxe/src/drivers/nvs/spi.c6
-rw-r--r--roms/ipxe/src/drivers/nvs/threewire.c6
-rw-r--r--roms/ipxe/src/drivers/usb/ehci.c1994
-rw-r--r--roms/ipxe/src/drivers/usb/ehci.h544
-rw-r--r--roms/ipxe/src/drivers/usb/uhci.c1577
-rw-r--r--roms/ipxe/src/drivers/usb/uhci.h350
-rw-r--r--roms/ipxe/src/drivers/usb/usbhid.c151
-rw-r--r--roms/ipxe/src/drivers/usb/usbhub.c547
-rw-r--r--roms/ipxe/src/drivers/usb/usbhub.h279
-rw-r--r--roms/ipxe/src/drivers/usb/usbkbd.c509
-rw-r--r--roms/ipxe/src/drivers/usb/usbkbd.h154
-rw-r--r--roms/ipxe/src/drivers/usb/usbnet.c284
-rw-r--r--roms/ipxe/src/drivers/usb/xhci.c3321
-rw-r--r--roms/ipxe/src/drivers/usb/xhci.h1150
-rw-r--r--roms/ipxe/src/hci/commands/autoboot_cmd.c6
-rw-r--r--roms/ipxe/src/hci/commands/config_cmd.c6
-rw-r--r--roms/ipxe/src/hci/commands/console_cmd.c6
-rw-r--r--roms/ipxe/src/hci/commands/dhcp_cmd.c6
-rw-r--r--roms/ipxe/src/hci/commands/fcmgmt_cmd.c6
-rw-r--r--roms/ipxe/src/hci/commands/gdbstub_cmd.c6
-rw-r--r--roms/ipxe/src/hci/commands/ifmgmt_cmd.c6
-rw-r--r--roms/ipxe/src/hci/commands/image_cmd.c6
-rw-r--r--roms/ipxe/src/hci/commands/image_trust_cmd.c9
-rw-r--r--roms/ipxe/src/hci/commands/ipstat_cmd.c6
-rw-r--r--roms/ipxe/src/hci/commands/login_cmd.c6
-rw-r--r--roms/ipxe/src/hci/commands/lotest_cmd.c6
-rw-r--r--roms/ipxe/src/hci/commands/menu_cmd.c6
-rw-r--r--roms/ipxe/src/hci/commands/neighbour_cmd.c6
-rw-r--r--roms/ipxe/src/hci/commands/nvo_cmd.c6
-rw-r--r--roms/ipxe/src/hci/commands/param_cmd.c6
-rw-r--r--roms/ipxe/src/hci/commands/pci_cmd.c6
-rw-r--r--roms/ipxe/src/hci/commands/ping_cmd.c6
-rw-r--r--roms/ipxe/src/hci/commands/poweroff_cmd.c6
-rw-r--r--roms/ipxe/src/hci/commands/profstat_cmd.c6
-rw-r--r--roms/ipxe/src/hci/commands/reboot_cmd.c6
-rw-r--r--roms/ipxe/src/hci/commands/route_cmd.c6
-rw-r--r--roms/ipxe/src/hci/commands/sanboot_cmd.c6
-rw-r--r--roms/ipxe/src/hci/commands/sync_cmd.c6
-rw-r--r--roms/ipxe/src/hci/commands/vlan_cmd.c6
-rw-r--r--roms/ipxe/src/hci/editstring.c6
-rw-r--r--roms/ipxe/src/hci/jumpscroll.c140
-rw-r--r--roms/ipxe/src/hci/mucurses/alert.c2
-rw-r--r--roms/ipxe/src/hci/mucurses/ansi_screen.c2
-rw-r--r--roms/ipxe/src/hci/mucurses/clear.c2
-rw-r--r--roms/ipxe/src/hci/mucurses/colour.c2
-rw-r--r--roms/ipxe/src/hci/mucurses/cursor.h2
-rw-r--r--roms/ipxe/src/hci/mucurses/edging.c2
-rw-r--r--roms/ipxe/src/hci/mucurses/kb.c2
-rw-r--r--roms/ipxe/src/hci/mucurses/mucurses.c2
-rw-r--r--roms/ipxe/src/hci/mucurses/mucurses.h2
-rw-r--r--roms/ipxe/src/hci/mucurses/print.c2
-rw-r--r--roms/ipxe/src/hci/mucurses/print_nadv.c2
-rw-r--r--roms/ipxe/src/hci/mucurses/slk.c2
-rw-r--r--roms/ipxe/src/hci/mucurses/widgets/editbox.c6
-rw-r--r--roms/ipxe/src/hci/mucurses/winattrs.c2
-rw-r--r--roms/ipxe/src/hci/mucurses/windows.c2
-rw-r--r--roms/ipxe/src/hci/mucurses/wininit.c2
-rw-r--r--roms/ipxe/src/hci/readline.c6
-rw-r--r--roms/ipxe/src/hci/shell.c9
-rw-r--r--roms/ipxe/src/hci/strerror.c9
-rw-r--r--roms/ipxe/src/hci/tui/login_ui.c6
-rw-r--r--roms/ipxe/src/hci/tui/menu_ui.c102
-rw-r--r--roms/ipxe/src/hci/tui/settings_ui.c355
-rw-r--r--roms/ipxe/src/image/elf.c145
-rw-r--r--roms/ipxe/src/image/embedded.c2
-rw-r--r--roms/ipxe/src/image/png.c6
-rw-r--r--roms/ipxe/src/image/pnm.c6
-rw-r--r--roms/ipxe/src/image/script.c6
-rw-r--r--roms/ipxe/src/image/segment.c6
-rw-r--r--roms/ipxe/src/include/.gitignore1
-rw-r--r--roms/ipxe/src/include/assert.h2
-rw-r--r--roms/ipxe/src/include/big_bswap.h35
-rw-r--r--roms/ipxe/src/include/byteswap.h185
-rw-r--r--roms/ipxe/src/include/compiler.h203
-rw-r--r--roms/ipxe/src/include/ctype.h118
-rw-r--r--roms/ipxe/src/include/curses.h2
-rw-r--r--roms/ipxe/src/include/elf.h277
-rw-r--r--roms/ipxe/src/include/endian.h31
-rw-r--r--roms/ipxe/src/include/errno.h6
-rw-r--r--roms/ipxe/src/include/getopt.h2
-rw-r--r--roms/ipxe/src/include/hci/ifmgmt_cmd.h6
-rw-r--r--roms/ipxe/src/include/ipxe/acpi.h2
-rw-r--r--roms/ipxe/src/include/ipxe/aes.h44
-rw-r--r--roms/ipxe/src/include/ipxe/ansicol.h2
-rw-r--r--roms/ipxe/src/include/ipxe/ansiesc.h2
-rw-r--r--roms/ipxe/src/include/ipxe/aoe.h2
-rw-r--r--roms/ipxe/src/include/ipxe/api.h2
-rw-r--r--roms/ipxe/src/include/ipxe/arp.h6
-rw-r--r--roms/ipxe/src/include/ipxe/asn1.h55
-rw-r--r--roms/ipxe/src/include/ipxe/ata.h2
-rw-r--r--roms/ipxe/src/include/ipxe/base16.h35
-rw-r--r--roms/ipxe/src/include/ipxe/base64.h7
-rw-r--r--roms/ipxe/src/include/ipxe/bigint.h2
-rw-r--r--roms/ipxe/src/include/ipxe/bitbash.h2
-rw-r--r--roms/ipxe/src/include/ipxe/bitmap.h2
-rw-r--r--roms/ipxe/src/include/ipxe/bitops.h6
-rw-r--r--roms/ipxe/src/include/ipxe/blockdev.h2
-rw-r--r--roms/ipxe/src/include/ipxe/blocktrans.h38
-rw-r--r--roms/ipxe/src/include/ipxe/bofm.h2
-rw-r--r--roms/ipxe/src/include/ipxe/cbc.h2
-rw-r--r--roms/ipxe/src/include/ipxe/cdc.h55
-rw-r--r--roms/ipxe/src/include/ipxe/certstore.h2
-rw-r--r--roms/ipxe/src/include/ipxe/chap.h2
-rw-r--r--roms/ipxe/src/include/ipxe/cms.h2
-rw-r--r--roms/ipxe/src/include/ipxe/command.h2
-rw-r--r--roms/ipxe/src/include/ipxe/console.h2
-rw-r--r--roms/ipxe/src/include/ipxe/cpio.h2
-rw-r--r--roms/ipxe/src/include/ipxe/crc32.h2
-rw-r--r--roms/ipxe/src/include/ipxe/crypto.h2
-rw-r--r--roms/ipxe/src/include/ipxe/deflate.h2
-rw-r--r--roms/ipxe/src/include/ipxe/device.h33
-rw-r--r--roms/ipxe/src/include/ipxe/dhcp.h12
-rw-r--r--roms/ipxe/src/include/ipxe/dhcpopts.h2
-rw-r--r--roms/ipxe/src/include/ipxe/dhcppkt.h2
-rw-r--r--roms/ipxe/src/include/ipxe/dhcpv6.h2
-rw-r--r--roms/ipxe/src/include/ipxe/dns.h2
-rw-r--r--roms/ipxe/src/include/ipxe/downloader.h2
-rw-r--r--roms/ipxe/src/include/ipxe/drbg.h2
-rw-r--r--roms/ipxe/src/include/ipxe/ecb.h55
-rw-r--r--roms/ipxe/src/include/ipxe/edd.h2
-rw-r--r--roms/ipxe/src/include/ipxe/editbox.h2
-rw-r--r--roms/ipxe/src/include/ipxe/editstring.h2
-rw-r--r--roms/ipxe/src/include/ipxe/efi/ProcessorBind.h2
-rw-r--r--roms/ipxe/src/include/ipxe/efi/Protocol/Rng.h158
-rw-r--r--roms/ipxe/src/include/ipxe/efi/efi_autoboot.h2
-rw-r--r--roms/ipxe/src/include/ipxe/efi/efi_driver.h2
-rw-r--r--roms/ipxe/src/include/ipxe/efi/efi_entropy.h35
-rw-r--r--roms/ipxe/src/include/ipxe/efi/efi_hii.h2
-rw-r--r--roms/ipxe/src/include/ipxe/efi/efi_pci.h2
-rw-r--r--roms/ipxe/src/include/ipxe/efi/efi_pci_api.h2
-rw-r--r--roms/ipxe/src/include/ipxe/efi/efi_reboot.h2
-rw-r--r--roms/ipxe/src/include/ipxe/efi/efi_smbios.h2
-rw-r--r--roms/ipxe/src/include/ipxe/efi/efi_snp.h27
-rw-r--r--roms/ipxe/src/include/ipxe/efi/efi_strings.h2
-rw-r--r--roms/ipxe/src/include/ipxe/efi/efi_time.h20
-rw-r--r--roms/ipxe/src/include/ipxe/efi/efi_timer.h2
-rw-r--r--roms/ipxe/src/include/ipxe/efi/efi_uaccess.h2
-rw-r--r--roms/ipxe/src/include/ipxe/efi/efi_umalloc.h2
-rw-r--r--roms/ipxe/src/include/ipxe/efi/efi_utils.h2
-rw-r--r--roms/ipxe/src/include/ipxe/efi/efi_watchdog.h31
-rw-r--r--roms/ipxe/src/include/ipxe/efi/efi_wrap.h2
-rw-r--r--roms/ipxe/src/include/ipxe/eisa.h2
-rw-r--r--roms/ipxe/src/include/ipxe/elf.h13
-rw-r--r--roms/ipxe/src/include/ipxe/eltorito.h2
-rw-r--r--roms/ipxe/src/include/ipxe/entropy.h3
-rw-r--r--roms/ipxe/src/include/ipxe/errfile.h37
-rw-r--r--roms/ipxe/src/include/ipxe/errno/efi.h2
-rw-r--r--roms/ipxe/src/include/ipxe/errno/linux.h2
-rw-r--r--roms/ipxe/src/include/ipxe/errortab.h2
-rw-r--r--roms/ipxe/src/include/ipxe/eth_slow.h2
-rw-r--r--roms/ipxe/src/include/ipxe/ethernet.h2
-rw-r--r--roms/ipxe/src/include/ipxe/fakedhcp.h2
-rw-r--r--roms/ipxe/src/include/ipxe/fault.h53
-rw-r--r--roms/ipxe/src/include/ipxe/fbcon.h2
-rw-r--r--roms/ipxe/src/include/ipxe/fc.h2
-rw-r--r--roms/ipxe/src/include/ipxe/fcels.h2
-rw-r--r--roms/ipxe/src/include/ipxe/fcns.h2
-rw-r--r--roms/ipxe/src/include/ipxe/fcoe.h2
-rw-r--r--roms/ipxe/src/include/ipxe/fcp.h2
-rw-r--r--roms/ipxe/src/include/ipxe/features.h2
-rw-r--r--roms/ipxe/src/include/ipxe/fragment.h2
-rw-r--r--roms/ipxe/src/include/ipxe/ftp.h2
-rw-r--r--roms/ipxe/src/include/ipxe/gdbserial.h13
-rw-r--r--roms/ipxe/src/include/ipxe/gdbstub.h2
-rw-r--r--roms/ipxe/src/include/ipxe/gdbudp.h2
-rw-r--r--roms/ipxe/src/include/ipxe/hash_df.h2
-rw-r--r--roms/ipxe/src/include/ipxe/hidemem.h2
-rw-r--r--roms/ipxe/src/include/ipxe/hmac.h2
-rw-r--r--roms/ipxe/src/include/ipxe/hmac_drbg.h2
-rw-r--r--roms/ipxe/src/include/ipxe/http.h490
-rw-r--r--roms/ipxe/src/include/ipxe/hyperv.h232
-rw-r--r--roms/ipxe/src/include/ipxe/i2c.h2
-rw-r--r--roms/ipxe/src/include/ipxe/ib_cm.h2
-rw-r--r--roms/ipxe/src/include/ipxe/ib_mad.h2
-rw-r--r--roms/ipxe/src/include/ipxe/ib_mcast.h2
-rw-r--r--roms/ipxe/src/include/ipxe/ib_mi.h2
-rw-r--r--roms/ipxe/src/include/ipxe/ib_packet.h2
-rw-r--r--roms/ipxe/src/include/ipxe/ib_pathrec.h2
-rw-r--r--roms/ipxe/src/include/ipxe/ib_sma.h2
-rw-r--r--roms/ipxe/src/include/ipxe/ib_smc.h2
-rw-r--r--roms/ipxe/src/include/ipxe/icmp.h2
-rw-r--r--roms/ipxe/src/include/ipxe/icmpv6.h14
-rw-r--r--roms/ipxe/src/include/ipxe/if_arp.h2
-rw-r--r--roms/ipxe/src/include/ipxe/if_ether.h2
-rw-r--r--roms/ipxe/src/include/ipxe/image.h3
-rw-r--r--roms/ipxe/src/include/ipxe/in.h40
-rw-r--r--roms/ipxe/src/include/ipxe/infiniband.h2
-rw-r--r--roms/ipxe/src/include/ipxe/init.h9
-rw-r--r--roms/ipxe/src/include/ipxe/interface.h7
-rw-r--r--roms/ipxe/src/include/ipxe/io.h2
-rw-r--r--roms/ipxe/src/include/ipxe/iobuf.h3
-rw-r--r--roms/ipxe/src/include/ipxe/ip.h2
-rw-r--r--roms/ipxe/src/include/ipxe/ipoib.h2
-rw-r--r--roms/ipxe/src/include/ipxe/ipstat.h2
-rw-r--r--roms/ipxe/src/include/ipxe/ipv6.h2
-rw-r--r--roms/ipxe/src/include/ipxe/isa_ids.h2
-rw-r--r--roms/ipxe/src/include/ipxe/isapnp.h6
-rw-r--r--roms/ipxe/src/include/ipxe/iscsi.h2
-rw-r--r--roms/ipxe/src/include/ipxe/iso9660.h2
-rw-r--r--roms/ipxe/src/include/ipxe/isqrt.h2
-rw-r--r--roms/ipxe/src/include/ipxe/job.h2
-rw-r--r--roms/ipxe/src/include/ipxe/jumpscroll.h50
-rw-r--r--roms/ipxe/src/include/ipxe/keymap.h2
-rw-r--r--roms/ipxe/src/include/ipxe/keys.h4
-rw-r--r--roms/ipxe/src/include/ipxe/linebuf.h14
-rw-r--r--roms/ipxe/src/include/ipxe/lineconsole.h2
-rw-r--r--roms/ipxe/src/include/ipxe/linux/linux_entropy.h12
-rw-r--r--roms/ipxe/src/include/ipxe/linux/linux_nap.h2
-rw-r--r--roms/ipxe/src/include/ipxe/linux/linux_pci.h2
-rw-r--r--roms/ipxe/src/include/ipxe/linux/linux_smbios.h4
-rw-r--r--roms/ipxe/src/include/ipxe/linux/linux_time.h2
-rw-r--r--roms/ipxe/src/include/ipxe/linux/linux_timer.h2
-rw-r--r--roms/ipxe/src/include/ipxe/linux/linux_uaccess.h126
-rw-r--r--roms/ipxe/src/include/ipxe/linux/linux_umalloc.h6
-rw-r--r--roms/ipxe/src/include/ipxe/linux_compat.h2
-rw-r--r--roms/ipxe/src/include/ipxe/list.h2
-rw-r--r--roms/ipxe/src/include/ipxe/login_ui.h2
-rw-r--r--roms/ipxe/src/include/ipxe/malloc.h4
-rw-r--r--roms/ipxe/src/include/ipxe/mca.h2
-rw-r--r--roms/ipxe/src/include/ipxe/md5.h2
-rw-r--r--roms/ipxe/src/include/ipxe/memblock.h2
-rw-r--r--roms/ipxe/src/include/ipxe/menu.h2
-rw-r--r--roms/ipxe/src/include/ipxe/mii.h4
-rw-r--r--roms/ipxe/src/include/ipxe/monojob.h2
-rw-r--r--roms/ipxe/src/include/ipxe/mount.h2
-rw-r--r--roms/ipxe/src/include/ipxe/nap.h2
-rw-r--r--roms/ipxe/src/include/ipxe/ndp.h2
-rw-r--r--roms/ipxe/src/include/ipxe/neighbour.h2
-rw-r--r--roms/ipxe/src/include/ipxe/net80211_err.h2
-rw-r--r--roms/ipxe/src/include/ipxe/netdevice.h41
-rw-r--r--roms/ipxe/src/include/ipxe/nfs.h2
-rw-r--r--roms/ipxe/src/include/ipxe/nfs_open.h2
-rw-r--r--roms/ipxe/src/include/ipxe/nfs_uri.h2
-rw-r--r--roms/ipxe/src/include/ipxe/null_entropy.h2
-rw-r--r--roms/ipxe/src/include/ipxe/null_nap.h2
-rw-r--r--roms/ipxe/src/include/ipxe/null_reboot.h2
-rw-r--r--roms/ipxe/src/include/ipxe/null_sanboot.h2
-rw-r--r--roms/ipxe/src/include/ipxe/null_time.h2
-rw-r--r--roms/ipxe/src/include/ipxe/nvo.h2
-rw-r--r--roms/ipxe/src/include/ipxe/nvs.h2
-rw-r--r--roms/ipxe/src/include/ipxe/nvsvpd.h2
-rw-r--r--roms/ipxe/src/include/ipxe/ocsp.h2
-rw-r--r--roms/ipxe/src/include/ipxe/oncrpc.h2
-rw-r--r--roms/ipxe/src/include/ipxe/oncrpc_iob.h2
-rw-r--r--roms/ipxe/src/include/ipxe/open.h2
-rw-r--r--roms/ipxe/src/include/ipxe/params.h2
-rw-r--r--roms/ipxe/src/include/ipxe/parseopt.h2
-rw-r--r--roms/ipxe/src/include/ipxe/pccrc.h447
-rw-r--r--roms/ipxe/src/include/ipxe/pccrd.h47
-rw-r--r--roms/ipxe/src/include/ipxe/pccrr.h376
-rw-r--r--roms/ipxe/src/include/ipxe/pci.h382
-rw-r--r--roms/ipxe/src/include/ipxe/pci_ids.h351
-rw-r--r--roms/ipxe/src/include/ipxe/pci_io.h2
-rw-r--r--roms/ipxe/src/include/ipxe/pcibackup.h2
-rw-r--r--roms/ipxe/src/include/ipxe/pcivpd.h2
-rw-r--r--roms/ipxe/src/include/ipxe/peerblk.h144
-rw-r--r--roms/ipxe/src/include/ipxe/peerdisc.h116
-rw-r--r--roms/ipxe/src/include/ipxe/peermux.h73
-rw-r--r--roms/ipxe/src/include/ipxe/pending.h2
-rw-r--r--roms/ipxe/src/include/ipxe/ping.h2
-rw-r--r--roms/ipxe/src/include/ipxe/pinger.h2
-rw-r--r--roms/ipxe/src/include/ipxe/pixbuf.h2
-rw-r--r--roms/ipxe/src/include/ipxe/png.h2
-rw-r--r--roms/ipxe/src/include/ipxe/pnm.h2
-rw-r--r--roms/ipxe/src/include/ipxe/pool.h127
-rw-r--r--roms/ipxe/src/include/ipxe/portmap.h2
-rw-r--r--roms/ipxe/src/include/ipxe/posix_io.h2
-rw-r--r--roms/ipxe/src/include/ipxe/privkey.h2
-rw-r--r--roms/ipxe/src/include/ipxe/process.h2
-rw-r--r--roms/ipxe/src/include/ipxe/profile.h16
-rw-r--r--roms/ipxe/src/include/ipxe/random_nz.h2
-rw-r--r--roms/ipxe/src/include/ipxe/rarp.h2
-rw-r--r--roms/ipxe/src/include/ipxe/rbg.h2
-rw-r--r--roms/ipxe/src/include/ipxe/reboot.h2
-rw-r--r--roms/ipxe/src/include/ipxe/refcnt.h2
-rw-r--r--roms/ipxe/src/include/ipxe/resolv.h2
-rw-r--r--roms/ipxe/src/include/ipxe/retry.h36
-rw-r--r--roms/ipxe/src/include/ipxe/rndis.h370
-rw-r--r--roms/ipxe/src/include/ipxe/rootcert.h2
-rw-r--r--roms/ipxe/src/include/ipxe/rotate.h22
-rw-r--r--roms/ipxe/src/include/ipxe/rsa.h3
-rw-r--r--roms/ipxe/src/include/ipxe/sanboot.h2
-rw-r--r--roms/ipxe/src/include/ipxe/script.h2
-rw-r--r--roms/ipxe/src/include/ipxe/scsi.h2
-rw-r--r--roms/ipxe/src/include/ipxe/segment.h2
-rw-r--r--roms/ipxe/src/include/ipxe/serial.h11
-rw-r--r--roms/ipxe/src/include/ipxe/settings.h3
-rw-r--r--roms/ipxe/src/include/ipxe/settings_ui.h2
-rw-r--r--roms/ipxe/src/include/ipxe/sha256.h17
-rw-r--r--roms/ipxe/src/include/ipxe/sha512.h98
-rw-r--r--roms/ipxe/src/include/ipxe/shell.h2
-rw-r--r--roms/ipxe/src/include/ipxe/smbios.h2
-rw-r--r--roms/ipxe/src/include/ipxe/socket.h2
-rw-r--r--roms/ipxe/src/include/ipxe/spi.h2
-rw-r--r--roms/ipxe/src/include/ipxe/spi_bit.h2
-rw-r--r--roms/ipxe/src/include/ipxe/stp.h76
-rw-r--r--roms/ipxe/src/include/ipxe/string.h14
-rw-r--r--roms/ipxe/src/include/ipxe/syslog.h2
-rw-r--r--roms/ipxe/src/include/ipxe/tables.h2
-rw-r--r--roms/ipxe/src/include/ipxe/tcp.h53
-rw-r--r--roms/ipxe/src/include/ipxe/tcpip.h11
-rw-r--r--roms/ipxe/src/include/ipxe/test.h2
-rw-r--r--roms/ipxe/src/include/ipxe/tftp.h2
-rw-r--r--roms/ipxe/src/include/ipxe/time.h3
-rw-r--r--roms/ipxe/src/include/ipxe/timer.h2
-rw-r--r--roms/ipxe/src/include/ipxe/tls.h30
-rw-r--r--roms/ipxe/src/include/ipxe/uaccess.h2
-rw-r--r--roms/ipxe/src/include/ipxe/uart.h132
-rw-r--r--roms/ipxe/src/include/ipxe/udp.h2
-rw-r--r--roms/ipxe/src/include/ipxe/umalloc.h2
-rw-r--r--roms/ipxe/src/include/ipxe/uri.h4
-rw-r--r--roms/ipxe/src/include/ipxe/usb.h1319
-rw-r--r--roms/ipxe/src/include/ipxe/usbhid.h106
-rw-r--r--roms/ipxe/src/include/ipxe/usbnet.h62
-rw-r--r--roms/ipxe/src/include/ipxe/uuid.h2
-rw-r--r--roms/ipxe/src/include/ipxe/validator.h2
-rw-r--r--roms/ipxe/src/include/ipxe/version.h2
-rw-r--r--roms/ipxe/src/include/ipxe/vlan.h2
-rw-r--r--roms/ipxe/src/include/ipxe/vmbus.h634
-rw-r--r--roms/ipxe/src/include/ipxe/vsprintf.h2
-rw-r--r--roms/ipxe/src/include/ipxe/x509.h2
-rw-r--r--roms/ipxe/src/include/ipxe/xen.h2
-rw-r--r--roms/ipxe/src/include/ipxe/xenbus.h2
-rw-r--r--roms/ipxe/src/include/ipxe/xenevent.h2
-rw-r--r--roms/ipxe/src/include/ipxe/xengrant.h2
-rw-r--r--roms/ipxe/src/include/ipxe/xenmem.h2
-rw-r--r--roms/ipxe/src/include/ipxe/xenstore.h2
-rw-r--r--roms/ipxe/src/include/ipxe/xenver.h2
-rw-r--r--roms/ipxe/src/include/ipxe/xfer.h4
-rw-r--r--roms/ipxe/src/include/ipxe/xferbuf.h78
-rw-r--r--roms/ipxe/src/include/libgen.h2
-rw-r--r--roms/ipxe/src/include/little_bswap.h37
-rw-r--r--roms/ipxe/src/include/nic.h19
-rw-r--r--roms/ipxe/src/include/readline/readline.h2
-rw-r--r--roms/ipxe/src/include/stdarg.h2
-rw-r--r--roms/ipxe/src/include/stddef.h40
-rw-r--r--roms/ipxe/src/include/stdint.h2
-rw-r--r--roms/ipxe/src/include/stdio.h2
-rw-r--r--roms/ipxe/src/include/stdlib.h30
-rw-r--r--roms/ipxe/src/include/string.h83
-rw-r--r--roms/ipxe/src/include/strings.h145
-rw-r--r--roms/ipxe/src/include/sys/time.h2
-rw-r--r--roms/ipxe/src/include/syslog.h2
-rw-r--r--roms/ipxe/src/include/time.h2
-rw-r--r--roms/ipxe/src/include/unistd.h2
-rw-r--r--roms/ipxe/src/include/usr/autoboot.h4
-rw-r--r--roms/ipxe/src/include/usr/dhcpmgmt.h2
-rw-r--r--roms/ipxe/src/include/usr/fcmgmt.h2
-rw-r--r--roms/ipxe/src/include/usr/ifmgmt.h2
-rw-r--r--roms/ipxe/src/include/usr/imgmgmt.h2
-rw-r--r--roms/ipxe/src/include/usr/imgtrust.h2
-rw-r--r--roms/ipxe/src/include/usr/ipstat.h2
-rw-r--r--roms/ipxe/src/include/usr/lotest.h2
-rw-r--r--roms/ipxe/src/include/usr/neighmgmt.h2
-rw-r--r--roms/ipxe/src/include/usr/pingmgmt.h2
-rw-r--r--roms/ipxe/src/include/usr/profstat.h2
-rw-r--r--roms/ipxe/src/include/usr/prompt.h2
-rw-r--r--roms/ipxe/src/include/usr/route.h2
-rw-r--r--roms/ipxe/src/include/usr/sync.h2
-rw-r--r--roms/ipxe/src/include/valgrind/memcheck.h (renamed from roms/ipxe/src/arch/x86/include/valgrind/memcheck.h)0
-rw-r--r--roms/ipxe/src/include/valgrind/valgrind.h (renamed from roms/ipxe/src/arch/x86/include/valgrind/valgrind.h)0
-rw-r--r--roms/ipxe/src/include/wchar.h2
-rw-r--r--roms/ipxe/src/interface/bofm/bofm.c6
-rw-r--r--roms/ipxe/src/interface/efi/efi_autoboot.c6
-rw-r--r--roms/ipxe/src/interface/efi/efi_bofm.c6
-rw-r--r--roms/ipxe/src/interface/efi/efi_debug.c8
-rw-r--r--roms/ipxe/src/interface/efi/efi_file.c6
-rw-r--r--roms/ipxe/src/interface/efi/efi_guid.c6
-rw-r--r--roms/ipxe/src/interface/efi/efi_hii.c6
-rw-r--r--roms/ipxe/src/interface/efi/efi_pci.c6
-rw-r--r--roms/ipxe/src/interface/efi/efi_reboot.c6
-rw-r--r--roms/ipxe/src/interface/efi/efi_snp.c181
-rw-r--r--roms/ipxe/src/interface/efi/efi_snp_hii.c9
-rw-r--r--roms/ipxe/src/interface/efi/efi_strings.c6
-rw-r--r--roms/ipxe/src/interface/efi/efi_time.c75
-rw-r--r--roms/ipxe/src/interface/efi/efi_timer.c6
-rw-r--r--roms/ipxe/src/interface/efi/efi_uaccess.c6
-rw-r--r--roms/ipxe/src/interface/efi/efi_umalloc.c6
-rw-r--r--roms/ipxe/src/interface/efi/efi_watchdog.c82
-rw-r--r--roms/ipxe/src/interface/efi/efi_wrap.c6
-rw-r--r--roms/ipxe/src/interface/hyperv/vmbus.c1333
-rw-r--r--roms/ipxe/src/interface/linux/linux_entropy.c6
-rw-r--r--roms/ipxe/src/interface/linux/linux_pci.c6
-rw-r--r--roms/ipxe/src/interface/linux/linux_time.c6
-rw-r--r--roms/ipxe/src/interface/linux/linux_uaccess.c1
-rw-r--r--roms/ipxe/src/interface/smbios/smbios.c6
-rw-r--r--roms/ipxe/src/interface/smbios/smbios_settings.c6
-rw-r--r--roms/ipxe/src/interface/xen/xenbus.c6
-rw-r--r--roms/ipxe/src/interface/xen/xengrant.c6
-rw-r--r--roms/ipxe/src/interface/xen/xenstore.c10
-rw-r--r--roms/ipxe/src/net/80211/net80211.c10
-rw-r--r--roms/ipxe/src/net/80211/wpa.c1
-rw-r--r--roms/ipxe/src/net/80211/wpa_ccmp.c2
-rw-r--r--roms/ipxe/src/net/80211/wpa_tkip.c2
-rw-r--r--roms/ipxe/src/net/aoe.c6
-rw-r--r--roms/ipxe/src/net/arp.c12
-rw-r--r--roms/ipxe/src/net/dhcpopts.c6
-rw-r--r--roms/ipxe/src/net/dhcppkt.c6
-rw-r--r--roms/ipxe/src/net/eth_slow.c6
-rw-r--r--roms/ipxe/src/net/ethernet.c50
-rw-r--r--roms/ipxe/src/net/fakedhcp.c6
-rw-r--r--roms/ipxe/src/net/fc.c12
-rw-r--r--roms/ipxe/src/net/fcels.c6
-rw-r--r--roms/ipxe/src/net/fcns.c6
-rw-r--r--roms/ipxe/src/net/fcoe.c6
-rw-r--r--roms/ipxe/src/net/fcp.c6
-rw-r--r--roms/ipxe/src/net/fragment.c6
-rw-r--r--roms/ipxe/src/net/icmp.c6
-rw-r--r--roms/ipxe/src/net/icmpv4.c6
-rw-r--r--roms/ipxe/src/net/icmpv6.c86
-rw-r--r--roms/ipxe/src/net/infiniband.c18
-rw-r--r--roms/ipxe/src/net/infiniband/ib_cm.c6
-rw-r--r--roms/ipxe/src/net/infiniband/ib_mcast.c12
-rw-r--r--roms/ipxe/src/net/infiniband/ib_mi.c6
-rw-r--r--roms/ipxe/src/net/infiniband/ib_packet.c6
-rw-r--r--roms/ipxe/src/net/infiniband/ib_pathrec.c6
-rw-r--r--roms/ipxe/src/net/infiniband/ib_sma.c6
-rw-r--r--roms/ipxe/src/net/infiniband/ib_smc.c6
-rw-r--r--roms/ipxe/src/net/infiniband/ib_srp.c2
-rw-r--r--roms/ipxe/src/net/iobpad.c6
-rw-r--r--roms/ipxe/src/net/ipv4.c130
-rw-r--r--roms/ipxe/src/net/ipv6.c22
-rw-r--r--roms/ipxe/src/net/neighbour.c12
-rw-r--r--roms/ipxe/src/net/netdev_settings.c10
-rw-r--r--roms/ipxe/src/net/netdevice.c74
-rw-r--r--roms/ipxe/src/net/nullnet.c6
-rw-r--r--roms/ipxe/src/net/pccrc.c818
-rw-r--r--roms/ipxe/src/net/pccrd.c286
-rw-r--r--roms/ipxe/src/net/peerblk.c1366
-rw-r--r--roms/ipxe/src/net/peerdisc.c551
-rw-r--r--roms/ipxe/src/net/peerdist.c145
-rw-r--r--roms/ipxe/src/net/peermux.c387
-rw-r--r--roms/ipxe/src/net/ping.c6
-rw-r--r--roms/ipxe/src/net/rarp.c6
-rw-r--r--roms/ipxe/src/net/retry.c90
-rw-r--r--roms/ipxe/src/net/rndis.c1052
-rw-r--r--roms/ipxe/src/net/socket.c6
-rw-r--r--roms/ipxe/src/net/stp.c152
-rw-r--r--roms/ipxe/src/net/tcp.c245
-rw-r--r--roms/ipxe/src/net/tcp/http.c26
-rw-r--r--roms/ipxe/src/net/tcp/httpauth.c190
-rw-r--r--roms/ipxe/src/net/tcp/httpbasic.c102
-rw-r--r--roms/ipxe/src/net/tcp/httpblock.c134
-rw-r--r--roms/ipxe/src/net/tcp/httpconn.c309
-rw-r--r--roms/ipxe/src/net/tcp/httpcore.c2676
-rw-r--r--roms/ipxe/src/net/tcp/httpdigest.c234
-rw-r--r--roms/ipxe/src/net/tcp/https.c27
-rw-r--r--roms/ipxe/src/net/tcp/iscsi.c76
-rw-r--r--roms/ipxe/src/net/tcp/syslogs.c6
-rw-r--r--roms/ipxe/src/net/tcpip.c4
-rw-r--r--roms/ipxe/src/net/tls.c146
-rw-r--r--roms/ipxe/src/net/udp.c2
-rw-r--r--roms/ipxe/src/net/udp/dhcp.c133
-rw-r--r--roms/ipxe/src/net/udp/dhcpv6.c6
-rw-r--r--roms/ipxe/src/net/udp/dns.c6
-rw-r--r--roms/ipxe/src/net/udp/slam.c6
-rw-r--r--roms/ipxe/src/net/udp/syslog.c6
-rw-r--r--roms/ipxe/src/net/udp/tftp.c60
-rw-r--r--roms/ipxe/src/net/validator.c14
-rw-r--r--roms/ipxe/src/net/vlan.c10
-rw-r--r--roms/ipxe/src/tests/aes_cbc_test.c193
-rw-r--r--roms/ipxe/src/tests/aes_test.c193
-rw-r--r--roms/ipxe/src/tests/base16_test.c52
-rw-r--r--roms/ipxe/src/tests/base64_test.c52
-rw-r--r--roms/ipxe/src/tests/bigint_test.c6
-rw-r--r--roms/ipxe/src/tests/bofm_test.c6
-rw-r--r--roms/ipxe/src/tests/byteswap_test.c6
-rw-r--r--roms/ipxe/src/tests/cbc_test.h57
-rw-r--r--roms/ipxe/src/tests/cipher_test.c (renamed from roms/ipxe/src/tests/cbc_test.c)118
-rw-r--r--roms/ipxe/src/tests/cipher_test.h111
-rw-r--r--roms/ipxe/src/tests/cms_test.c7
-rw-r--r--roms/ipxe/src/tests/crc32_test.c6
-rw-r--r--roms/ipxe/src/tests/deflate_test.c6
-rw-r--r--roms/ipxe/src/tests/digest_test.c69
-rw-r--r--roms/ipxe/src/tests/digest_test.h120
-rw-r--r--roms/ipxe/src/tests/dns_test.c6
-rw-r--r--roms/ipxe/src/tests/entropy_sample.c6
-rw-r--r--roms/ipxe/src/tests/hash_df_test.c6
-rw-r--r--roms/ipxe/src/tests/hmac_drbg_test.c6
-rw-r--r--roms/ipxe/src/tests/ipv4_test.c154
-rw-r--r--roms/ipxe/src/tests/ipv6_test.c6
-rw-r--r--roms/ipxe/src/tests/linebuf_test.c337
-rw-r--r--roms/ipxe/src/tests/list_test.c6
-rw-r--r--roms/ipxe/src/tests/math_test.c80
-rw-r--r--roms/ipxe/src/tests/md5_test.c82
-rw-r--r--roms/ipxe/src/tests/memcpy_test.c6
-rw-r--r--roms/ipxe/src/tests/memset_test.c157
-rw-r--r--roms/ipxe/src/tests/ocsp_test.c7
-rw-r--r--roms/ipxe/src/tests/pccrc_test.c529
-rw-r--r--roms/ipxe/src/tests/pixbuf_test.c13
-rw-r--r--roms/ipxe/src/tests/pixbuf_test.h2
-rw-r--r--roms/ipxe/src/tests/png_test.c6
-rw-r--r--roms/ipxe/src/tests/pnm_test.c6
-rw-r--r--roms/ipxe/src/tests/profile_test.c6
-rw-r--r--roms/ipxe/src/tests/pubkey_test.h2
-rw-r--r--roms/ipxe/src/tests/rsa_test.c6
-rw-r--r--roms/ipxe/src/tests/setjmp_test.c171
-rw-r--r--roms/ipxe/src/tests/settings_test.c25
-rw-r--r--roms/ipxe/src/tests/sha1_test.c92
-rw-r--r--roms/ipxe/src/tests/sha256_test.c131
-rw-r--r--roms/ipxe/src/tests/sha512_test.c185
-rw-r--r--roms/ipxe/src/tests/string_test.c142
-rw-r--r--roms/ipxe/src/tests/tcpip_test.c6
-rw-r--r--roms/ipxe/src/tests/test.c6
-rw-r--r--roms/ipxe/src/tests/tests.c15
-rw-r--r--roms/ipxe/src/tests/time_test.c6
-rw-r--r--roms/ipxe/src/tests/uri_test.c30
-rw-r--r--roms/ipxe/src/tests/vsprintf_test.c6
-rw-r--r--roms/ipxe/src/tests/x509_test.c7
-rw-r--r--roms/ipxe/src/usr/autoboot.c49
-rw-r--r--roms/ipxe/src/usr/dhcpmgmt.c6
-rw-r--r--roms/ipxe/src/usr/fcmgmt.c6
-rw-r--r--roms/ipxe/src/usr/ifmgmt.c9
-rw-r--r--roms/ipxe/src/usr/imgmgmt.c6
-rw-r--r--roms/ipxe/src/usr/imgtrust.c6
-rw-r--r--roms/ipxe/src/usr/ipstat.c6
-rw-r--r--roms/ipxe/src/usr/lotest.c6
-rw-r--r--roms/ipxe/src/usr/neighmgmt.c6
-rw-r--r--roms/ipxe/src/usr/pingmgmt.c6
-rw-r--r--roms/ipxe/src/usr/profstat.c6
-rw-r--r--roms/ipxe/src/usr/prompt.c6
-rw-r--r--roms/ipxe/src/usr/pxemenu.c6
-rw-r--r--roms/ipxe/src/usr/route.c10
-rw-r--r--roms/ipxe/src/usr/route_ipv4.c6
-rw-r--r--roms/ipxe/src/usr/route_ipv6.c6
-rw-r--r--roms/ipxe/src/usr/sync.c6
-rw-r--r--roms/ipxe/src/util/Option/ROM.pm20
-rwxr-xr-xroms/ipxe/src/util/disrom.pl4
-rw-r--r--roms/ipxe/src/util/elf2efi.c6
-rwxr-xr-xroms/ipxe/src/util/licence.pl13
-rwxr-xr-xroms/ipxe/src/util/parserom.pl296
-rwxr-xr-xroms/ipxe/src/util/relicense.pl169
-rw-r--r--roms/ipxe/src/util/zbin.c96
-rw-r--r--roms/openbios/arch/ppc/qemu/init.c62
-rw-r--r--roms/openbios/arch/ppc/qemu/methods.c36
-rw-r--r--roms/openbios/arch/ppc/qemu/qemu.fs28
-rw-r--r--roms/openbios/arch/ppc/qemu/tree.fs8
-rwxr-xr-xroms/openbios/config/scripts/switch-arch28
-rw-r--r--roms/openbios/drivers/cuda.c21
-rw-r--r--roms/openbios/drivers/escc.c88
-rw-r--r--roms/openbios/drivers/escc.h2
-rw-r--r--roms/openbios/drivers/ide.c36
-rw-r--r--roms/openbios/drivers/pci.c8
-rw-r--r--roms/openbios/include/drivers/drivers.h1
-rw-r--r--roms/openbios/libopenbios/bootinfo_load.c6
1056 files changed, 51190 insertions, 8909 deletions
diff --git a/roms/Makefile b/roms/Makefile
index 7b3f15632..09e33b59e 100644
--- a/roms/Makefile
+++ b/roms/Makefile
@@ -120,20 +120,17 @@ efi-rom-%: build-pxe-roms build-efi-roms
-ec ipxe/src/bin-x86_64-efi/$(VID)$(DID).efidrv \
-o ../pc-bios/efi-$*.rom
-build-pxe-roms: ipxe/src/config/local/general.h
- $(MAKE) -C ipxe/src GITVERSION="" \
+build-pxe-roms:
+ $(MAKE) -C ipxe/src CONFIG=qemu \
CROSS_COMPILE=$(x86_64_cross_prefix) \
$(patsubst %,bin/%.rom,$(pxerom_targets))
-build-efi-roms: build-pxe-roms ipxe/src/config/local/general.h
- $(MAKE) -C ipxe/src GITVERSION="" \
+build-efi-roms: build-pxe-roms
+ $(MAKE) -C ipxe/src CONFIG=qemu \
CROSS_COMPILE=$(x86_64_cross_prefix) \
$(patsubst %,bin-i386-efi/%.efidrv,$(pxerom_targets)) \
$(patsubst %,bin-x86_64-efi/%.efidrv,$(pxerom_targets))
-ipxe/src/config/local/%: config.ipxe.%
- cp $< $@
-
slof:
$(MAKE) -C SLOF CROSS=$(powerpc64_cross_prefix) qemu
diff --git a/roms/SLOF/README b/roms/SLOF/README
index 58e929427..789504568 100644
--- a/roms/SLOF/README
+++ b/roms/SLOF/README
@@ -11,6 +11,7 @@ Index
2.2 Overview of the source code
2.4 Extending the Forth engine
3.0 Limitations
+4.0 Submitting patches
1.0 Introduction to Slimline Open Firmware
@@ -236,6 +237,16 @@ To add primitives:
On a JS21 all memory configurations should work.
+4.0 Submitting patches
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Patches for SLOF should be made against https://github.com/aik/SLOF,
+the master branch and posted to slof@lists.ozlabs.org.
+The patches must be signed using "Signed-off-by" tag with a real name to
+confirm that you certify the Developer Certificate of Origin Version 1.1,
+see [3] for details.
+
+
Documentation
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -244,3 +255,6 @@ Documentation
[2] PAPR Standard, Power.org(TM) Standard for Power Architecture(R) Platform
Requirements (Workstation, Server), Version 2.4, December 7, 2009
+
+[3] Developer Certificate of Origin Version 1.1
+ http://developercertificate.org/
diff --git a/roms/SLOF/VERSION b/roms/SLOF/VERSION
index 20bdb2eb7..c99837873 100644
--- a/roms/SLOF/VERSION
+++ b/roms/SLOF/VERSION
@@ -1 +1 @@
-20150429
+20151103
diff --git a/roms/SLOF/board-js2x/llfw/stage2.lds b/roms/SLOF/board-js2x/llfw/stage2.lds
index f91f0658a..e6315c3c8 100644
--- a/roms/SLOF/board-js2x/llfw/stage2.lds
+++ b/roms/SLOF/board-js2x/llfw/stage2.lds
@@ -45,7 +45,8 @@ SECTIONS {
__bss_end = .;
__bss_size = (__bss_end - __bss_start);
- __toc_start = .;
+ . = ALIGN(256);
+ __toc_start = DEFINED (.TOC.) ? .TOC. : ADDR (.got) + 0x8000;
.got :
{
*(.toc .got)
diff --git a/roms/SLOF/board-js2x/llfw/stage2_head.S b/roms/SLOF/board-js2x/llfw/stage2_head.S
index 5460bfebb..f3f5e0c8c 100644
--- a/roms/SLOF/board-js2x/llfw/stage2_head.S
+++ b/roms/SLOF/board-js2x/llfw/stage2_head.S
@@ -79,8 +79,6 @@ bsscdone:
/* ------------------------------------ */
ASM_ENTRY(toc_init)
LOAD64(r2, __toc_start)
- addi r2,r2,0x4000
- addi r2,r2,0x4000
blr
/* ------------------------------------ */
diff --git a/roms/SLOF/board-js2x/slof/Makefile b/roms/SLOF/board-js2x/slof/Makefile
index ab3e683a4..fdc716fc6 100644
--- a/roms/SLOF/board-js2x/slof/Makefile
+++ b/roms/SLOF/board-js2x/slof/Makefile
@@ -82,6 +82,7 @@ OF_FFS_FILES = \
$(SLOFCMNDIR)/fs/scsi-host-helpers.fs \
$(SLOFCMNDIR)/fs/scsi-probe-helpers.fs \
$(SLOFCMNDIR)/fs/scsi-support.fs \
+ $(SLOFCMNDIR)/fs/dma-function.fs \
$(SLOFCMNDIR)/fs/pci-device.fs \
$(SLOFCMNDIR)/fs/pci-bridge.fs \
$(SLOFCMNDIR)/fs/pci-properties.fs \
diff --git a/roms/SLOF/board-js2x/slof/helper.fs b/roms/SLOF/board-js2x/slof/helper.fs
index 34d60da1f..1e2b03063 100644
--- a/roms/SLOF/board-js2x/slof/helper.fs
+++ b/roms/SLOF/board-js2x/slof/helper.fs
@@ -26,3 +26,14 @@
s" , " $cat
bdate2human $cat encode-string THEN
;
+
+: invert-region ( addr len -- )
+ 2dup or 7 and CASE
+ 0 OF 3 rshift 0 ?DO dup dup rx@ -1 xor swap rx! xa1+ LOOP ENDOF
+ 4 OF 2 rshift 0 ?DO dup dup rl@ -1 xor swap rl! la1+ LOOP ENDOF
+ 3 and
+ 2 OF 1 rshift 0 ?DO dup dup rw@ -1 xor swap rw! wa1+ LOOP ENDOF
+ dup OF 0 ?DO dup dup rb@ -1 xor swap rb! 1+ LOOP ENDOF
+ ENDCASE
+ drop
+;
diff --git a/roms/SLOF/board-qemu/llfw/stage2.lds b/roms/SLOF/board-qemu/llfw/stage2.lds
index e060dd189..28c9dca93 100644
--- a/roms/SLOF/board-qemu/llfw/stage2.lds
+++ b/roms/SLOF/board-qemu/llfw/stage2.lds
@@ -49,7 +49,8 @@ SECTIONS {
__bss_end = .;
__bss_size = (__bss_end - __bss_start);
- __toc_start = .;
+ . = ALIGN(256);
+ __toc_start = DEFINED (.TOC.) ? .TOC. : ADDR (.got) + 0x8000;
.got :
{
*(.toc .got)
diff --git a/roms/SLOF/board-qemu/llfw/stage2_head.S b/roms/SLOF/board-qemu/llfw/stage2_head.S
index c56b117ce..adf75547b 100644
--- a/roms/SLOF/board-qemu/llfw/stage2_head.S
+++ b/roms/SLOF/board-qemu/llfw/stage2_head.S
@@ -77,8 +77,6 @@ bsscdone:
/* ------------------------------------ */
ASM_ENTRY(toc_init)
LOAD64(r2, __toc_start)
- addi r2,r2,0x4000
- addi r2,r2,0x4000
blr
/* ------------------------------------ */
diff --git a/roms/SLOF/board-qemu/slof/Makefile b/roms/SLOF/board-qemu/slof/Makefile
index 283f77d32..a3fe6abd0 100644
--- a/roms/SLOF/board-qemu/slof/Makefile
+++ b/roms/SLOF/board-qemu/slof/Makefile
@@ -69,6 +69,7 @@ VIO_FFS_FILES = \
$(SLOFBRDDIR)/pci-device_1af4_1001.fs \
$(SLOFBRDDIR)/pci-device_1af4_1004.fs \
$(SLOFBRDDIR)/pci-device_1af4_1009.fs \
+ $(SLOFBRDDIR)/pci-device_1af4_1050.fs \
$(SLOFBRDDIR)/vio-hvterm.fs \
$(SLOFBRDDIR)/vio-vscsi.fs \
$(SLOFBRDDIR)/vio-veth.fs \
@@ -103,6 +104,7 @@ OF_FFS_FILES = \
$(SLOFBRDDIR)/pci-device_1013_00b8.fs \
$(SLOFBRDDIR)/pci-device_8086_100e.fs \
$(SLOFBRDDIR)/e1k.fs \
+ $(SLOFBRDDIR)/qemu-vga.fs \
$(FCODE_FFS_FILES)
# Uncomment the following line to enable the USB code:
diff --git a/roms/SLOF/board-qemu/slof/helper.fs b/roms/SLOF/board-qemu/slof/helper.fs
index 96da49894..40d4abc3a 100644
--- a/roms/SLOF/board-qemu/slof/helper.fs
+++ b/roms/SLOF/board-qemu/slof/helper.fs
@@ -33,3 +33,16 @@
swap -
;
+: invert-region-cs ( addr len cellsize -- )
+ >r over swap r@ rshift r> swap 1 hv-logical-memop drop
+;
+
+: invert-region ( addr len -- )
+ 2dup or 7 and CASE
+ 0 OF 3 invert-region-cs ENDOF
+ 4 OF 2 invert-region-cs ENDOF
+ 3 and
+ 2 OF 1 invert-region-cs ENDOF
+ dup OF 0 invert-region-cs ENDOF
+ ENDCASE
+;
diff --git a/roms/SLOF/board-qemu/slof/pci-device_1234_1111.fs b/roms/SLOF/board-qemu/slof/pci-device_1234_1111.fs
index a5c3584f9..22ea45d5c 100644
--- a/roms/SLOF/board-qemu/slof/pci-device_1234_1111.fs
+++ b/roms/SLOF/board-qemu/slof/pci-device_1234_1111.fs
@@ -10,233 +10,6 @@
\ * IBM Corporation - initial implementation
\ ****************************************************************************/
-my-space pci-device-generic-setup
-
-\ Defaults, overriden from qemu
-d# 800 VALUE disp-width
-d# 600 VALUE disp-height
-d# 8 VALUE disp-depth
-
-\ Determine base address
-10 config-l@ translate-my-address f not AND VALUE fb-base
-
-\ Fixed up later
--1 VALUE io-base
-
-\ We support only one instance
-false VALUE is-installed?
-
-: vga-io-xlate ( port -- addr )
- io-base -1 = IF
- dup translate-my-address fff not and to io-base
- THEN
- io-base +
-;
-
-: vga-w! ( value port -- )
- vga-io-xlate rw!-le
-;
-
-: vga-w@ ( port -- value )
- vga-io-xlate rw@-le
-;
-
-: vga-b! ( value port -- )
- vga-io-xlate rb!
-;
-
-: vga-b@ ( port -- value )
- vga-io-xlate rb@
-;
-
-: vbe! ( value index -- )
- 1ce vga-w! 1d0 vga-w!
-;
-
-: vbe@ ( index -- value )
- 1ce vga-w! 1d0 vga-w@
-;
-
-: color! ( r g b number -- )
- 3c8 vga-b!
- rot 3c9 vga-b!
- swap 3c9 vga-b!
- 3c9 vga-b!
-;
-
-: color@ ( number -- r g b )
- 3c8 vga-b!
- 3c9 vga-b@
- 3c9 vga-b@
- 3c9 vga-b@
-;
-
-: set-colors ( adr number #numbers -- )
- over 3c8 vga-b!
- swap DO
- rb@ 3c9 vga-b!
- rb@ 3c9 vga-b!
- rb@ 3c9 vga-b!
- LOOP
- 3drop
-;
-
-: get-colors ( adr number #numbers -- )
- 3drop
-;
-
-include graphics.fs
-
-\ qemu fake VBE IO registers
-0 CONSTANT VBE_DISPI_INDEX_ID
-1 CONSTANT VBE_DISPI_INDEX_XRES
-2 CONSTANT VBE_DISPI_INDEX_YRES
-3 CONSTANT VBE_DISPI_INDEX_BPP
-4 CONSTANT VBE_DISPI_INDEX_ENABLE
-5 CONSTANT VBE_DISPI_INDEX_BANK
-6 CONSTANT VBE_DISPI_INDEX_VIRT_WIDTH
-7 CONSTANT VBE_DISPI_INDEX_VIRT_HEIGHT
-8 CONSTANT VBE_DISPI_INDEX_X_OFFSET
-9 CONSTANT VBE_DISPI_INDEX_Y_OFFSET
-a CONSTANT VBE_DISPI_INDEX_NB
-
-\ ENABLE register
-00 CONSTANT VBE_DISPI_DISABLED
-01 CONSTANT VBE_DISPI_ENABLED
-02 CONSTANT VBE_DISPI_GETCAPS
-20 CONSTANT VBE_DISPI_8BIT_DAC
-40 CONSTANT VBE_DISPI_LFB_ENABLED
-80 CONSTANT VBE_DISPI_NOCLEARMEM
-
-: init-mode
- 0 3c0 vga-b!
- VBE_DISPI_DISABLED VBE_DISPI_INDEX_ENABLE vbe!
- 0 VBE_DISPI_INDEX_X_OFFSET vbe!
- 0 VBE_DISPI_INDEX_Y_OFFSET vbe!
- disp-width VBE_DISPI_INDEX_XRES vbe!
- disp-height VBE_DISPI_INDEX_YRES vbe!
- disp-depth VBE_DISPI_INDEX_BPP vbe!
- VBE_DISPI_ENABLED VBE_DISPI_8BIT_DAC or VBE_DISPI_INDEX_ENABLE vbe!
- 0 3c0 vga-b!
- 20 3c0 vga-b!
-;
-
-: clear-screen
- fb-base disp-width disp-height disp-depth 7 + 8 / * * 0 rfill
-;
-
-: read-settings
- s" qemu,graphic-width" get-chosen IF
- decode-int to disp-width 2drop
- THEN
- s" qemu,graphic-height" get-chosen IF
- decode-int to disp-height 2drop
- THEN
- s" qemu,graphic-depth" get-chosen IF
- decode-int nip nip
- dup 8 =
- over f = or
- over 10 = or
- over 20 = or IF
- to disp-depth
- ELSE
- ." Unsupported bit depth, using 8bpp " drop cr
- THEN
- THEN
-;
-
-: add-legacy-reg
- \ add legacy I/O Ports / Memory regions to assigned-addresses
- \ see PCI Bus Binding Revision 2.1 Section 7.
- s" reg" get-node get-property IF
- \ "reg" does not exist, create new
- encode-start
- ELSE
- \ "reg" does exist, copy it
- encode-bytes
- THEN
- \ I/O Range 0x1ce-0x1d2
- my-space a1000000 or encode-int+ \ non-relocatable, aliased I/O space
- 1ce encode-64+ 4 encode-64+ \ addr size
- \ I/O Range 0x3B0-0x3BB
- my-space a1000000 or encode-int+ \ non-relocatable, aliased I/O space
- 3b0 encode-64+ c encode-64+ \ addr size
- \ I/O Range 0x3C0-0x3DF
- my-space a1000000 or encode-int+ \ non-relocatable, aliased I/O space
- 3c0 encode-64+ 20 encode-64+ \ addr size
- \ Memory Range 0xA0000-0xBFFFF
- my-space a2000000 or encode-int+ \ non-relocatable, <1MB Memory space
- a0000 encode-64+ 20000 encode-64+ \ addr size
- s" reg" property \ store "reg" property
-;
-
-: setup-properties
- \ Shouldn't this be done from open ?
- disp-width encode-int s" width" property
- disp-height encode-int s" height" property
- disp-width disp-depth 7 + 8 / * encode-int s" linebytes" property
- disp-depth encode-int s" depth" property
- s" ISO8859-1" encode-string s" character-set" property \ i hope this is ok...
- \ add "device_type" property
- s" display" device-type
- s" qemu,std-vga" encode-string s" compatible" property
- \ XXX We don't create an "address" property because Linux doesn't know what
- \ to do with it for >32-bit
-;
-
-\ words for installation/removal, needed by is-install/is-remove, see display.fs
-: display-remove ( -- )
-;
-
-: hcall-invert-screen ( -- )
- frame-buffer-adr frame-buffer-adr 3
- screen-height screen-width * screen-depth * /x /
- 1 hv-logical-memop
- drop
-;
-
-: hcall-blink-screen ( -- )
- \ 32 msec delay for visually noticing the blink
- hcall-invert-screen 20 ms hcall-invert-screen
-;
-
-: display-install ( -- )
- is-installed? NOT IF
- ." Installing QEMU fb" cr
- fb-base to frame-buffer-adr
- clear-screen
- default-font
- set-font
- disp-width disp-height
- disp-width char-width / disp-height char-height /
- disp-depth 7 + 8 / ( width height #lines #cols depth )
- fb-install
- ['] hcall-invert-screen to invert-screen
- ['] hcall-blink-screen to blink-screen
- true to is-installed?
- THEN
-;
-
-: set-alias
- s" screen" find-alias 0= IF
- \ no previous screen alias defined, define it...
- s" screen" get-node node>path set-alias
- ELSE
- drop
- THEN
-;
-
-
." qemu vga" cr
-pci-master-enable
-pci-mem-enable
-pci-io-enable
-add-legacy-reg
-read-settings
-init-mode
-init-default-palette
-setup-properties
-' display-install is-install
-' display-remove is-remove
-set-alias
+s" qemu-vga.fs" included
diff --git a/roms/SLOF/board-qemu/slof/pci-device_1af4_1050.fs b/roms/SLOF/board-qemu/slof/pci-device_1af4_1050.fs
new file mode 100644
index 000000000..516056aad
--- /dev/null
+++ b/roms/SLOF/board-qemu/slof/pci-device_1af4_1050.fs
@@ -0,0 +1,15 @@
+\ *****************************************************************************
+\ * Copyright (c) 2015 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ * IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+s" virtio [ vga ]" type cr
+
+s" qemu-vga.fs" included
diff --git a/roms/SLOF/board-qemu/slof/qemu-vga.fs b/roms/SLOF/board-qemu/slof/qemu-vga.fs
new file mode 100644
index 000000000..3f4c237fc
--- /dev/null
+++ b/roms/SLOF/board-qemu/slof/qemu-vga.fs
@@ -0,0 +1,198 @@
+\ *****************************************************************************
+\ * Copyright (c) 2015 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ * IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+my-space pci-device-generic-setup
+
+\ Defaults, overriden from qemu
+d# 800 VALUE disp-width
+d# 600 VALUE disp-height
+d# 8 VALUE disp-depth
+
+: map-in " map-in" my-phandle parent $call-static ;
+: map-out " map-out" my-phandle parent $call-static ;
+
+\ Determine base address
+0 0 my-space h# 02000010 + 1 map-in VALUE fb-base
+0 0 my-space h# 02000018 + 1 map-in VALUE reg-base
+
+\ We support only one instance
+false VALUE is-installed?
+
+: vga-w! ( value port -- )
+ 3c0 - reg-base 400 + + rw!-le
+;
+
+: vga-w@ ( port -- value )
+ 3c0 - reg-base 400 + + rw@-le
+;
+
+: vga-b! ( value port -- )
+ 3c0 - reg-base 400 + + rb!
+;
+
+: vga-b@ ( port -- value )
+ 3c0 - reg-base 400 + + rb@
+;
+
+: vbe! ( value index -- )
+ 1 << reg-base 500 + + rw!-le
+;
+
+: vbe@ ( index -- value )
+ 1 << reg-base 500 + + rw@-le
+;
+
+: color! ( r g b number -- )
+ 3c8 vga-b!
+ rot 3c9 vga-b!
+ swap 3c9 vga-b!
+ 3c9 vga-b!
+;
+
+: color@ ( number -- r g b )
+ 3c8 vga-b!
+ 3c9 vga-b@
+ 3c9 vga-b@
+ 3c9 vga-b@
+;
+
+: set-colors ( adr number #numbers -- )
+ over 3c8 vga-b!
+ swap DO
+ rb@ 3c9 vga-b!
+ rb@ 3c9 vga-b!
+ rb@ 3c9 vga-b!
+ LOOP
+ 3drop
+;
+
+: get-colors ( adr number #numbers -- )
+ 3drop
+;
+
+include graphics.fs
+
+\ qemu fake VBE IO registers
+0 CONSTANT VBE_DISPI_INDEX_ID
+1 CONSTANT VBE_DISPI_INDEX_XRES
+2 CONSTANT VBE_DISPI_INDEX_YRES
+3 CONSTANT VBE_DISPI_INDEX_BPP
+4 CONSTANT VBE_DISPI_INDEX_ENABLE
+5 CONSTANT VBE_DISPI_INDEX_BANK
+6 CONSTANT VBE_DISPI_INDEX_VIRT_WIDTH
+7 CONSTANT VBE_DISPI_INDEX_VIRT_HEIGHT
+8 CONSTANT VBE_DISPI_INDEX_X_OFFSET
+9 CONSTANT VBE_DISPI_INDEX_Y_OFFSET
+a CONSTANT VBE_DISPI_INDEX_NB
+
+\ ENABLE register
+00 CONSTANT VBE_DISPI_DISABLED
+01 CONSTANT VBE_DISPI_ENABLED
+02 CONSTANT VBE_DISPI_GETCAPS
+20 CONSTANT VBE_DISPI_8BIT_DAC
+40 CONSTANT VBE_DISPI_LFB_ENABLED
+80 CONSTANT VBE_DISPI_NOCLEARMEM
+
+: init-mode
+ 0 3c0 vga-b!
+ VBE_DISPI_DISABLED VBE_DISPI_INDEX_ENABLE vbe!
+ 0 VBE_DISPI_INDEX_X_OFFSET vbe!
+ 0 VBE_DISPI_INDEX_Y_OFFSET vbe!
+ disp-width VBE_DISPI_INDEX_XRES vbe!
+ disp-height VBE_DISPI_INDEX_YRES vbe!
+ disp-depth VBE_DISPI_INDEX_BPP vbe!
+ VBE_DISPI_ENABLED VBE_DISPI_8BIT_DAC or VBE_DISPI_INDEX_ENABLE vbe!
+ 0 3c0 vga-b!
+ 20 3c0 vga-b!
+;
+
+: clear-screen
+ fb-base disp-width disp-height disp-depth 7 + 8 / * * 0 rfill
+;
+
+: read-settings
+ s" qemu,graphic-width" get-chosen IF
+ decode-int to disp-width 2drop
+ THEN
+ s" qemu,graphic-height" get-chosen IF
+ decode-int to disp-height 2drop
+ THEN
+ s" qemu,graphic-depth" get-chosen IF
+ decode-int nip nip
+ dup 8 =
+ over f = or
+ over 10 = or
+ over 20 = or IF
+ to disp-depth
+ ELSE
+ ." Unsupported bit depth, using 8bpp " drop cr
+ THEN
+ THEN
+;
+
+: setup-properties
+ \ Shouldn't this be done from open ?
+ disp-width encode-int s" width" property
+ disp-height encode-int s" height" property
+ disp-width disp-depth 7 + 8 / * encode-int s" linebytes" property
+ disp-depth encode-int s" depth" property
+ s" ISO8859-1" encode-string s" character-set" property \ i hope this is ok...
+ \ add "device_type" property
+ s" display" device-type
+ s" qemu,std-vga" encode-string s" compatible" property
+ \ XXX We don't create an "address" property because Linux doesn't know what
+ \ to do with it for >32-bit
+;
+
+\ words for installation/removal, needed by is-install/is-remove, see display.fs
+: display-remove ( -- )
+;
+
+: slow-blink-screen ( -- )
+ \ 32 msec delay for visually noticing the blink
+ invert-screen 20 ms invert-screen
+;
+
+: display-install ( -- )
+ is-installed? NOT IF
+ ." Installing QEMU fb" cr
+ fb-base to frame-buffer-adr
+ clear-screen
+ default-font
+ set-font
+ disp-width disp-height
+ disp-width char-width / disp-height char-height /
+ disp-depth 7 + 8 / ( width height #lines #cols depth )
+ fb-install
+ ['] slow-blink-screen to blink-screen
+ true to is-installed?
+ THEN
+;
+
+: set-alias
+ s" screen" find-alias 0= IF
+ \ no previous screen alias defined, define it...
+ s" screen" get-node node>path set-alias
+ ELSE
+ drop
+ THEN
+;
+
+pci-master-enable
+pci-mem-enable
+read-settings
+init-mode
+init-default-palette
+setup-properties
+' display-install is-install
+' display-remove is-remove
+set-alias
diff --git a/roms/SLOF/clients/net-snk/client.lds b/roms/SLOF/clients/net-snk/client.lds
index 39d04594e..c2086445b 100644
--- a/roms/SLOF/clients/net-snk/client.lds
+++ b/roms/SLOF/clients/net-snk/client.lds
@@ -44,10 +44,10 @@ SECTIONS {
*(.opd)
}
- . = ALIGN(0x10);
+ . = ALIGN(256);
.got :
{
- _got = .;
+ _got = DEFINED (.TOC.) ? .TOC. : ADDR (.got) + 0x8000;
*(.got)
*(.toc)
_got_end = .;
diff --git a/roms/SLOF/clients/net-snk/kernel/entry.S b/roms/SLOF/clients/net-snk/kernel/entry.S
index 8849fb9d1..bf10542bd 100644
--- a/roms/SLOF/clients/net-snk/kernel/entry.S
+++ b/roms/SLOF/clients/net-snk/kernel/entry.S
@@ -44,7 +44,7 @@ C_ENTRY(_entry)
bcl 20,31,over # branch after pointer table
base:
.align 3
-.LCgot: .quad _got-base+0x8000
+.LCgot: .quad _got-base
.LCstack: .quad _stack+STACKSIZE-0x80-base
over:
mflr r8 # gpr 8 is the base
diff --git a/roms/SLOF/clients/takeover/client.lds b/roms/SLOF/clients/takeover/client.lds
index 2701d8e1e..0ab428a01 100644
--- a/roms/SLOF/clients/takeover/client.lds
+++ b/roms/SLOF/clients/takeover/client.lds
@@ -43,8 +43,8 @@ SECTIONS {
.got :
{
- . = ALIGN(8);
- _got = .;
+ . = ALIGN(256);
+ _got = DEFINED (.TOC.) ? .TOC. : ADDR (.got) + 0x8000;
*(.got .toc)
_got_end = .;
}
diff --git a/roms/SLOF/clients/takeover/entry.S b/roms/SLOF/clients/takeover/entry.S
index a1030eb40..ff482732d 100644
--- a/roms/SLOF/clients/takeover/entry.S
+++ b/roms/SLOF/clients/takeover/entry.S
@@ -21,7 +21,7 @@ _wrapclient:
bcl 20,31,over # branch after pointer table
base:
.align 3
-.LCgot: .quad _got-base+0x8000
+.LCgot: .quad _got-base
over:
mflr r8 # gpr 8 is the base
ld r2, .LCgot-base(r8) # load got pointer
diff --git a/roms/SLOF/clients/takeover/main.c b/roms/SLOF/clients/takeover/main.c
index 360d8eaed..1e1b02614 100644
--- a/roms/SLOF/clients/takeover/main.c
+++ b/roms/SLOF/clients/takeover/main.c
@@ -16,7 +16,7 @@
#include <of.h>
#include <pci.h>
#include <cpu.h>
-#include <ioctl.h>
+#include <unistd.h>
#include <takeover.h>
extern void call_client_interface(of_arg_t *);
diff --git a/roms/SLOF/include/ppc970/cache.h b/roms/SLOF/include/ppc970/cache.h
index b74868986..500182ea6 100644
--- a/roms/SLOF/include/ppc970/cache.h
+++ b/roms/SLOF/include/ppc970/cache.h
@@ -55,8 +55,8 @@ cache_inhibited_access(uint64_t, 64)
#define _FASTMOVE(s, d, size) \
switch (((type_u)s | (type_u)d | size) & (sizeof(type_u)-1)) { \
case 0: _MOVE(s, d, size, type_u); break; \
- case sizeof(type_l): _MOVE(s, d, size, type_l); break; \
- case sizeof(type_w): _MOVE(s, d, size, type_w); break; \
+ case 4: _MOVE(s, d, size, type_l); break; \
+ case 2: case 6: _MOVE(s, d, size, type_w); break; \
default: _MOVE(s, d, size, type_c); break; \
}
@@ -78,9 +78,51 @@ cache_inhibited_access(uint64_t, 64)
#define _FASTRMOVE(s, d, size) \
switch (((type_u)s | (type_u)d | size) & (sizeof(type_u)-1)) { \
case 0: _RMOVE(s, d, size, type_u); break; \
- case sizeof(type_l): _RMOVE(s, d, size, type_l); break; \
- case sizeof(type_w): _RMOVE(s, d, size, type_w); break; \
+ case 4: _RMOVE(s, d, size, type_l); break; \
+ case 2: case 6: _RMOVE(s, d, size, type_w); break; \
default: _RMOVE(s, d, size, type_c); break; \
}
+/* main RAM to IO memory move */
+#define FAST_MRMOVE_TYPED(s, d, size, t) \
+{ \
+ t *s1 = (s), *d1 = (d); \
+ register t tmp; \
+ while (size > 0) { \
+ tmp = *s1++; SET_CI; *d1++ = tmp; CLR_CI; size -= sizeof(t); \
+ } \
+}
+
+#define FAST_MRMOVE(s, d, size) \
+ switch (((type_u)(s) | (type_u)(d) | (size)) & (sizeof(type_u)-1)) { \
+ case 0: FAST_MRMOVE_TYPED(s, d, size, type_u); break; \
+ case 4: FAST_MRMOVE_TYPED(s, d, size, type_l); break; \
+ case 2: case 6: FAST_MRMOVE_TYPED(s, d, size, type_w); break; \
+ default: FAST_MRMOVE_TYPED(s, d, size, type_c); break; \
+ }
+
+/* fill IO memory with pattern */
+#define FAST_RFILL_TYPED(dst, size, pat, t) \
+{ \
+ t *d1 = (dst); \
+ register t tmp = 0; \
+ int i = sizeof(t); \
+ while (i-- > 0) { \
+ tmp <<= 8; tmp |= pat & 0xff; \
+ } \
+ SET_CI; \
+ while (size > 0) { \
+ *d1++ = tmp; size -= sizeof(t); \
+ } \
+ CLR_CI; \
+}
+
+#define FAST_RFILL(dst, size, pat) \
+ switch (((type_u)dst | size) & (sizeof(type_u)-1)) { \
+ case 0: FAST_RFILL_TYPED(dst, size, pat, type_u); break; \
+ case 4: FAST_RFILL_TYPED(dst, size, pat, type_l); break; \
+ case 2: case 6: FAST_RFILL_TYPED(dst, size, pat, type_w); break; \
+ default: FAST_RFILL_TYPED(dst, size, pat, type_c); break; \
+ }
+
#endif
diff --git a/roms/SLOF/include/ppcp7/cache.h b/roms/SLOF/include/ppcp7/cache.h
index dc6837196..27975f09c 100644
--- a/roms/SLOF/include/ppcp7/cache.h
+++ b/roms/SLOF/include/ppcp7/cache.h
@@ -81,8 +81,8 @@ cache_inhibited_access(uint64_t, 64)
#define _FASTMOVE(s, d, size) \
switch (((type_u)s | (type_u)d | size) & (sizeof(type_u)-1)) { \
case 0: _MOVE(s, d, size, type_u); break; \
- case sizeof(type_l): _MOVE(s, d, size, type_l); break; \
- case sizeof(type_w): _MOVE(s, d, size, type_w); break; \
+ case 4: _MOVE(s, d, size, type_l); break; \
+ case 2: case 6: _MOVE(s, d, size, type_w); break; \
default: _MOVE(s, d, size, type_c); break; \
}
@@ -116,12 +116,26 @@ static inline void ci_rmove(void *dst, void *src, unsigned long esize,
#define _FASTRMOVE(s, d, size) do { \
switch (((type_u)s | (type_u)d | size) & (sizeof(type_u)-1)) {\
case 0: ci_rmove(d,s,3,size>>3); break; \
- case sizeof(type_l): ci_rmove(d,s,2,size>>2); break; \
- case sizeof(type_w): ci_rmove(d,s,1,size>>1); break; \
+ case 4: ci_rmove(d,s,2,size>>2); break; \
+ case 2: case 6: ci_rmove(d,s,1,size>>1); break; \
default: ci_rmove(d,s,0,size); break; \
} \
} while(0)
+#define FAST_MRMOVE(s, d, size) _FASTRMOVE(s, d, size)
+
+#define FAST_RFILL(dst, size, pat) do { \
+ type_u buf[64]; \
+ char *d = (char *)(dst); \
+ memset(buf, pat, size < sizeof(buf) ? size : sizeof(buf)); \
+ while (size > sizeof(buf)) { \
+ FAST_MRMOVE(buf, d, sizeof(buf)); \
+ d += sizeof(buf); \
+ size -= sizeof(buf); \
+ } \
+ FAST_MRMOVE(buf, d, size); \
+ } while(0)
+
static inline uint16_t bswap16_load(uint64_t addr)
{
unsigned int val;
diff --git a/roms/SLOF/lib/libusb/usb-hid.c b/roms/SLOF/lib/libusb/usb-hid.c
index f0cab8a69..ac6616aba 100644
--- a/roms/SLOF/lib/libusb/usb-hid.c
+++ b/roms/SLOF/lib/libusb/usb-hid.c
@@ -28,6 +28,10 @@
#define HID_REQ_SET_IDLE 0x0A
#define HID_REQ_SET_PROTOCOL 0x0B
+//key position for latin letters
+#define KEYP_LATIN_A 4
+#define KEYP_LATIN_Z 29
+
//#define KEY_DEBUG
/* HID SPEC - 7.2.6 Set_Protocol Request */
@@ -83,6 +87,8 @@ uint8_t set_leds;
const uint8_t *key_std = NULL;
const uint8_t *key_std_shift = NULL;
+uint8_t ctrl; /* modifiers */
+
/**
* read character from Keyboard-Buffer
*
@@ -111,6 +117,16 @@ static void write_key(uint8_t key)
}
/**
+ * Checks if keypos is a latin key
+ * @param keypos
+ * @return -
+ */
+static bool is_latin(uint8_t keypos)
+{
+ return keypos >= KEYP_LATIN_A && keypos <= KEYP_LATIN_Z;
+}
+
+/**
* Convert keyboard usage-ID to ANSI-Code
*
* @param Ctrl=Modifier Byte
@@ -120,22 +136,24 @@ static void write_key(uint8_t key)
static void get_char(uint8_t ctrl, uint8_t keypos)
{
uint8_t ch;
+ bool caps = false;
#ifdef KEY_DEBUG
printf("pos %02X\n", keypos);
#endif
if (set_leds & LED_CAPS_LOCK) /* is CAPS Lock set ? */
- ctrl |= MODIFIER_SHIFT; /* simulate shift */
+ caps = true;
- if (ctrl == 0) {
+ /* caps is a shift only for latin chars */
+ if ((!caps && ctrl == 0) || (caps && !is_latin(keypos))) {
ch = key_std[keypos];
if (ch != 0)
write_key(ch);
return;
}
- if (ctrl & MODIFIER_SHIFT) {
+ if ((ctrl & MODIFIER_SHIFT) || caps) {
ch = key_std_shift[keypos];
if (ch != 0)
write_key(ch);
@@ -187,36 +205,38 @@ static void check_key_code(uint8_t *buf)
set_leds ^= LED_CAPS_LOCK;
break;
+ case 0x36: /*Shift pressed*/
+ ctrl |= MODIFIER_SHIFT;
+ break;
+ case 0xb6: /*Shift unpressed*/
+ ctrl &= ~MODIFIER_SHIFT;
+ break;
case 0x3a: /* F1 */
write_key(0x1b);
write_key(0x5b);
- write_key(0x31);
- write_key(0x31);
- write_key(0x7e);
+ write_key(0x4f);
+ write_key(0x50);
break;
case 0x3b: /* F2 */
write_key(0x1b);
write_key(0x5b);
- write_key(0x31);
- write_key(0x32);
- write_key(0x7e);
+ write_key(0x4f);
+ write_key(0x51);
break;
case 0x3c:
write_key(0x1b); /* F3 */
write_key(0x5b);
- write_key(0x31);
- write_key(0x33);
- write_key(0x7e);
+ write_key(0x4f);
+ write_key(0x52);
break;
case 0x3d:
write_key(0x1b); /* F4 */
write_key(0x5b);
- write_key(0x31);
- write_key(0x34);
- write_key(0x7e);
+ write_key(0x4f);
+ write_key(0x53);
break;
case 0x3e:
@@ -254,7 +274,7 @@ static void check_key_code(uint8_t *buf)
case 0x42:
write_key(0x1b); /* F9 */
write_key(0x5b);
- write_key(0x31);
+ write_key(0x32);
write_key(0x30);
write_key(0x7e);
break;
@@ -262,7 +282,7 @@ static void check_key_code(uint8_t *buf)
case 0x43:
write_key(0x1b); /* F10 */
write_key(0x5b);
- write_key(0x31);
+ write_key(0x32);
write_key(0x31);
write_key(0x7e);
break;
@@ -270,7 +290,7 @@ static void check_key_code(uint8_t *buf)
case 0x44:
write_key(0x1b); /* F11 */
write_key(0x5b);
- write_key(0x31);
+ write_key(0x32);
write_key(0x33);
write_key(0x7e);
break;
@@ -278,7 +298,7 @@ static void check_key_code(uint8_t *buf)
case 0x45:
write_key(0x1b); /* F12 */
write_key(0x5b);
- write_key(0x31);
+ write_key(0x32);
write_key(0x34);
write_key(0x7e);
break;
@@ -290,36 +310,34 @@ static void check_key_code(uint8_t *buf)
case 0x49:
write_key(0x1b); /* INS */
write_key(0x5b);
- write_key(0x31);
+ write_key(0x32);
write_key(0x7e);
break;
case 0x4a:
write_key(0x1b); /* HOME */
- write_key(0x5b);
- write_key(0x32);
- write_key(0x7e);
+ write_key(0x4f);
+ write_key(0x48);
break;
case 0x4b:
write_key(0x1b); /* PgUp */
write_key(0x5b);
- write_key(0x33);
+ write_key(0x35);
write_key(0x7e);
break;
case 0x4c:
write_key(0x1b); /* DEL */
write_key(0x5b);
- write_key(0x34);
+ write_key(0x33);
write_key(0x7e);
break;
case 0x4d:
write_key(0x1b); /* END */
- write_key(0x5b);
- write_key(0x35);
- write_key(0x7e);
+ write_key(0x4f);
+ write_key(0x46);
break;
case 0x4e:
@@ -443,11 +461,8 @@ unsigned char usb_key_available(void *dev)
unsigned char usb_read_keyb(void *vdev)
{
- if (!vdev)
- return false;
-
- while (usb_poll_key(vdev)) {
- /* loop for all pending keys */
- }
- return read_key();
+ if (usb_key_available(vdev))
+ return read_key();
+ else
+ return 0;
}
diff --git a/roms/SLOF/lib/libusb/usb-xhci.c b/roms/SLOF/lib/libusb/usb-xhci.c
index 0c3d6e47f..7683c51d6 100644
--- a/roms/SLOF/lib/libusb/usb-xhci.c
+++ b/roms/SLOF/lib/libusb/usb-xhci.c
@@ -225,11 +225,11 @@ static void xhci_handle_cmd_completion(struct xhci_hcd *xhcd,
xhcd->slot_id = 0;
}
-static struct xhci_event_trb *xhci_poll_event(struct xhci_hcd *xhcd,
- uint32_t event_type)
+static uint64_t xhci_poll_event(struct xhci_hcd *xhcd,
+ uint32_t event_type)
{
struct xhci_event_trb *event;
- uint64_t val;
+ uint64_t val, retval = 0;
uint32_t flags, time;
int index;
@@ -244,7 +244,7 @@ static struct xhci_event_trb *xhci_poll_event(struct xhci_hcd *xhcd,
mb();
flags = le32_to_cpu(event->flags);
if (time < SLOF_GetTimer())
- return NULL;
+ return 0;
}
mb();
@@ -273,6 +273,7 @@ static struct xhci_event_trb *xhci_poll_event(struct xhci_hcd *xhcd,
break;
}
xhcd->ering.deq = (uint64_t) (event + 1);
+ retval = le64_to_cpu(event->addr);
event->addr = 0;
event->status = 0;
@@ -289,7 +290,11 @@ static struct xhci_event_trb *xhci_poll_event(struct xhci_hcd *xhcd,
dprintf("Update start %x deq %x index %d\n",
xhcd->ering.trbs_dma, val, index/sizeof(*event));
write_reg64(&xhcd->run_regs->irs[0].erdp, val);
- return event;
+
+ if (retval == 0)
+ return (uint64_t)event;
+ else
+ return retval;
}
static void xhci_send_cmd(struct xhci_hcd *xhcd, uint32_t field1,
@@ -388,10 +393,12 @@ static void xhci_init_seg(struct xhci_seg *seg, uint32_t size, uint32_t type)
seg->deq = (uint64_t)seg->trbs;
memset((void *)seg->trbs, 0, size);
- link =(struct xhci_link_trb *) (seg->trbs + seg->size - 1);
- link->addr = cpu_to_le64(seg->trbs_dma);
- link->field2 = 0;
- link->field3 = cpu_to_le32(0x1 | TRB_CMD_TYPE(TRB_LINK));
+ if (type != TYPE_EVENT) {
+ link =(struct xhci_link_trb *) (seg->trbs + seg->size - 1);
+ link->addr = cpu_to_le64(seg->trbs_dma);
+ link->field2 = 0;
+ link->field3 = cpu_to_le32(0x1 | TRB_CMD_TYPE(TRB_LINK));
+ }
return;
}
@@ -616,6 +623,7 @@ static void xhci_free_dev(struct xhci_dev *xdev)
{
xhci_free_seg(&xdev->bulk_in, XHCI_DATA_TRBS_SIZE);
xhci_free_seg(&xdev->bulk_out, XHCI_DATA_TRBS_SIZE);
+ xhci_free_seg(&xdev->intr, XHCI_INTR_TRBS_SIZE);
xhci_free_seg(&xdev->control, XHCI_CONTROL_TRBS_SIZE);
xhci_free_ctx(&xdev->in_ctx, XHCI_CTX_BUF_SIZE);
xhci_free_ctx(&xdev->out_ctx, XHCI_CTX_BUF_SIZE);
@@ -637,7 +645,25 @@ static bool usb3_dev_init(struct xhci_hcd *xhcd, uint32_t port)
return true;
}
-static int xhci_hub_check_ports(struct xhci_hcd *xhcd)
+static int xhci_device_present(uint32_t portsc, uint32_t usb_ver)
+{
+ if (usb_ver == USB_XHCI) {
+ /* Device present and enabled state */
+ if ((portsc & PORTSC_CCS) &&
+ (portsc & PORTSC_PP) &&
+ (portsc & PORTSC_PED)) {
+ return true;
+ }
+ } else if (usb_ver == USB_EHCI) {
+ /* Device present and in disabled state */
+ if ((portsc & PORTSC_CCS) && (portsc & PORTSC_CSC))
+ return true;
+ }
+ return false;
+}
+
+static int xhci_port_scan(struct xhci_hcd *xhcd,
+ uint32_t usb_ver)
{
uint32_t num_ports, portsc, i;
struct xhci_op_regs *op;
@@ -645,7 +671,7 @@ static int xhci_hub_check_ports(struct xhci_hcd *xhcd)
struct xhci_cap_regs *cap;
uint32_t xecp_off;
uint32_t *xecp_addr, *base;
- uint32_t port_off = 1, port_cnt;
+ uint32_t port_off = 0, port_cnt;
dprintf("enter\n");
@@ -658,14 +684,14 @@ static int xhci_hub_check_ports(struct xhci_hcd *xhcd)
base = (uint32_t *)cap;
while (xecp_off > 0) {
xecp_addr = base + xecp_off;
- dprintf(stderr, "xecp_off %d %p %p \n", xecp_off, base, xecp_addr);
+ dprintf("xecp_off %d %p %p \n", xecp_off, base, xecp_addr);
if (XHCI_XECP_CAP_ID(read_reg32(xecp_addr)) == XHCI_XECP_CAP_SP &&
- XHCI_XECP_CAP_SP_MJ(read_reg32(xecp_addr)) == 3 &&
+ XHCI_XECP_CAP_SP_MJ(read_reg32(xecp_addr)) == usb_ver &&
XHCI_XECP_CAP_SP_MN(read_reg32(xecp_addr)) == 0) {
port_cnt = XHCI_XECP_CAP_SP_PC(read_reg32(xecp_addr + 2));
port_off = XHCI_XECP_CAP_SP_PO(read_reg32(xecp_addr + 2));
- dprintf(stderr, "PortCount %d Portoffset %d\n", port_cnt, port_off);
+ dprintf("PortCount %d Portoffset %d\n", port_cnt, port_off);
}
base = xecp_addr;
xecp_off = XHCI_XECP_NEXT_PTR(read_reg32(xecp_addr));
@@ -675,10 +701,8 @@ static int xhci_hub_check_ports(struct xhci_hcd *xhcd)
for (i = (port_off - 1); i < (port_off + port_cnt - 1); i++) {
prs = &op->prs[i];
portsc = read_reg32(&prs->portsc);
- if ((portsc & PORTSC_CCS) &&
- (portsc & PORTSC_PP) &&
- (portsc & PORTSC_PED)) {
- /* Device present and enabled */
+ if (xhci_device_present(portsc, usb_ver)) {
+ /* Device present */
dprintf("Device present on port %d\n", i);
/* Reset the port */
portsc = read_reg32(&prs->portsc);
@@ -701,6 +725,11 @@ static int xhci_hub_check_ports(struct xhci_hcd *xhcd)
return true;
}
+static int xhci_hub_check_ports(struct xhci_hcd *xhcd)
+{
+ return xhci_port_scan(xhcd, USB_XHCI) | xhci_port_scan(xhcd, USB_EHCI);
+}
+
static bool xhci_hcd_init(struct xhci_hcd *xhcd)
{
struct xhci_op_regs *op;
@@ -868,6 +897,18 @@ static bool xhci_hcd_exit(struct xhci_hcd *xhcd)
SLOF_dma_map_out(xhcd->dcbaap_dma, (void *)xhcd->dcbaap, XHCI_DCBAAP_MAX_SIZE);
SLOF_dma_free((void *)xhcd->dcbaap, XHCI_DCBAAP_MAX_SIZE);
}
+
+ /*
+ * QEMU implementation of XHCI doesn't implement halt
+ * properly. It basically says that it's halted immediately
+ * but doesn't actually terminate ongoing activities and
+ * DMAs. This needs to be fixed in QEMU.
+ *
+ * For now, wait for 50ms grace time till qemu stops using
+ * this device.
+ */
+ SLOF_msleep(50);
+
return true;
}
@@ -1079,18 +1120,17 @@ static inline struct xhci_seg *xhci_pipe_get_seg(struct usb_pipe *pipe)
static inline void *xhci_get_trb(struct xhci_seg *seg)
{
uint64_t val, enq;
- uint32_t size;
+ int index;
struct xhci_link_trb *link;
enq = val = seg->enq;
val = val + XHCI_TRB_SIZE;
- size = seg->size * XHCI_TRB_SIZE;
- /* TRBs being a cyclic buffer, here we cycle back to beginning. */
- if ((val % size) == 0) {
+ index = (enq - (uint64_t)seg->trbs) / XHCI_TRB_SIZE + 1;
+ dprintf("%s: enq %llx, val %llx %x\n", __func__, enq, val, index);
+ /* TRBs being a cyclic buffer, here we cycle back to beginning. */
+ if (index == (seg->size - 1)) {
+ dprintf("%s: rounding \n", __func__);
seg->enq = (uint64_t)seg->trbs;
- enq = seg->enq;
- seg->enq = seg->enq + XHCI_TRB_SIZE;
- val = 0;
seg->cycle_state ^= seg->cycle_state;
link = (struct xhci_link_trb *) (seg->trbs + seg->size - 1);
link->addr = cpu_to_le64(seg->trbs_dma);
@@ -1105,6 +1145,12 @@ static inline void *xhci_get_trb(struct xhci_seg *seg)
return (void *)enq;
}
+static uint64_t xhci_get_trb_phys(struct xhci_seg *seg, uint64_t trb)
+{
+ return seg->trbs_dma + (trb - (uint64_t)seg->trbs);
+}
+
+static int usb_kb = false;
static int xhci_transfer_bulk(struct usb_pipe *pipe, void *td, void *td_phys,
void *data, int datalen)
{
@@ -1114,7 +1160,8 @@ static int xhci_transfer_bulk(struct usb_pipe *pipe, void *td, void *td_phys,
struct xhci_transfer_trb *trb;
struct xhci_db_regs *dbr;
int ret = true;
- uint32_t slot_id, epno;
+ uint32_t slot_id, epno, time;
+ uint64_t trb_phys, event_phys;
if (!pipe->dev || !pipe->dev->hcidev) {
dprintf(" NULL pointer\n");
@@ -1139,13 +1186,26 @@ static int xhci_transfer_bulk(struct usb_pipe *pipe, void *td, void *td_phys,
}
trb = xhci_get_trb(seg);
+ trb_phys = xhci_get_trb_phys(seg, (uint64_t)trb);
fill_normal_trb(trb, (void *)data, datalen);
epno = xhci_get_epno(pipe);
write_reg32(&dbr->db[slot_id], epno);
- if (!xhci_poll_event(xhcd, 0)) {
- dprintf("Bulk failed\n");
- ret = false;
+
+ time = SLOF_GetTimer() + USB_TIMEOUT;
+ while (1) {
+ event_phys = xhci_poll_event(xhcd, 0);
+ if (event_phys == trb_phys) {
+ break;
+ } else if (event_phys == 0) { /* polling timed out */
+ ret = false;
+ break;
+ } else
+ usb_kb = true;
+
+ /* transfer timed out */
+ if (time < SLOF_GetTimer())
+ return false;
}
trb->addr = 0;
trb->len = 0;
@@ -1214,7 +1274,8 @@ static void xhci_init_bulk_ep(struct usb_dev *dev, struct usb_pipe *pipe)
if (!seg->trbs) {
if (!xhci_alloc_seg(seg, XHCI_DATA_TRBS_SIZE, TYPE_BULK)) {
- dprintf("Failed allocating seg\n");
+ printf("usb-xhci: allocation failed for bulk endpoint\n");
+ return;
}
} else {
xhci_init_seg(seg, XHCI_DATA_TRBS_SIZE, TYPE_BULK);
@@ -1235,6 +1296,61 @@ static void xhci_init_bulk_ep(struct usb_dev *dev, struct usb_pipe *pipe)
xpipe->seg = seg;
}
+static int xhci_get_pipe_intr(struct usb_pipe *pipe,
+ struct xhci_hcd *xhcd,
+ char *buf, size_t len)
+{
+ struct xhci_dev *xdev;
+ struct xhci_seg *seg;
+ struct xhci_pipe *xpipe;
+ struct xhci_control_ctx *ctrl;
+ struct xhci_ep_ctx *ep;
+ uint32_t x_epno, val, type;
+ struct usb_dev *dev;
+ struct xhci_transfer_trb *trb;
+
+ dev = pipe->dev;
+ if (dev->class != DEV_HID_KEYB)
+ return false;
+
+ xdev = dev->priv;
+ pipe->mps = 8;
+ seg = xhci_pipe_get_seg(pipe);
+ xpipe = xhci_pipe_get_xpipe(pipe);
+ type = EP_INT_IN;
+ seg = &xdev->intr;
+
+ if (!seg->trbs) {
+ if (!xhci_alloc_seg(seg, XHCI_INTR_TRBS_SIZE, TYPE_BULK)) {
+ printf("usb-xhci: allocation failed for interrupt endpoint\n");
+ return false;
+ }
+ } else {
+ xhci_init_seg(seg, XHCI_EVENT_TRBS_SIZE, TYPE_BULK);
+ }
+
+ xpipe->buf = buf;
+ xpipe->buf_phys = SLOF_dma_map_in(buf, len, false);
+ xpipe->buflen = len;
+
+ ctrl = xhci_get_control_ctx(&xdev->in_ctx);
+ x_epno = xhci_get_epno(pipe);
+ ep = xhci_get_ep_ctx(&xdev->in_ctx, xdev->ctx_size, x_epno);
+ val = EP_TYPE(type) | MAX_BURST(0) | ERROR_COUNT(3) |
+ MAX_PACKET_SIZE(pipe->mps);
+ ep->field2 = cpu_to_le32(val);
+ ep->deq_addr = cpu_to_le64(seg->trbs_dma | seg->cycle_state);
+ ep->field4 = cpu_to_le32(8);
+ ctrl->a_flags = cpu_to_le32(BIT(x_epno) | 0x1);
+ ctrl->d_flags = 0;
+ xhci_configure_ep(xhcd, xdev->slot_id, xdev->in_ctx.dma_addr);
+ xpipe->seg = seg;
+
+ trb = xhci_get_trb(seg);
+ fill_normal_trb(trb, (void *)xpipe->buf_phys, pipe->mps);
+ return true;
+}
+
static struct usb_pipe* xhci_get_pipe(struct usb_dev *dev, struct usb_ep_descr *ep, char *buf, size_t len)
{
struct xhci_hcd *xhcd;
@@ -1264,6 +1380,12 @@ static struct usb_pipe* xhci_get_pipe(struct usb_dev *dev, struct usb_ep_descr *
new->dir = (ep->bEndpointAddress & 0x80) >> 7;
new->epno = ep->bEndpointAddress & 0x0f;
+ if (new->type == USB_EP_TYPE_INTR) {
+ if (!xhci_get_pipe_intr(new, xhcd, buf, len)) {
+ printf("usb-xhci: %s alloc_intr failed %p\n",
+ __func__, new);
+ }
+ }
if (new->type == USB_EP_TYPE_BULK)
xhci_init_bulk_ep(dev, new);
@@ -1284,6 +1406,10 @@ static void xhci_put_pipe(struct usb_pipe *pipe)
if (pipe->type == USB_EP_TYPE_BULK) {
xpipe = xhci_pipe_get_xpipe(pipe);
xpipe->seg = NULL;
+ } else if (pipe->type == USB_EP_TYPE_INTR) {
+ xpipe = xhci_pipe_get_xpipe(pipe);
+ SLOF_dma_map_out(xpipe->buf_phys, xpipe->buf, xpipe->buflen);
+ xpipe->seg = NULL;
}
if (xhcd->end)
xhcd->end->next = pipe;
@@ -1298,6 +1424,51 @@ static void xhci_put_pipe(struct usb_pipe *pipe)
dprintf("usb-xhci: %s exit\n", __func__);
}
+static int xhci_poll_intr(struct usb_pipe *pipe, uint8_t *data)
+{
+ struct xhci_transfer_trb *trb;
+ struct xhci_seg *seg;
+ struct xhci_pipe *xpipe;
+ struct xhci_dev *xdev;
+ struct xhci_hcd *xhcd;
+ struct xhci_db_regs *dbr;
+ uint32_t x_epno;
+ uint8_t *buf, ret = 1;
+
+ if (!pipe || !pipe->dev || !pipe->dev->hcidev)
+ return 0;
+ xdev = pipe->dev->priv;
+ xhcd = (struct xhci_hcd *)pipe->dev->hcidev->priv;
+ x_epno = xhci_get_epno(pipe);
+ seg = xhci_pipe_get_seg(pipe);
+ xpipe = xhci_pipe_get_xpipe(pipe);
+
+ if (usb_kb == true) {
+ /* This event was consumed by bulk transfer */
+ usb_kb = false;
+ goto skip_poll;
+ }
+ buf = xpipe->buf;
+ memset(buf, 0, 8);
+
+ mb();
+ /* Ring the doorbell - x_epno */
+ dbr = xhcd->db_regs;
+ write_reg32(&dbr->db[xdev->slot_id], x_epno);
+ if (!xhci_poll_event(xhcd, 0)) {
+ printf("poll intr failed\n");
+ return 0;
+ }
+ mb();
+ memcpy(data, buf, 8);
+
+skip_poll:
+ trb = xhci_get_trb(seg);
+ fill_normal_trb(trb, (void *)xpipe->buf_phys, pipe->mps);
+ mb();
+ return ret;
+}
+
struct usb_hcd_ops xhci_ops = {
.name = "xhci-hcd",
.init = xhci_init,
@@ -1305,6 +1476,7 @@ struct usb_hcd_ops xhci_ops = {
.usb_type = USB_XHCI,
.get_pipe = xhci_get_pipe,
.put_pipe = xhci_put_pipe,
+ .poll_intr = xhci_poll_intr,
.send_ctrl = xhci_send_ctrl,
.transfer_bulk = xhci_transfer_bulk,
.next = NULL,
diff --git a/roms/SLOF/lib/libusb/usb-xhci.h b/roms/SLOF/lib/libusb/usb-xhci.h
index faeb07ead..3fc7e7889 100644
--- a/roms/SLOF/lib/libusb/usb-xhci.h
+++ b/roms/SLOF/lib/libusb/usb-xhci.h
@@ -266,6 +266,7 @@ struct xhci_seg {
#define XHCI_EVENT_TRBS_SIZE 4096
#define XHCI_CONTROL_TRBS_SIZE 4096
#define XHCI_DATA_TRBS_SIZE 4096
+#define XHCI_INTR_TRBS_SIZE 4096
#define XHCI_ERST_NUM_SEGS 1
#define XHCI_MAX_BULK_SIZE 0xF000
@@ -349,6 +350,7 @@ struct xhci_dev {
struct xhci_ctx in_ctx;
struct xhci_ctx out_ctx;
struct xhci_seg control;
+ struct xhci_seg intr;
struct xhci_seg bulk_in;
struct xhci_seg bulk_out;
uint32_t ctx_size;
@@ -381,6 +383,9 @@ struct xhci_hcd {
struct xhci_pipe {
struct usb_pipe pipe;
struct xhci_seg *seg;
+ void *buf;
+ long buf_phys;
+ uint32_t buflen;
};
#endif /* USB_XHCI_H */
diff --git a/roms/SLOF/make.rules b/roms/SLOF/make.rules
index aebc4e360..cbc63530a 100644
--- a/roms/SLOF/make.rules
+++ b/roms/SLOF/make.rules
@@ -19,8 +19,12 @@
ARCH := $(shell uname -p)
# Auto-detect ppc64
-ifeq ($(ARCH), ppc64)
-CROSS = ""
+ifeq (ppc64,$(findstring ppc64,$(ARCH)))
+ ifeq ($(ARCH), ppc64le)
+ EXTRA_CC = -mbig -mabi=elfv1
+ EXTRA_LD = -mbig
+ endif
+CROSS ?=
else
CROSS ?= powerpc64-linux-
endif
@@ -31,8 +35,8 @@ HOSTCC ?= gcc
HOSTCFLAGS = -g -Wall -W -O2 -I. -I../include
DD = dd
-ONLY_CC = $(CROSS)gcc -m$(CELLSIZE)
-ONLY_AS = $(CROSS)as -m$(CELLSIZE)
+ONLY_CC = $(CROSS)gcc -m$(CELLSIZE) $(EXTRA_CC)
+ONLY_AS = $(CROSS)as -m$(CELLSIZE) $(EXTRA_LD)
ONLY_LD = $(CROSS)ld -melf$(CELLSIZE)ppc
# Verbose level:
diff --git a/roms/SLOF/rtas/reloc.S b/roms/SLOF/rtas/reloc.S
index e24d293d4..1b5b59a68 100644
--- a/roms/SLOF/rtas/reloc.S
+++ b/roms/SLOF/rtas/reloc.S
@@ -61,7 +61,7 @@ _rtas_start:
._rtas_entry_offset: .quad rtas_entry-_rtas_start
._rtas_config_offset: .quad rtas_config-_rtas_start
._rtas_stack: .quad .stack-_rtas_start+RTAS_STACKSIZE-0x60
-._rtas_toc: .quad _got-_rtas_start+0x8000
+._rtas_toc: .quad _got-_rtas_start
.over:
mflr r8 # gpr 8 is the base
diff --git a/roms/SLOF/rtas/rtas.lds b/roms/SLOF/rtas/rtas.lds
index a5ba1daaf..30b18dd26 100644
--- a/roms/SLOF/rtas/rtas.lds
+++ b/roms/SLOF/rtas/rtas.lds
@@ -28,7 +28,8 @@ SECTIONS {
}
.got :
{
- _got = .;
+ . = ALIGN(256);
+ _got = DEFINED (.TOC.) ? .TOC. : ADDR (.got) + 0x8000;
*(.got .toc)
}
.reloc :
diff --git a/roms/SLOF/rtas/rtas_entry.S b/roms/SLOF/rtas/rtas_entry.S
index 74693aa48..424137bf5 100644
--- a/roms/SLOF/rtas/rtas_entry.S
+++ b/roms/SLOF/rtas/rtas_entry.S
@@ -39,7 +39,7 @@ rtas_entry:
bcl 20,31,.over # branch to over
.base:
.align 3
-..got: .quad _got-.base+0x8000
+..got: .quad _got-.base
..stack: .quad .stack+RTAS_STACKSIZE-0x60-.base
.over:
mflr r8 # gpr 8 is the base
diff --git a/roms/SLOF/slof/entry.S b/roms/SLOF/slof/entry.S
index dcff57ba0..d3d29f852 100644
--- a/roms/SLOF/slof/entry.S
+++ b/roms/SLOF/slof/entry.S
@@ -207,4 +207,13 @@ call_client:
li 3, -1 # client app return
blr
+
+ # Call another function via pointer in r6
+ # (arguments can be provided in r3 to r5)
+ # Destination function should jump back to lr
+C_ENTRY(call_c)
+ mtctr r6
+ bctr
+
+
.lcomm the_system_stack, STACKSIZE, 16
diff --git a/roms/SLOF/slof/fs/archsupport.fs b/roms/SLOF/slof/fs/archsupport.fs
index cc4668769..f564ab4e0 100644
--- a/roms/SLOF/slof/fs/archsupport.fs
+++ b/roms/SLOF/slof/fs/archsupport.fs
@@ -10,9 +10,9 @@
\ * IBM Corporation - initial implementation
\ ****************************************************************************/
-\ Qemu supports max 256cpus, 32K will be able to accomodate the fdt changes if
-\ needed.
-8000 VALUE size
+\ 128KB FDT buffer size is enough to accommodate 255 CPU cores and 1TB of
+\ maxmem specification.
+20000 VALUE size
: ibm,client-architecture-support ( vec -- err? )
\ Store require parameters in nvram
\ to come back to right boot device
diff --git a/roms/SLOF/slof/fs/base.fs b/roms/SLOF/slof/fs/base.fs
index e71e087eb..03e77e54f 100644
--- a/roms/SLOF/slof/fs/base.fs
+++ b/roms/SLOF/slof/fs/base.fs
@@ -579,8 +579,6 @@ defer cursor-off ( -- )
#include "debug.fs"
\ provide 7.5.3.1 Dictionary search
#include "dictionary.fs"
-\ block data access for IO devices - ought to be implemented in engine
-#include "rmove.fs"
\ provide a simple run time preprocessor
#include <preprocessor.fs>
diff --git a/roms/SLOF/slof/fs/boot.fs b/roms/SLOF/slof/fs/boot.fs
index 9a0ded0c2..a0fe29a1b 100644
--- a/roms/SLOF/slof/fs/boot.fs
+++ b/roms/SLOF/slof/fs/boot.fs
@@ -187,11 +187,6 @@ defer go ( -- )
dup to my-self
dup ihandle>phandle set-node
-rot ( ihandle devstr len )
- my-args nip 0= IF
- 2dup 1- + c@ [char] : <> IF \ Add : to device path if missing
- 1+ strdup 2dup 1- + [char] : swap c!
- THEN
- THEN
encode-string s" bootpath" set-chosen
$bootargs encode-string s" bootargs" set-chosen
get-load-base s" load" 3 pick ['] $call-method CATCH IF
@@ -211,7 +206,7 @@ defer go ( -- )
: parse-load ( "{devlist}" -- success ) \ Parse-execute boot-device list
cr BEGIN parse-word dup WHILE
- ( de-alias ) do-load dup 0< IF drop 0 THEN IF
+ de-alias do-load dup 0< IF drop 0 THEN IF
state-valid @ IF ." Successfully loaded" cr THEN
true 0d parse strdup load-list 2! EXIT
THEN
diff --git a/roms/SLOF/slof/fs/client.fs b/roms/SLOF/slof/fs/client.fs
index 1b2bb0326..7d537a668 100644
--- a/roms/SLOF/slof/fs/client.fs
+++ b/roms/SLOF/slof/fs/client.fs
@@ -282,6 +282,18 @@ ALSO client-voc DEFINITIONS
;
\
+\ Standard for Boot, defined in 6.3.2.5:
+\
+: boot ( zstr -- )
+ zcount
+ debug-client-interface? IF
+ ." ci: boot " 2dup type cr
+ THEN
+ " boot " 2swap $cat " boot-command" $setenv (nvupdate)
+ reset-all
+;
+
+\
\ User Interface, defined in 6.3.2.6
\
: interpret ( ... zstr -- result ... )
diff --git a/roms/SLOF/slof/fs/fbuffer.fs b/roms/SLOF/slof/fs/fbuffer.fs
index 756f05a95..47046087d 100644
--- a/roms/SLOF/slof/fs/fbuffer.fs
+++ b/roms/SLOF/slof/fs/fbuffer.fs
@@ -19,6 +19,7 @@
0 VALUE screen-height
0 VALUE screen-width
0 VALUE screen-depth
+0 VALUE screen-line-bytes
0 VALUE window-top
0 VALUE window-left
@@ -54,10 +55,10 @@
: fb8-background inverse? ;
: fb8-foreground inverse? invert ;
-: fb8-lines2bytes ( #lines -- #bytes ) char-height * screen-width * screen-depth * ;
+: fb8-lines2bytes ( #lines -- #bytes ) char-height * screen-line-bytes * ;
: fb8-columns2bytes ( #columns -- #bytes ) char-width * screen-depth * ;
: fb8-line2addr ( line# -- addr )
- char-height * window-top + screen-width * screen-depth *
+ char-height * window-top + screen-line-bytes *
frame-buffer-adr + window-left screen-depth * +
;
@@ -98,9 +99,10 @@ CREATE bitmap-buffer 400 4 * allot
: fb8-toggle-cursor ( -- )
line# fb8-line2addr column# fb8-columns2bytes +
- char-height 0 ?DO
- char-width screen-depth * 0 ?DO dup dup rb@ -1 xor swap rb! 1+ LOOP
- screen-width screen-depth * + char-width screen-depth * -
+ char-height 2 - screen-line-bytes * +
+ 2 0 ?DO
+ dup char-width screen-depth * invert-region
+ screen-line-bytes +
LOOP drop
;
@@ -110,7 +112,7 @@ CREATE bitmap-buffer 400 4 * allot
line# fb8-line2addr column# fb8-columns2bytes + ( bitmap-buf fb-addr )
char-height 0 ?DO
2dup char-width screen-depth * mrmove
- screen-width screen-depth * + >r char-width screen-depth * + r>
+ screen-line-bytes + >r char-width screen-depth * + r>
LOOP 2drop
ELSE 2drop r> 3drop THEN
;
@@ -135,12 +137,12 @@ CREATE bitmap-buffer 400 4 * allot
fb8-columns2bytes swap fb8-columns2bytes tuck -
over r@ tuck + rot char-height 0 ?DO
3dup rmove
- -rot screen-width screen-depth * tuck + -rot + swap rot
+ -rot screen-line-bytes tuck + -rot + swap rot
LOOP
3drop r>
THEN
char-height 0 ?DO
- dup 2 pick fb8-erase-block screen-width screen-depth * +
+ dup 2 pick fb8-erase-block screen-line-bytes +
LOOP
2drop
;
@@ -153,12 +155,12 @@ CREATE bitmap-buffer 400 4 * allot
fb8-columns2bytes swap fb8-columns2bytes tuck -
over r@ + 2dup + r> swap >r rot char-height 0 ?DO
3dup rmove
- -rot screen-width screen-depth * tuck + -rot + swap rot
+ -rot screen-line-bytes tuck + -rot + swap rot
LOOP
3drop r> over -
THEN
char-height 0 ?DO
- dup 2 pick fb8-erase-block screen-width screen-depth * +
+ dup 2 pick fb8-erase-block screen-line-bytes +
LOOP
2drop
;
@@ -166,13 +168,11 @@ CREATE bitmap-buffer 400 4 * allot
: fb8-reset-screen ( -- ) ( Left as no-op by design ) ;
: fb8-erase-screen ( -- )
- frame-buffer-adr screen-height screen-width * screen-depth * fb8-erase-block
+ frame-buffer-adr screen-height screen-line-bytes * fb8-erase-block
;
: fb8-invert-screen ( -- )
- frame-buffer-adr screen-height screen-width * screen-depth * 2dup /x / 0 ?DO
- dup rx@ -1 xor over rx! xa1+
- LOOP 3drop
+ frame-buffer-adr screen-height screen-line-bytes * invert-region
;
: fb8-blink-screen ( -- ) fb8-invert-screen fb8-invert-screen ;
@@ -180,6 +180,7 @@ CREATE bitmap-buffer 400 4 * allot
: fb8-install ( width height #columns #lines -- )
1 to screen-depth
2swap to screen-height to screen-width
+ screen-width to screen-line-bytes
screen-#rows min to #lines
screen-#columns min to #columns
screen-height char-height #lines * - 2/ to window-top
@@ -201,6 +202,7 @@ CREATE bitmap-buffer 400 4 * allot
>r
fb8-install
r> to screen-depth
+ screen-width screen-depth * to screen-line-bytes
;
diff --git a/roms/SLOF/slof/fs/little-endian.fs b/roms/SLOF/slof/fs/little-endian.fs
index f2e4e8d42..6b4779ee0 100644
--- a/roms/SLOF/slof/fs/little-endian.fs
+++ b/roms/SLOF/slof/fs/little-endian.fs
@@ -17,6 +17,9 @@ here c@ ef = CONSTANT ?littleendian
?bigendian [IF]
+: x!-le >r xbflip r> x! ;
+: x@-le x@ xbflip ;
+
: l!-le >r lbflip r> l! ;
: l@-le l@ lbflip ;
@@ -47,6 +50,9 @@ here c@ ef = CONSTANT ?littleendian
[ELSE]
+: x!-le x! ;
+: x@-le x@ ;
+
: l!-le l! ;
: l@-le l@ ;
diff --git a/roms/SLOF/slof/fs/packages/disk-label.fs b/roms/SLOF/slof/fs/packages/disk-label.fs
index fe1c25e7a..e034d6408 100644
--- a/roms/SLOF/slof/fs/packages/disk-label.fs
+++ b/roms/SLOF/slof/fs/packages/disk-label.fs
@@ -20,6 +20,7 @@ false VALUE debug-disk-label?
\ If we ever want to put a large kernel with initramfs from a PREP partition
\ we might need to increase this value. The default value is 65536 blocks (32MB)
d# 65536 value max-prep-partition-blocks
+d# 4096 CONSTANT block-array-size
s" disk-label" device-name
@@ -152,8 +153,8 @@ CONSTANT /gpt-part-entry
: init-block ( -- )
s" block-size" ['] $call-parent CATCH IF ABORT" parent has no block-size." THEN
to block-size
- d# 4096 alloc-mem
- dup d# 4096 erase
+ block-array-size alloc-mem
+ dup block-array-size erase
to block
debug-disk-label? IF
." init-block: block-size=" block-size .d ." block=0x" block u. cr
@@ -178,7 +179,8 @@ CONSTANT /gpt-part-entry
\ This word returns true if the currently loaded block has _NO_ GPT partition id
: no-gpt? ( -- true|false )
0 read-sector
- 1 partition>part-entry part-entry>id c@ ee <>
+ 1 partition>part-entry part-entry>id c@ ee <> IF true EXIT THEN
+ block mbr>magic w@-le aa55 <>
;
: pc-extended-partition? ( part-entry-addr -- true|false )
@@ -266,7 +268,10 @@ CONSTANT /gpt-part-entry
: try-dos-partition ( -- okay? )
\ Read partition table and check magic.
- no-mbr? IF cr ." No DOS disk-label found." cr false EXIT THEN
+ no-mbr? IF
+ debug-disk-label? IF cr ." No DOS disk-label found." cr THEN
+ false EXIT
+ THEN
count-dos-logical-partitions TO dos-logical-partitions
@@ -320,6 +325,14 @@ CONSTANT /gpt-part-entry
\ Load from first active DOS boot partition.
+: fat-bootblock? ( addr -- flag )
+ \ byte 0-2 of the bootblock is a jump instruction in
+ \ all FAT filesystems.
+ \ e9 and eb are jump instructions in x86 assembler.
+ dup c@ e9 = IF drop true EXIT THEN
+ dup c@ eb = swap 2+ c@ 90 = and
+;
+
\ NOTE: block-size is always 512 bytes for DOS partition tables.
: load-from-dos-boot-partition ( addr -- size )
@@ -352,60 +365,103 @@ CONSTANT /gpt-part-entry
drop 0
;
-\ Check for GPT PReP partition GUID
-9E1A2D38 CONSTANT GPT-PREP-PARTITION-1
-C612 CONSTANT GPT-PREP-PARTITION-2
-4316 CONSTANT GPT-PREP-PARTITION-3
-AA26 CONSTANT GPT-PREP-PARTITION-4
-8B49521E5A8B CONSTANT GPT-PREP-PARTITION-5
+\ Check for GPT PReP partition GUID. Only first 3 blocks are
+\ byte-swapped treating last two blocks as contigous for simplifying
+\ comparison
+9E1A2D38 CONSTANT GPT-PREP-PARTITION-1
+C612 CONSTANT GPT-PREP-PARTITION-2
+4316 CONSTANT GPT-PREP-PARTITION-3
+AA268B49521E5A8B CONSTANT GPT-PREP-PARTITION-4
: gpt-prep-partition? ( -- true|false )
- block gpt-part-entry>part-type-guid l@-le GPT-PREP-PARTITION-1 = IF
- block gpt-part-entry>part-type-guid 4 + w@-le
- GPT-PREP-PARTITION-2 = IF
- block gpt-part-entry>part-type-guid 6 + w@-le
- GPT-PREP-PARTITION-3 = IF
- block gpt-part-entry>part-type-guid 8 + w@
- GPT-PREP-PARTITION-4 = IF
- block gpt-part-entry>part-type-guid a + w@
- block gpt-part-entry>part-type-guid c + l@ swap lxjoin
- GPT-PREP-PARTITION-5 = IF
- TRUE EXIT
- THEN
- THEN
- THEN
- THEN
+ block gpt-part-entry>part-type-guid
+ dup l@-le GPT-PREP-PARTITION-1 <> IF drop false EXIT THEN
+ dup 4 + w@-le GPT-PREP-PARTITION-2 <> IF drop false EXIT THEN
+ dup 6 + w@-le GPT-PREP-PARTITION-3 <> IF drop false EXIT THEN
+ 8 + x@ GPT-PREP-PARTITION-4 =
+;
+
+\ Check for GPT MSFT BASIC DATA GUID - fat based
+EBD0A0A2 CONSTANT GPT-BASIC-DATA-PARTITION-1
+B9E5 CONSTANT GPT-BASIC-DATA-PARTITION-2
+4433 CONSTANT GPT-BASIC-DATA-PARTITION-3
+87C068B6B72699C7 CONSTANT GPT-BASIC-DATA-PARTITION-4
+
+: gpt-basic-data-partition? ( -- true|false )
+ block gpt-part-entry>part-type-guid
+ dup l@-le GPT-BASIC-DATA-PARTITION-1 <> IF drop false EXIT THEN
+ dup 4 + w@-le GPT-BASIC-DATA-PARTITION-2 <> IF drop false EXIT THEN
+ dup 6 + w@-le GPT-BASIC-DATA-PARTITION-3 <> IF drop false EXIT THEN
+ 8 + x@ GPT-BASIC-DATA-PARTITION-4 =
+;
+
+\
+\ GPT Signature
+\ ("EFI PART", 45h 46h 49h 20h 50h 41h 52h 54h)
+\
+4546492050415254 CONSTANT GPT-SIGNATURE
+
+\ The routine checks whether the protective MBR has GPT ID and then
+\ reads the gpt data from the sector. Also set the seek position and
+\ the partition size used in caller routines.
+
+: get-gpt-partition ( -- true|false )
+ no-gpt? IF false EXIT THEN
+ debug-disk-label? IF cr ." GPT partition found " cr THEN
+ 1 read-sector
+ block gpt>part-entry-lba x@-le
+ block-size * to seek-pos
+ block gpt>part-entry-size l@-le to gpt-part-size
+ gpt-part-size block-array-size > IF
+ cr ." GPT part size exceeds buffer allocated " cr
+ false exit
THEN
- FALSE
+ block gpt>signature x@ GPT-SIGNATURE =
;
: load-from-gpt-prep-partition ( addr -- size )
- no-gpt? IF drop FALSE EXIT THEN
- debug-disk-label? IF
- cr ." GPT partition found " cr
- THEN
- 1 read-sector block gpt>part-entry-lba l@-le
- block-size * to seek-pos
- block gpt>part-entry-size l@-le to gpt-part-size
- block gpt>num-part-entry l@-le dup 0= IF FALSE EXIT THEN
+ get-gpt-partition 0= IF false EXIT THEN
+ block gpt>num-part-entry l@-le dup 0= IF false exit THEN
1+ 1 ?DO
seek-pos 0 seek drop
block gpt-part-size read drop gpt-prep-partition? IF
- debug-disk-label? IF
- ." GPT PReP partition found " cr
- THEN
- block gpt-part-entry>first-lba x@ xbflip
- block gpt-part-entry>last-lba x@ xbflip
- over - 1+ ( addr offset len )
- swap ( addr len offset )
- block-size * to part-offset
- 0 0 seek drop ( addr len )
- block-size * read ( size )
+ debug-disk-label? IF ." GPT PReP partition found " cr THEN
+ block gpt-part-entry>first-lba x@-le ( addr first-lba )
+ block gpt-part-entry>last-lba x@-le ( addr first-lba last-lba)
+ over - 1+ ( addr first-lba blocks )
+ swap ( addr blocks first-lba )
+ block-size * to part-offset ( addr blocks )
+ 0 0 seek drop ( addr blocks )
+ block-size * read ( size )
+ UNLOOP EXIT
+ THEN
+ seek-pos gpt-part-size + to seek-pos
+ LOOP
+ false
+;
+
+: try-gpt-dos-partition ( -- true|false )
+ get-gpt-partition 0= IF false EXIT THEN
+ block gpt>num-part-entry l@-le dup 0= IF false EXIT THEN
+ 1+ 1 ?DO
+ seek-pos 0 seek drop
+ block gpt-part-size read drop
+ gpt-basic-data-partition? IF
+ debug-disk-label? IF ." GPT BASIC DATA partition found " cr THEN
+ block gpt-part-entry>first-lba x@-le ( first-lba )
+ dup to part-start ( first-lba )
+ block gpt-part-entry>last-lba x@-le ( first-lba last-lba )
+ over - 1+ ( first-lba s1 )
+ block-size * to part-size ( first-lba )
+ block-size * to part-offset ( )
+ 0 0 seek drop
+ block block-size read drop
+ block fat-bootblock? ( true|false )
UNLOOP EXIT
THEN
- seek-pos gpt-part-size i * + to seek-pos
+ seek-pos gpt-part-size + to seek-pos
LOOP
- FALSE
+ false
;
\ Extract the boot loader path from a bootinfo.txt file
@@ -493,7 +549,7 @@ AA26 CONSTANT GPT-PREP-PARTITION-4
debug-disk-label? IF ." Trying CHRP boot " .s cr THEN
1 disk-chrp-boot !
- dup load-chrp-boot-file ?dup 0 <> IF .s cr nip EXIT THEN
+ dup load-chrp-boot-file ?dup 0 <> IF nip EXIT THEN
0 disk-chrp-boot !
debug-disk-label? IF ." Trying GPT boot " .s cr THEN
@@ -558,14 +614,7 @@ AA26 CONSTANT GPT-PREP-PARTITION-4
: try-dos-files ( -- found? )
no-mbr? IF false EXIT THEN
- \ block 0 byte 0-2 is a jump instruction in all FAT
- \ filesystems.
- \ e9 and eb are jump instructions in x86 assembler.
- block c@ e9 <> IF
- block c@ eb <>
- block 2+ c@ 90 <> or
- IF false EXIT THEN
- THEN
+ block fat-bootblock? 0= IF false EXIT THEN
s" fat-files" (interpose-filesystem)
true
;
@@ -600,6 +649,7 @@ AA26 CONSTANT GPT-PREP-PARTITION-4
: try-partitions ( -- found? )
try-dos-partition IF try-files EXIT THEN
+ try-gpt-dos-partition IF try-files EXIT THEN
\ try-iso9660-partition IF try-files EXIT THEN
\ ... more partition types here...
false
@@ -610,7 +660,7 @@ AA26 CONSTANT GPT-PREP-PARTITION-4
: close ( -- )
debug-disk-label? IF ." Closing disk-label: block=0x" block u. ." block-size=" block-size .d cr THEN
- block d# 4096 free-mem
+ block block-array-size free-mem
;
diff --git a/roms/SLOF/slof/fs/pci-scan.fs b/roms/SLOF/slof/fs/pci-scan.fs
index b8b9fe61f..2fdf0e8f5 100644
--- a/roms/SLOF/slof/fs/pci-scan.fs
+++ b/roms/SLOF/slof/fs/pci-scan.fs
@@ -110,10 +110,13 @@ here 100 allot CONSTANT pci-device-vec
dup 100000 + pci-next-mem ! \ and write back with 1MB for bridge
over 24 + rtas-config-w@ \ check if 64bit support
1 and IF \ IF 64 bit support
- 2dup 20 rshift \ | keep upper 32 bits
- swap 28 + rtas-config-l! \ | and write it into the Base-Upper32-bits
- pci-max-mem @ 20 rshift \ | fetch max Limit address and keep upper 32 bits
- 2 pick 2C + rtas-config-l! \ | and set the Limit
+ pci-next-mem64 @ 100000000 #aligned \ | read the current Value of 64-bit and align to 4GB boundary
+ dup 100000000 + pci-next-mem64 x! \ | and write back with 1GB for bridge
+ 2 pick swap \ |
+ 20 rshift \ | keep upper 32 bits
+ swap 28 + rtas-config-l! \ | and write it into the Base-Upper32-bits
+ pci-max-mem64 @ 20 rshift \ | fetch max Limit address and keep upper 32 bits
+ 2 pick 2C + rtas-config-l! \ | and set the Limit
THEN \ FI
10 rshift \ keep upper 16 bits
pci-max-mem @ 1- FFFF0000 and or \ and Insert mmem Limit (set it to max)
@@ -129,8 +132,12 @@ here 100 allot CONSTANT pci-device-vec
1- \ make limit one less than boundary
over 24 + rtas-config-w@ \ check if 64bit support
1 and IF \ IF 64 bit support
- 2dup 20 rshift \ | keep upper 32 bits
- swap 2C + rtas-config-l! \ | and write it into the Limit-Upper32-bits
+ pci-next-mem64 @ 100000000 #aligned \ | Reat current value of 64-bar and align at 4GB
+ dup pci-next-mem64 x! \ | and write it back
+ 1- \ | make limite one less than boundary
+ 2 pick swap \ |
+ 20 rshift \ | keep upper 32 bits
+ swap 2C + rtas-config-l! \ | and write it into the Limit-Upper32-bits
THEN \ FI
FFFF0000 and \ keep upper 16 bits
over 24 + rtas-config-l@ 0000FFFF and \ fetch original Value
diff --git a/roms/SLOF/slof/fs/rmove.fs b/roms/SLOF/slof/fs/rmove.fs
deleted file mode 100644
index c28dba9c4..000000000
--- a/roms/SLOF/slof/fs/rmove.fs
+++ /dev/null
@@ -1,53 +0,0 @@
-\ *****************************************************************************
-\ * Copyright (c) 2004, 2008 IBM Corporation
-\ * All rights reserved.
-\ * This program and the accompanying materials
-\ * are made available under the terms of the BSD License
-\ * which accompanies this distribution, and is available at
-\ * http://www.opensource.org/licenses/bsd-license.php
-\ *
-\ * Contributors:
-\ * IBM Corporation - initial implementation
-\ ****************************************************************************/
-
-defer '(r@)
-defer '(r!)
-1 VALUE /(r)
-
-
-\ The rest of the code already implemented in prim.in
-\ In the end all of this should be moved over there and this file terminated
-
-: (rfill) ( addr size pattern 'r! /r -- )
- to /(r) to '(r!) ff and
- dup 8 lshift or dup 10 lshift or dup 20 lshift or
- -rot bounds ?do dup i '(r!) /(r) +loop drop
-;
-
-: (fwrmove) ( src dest size -- )
- >r 0 -rot r> bounds ?do + dup '(r@) i '(r!) /(r) dup +loop 2drop
-;
-
-\ Move from main to device memory
-: mrmove ( src dest size -- )
- 3dup or or 7 AND CASE
- 0 OF ['] x@ ['] rx! /x ENDOF
- 4 OF ['] l@ ['] rl! /l ENDOF
- 2 OF ['] w@ ['] rw! /w ENDOF
- dup OF ['] c@ ['] rb! /c ENDOF
- ENDCASE
- ( We already know that source and destination do not overlap )
- to /(r) to '(r!) to '(r@) (fwrmove)
-;
-
-: rfill ( addr size pattern -- )
- 3dup drop or 7 AND CASE
- 0 OF ['] rx! /x ENDOF
- 4 OF ['] rl! /l ENDOF
- 2 OF ['] rw! /w ENDOF
- dup OF ['] rb! /c ENDOF
- ENDCASE (rfill)
-;
-
-
-
diff --git a/roms/SLOF/slof/fs/terminal.fs b/roms/SLOF/slof/fs/terminal.fs
index 582bedeb3..dc82e7bf4 100644
--- a/roms/SLOF/slof/fs/terminal.fs
+++ b/roms/SLOF/slof/fs/terminal.fs
@@ -167,6 +167,7 @@ false VALUE stopcsi
CREATE twtracebuf 4000 allot twtracebuf 4000 erase
twtracebuf VALUE twbp
0 VALUE twbc
+0 VALUE twtrace-enabled?
: twtrace
twbc 4000 = IF 0 to twbc twtracebuf to twbp THEN
@@ -176,7 +177,7 @@ twtracebuf VALUE twbp
: terminal-write ( addr len -- actual-len )
cursor-off
tuck bounds ?DO i c@
- twtrace
+ twtrace-enabled? IF twtrace THEN
esc-on IF esc-process
ELSE CASE
1B OF true to esc-on ENDOF
diff --git a/roms/SLOF/slof/ppc64.c b/roms/SLOF/slof/ppc64.c
index 20d927069..619d95ec7 100644
--- a/roms/SLOF/slof/ppc64.c
+++ b/roms/SLOF/slof/ppc64.c
@@ -42,24 +42,7 @@ cell *the_heap_start = &the_heap[0];
cell *the_heap_end = &the_heap[HEAP_SIZE / CELLSIZE];
extern void io_putchar(unsigned char);
-
-
-static unsigned long __attribute__((noinline))
-call_c(cell arg0, cell arg1, cell arg2, cell entry)
-{
- register unsigned long r3 asm("r3") = arg0.u;
- register unsigned long r4 asm("r4") = arg1.u;
- register unsigned long r5 asm("r5") = arg2.u;
- register unsigned long r6 = entry.u ;
-
- asm volatile("mflr 31 ; mtctr %4 ; bctrl ; mtlr 31"
- : "=r" (r3)
- : "r" (r3), "r" (r4), "r" (r5), "r" (r6)
- : "ctr", "r6", "r7", "r8", "r9", "r10", "r11",
- "r12", "r13", "r31", "lr", "cc");
-
- return r3;
-}
+extern unsigned long call_c(cell arg0, cell arg1, cell arg2, cell entry);
long
diff --git a/roms/SLOF/slof/prim.code b/roms/SLOF/slof/prim.code
index 9fbed7168..bb9e036a9 100644
--- a/roms/SLOF/slof/prim.code
+++ b/roms/SLOF/slof/prim.code
@@ -520,6 +520,19 @@ PRIM(RMOVE)
MIRP
+PRIM(MRMOVE)
+ type_u size = TOS.u; POP;
+ void *d = TOS.a; POP;
+ void *s = TOS.a; POP;
+ FAST_MRMOVE(s, d, size);
+ MIRP
+
+PRIM(RFILL)
+ type_u pat = TOS.u; POP;
+ type_u size = TOS.u; POP;
+ void *dst = TOS.a; POP;
+ FAST_RFILL(dst, size, pat);
+ MIRP
// String compare, case insensitive:
// : string=ci ( str1 len1 str2 len2 -- equal? )
diff --git a/roms/SLOF/slof/prim.in b/roms/SLOF/slof/prim.in
index 7a0d6a2ed..855f59262 100644
--- a/roms/SLOF/slof/prim.in
+++ b/roms/SLOF/slof/prim.in
@@ -104,8 +104,9 @@ cod(SEMICOLON)
cod(EXECUTE)
cod(MOVE)
-// cod(RMOVE64)
cod(RMOVE)
+cod(MRMOVE)
+cod(RFILL)
cod(ZCOUNT)
con(HASH-SIZE HASHSIZE)
cod(HASH)
diff --git a/roms/config.ipxe.general.h b/roms/config.ipxe.general.h
deleted file mode 100644
index 619ee4c15..000000000
--- a/roms/config.ipxe.general.h
+++ /dev/null
@@ -1,4 +0,0 @@
-#undef BANNER_TIMEOUT
-#define BANNER_TIMEOUT 30
-#undef ROM_BANNER_TIMEOUT
-#define ROM_BANNER_TIMEOUT 0
diff --git a/roms/ipxe/COPYING b/roms/ipxe/COPYING
index a43ea2126..342330bb9 100644
--- a/roms/ipxe/COPYING
+++ b/roms/ipxe/COPYING
@@ -1,339 +1,12 @@
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
+In general iPXE files are licensed under the GPL. For historical
+reasons, individual files may contain their own licence declarations.
+Most builds of iPXE do not contain all iPXE code (in particular, most
+builds will include only one driver), and so the overall licence can
+vary depending on what target you are building.
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- 675 Mass Ave, Cambridge, MA 02139, USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
+The resultant applicable licence(s) for any particular build can be
+determined by using "make bin/xxxxxxx.yyy.licence"; for example:
- Preamble
+ make bin/rtl8139.rom.licence
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- Appendix: How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) 19yy <name of author>
-
- 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.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) 19yy name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- <signature of Ty Coon>, 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Library General
-Public License instead of this License.
+to determine the resultant licence(s) for the build bin/rtl8139.rom
diff --git a/roms/ipxe/COPYING.GPLv2 b/roms/ipxe/COPYING.GPLv2
new file mode 100644
index 000000000..d159169d1
--- /dev/null
+++ b/roms/ipxe/COPYING.GPLv2
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/roms/ipxe/COPYING.UBDL b/roms/ipxe/COPYING.UBDL
new file mode 100644
index 000000000..780ddcd77
--- /dev/null
+++ b/roms/ipxe/COPYING.UBDL
@@ -0,0 +1,59 @@
+UNMODIFIED BINARY DISTRIBUTION LICENCE
+
+
+PREAMBLE
+
+The GNU General Public License provides a legal guarantee that
+software covered by it remains free (in the sense of freedom, not
+price). It achieves this guarantee by imposing obligations on anyone
+who chooses to distribute the software.
+
+Some of these obligations may be seen as unnecessarily burdensome. In
+particular, when the source code for the software is already publicly
+and freely available, there is minimal value in imposing upon each
+distributor the obligation to provide the complete source code (or an
+equivalent written offer to provide the complete source code).
+
+This Licence allows for the distribution of unmodified binaries built
+from publicly available source code, without imposing the obligations
+of the GNU General Public License upon anyone who chooses to
+distribute only the unmodified binaries built from that source code.
+
+The extra permissions granted by this Licence apply only to unmodified
+binaries built from source code which has already been made available
+to the public in accordance with the terms of the GNU General Public
+Licence. Nothing in this Licence allows for the creation of
+closed-source modified versions of the Program. Any modified versions
+of the Program are subject to the usual terms and conditions of the
+GNU General Public License.
+
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+This Licence applies to any Program or other work which contains a
+notice placed by the copyright holder saying it may be distributed
+under the terms of this Unmodified Binary Distribution Licence. All
+terms used in the text of this Licence are to be interpreted as they
+are used in version 2 of the GNU General Public License as published
+by the Free Software Foundation.
+
+If you have made this Program available to the public in both source
+code and executable form in accordance with 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, then you are hereby granted an additional permission to use,
+copy, and distribute the unmodified executable form of this Program
+(the "Unmodified Binary") without restriction, including the right to
+permit persons to whom the Unmodified Binary is furnished to do
+likewise, subject to the following conditions:
+
+- when started running, the Program must display an announcement which
+ includes the details of your existing publication of the Program
+ made in accordance with the terms of the GNU General Public License.
+ For example, the Program could display the URL of the publicly
+ available source code from which the Unmodified Binary was built.
+
+- when exercising your right to grant permissions under this Licence,
+ you do not need to refer directly to the text of this Licence, but
+ you may not grant permissions beyond those granted to you by this
+ Licence.
diff --git a/roms/ipxe/COPYRIGHTS b/roms/ipxe/COPYRIGHTS
deleted file mode 100644
index 342330bb9..000000000
--- a/roms/ipxe/COPYRIGHTS
+++ /dev/null
@@ -1,12 +0,0 @@
-In general iPXE files are licensed under the GPL. For historical
-reasons, individual files may contain their own licence declarations.
-Most builds of iPXE do not contain all iPXE code (in particular, most
-builds will include only one driver), and so the overall licence can
-vary depending on what target you are building.
-
-The resultant applicable licence(s) for any particular build can be
-determined by using "make bin/xxxxxxx.yyy.licence"; for example:
-
- make bin/rtl8139.rom.licence
-
-to determine the resultant licence(s) for the build bin/rtl8139.rom
diff --git a/roms/ipxe/src/Makefile b/roms/ipxe/src/Makefile
index b742d1283..2a9cc9e8f 100644
--- a/roms/ipxe/src/Makefile
+++ b/roms/ipxe/src/Makefile
@@ -83,11 +83,13 @@ SRCDIRS += drivers/block
SRCDIRS += drivers/nvs
SRCDIRS += drivers/bitbash
SRCDIRS += drivers/infiniband
+SRCDIRS += drivers/usb
SRCDIRS += interface/pxe interface/efi interface/smbios
SRCDIRS += interface/bofm
SRCDIRS += interface/xen
+SRCDIRS += interface/hyperv
SRCDIRS += tests
-SRCDIRS += crypto crypto/axtls crypto/matrixssl
+SRCDIRS += crypto crypto/mishmash
SRCDIRS += hci hci/commands hci/tui
SRCDIRS += hci/mucurses hci/mucurses/widgets
SRCDIRS += hci/keymap
diff --git a/roms/ipxe/src/Makefile.housekeeping b/roms/ipxe/src/Makefile.housekeeping
index 1a75d3939..03800c8ef 100644
--- a/roms/ipxe/src/Makefile.housekeeping
+++ b/roms/ipxe/src/Makefile.housekeeping
@@ -157,17 +157,6 @@ SP_FLAGS := $(shell $(SP_TEST) && $(ECHO) '-fno-stack-protector')
WORKAROUND_CFLAGS += $(SP_FLAGS)
endif
-# Some widespread patched versions of gcc include -fPIE -Wl,-pie by
-# default. Note that gcc will exit *successfully* if it fails to
-# recognise an option that starts with "no", so we have to test for
-# output on stderr instead of checking the exit status.
-#
-ifeq ($(CCTYPE),gcc)
-PIE_TEST = [ -z "`$(CC) -fno-PIE -nopie -x c -c /dev/null -o /dev/null 2>&1`" ]
-PIE_FLAGS := $(shell $(PIE_TEST) && $(ECHO) '-fno-PIE -nopie')
-WORKAROUND_CFLAGS += $(PIE_FLAGS)
-endif
-
# gcc 4.4 generates .eh_frame sections by default, which distort the
# output of "size". Inhibit this.
#
@@ -533,6 +522,7 @@ endif
#
COMPILE_c = $(CC) $(CFLAGS) $(CFLAGS_c) $(OBJ_CFLAGS)
RULE_c = $(Q)$(COMPILE_c) -c $< -o $@ $(POST_O)
+RULE_c_to_ids.o = $(Q)$(ECHO_E) '$(OBJ_IDS_ASM_NL)' | $(ASSEMBLE_S) -o $@
RULE_c_to_dbg%.o = $(Q)$(COMPILE_c) -DDBGLVL_MAX=$* -c $< -o $@ $(POST_O)
RULE_c_to_c = $(Q)$(COMPILE_c) -E -c $< > $@
RULE_c_to_s = $(Q)$(COMPILE_c) -S -g0 -c $< -o $@
@@ -543,7 +533,7 @@ RULE_S = $(Q)$(PREPROCESS_S) $< | $(ASSEMBLE_S) -o $@
RULE_S_to_dbg%.o = $(Q)$(PREPROCESS_S) -DDBGLVL_MAX=$* $< | $(ASSEMBLE_S) -o $@
RULE_S_to_s = $(Q)$(PREPROCESS_S) $< > $@
-DEBUG_TARGETS += dbg%.o c s
+GENERIC_TARGETS += ids.o dbg%.o c s
# List of embedded images included in the last build of embedded.o.
# This is needed in order to correctly rebuild embedded.o whenever the
@@ -775,8 +765,6 @@ define deps_template_parts
$(Q)$(CPP) $(CFLAGS) $(CFLAGS_$(2)) $(CFLAGS_$(3)) -DOBJECT=$(3) \
-Wno-error -M $(1) -MG -MP | \
sed 's/\.o\s*:/_DEPS +=/' > $(BIN)/deps/$(1).d
- $(Q)$(if $(findstring drivers/,$(1)),\
- $(PERL) $(PARSEROM) $(1) >> $(BIN)/deps/$(1).d)
endef
# rules_template : generate rules for a given source file
@@ -796,7 +784,7 @@ $$(BIN)/$(3).o : $(1) $$(MAKEDEPS) $$(POST_O_DEPS) $$($(3)_DEPS)
$$(QM)$(ECHO) " [BUILD] $$@"
$$(RULE_$(2))
BOBJS += $$(BIN)/$(3).o
-$(foreach TGT,$(DEBUG_TARGETS),$(if $(RULE_$(2)_to_$(TGT)),$(NEWLINE)$(call rules_template_target,$(1),$(2),$(3),$(TGT))))
+$(foreach TGT,$(GENERIC_TARGETS),$(if $(RULE_$(2)_to_$(TGT)),$(NEWLINE)$(call rules_template_target,$(1),$(2),$(3),$(TGT))))
$$(BIN)/deps/$(1).d : $$($(3)_DEPS)
TAGS : $$($(3)_DEPS)
endef
@@ -824,7 +812,7 @@ endef
# Generate the dependency files
#
-$(BIN)/deps/%.d : % $(MAKEDEPS) $(PARSEROM)
+$(BIN)/deps/%.d : % $(MAKEDEPS)
$(call deps_template_file,$<)
# Calculate list of dependency files
@@ -866,10 +854,69 @@ endif
endif
endif
-# The following variables are created by the rules files
+# Files to be parsed using parserom.pl
+#
+ROM_SRCS = $(foreach SRC,$(AUTO_SRCS),\
+ $(if $(findstring drivers/,$(SRC)),$(SRC)))
+romsrcs :
+ @$(ECHO) $(ROM_SRCS)
+
+# List of files to be parsed using parserom.pl
+#
+ROM_SRCS_LIST := $(BIN)/.rom.list
+ifeq ($(wildcard $(ROM_SRCS_LIST)),)
+ROM_SRCS_OLD := <invalid>
+else
+ROM_SRCS_OLD := $(shell cat $(ROM_SRCS_LIST))
+endif
+ifneq ($(ROM_SRCS_OLD),$(ROM_SRCS))
+$(shell $(ECHO) "$(ROM_SRCS)" > $(ROM_SRCS_LIST))
+endif
+
+$(ROM_SRCS_LIST) : $(MAKEDEPS)
+
+VERYCLEANUP += $(ROM_SRCS_LIST)
+
+# ROM definition file
+#
+ROMDEFS = $(BIN)/.rom.defs
+$(ROMDEFS) : $(ROM_SRCS) $(ROM_SRCS_LIST) $(PARSEROM) $(MAKEDEPS)
+ $(QM)$(ECHO) " [PARSEROM]"
+ $(Q)$(PERL) $(PARSEROM) $(ROM_SRCS) > $@
+
+VERYCLEANUP += $(ROMDEFS)
+
+# Evaluate ROM definition file
+ifdef NEED_DEPS
+ifneq ($(ROM_SRCS),)
+-include $(ROMDEFS)
+endif
+endif
+
+# Device ID tables (using IDs from ROM definition file)
+#
+define obj_pci_id_asm
+ .section ".pci_devlist.$(1)", "a", @progbits
+ .globl pci_devlist_$(1)
+pci_devlist_$(1):
+ .short ( 0x$(1) & 0xffff )
+
+endef
+define obj_isa_id_asm
+endef
+OBJ_IDS_ASM = $(foreach ROM,$(ROMS_$(OBJECT)),$(call obj_$(ROM_TYPE_$(ROM))_id_asm,$(ROM)))
+OBJ_IDS_ASM_NL = $(subst $(NEWLINE),\n,$(OBJ_IDS_ASM))
+$(BIN)/%.ids :
+ @$(ECHO_E) '$(OBJ_IDS_ASM_NL)'
+
+BOBJS += $(patsubst %,$(BIN)/%.ids.o,$(DRIVERS))
+
+# The following variables are created by the autogenerated rules
#
bobjs :
@$(ECHO) $(BOBJS)
+drivers_% :
+ @$(ECHO) $(DRIVERS_$*)
drivers :
@$(ECHO) $(DRIVERS)
.PHONY : drivers
@@ -900,6 +947,11 @@ $(BIN)/NIC : $(AUTO_DEPS)
@perl -ne 'chomp; print "$$1\n" if /\# NIC\t(.*)$$/' $^ >> $@
CLEANUP += $(BIN)/NIC # Doesn't match the $(BIN)/*.* pattern
+# Select drivers to be included in the all-drivers build
+#
+DRIVERS_ipxe = $(DRIVERS_net) $(DRIVERS_infiniband) \
+ $(DRIVERS_xen) $(DRIVERS_hyperv)
+
# Analyse a target name (e.g. "bin/dfe538--prism2_pci.rom.tmp") and
# derive the variables:
#
@@ -908,7 +960,6 @@ CLEANUP += $(BIN)/NIC # Doesn't match the $(BIN)/*.* pattern
# TGT_DRIVERS : the driver for each element (e.g. "rtl8139 prism2_pci")
# TGT_ROM_NAME : the ROM name (e.g. "dfe538")
#
-DRIVERS_ipxe = $(DRIVERS)
CARD_DRIVER = $(firstword $(DRIVER_$(1)) $(1))
TGT_ELEMENTS = $(subst --, ,$(firstword $(subst ., ,$(notdir $@))))
TGT_ROM_NAME = $(firstword $(TGT_ELEMENTS))
@@ -941,6 +992,8 @@ TGT_PCI_DEVICE = $(PCI_DEVICE_$(TGT_ROM_NAME))
TGT_LD_DRIVERS = $(subst -,_,$(patsubst %,obj_%,$(TGT_DRIVERS)))
TGT_LD_IDS = pci_vendor_id=$(firstword $(TGT_PCI_VENDOR) 0) \
pci_device_id=$(firstword $(TGT_PCI_DEVICE) 0)
+TGT_LD_DEVLIST = $(foreach ELEM,$(TGT_ELEMENTS),$(if $(PCI_VENDOR_$(ELEM)),\
+ pci_devlist_$(patsubst 0x%,%,$(PCI_VENDOR_$(ELEM)))$(patsubst 0x%,%,$(PCI_DEVICE_$(ELEM)))))
TGT_LD_ENTRY = _$(TGT_PREFIX)_start
# Calculate linker flags based on link-time options for the current
@@ -951,7 +1004,8 @@ TGT_LD_ENTRY = _$(TGT_PREFIX)_start
# "-u obj_zpciprefix -u obj_rtl8139 -u obj_prism2_pci
# --defsym pci_vendor=0x1186 --defsym pci_device=0x1300")
#
-TGT_LD_FLAGS = $(foreach SYM,$(TGT_LD_ENTRY) $(TGT_LD_DRIVERS) obj_config,\
+TGT_LD_FLAGS = $(foreach SYM,$(TGT_LD_ENTRY) $(TGT_LD_DRIVERS) \
+ $(TGT_LD_DEVLIST) obj_config,\
-u $(SYM) --defsym check_$(SYM)=$(SYM) ) \
$(patsubst %,--defsym %,$(TGT_LD_IDS)) \
-e $(TGT_LD_ENTRY)
@@ -981,6 +1035,7 @@ $(BIN)/%.info :
@$(ECHO)
@$(ECHO) 'LD driver symbols : $(TGT_LD_DRIVERS)'
@$(ECHO) 'LD ID symbols : $(TGT_LD_IDS)'
+ @$(ECHO) 'LD devlist symbols : $(TGT_LD_DEVLIST)'
@$(ECHO) 'LD entry point : $(TGT_LD_ENTRY)'
@$(ECHO)
@$(ECHO) 'LD target flags : $(TGT_LD_FLAGS)'
@@ -1012,7 +1067,7 @@ BLIB = $(BIN)/blib.a
$(BLIB) : $(BLIB_OBJS) $(BLIB_LIST) $(MAKEDEPS)
$(Q)$(RM) $(BLIB)
$(QM)$(ECHO) " [AR] $@"
- $(Q)$(AR) r $@ $(BLIB_OBJS)
+ $(Q)$(AR) r $@ $(sort $(BLIB_OBJS))
$(Q)$(RANLIB) $@
blib : $(BLIB)
@@ -1231,15 +1286,12 @@ endif # defined(BIN)
#
# The compression utilities
#
-$(NRV2B) : util/nrv2b.c $(MAKEDEPS)
- $(QM)$(ECHO) " [HOSTCC] $@"
- $(Q)$(HOST_CC) $(HOST_CFLAGS) -DENCODE -DDECODE -DMAIN -DVERBOSE \
- -DNDEBUG -DBITSIZE=32 -DENDIAN=0 -o $@ $<
-CLEANUP += $(NRV2B)
-$(ZBIN) : util/zbin.c util/nrv2b.c $(MAKEDEPS)
+ZBIN_LDFLAGS := -llzma
+
+$(ZBIN) : util/zbin.c $(MAKEDEPS)
$(QM)$(ECHO) " [HOSTCC] $@"
- $(Q)$(HOST_CC) $(HOST_CFLAGS) -o $@ $<
+ $(Q)$(HOST_CC) $(HOST_CFLAGS) $< $(ZBIN_LDFLAGS) -o $@
CLEANUP += $(ZBIN)
###############################################################################
@@ -1319,31 +1371,6 @@ endif
###############################################################################
#
-# 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.
-#
-BUILDSERIAL_H = config/.buildserial.h
-BUILDSERIAL_NOW = config/.buildserial.now
-BUILDSERIAL_NEXT = config/.buildserial.next
-
-$(BUILDSERIAL_NOW) $(BUILDSERIAL_NEXT) :
- $(ECHO) 1 > $@
-
-$(BUILDSERIAL_H) : $(BUILDSERIAL_NOW) $(BUILDSERIAL_NEXT)
- $(ECHO) '#define BUILD_SERIAL_NUM $(shell cat $<)' > $@
-
-ifeq ($(filter bs,$(MAKECMDGOALS)),bs)
-$(shell diff -q $(BUILDSERIAL_NOW) $(BUILDSERIAL_NEXT) > /dev/null || \
- cp -f $(BUILDSERIAL_NEXT) $(BUILDSERIAL_NOW))
-endif
-
-bs : $(BUILDSERIAL_NOW)
- @$(ECHO) $$(( $(shell cat $<) + 1 )) > $(BUILDSERIAL_NEXT)
- @$(ECHO) "Build serial number is $(shell cat $<)"
-
-###############################################################################
-#
# Build the TAGS file(s) for emacs
#
TAGS :
diff --git a/roms/ipxe/src/arch/i386/Makefile b/roms/ipxe/src/arch/i386/Makefile
index 4925cc4e6..99f875314 100644
--- a/roms/ipxe/src/arch/i386/Makefile
+++ b/roms/ipxe/src/arch/i386/Makefile
@@ -69,6 +69,17 @@ CFLAGS += -fshort-wchar
#
CFLAGS += -Ui386
+# Some widespread patched versions of gcc include -fPIE -Wl,-pie by
+# default. Note that gcc will exit *successfully* if it fails to
+# recognise an option that starts with "no", so we have to test for
+# output on stderr instead of checking the exit status.
+#
+ifeq ($(CCTYPE),gcc)
+PIE_TEST = [ -z "`$(CC) -fno-PIE -nopie -x c -c /dev/null -o /dev/null 2>&1`" ]
+PIE_FLAGS := $(shell $(PIE_TEST) && $(ECHO) '-fno-PIE -nopie')
+WORKAROUND_CFLAGS += $(PIE_FLAGS)
+endif
+
# Define version string for lkrnprefix.S
#
CFLAGS_lkrnprefix += -DVERSION="\"$(VERSION)\""
diff --git a/roms/ipxe/src/arch/i386/core/basemem_packet.c b/roms/ipxe/src/arch/i386/core/basemem_packet.c
index 06ffa3bbd..9f5fbf330 100644
--- a/roms/ipxe/src/arch/i386/core/basemem_packet.c
+++ b/roms/ipxe/src/arch/i386/core/basemem_packet.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @file
diff --git a/roms/ipxe/src/arch/i386/core/cachedhcp.c b/roms/ipxe/src/arch/i386/core/cachedhcp.c
index 3cac28e7d..a5c624035 100644
--- a/roms/ipxe/src/arch/i386/core/cachedhcp.c
+++ b/roms/ipxe/src/arch/i386/core/cachedhcp.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/arch/i386/core/gdbmach.c b/roms/ipxe/src/arch/i386/core/gdbmach.c
index 4d6897f7d..d92a4ac08 100644
--- a/roms/ipxe/src/arch/i386/core/gdbmach.c
+++ b/roms/ipxe/src/arch/i386/core/gdbmach.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <stdio.h>
diff --git a/roms/ipxe/src/arch/i386/core/patch_cf.S b/roms/ipxe/src/arch/i386/core/patch_cf.S
index 97a62f494..4365563fe 100644
--- a/roms/ipxe/src/arch/i386/core/patch_cf.S
+++ b/roms/ipxe/src/arch/i386/core/patch_cf.S
@@ -14,9 +14,13 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER )
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
.text
.arch i386
diff --git a/roms/ipxe/src/arch/i386/core/pci_autoboot.c b/roms/ipxe/src/arch/i386/core/pci_autoboot.c
index a3eb1f97d..337598091 100644
--- a/roms/ipxe/src/arch/i386/core/pci_autoboot.c
+++ b/roms/ipxe/src/arch/i386/core/pci_autoboot.c
@@ -16,9 +16,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/device.h>
diff --git a/roms/ipxe/src/arch/i386/core/rdtsc_timer.c b/roms/ipxe/src/arch/i386/core/rdtsc_timer.c
index 2f31afc66..e720a239c 100644
--- a/roms/ipxe/src/arch/i386/core/rdtsc_timer.c
+++ b/roms/ipxe/src/arch/i386/core/rdtsc_timer.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
@@ -27,7 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <assert.h>
#include <ipxe/timer.h>
-#include <ipxe/timer2.h>
+#include <ipxe/pit8254.h>
/**
* Number of TSC ticks per microsecond
@@ -56,10 +60,10 @@ static void rdtsc_udelay ( unsigned long usecs ) {
elapsed = ( currticks() - start );
} while ( elapsed < ( usecs * rdtsc_ticks_per_usec ) );
} else {
- /* Not yet calibrated; use timer2 and calibrate
+ /* Not yet calibrated; use 8254 PIT and calibrate
* based on result.
*/
- timer2_udelay ( usecs );
+ pit8254_udelay ( usecs );
elapsed = ( currticks() - start );
rdtsc_ticks_per_usec = ( elapsed / usecs );
DBG ( "RDTSC timer calibrated: %ld ticks in %ld usecs "
diff --git a/roms/ipxe/src/arch/i386/core/relocate.c b/roms/ipxe/src/arch/i386/core/relocate.c
index 5fbf2d2c2..54ad387e4 100644
--- a/roms/ipxe/src/arch/i386/core/relocate.c
+++ b/roms/ipxe/src/arch/i386/core/relocate.c
@@ -8,7 +8,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/*
* The linker passes in the symbol _max_align, which is the alignment
diff --git a/roms/ipxe/src/arch/i386/core/runtime.c b/roms/ipxe/src/arch/i386/core/runtime.c
index 18ca7936e..d160fee04 100644
--- a/roms/ipxe/src/arch/i386/core/runtime.c
+++ b/roms/ipxe/src/arch/i386/core/runtime.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/arch/i386/core/setjmp.S b/roms/ipxe/src/arch/i386/core/setjmp.S
index 03727148c..81d3b4911 100644
--- a/roms/ipxe/src/arch/i386/core/setjmp.S
+++ b/roms/ipxe/src/arch/i386/core/setjmp.S
@@ -1,42 +1,64 @@
-/* setjmp and longjmp. Use of these functions is deprecated. */
-
-FILE_LICENCE ( GPL2_OR_LATER )
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
.text
.arch i386
.code32
-
-/**************************************************************************
-SETJMP - Save stack context for non-local goto
-**************************************************************************/
+
+ /* Must match jmp_buf structure layout */
+ .struct 0
+env_retaddr: .long 0
+env_stack: .long 0
+env_ebx: .long 0
+env_esi: .long 0
+env_edi: .long 0
+env_ebp: .long 0
+ .previous
+
+/*
+ * Save stack context for non-local goto
+ */
.globl setjmp
setjmp:
- movl 4(%esp),%ecx /* jmpbuf */
- movl 0(%esp),%edx /* return address */
- movl %edx,0(%ecx)
- movl %ebx,4(%ecx)
- movl %esp,8(%ecx)
- movl %ebp,12(%ecx)
- movl %esi,16(%ecx)
- movl %edi,20(%ecx)
- movl $0,%eax
+ /* Get jmp_buf pointer in %edx */
+ movl 4(%esp),%edx
+ /* Save return address */
+ movl 0(%esp),%eax
+ movl %eax, env_retaddr(%edx)
+ /* Save stack pointer */
+ movl %esp, env_stack(%edx)
+ /* Save other registers */
+ movl %ebx, env_ebx(%edx)
+ movl %esi, env_esi(%edx)
+ movl %edi, env_edi(%edx)
+ movl %ebp, env_ebp(%edx)
+ /* Return 0 when returning as setjmp() */
+ xorl %eax, %eax
ret
+ .size setjmp, . - setjmp
-/**************************************************************************
-LONGJMP - Non-local jump to a saved stack context
-**************************************************************************/
+/*
+ * Non-local jump to a saved stack context
+ */
.globl longjmp
longjmp:
- movl 4(%esp),%edx /* jumpbuf */
- movl 8(%esp),%eax /* result */
- movl 0(%edx),%ecx
- movl 4(%edx),%ebx
- movl 8(%edx),%esp
- movl 12(%edx),%ebp
- movl 16(%edx),%esi
- movl 20(%edx),%edi
- cmpl $0,%eax
- jne 1f
- movl $1,%eax
-1: movl %ecx,0(%esp)
+ /* Get jmp_buf pointer in %edx */
+ movl 4(%esp),%edx
+ /* Get result in %eax */
+ movl 8(%esp),%eax
+ /* Force result to non-zero */
+ testl %eax, %eax
+ jnz 1f
+ incl %eax
+1: /* Restore stack pointer */
+ movl env_stack(%edx), %esp
+ /* Restore other registers */
+ movl env_ebx(%edx), %ebx
+ movl env_esi(%edx), %esi
+ movl env_edi(%edx), %edi
+ movl env_ebp(%edx), %ebp
+ /* Replace return address on the new stack */
+ popl %ecx /* discard */
+ pushl env_retaddr(%edx)
+ /* Return to setjmp() caller */
ret
+ .size longjmp, . - longjmp
diff --git a/roms/ipxe/src/arch/i386/core/stack.S b/roms/ipxe/src/arch/i386/core/stack.S
index 737ec0eed..98f1cd9b9 100644
--- a/roms/ipxe/src/arch/i386/core/stack.S
+++ b/roms/ipxe/src/arch/i386/core/stack.S
@@ -1,4 +1,4 @@
-FILE_LICENCE ( GPL2_OR_LATER )
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
.arch i386
diff --git a/roms/ipxe/src/arch/i386/core/stack16.S b/roms/ipxe/src/arch/i386/core/stack16.S
index 523f0288b..4bc6f081a 100644
--- a/roms/ipxe/src/arch/i386/core/stack16.S
+++ b/roms/ipxe/src/arch/i386/core/stack16.S
@@ -1,4 +1,4 @@
-FILE_LICENCE ( GPL2_OR_LATER )
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
.arch i386
diff --git a/roms/ipxe/src/arch/i386/core/timer2.c b/roms/ipxe/src/arch/i386/core/timer2.c
deleted file mode 100644
index 077866562..000000000
--- a/roms/ipxe/src/arch/i386/core/timer2.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * arch/i386/core/i386_timer.c
- *
- * Use the "System Timer 2" to implement the udelay callback in
- * the BIOS timer driver. Also used to calibrate the clock rate
- * in the RTDSC timer driver.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2, or (at
- * your option) any later version.
- */
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#include <stddef.h>
-#include <ipxe/timer2.h>
-#include <ipxe/io.h>
-
-/* Timers tick over at this rate */
-#define TIMER2_TICKS_PER_SEC 1193180U
-
-/* Parallel Peripheral Controller Port B */
-#define PPC_PORTB 0x61
-
-/* Meaning of the port bits */
-#define PPCB_T2OUT 0x20 /* Bit 5 */
-#define PPCB_SPKR 0x02 /* Bit 1 */
-#define PPCB_T2GATE 0x01 /* Bit 0 */
-
-/* Ports for the 8254 timer chip */
-#define TIMER2_PORT 0x42
-#define TIMER_MODE_PORT 0x43
-
-/* Meaning of the mode bits */
-#define TIMER0_SEL 0x00
-#define TIMER1_SEL 0x40
-#define TIMER2_SEL 0x80
-#define READBACK_SEL 0xC0
-
-#define LATCH_COUNT 0x00
-#define LOBYTE_ACCESS 0x10
-#define HIBYTE_ACCESS 0x20
-#define WORD_ACCESS 0x30
-
-#define MODE0 0x00
-#define MODE1 0x02
-#define MODE2 0x04
-#define MODE3 0x06
-#define MODE4 0x08
-#define MODE5 0x0A
-
-#define BINARY_COUNT 0x00
-#define BCD_COUNT 0x01
-
-static void load_timer2 ( unsigned int ticks ) {
- /*
- * Now let's take care of PPC channel 2
- *
- * Set the Gate high, program PPC channel 2 for mode 0,
- * (interrupt on terminal count mode), binary count,
- * load 5 * LATCH count, (LSB and MSB) to begin countdown.
- *
- * Note some implementations have a bug where the high bits byte
- * of channel 2 is ignored.
- */
- /* Set up the timer gate, turn off the speaker */
- /* Set the Gate high, disable speaker */
- outb((inb(PPC_PORTB) & ~PPCB_SPKR) | PPCB_T2GATE, PPC_PORTB);
- /* binary, mode 0, LSB/MSB, Ch 2 */
- outb(TIMER2_SEL|WORD_ACCESS|MODE0|BINARY_COUNT, TIMER_MODE_PORT);
- /* LSB of ticks */
- outb(ticks & 0xFF, TIMER2_PORT);
- /* MSB of ticks */
- outb(ticks >> 8, TIMER2_PORT);
-}
-
-static int timer2_running ( void ) {
- return ((inb(PPC_PORTB) & PPCB_T2OUT) == 0);
-}
-
-void timer2_udelay ( unsigned long usecs ) {
- load_timer2 ( ( usecs * TIMER2_TICKS_PER_SEC ) / ( 1000 * 1000 ) );
- while (timer2_running()) {
- /* Do nothing */
- }
-}
diff --git a/roms/ipxe/src/arch/i386/core/virtaddr.S b/roms/ipxe/src/arch/i386/core/virtaddr.S
index 5e5d77352..425591570 100644
--- a/roms/ipxe/src/arch/i386/core/virtaddr.S
+++ b/roms/ipxe/src/arch/i386/core/virtaddr.S
@@ -4,7 +4,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER )
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
#include "librm.h"
diff --git a/roms/ipxe/src/arch/i386/drivers/net/undi.c b/roms/ipxe/src/arch/i386/drivers/net/undi.c
index 2bc54824c..9820cf629 100644
--- a/roms/ipxe/src/arch/i386/drivers/net/undi.c
+++ b/roms/ipxe/src/arch/i386/drivers/net/undi.c
@@ -68,10 +68,6 @@ static int undipci_probe ( struct pci_device *pci ) {
struct undi_rom *undirom;
int rc;
- /* Ignore non-network devices */
- if ( PCI_BASE_CLASS ( pci->class ) != PCI_BASE_CLASS_NETWORK )
- return -ENOTTY;
-
/* Allocate UNDI device structure */
undi = zalloc ( sizeof ( *undi ) );
if ( ! undi )
@@ -138,12 +134,13 @@ static void undipci_remove ( struct pci_device *pci ) {
}
static struct pci_device_id undipci_nics[] = {
-PCI_ROM ( 0xffff, 0xffff, "undipci", "UNDI (PCI)", 0 ),
+ PCI_ROM ( 0xffff, 0xffff, "undipci", "UNDI (PCI)", 0 ),
};
struct pci_driver undipci_driver __pci_driver_fallback = {
.ids = undipci_nics,
.id_count = ( sizeof ( undipci_nics ) / sizeof ( undipci_nics[0] ) ),
+ .class = PCI_CLASS_ID ( PCI_CLASS_NETWORK, PCI_ANY_ID, PCI_ANY_ID ),
.probe = undipci_probe,
.remove = undipci_remove,
};
diff --git a/roms/ipxe/src/arch/i386/drivers/net/undiload.c b/roms/ipxe/src/arch/i386/drivers/net/undiload.c
index 77134dcb8..7160ee384 100644
--- a/roms/ipxe/src/arch/i386/drivers/net/undiload.c
+++ b/roms/ipxe/src/arch/i386/drivers/net/undiload.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/arch/i386/drivers/net/undionly.c b/roms/ipxe/src/arch/i386/drivers/net/undionly.c
index 028fac5d9..70dbe4bfd 100644
--- a/roms/ipxe/src/arch/i386/drivers/net/undionly.c
+++ b/roms/ipxe/src/arch/i386/drivers/net/undionly.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/arch/i386/drivers/net/undipreload.c b/roms/ipxe/src/arch/i386/drivers/net/undipreload.c
index 81d7a80eb..fca771843 100644
--- a/roms/ipxe/src/arch/i386/drivers/net/undipreload.c
+++ b/roms/ipxe/src/arch/i386/drivers/net/undipreload.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <realmode.h>
#include <undipreload.h>
diff --git a/roms/ipxe/src/arch/i386/firmware/pcbios/basemem.c b/roms/ipxe/src/arch/i386/firmware/pcbios/basemem.c
index b23f2c356..6a46081aa 100644
--- a/roms/ipxe/src/arch/i386/firmware/pcbios/basemem.c
+++ b/roms/ipxe/src/arch/i386/firmware/pcbios/basemem.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <realmode.h>
diff --git a/roms/ipxe/src/arch/i386/firmware/pcbios/bios_console.c b/roms/ipxe/src/arch/i386/firmware/pcbios/bios_console.c
index bd73838b5..63413cdc1 100644
--- a/roms/ipxe/src/arch/i386/firmware/pcbios/bios_console.c
+++ b/roms/ipxe/src/arch/i386/firmware/pcbios/bios_console.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <assert.h>
#include <realmode.h>
@@ -39,6 +43,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define ATTR_FCOL_YELLOW 0x06
#define ATTR_FCOL_WHITE 0x07
+#define ATTR_BLINK 0x80
+
#define ATTR_BCOL_MASK 0x70
#define ATTR_BCOL_BLACK 0x00
#define ATTR_BCOL_BLUE 0x10
@@ -137,8 +143,12 @@ static void bios_handle_sgr ( struct ansiesc_context *ctx __unused,
bios_attr = ATTR_DEFAULT;
} else if ( aspect == 1 ) {
bios_attr |= ATTR_BOLD;
+ } else if ( aspect == 5 ) {
+ bios_attr |= ATTR_BLINK;
} else if ( aspect == 22 ) {
bios_attr &= ~ATTR_BOLD;
+ } else if ( aspect == 25 ) {
+ bios_attr &= ~ATTR_BLINK;
} else if ( ( aspect >= 30 ) && ( aspect <= 39 ) ) {
bios_attr &= ~ATTR_FCOL_MASK;
bios_attr |= bios_attr_fcols[ aspect - 30 ];
diff --git a/roms/ipxe/src/arch/i386/firmware/pcbios/e820mangler.S b/roms/ipxe/src/arch/i386/firmware/pcbios/e820mangler.S
index cea17ef8e..d5d97b482 100644
--- a/roms/ipxe/src/arch/i386/firmware/pcbios/e820mangler.S
+++ b/roms/ipxe/src/arch/i386/firmware/pcbios/e820mangler.S
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER )
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
.text
.arch i386
diff --git a/roms/ipxe/src/arch/i386/firmware/pcbios/fakee820.c b/roms/ipxe/src/arch/i386/firmware/pcbios/fakee820.c
index e5f713728..15f4d772f 100644
--- a/roms/ipxe/src/arch/i386/firmware/pcbios/fakee820.c
+++ b/roms/ipxe/src/arch/i386/firmware/pcbios/fakee820.c
@@ -14,9 +14,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <realmode.h>
#include <biosint.h>
diff --git a/roms/ipxe/src/arch/i386/firmware/pcbios/hidemem.c b/roms/ipxe/src/arch/i386/firmware/pcbios/hidemem.c
index 8f3069e18..253c601ff 100644
--- a/roms/ipxe/src/arch/i386/firmware/pcbios/hidemem.c
+++ b/roms/ipxe/src/arch/i386/firmware/pcbios/hidemem.c
@@ -14,9 +14,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <assert.h>
#include <realmode.h>
diff --git a/roms/ipxe/src/arch/i386/firmware/pcbios/memmap.c b/roms/ipxe/src/arch/i386/firmware/pcbios/memmap.c
index 0937a7ce2..bcacecd6a 100644
--- a/roms/ipxe/src/arch/i386/firmware/pcbios/memmap.c
+++ b/roms/ipxe/src/arch/i386/firmware/pcbios/memmap.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <errno.h>
diff --git a/roms/ipxe/src/arch/i386/firmware/pcbios/pnpbios.c b/roms/ipxe/src/arch/i386/firmware/pcbios/pnpbios.c
index 5c74b0431..20ec35d75 100644
--- a/roms/ipxe/src/arch/i386/firmware/pcbios/pnpbios.c
+++ b/roms/ipxe/src/arch/i386/firmware/pcbios/pnpbios.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <string.h>
diff --git a/roms/ipxe/src/arch/i386/hci/commands/pxe_cmd.c b/roms/ipxe/src/arch/i386/hci/commands/pxe_cmd.c
index 523724ab0..473b97f97 100644
--- a/roms/ipxe/src/arch/i386/hci/commands/pxe_cmd.c
+++ b/roms/ipxe/src/arch/i386/hci/commands/pxe_cmd.c
@@ -15,6 +15,10 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
#include <ipxe/netdevice.h>
@@ -23,7 +27,7 @@
#include <hci/ifmgmt_cmd.h>
#include <pxe_call.h>
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/arch/i386/image/bootsector.c b/roms/ipxe/src/arch/i386/image/bootsector.c
index 9a089e6bb..dba87613c 100644
--- a/roms/ipxe/src/arch/i386/image/bootsector.c
+++ b/roms/ipxe/src/arch/i386/image/bootsector.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @file
diff --git a/roms/ipxe/src/arch/i386/image/bzimage.c b/roms/ipxe/src/arch/i386/image/bzimage.c
index 4865c394c..a64206cd3 100644
--- a/roms/ipxe/src/arch/i386/image/bzimage.c
+++ b/roms/ipxe/src/arch/i386/image/bzimage.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @file
diff --git a/roms/ipxe/src/arch/i386/image/elfboot.c b/roms/ipxe/src/arch/i386/image/elfboot.c
index 0f6957f02..dc3568929 100644
--- a/roms/ipxe/src/arch/i386/image/elfboot.c
+++ b/roms/ipxe/src/arch/i386/image/elfboot.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <errno.h>
#include <elf.h>
@@ -75,6 +79,27 @@ static int elfboot_exec ( struct image *image ) {
}
/**
+ * Check that ELF segment uses flat physical addressing
+ *
+ * @v image ELF file
+ * @v phdr ELF program header
+ * @v dest Destination address
+ * @ret rc Return status code
+ */
+static int elfboot_check_segment ( struct image *image, Elf_Phdr *phdr,
+ physaddr_t dest ) {
+
+ /* Check that ELF segment uses flat physical addressing */
+ if ( phdr->p_vaddr != dest ) {
+ DBGC ( image, "ELF %p uses virtual addressing (phys %x, "
+ "virt %x)\n", image, phdr->p_paddr, phdr->p_vaddr );
+ return -ENOEXEC;
+ }
+
+ return 0;
+}
+
+/**
* Probe ELF image
*
* @v image ELF file
@@ -91,14 +116,24 @@ static int elfboot_probe ( struct image *image ) {
[EI_DATA] = ELFDATA2LSB,
[EI_VERSION] = EV_CURRENT,
};
+ physaddr_t entry;
+ physaddr_t max;
+ int rc;
/* Read ELF header */
copy_from_user ( &ehdr, image->data, 0, sizeof ( ehdr ) );
if ( memcmp ( ehdr.e_ident, e_ident, sizeof ( e_ident ) ) != 0 ) {
- DBG ( "Invalid ELF identifier\n" );
+ DBGC ( image, "Invalid ELF identifier\n" );
return -ENOEXEC;
}
+ /* Check that this image uses flat physical addressing */
+ if ( ( rc = elf_segments ( image, &ehdr, elfboot_check_segment,
+ &entry, &max ) ) != 0 ) {
+ DBGC ( image, "Unloadable ELF image\n" );
+ return rc;
+ }
+
return 0;
}
diff --git a/roms/ipxe/src/arch/i386/image/initrd.c b/roms/ipxe/src/arch/i386/image/initrd.c
index eaba3a645..80c197417 100644
--- a/roms/ipxe/src/arch/i386/image/initrd.c
+++ b/roms/ipxe/src/arch/i386/image/initrd.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <errno.h>
#include <initrd.h>
diff --git a/roms/ipxe/src/arch/i386/image/multiboot.c b/roms/ipxe/src/arch/i386/image/multiboot.c
index 86b0bc12d..0c85df708 100644
--- a/roms/ipxe/src/arch/i386/image/multiboot.c
+++ b/roms/ipxe/src/arch/i386/image/multiboot.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @file
diff --git a/roms/ipxe/src/arch/i386/image/pxe_image.c b/roms/ipxe/src/arch/i386/image/pxe_image.c
index dc28f6082..5b0f6eb89 100644
--- a/roms/ipxe/src/arch/i386/image/pxe_image.c
+++ b/roms/ipxe/src/arch/i386/image/pxe_image.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @file
@@ -34,6 +38,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/netdevice.h>
#include <ipxe/features.h>
#include <ipxe/console.h>
+#include <ipxe/efi/efi.h>
+#include <ipxe/efi/IndustryStandard/PeImage.h>
FEATURE ( FEATURE_IMAGE, "PXE", DHCP_EB_FEATURE_PXE, 1 );
@@ -121,9 +127,45 @@ int pxe_probe ( struct image *image ) {
return 0;
}
+/**
+ * Probe PXE image (with rejection of potential EFI images)
+ *
+ * @v image PXE file
+ * @ret rc Return status code
+ */
+int pxe_probe_no_mz ( struct image *image ) {
+ uint16_t magic;
+ int rc;
+
+ /* Probe PXE image */
+ if ( ( rc = pxe_probe ( image ) ) != 0 )
+ return rc;
+
+ /* Reject image with an "MZ" signature which may indicate an
+ * EFI image incorrectly handed out to a BIOS system.
+ */
+ if ( image->len >= sizeof ( magic ) ) {
+ copy_from_user ( &magic, image->data, 0, sizeof ( magic ) );
+ if ( magic == cpu_to_le16 ( EFI_IMAGE_DOS_SIGNATURE ) ) {
+ DBGC ( image, "IMAGE %p may be an EFI image\n",
+ image );
+ return -ENOTTY;
+ }
+ }
+
+ return 0;
+}
+
/** PXE image type */
-struct image_type pxe_image_type __image_type ( PROBE_PXE ) = {
- .name = "PXE",
- .probe = pxe_probe,
- .exec = pxe_exec,
+struct image_type pxe_image_type[] __image_type ( PROBE_PXE ) = {
+ {
+ .name = "PXE-NBP",
+ .probe = pxe_probe_no_mz,
+ .exec = pxe_exec,
+ },
+ {
+ .name = "PXE-NBP (may be EFI?)",
+ .probe = pxe_probe,
+ .exec = pxe_exec,
+ },
};
diff --git a/roms/ipxe/src/arch/i386/image/sdi.c b/roms/ipxe/src/arch/i386/image/sdi.c
index df1c3a868..fa2d0b73f 100644
--- a/roms/ipxe/src/arch/i386/image/sdi.c
+++ b/roms/ipxe/src/arch/i386/image/sdi.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <string.h>
diff --git a/roms/ipxe/src/arch/i386/include/basemem.h b/roms/ipxe/src/arch/i386/include/basemem.h
index c477c7fe2..01c2ea917 100644
--- a/roms/ipxe/src/arch/i386/include/basemem.h
+++ b/roms/ipxe/src/arch/i386/include/basemem.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <realmode.h>
diff --git a/roms/ipxe/src/arch/i386/include/basemem_packet.h b/roms/ipxe/src/arch/i386/include/basemem_packet.h
index 3cb477671..def6dee31 100644
--- a/roms/ipxe/src/arch/i386/include/basemem_packet.h
+++ b/roms/ipxe/src/arch/i386/include/basemem_packet.h
@@ -1,7 +1,7 @@
#ifndef BASEMEM_PACKET_H
#define BASEMEM_PACKET_H
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <realmode.h>
diff --git a/roms/ipxe/src/arch/i386/include/bios.h b/roms/ipxe/src/arch/i386/include/bios.h
index 0754b1168..988bbc62b 100644
--- a/roms/ipxe/src/arch/i386/include/bios.h
+++ b/roms/ipxe/src/arch/i386/include/bios.h
@@ -1,7 +1,7 @@
#ifndef BIOS_H
#define BIOS_H
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define BDA_SEG 0x0040
#define BDA_EQUIPMENT_WORD 0x0010
diff --git a/roms/ipxe/src/arch/i386/include/biosint.h b/roms/ipxe/src/arch/i386/include/biosint.h
index ab466af3c..67d6a3811 100644
--- a/roms/ipxe/src/arch/i386/include/biosint.h
+++ b/roms/ipxe/src/arch/i386/include/biosint.h
@@ -6,7 +6,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <realmode.h>
diff --git a/roms/ipxe/src/arch/i386/include/bits/byteswap.h b/roms/ipxe/src/arch/i386/include/bits/byteswap.h
index 0d9cb967c..53b6a454d 100644
--- a/roms/ipxe/src/arch/i386/include/bits/byteswap.h
+++ b/roms/ipxe/src/arch/i386/include/bits/byteswap.h
@@ -9,7 +9,7 @@
#include <stdint.h>
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
static inline __attribute__ (( always_inline, const )) uint16_t
__bswap_variable_16 ( uint16_t x ) {
diff --git a/roms/ipxe/src/arch/i386/include/bits/compiler.h b/roms/ipxe/src/arch/i386/include/bits/compiler.h
index d48b4b385..87201135f 100644
--- a/roms/ipxe/src/arch/i386/include/bits/compiler.h
+++ b/roms/ipxe/src/arch/i386/include/bits/compiler.h
@@ -1,7 +1,10 @@
#ifndef _BITS_COMPILER_H
#define _BITS_COMPILER_H
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/** Dummy relocation type */
+#define RELOC_TYPE_NONE R_386_NONE
#ifndef ASSEMBLY
diff --git a/roms/ipxe/src/arch/i386/include/bits/endian.h b/roms/ipxe/src/arch/i386/include/bits/endian.h
deleted file mode 100644
index 841885424..000000000
--- a/roms/ipxe/src/arch/i386/include/bits/endian.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef ETHERBOOT_BITS_ENDIAN_H
-#define ETHERBOOT_BITS_ENDIAN_H
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#define __BYTE_ORDER __LITTLE_ENDIAN
-
-#endif /* ETHERBOOT_BITS_ENDIAN_H */
diff --git a/roms/ipxe/src/arch/i386/include/bits/entropy.h b/roms/ipxe/src/arch/i386/include/bits/entropy.h
index 6dcceec6d..bfeb5e3b5 100644
--- a/roms/ipxe/src/arch/i386/include/bits/entropy.h
+++ b/roms/ipxe/src/arch/i386/include/bits/entropy.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/rtc_entropy.h>
diff --git a/roms/ipxe/src/arch/i386/include/bits/hyperv.h b/roms/ipxe/src/arch/i386/include/bits/hyperv.h
new file mode 100644
index 000000000..3565c8a83
--- /dev/null
+++ b/roms/ipxe/src/arch/i386/include/bits/hyperv.h
@@ -0,0 +1,72 @@
+#ifndef _BITS_HYPERV_H
+#define _BITS_HYPERV_H
+
+/** @file
+ *
+ * Hyper-V interface
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stddef.h>
+#include <stdint.h>
+#include <ipxe/io.h>
+
+/**
+ * Issue hypercall
+ *
+ * @v hv Hyper-V hypervisor
+ * @v code Call code
+ * @v in Input parameters
+ * @v out Output parameters
+ * @ret status Status code
+ */
+static inline __attribute__ (( always_inline )) int
+hv_call ( struct hv_hypervisor *hv, unsigned int code, const void *in,
+ void *out ) {
+ void *hypercall = hv->hypercall;
+ uint32_t in_phys;
+ uint32_t out_phys;
+ uint32_t discard_ecx;
+ uint32_t discard_edx;
+ uint16_t result;
+
+ in_phys = ( ( __builtin_constant_p ( in ) && ( in == NULL ) )
+ ? 0 : virt_to_phys ( in ) );
+ out_phys = ( ( __builtin_constant_p ( out ) && ( out == NULL ) )
+ ? 0 : virt_to_phys ( out ) );
+ __asm__ __volatile__ ( "call *%9"
+ : "=a" ( result ), "=c" ( discard_ecx ),
+ "=d" ( discard_edx )
+ : "d" ( 0 ), "a" ( code ),
+ "b" ( 0 ), "c" ( in_phys ),
+ "D" ( 0 ), "S" ( out_phys ),
+ "m" ( hypercall ) );
+ return result;
+}
+
+/**
+ * Set bit atomically
+ *
+ * @v bits Bit field
+ * @v bit Bit to set
+ */
+static inline __attribute__ (( always_inline )) void
+hv_set_bit ( void *bits, unsigned int bit ) {
+ struct {
+ uint32_t dword[ ( bit / 32 ) + 1 ];
+ } *dwords = bits;
+
+ /* Set bit using "lock bts". Inform compiler that any memory
+ * from the start of the bit field up to and including the
+ * dword containing this bit may be modified. (This is
+ * overkill but shouldn't matter in practice since we're
+ * unlikely to subsequently read other bits from the same bit
+ * field.)
+ */
+ __asm__ __volatile__ ( "lock bts %1, %0"
+ : "+m" ( *dwords ) : "Ir" ( bit ) );
+}
+
+#endif /* _BITS_HYPERV_H */
diff --git a/roms/ipxe/src/arch/i386/include/bits/nap.h b/roms/ipxe/src/arch/i386/include/bits/nap.h
index 64066e6ab..e8bcfd13b 100644
--- a/roms/ipxe/src/arch/i386/include/bits/nap.h
+++ b/roms/ipxe/src/arch/i386/include/bits/nap.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/bios_nap.h>
#include <ipxe/efi/efix86_nap.h>
diff --git a/roms/ipxe/src/arch/i386/include/bits/profile.h b/roms/ipxe/src/arch/i386/include/bits/profile.h
index f3ee54ae9..e184d7b51 100644
--- a/roms/ipxe/src/arch/i386/include/bits/profile.h
+++ b/roms/ipxe/src/arch/i386/include/bits/profile.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
diff --git a/roms/ipxe/src/arch/i386/include/bits/reboot.h b/roms/ipxe/src/arch/i386/include/bits/reboot.h
index 5b09e95f7..803dacfe4 100644
--- a/roms/ipxe/src/arch/i386/include/bits/reboot.h
+++ b/roms/ipxe/src/arch/i386/include/bits/reboot.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/bios_reboot.h>
diff --git a/roms/ipxe/src/arch/i386/include/bits/sanboot.h b/roms/ipxe/src/arch/i386/include/bits/sanboot.h
index 9c77a4d42..f02d2e649 100644
--- a/roms/ipxe/src/arch/i386/include/bits/sanboot.h
+++ b/roms/ipxe/src/arch/i386/include/bits/sanboot.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/bios_sanboot.h>
diff --git a/roms/ipxe/src/arch/i386/include/bits/smbios.h b/roms/ipxe/src/arch/i386/include/bits/smbios.h
index cc79eec51..2ab31e74b 100644
--- a/roms/ipxe/src/arch/i386/include/bits/smbios.h
+++ b/roms/ipxe/src/arch/i386/include/bits/smbios.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/bios_smbios.h>
diff --git a/roms/ipxe/src/arch/i386/include/bits/stdint.h b/roms/ipxe/src/arch/i386/include/bits/stdint.h
index 8edf13192..fe1f9946a 100644
--- a/roms/ipxe/src/arch/i386/include/bits/stdint.h
+++ b/roms/ipxe/src/arch/i386/include/bits/stdint.h
@@ -1,7 +1,7 @@
#ifndef _BITS_STDINT_H
#define _BITS_STDINT_H
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
typedef __SIZE_TYPE__ size_t;
typedef signed long ssize_t;
diff --git a/roms/ipxe/src/arch/i386/include/bits/strings.h b/roms/ipxe/src/arch/i386/include/bits/strings.h
index 092bcb593..453545f00 100644
--- a/roms/ipxe/src/arch/i386/include/bits/strings.h
+++ b/roms/ipxe/src/arch/i386/include/bits/strings.h
@@ -1,7 +1,51 @@
#ifndef _BITS_STRINGS_H
#define _BITS_STRINGS_H
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/**
+ * Find first (i.e. least significant) set bit
+ *
+ * @v value Value
+ * @ret lsb Least significant bit set in value (LSB=1), or zero
+ */
+static inline __attribute__ (( always_inline )) int __ffsl ( long value ) {
+ long lsb_minus_one;
+
+ /* If the input value is zero, the BSF instruction returns
+ * ZF=0 and leaves an undefined value in the output register.
+ * Perform this check in C rather than asm so that it can be
+ * omitted in cases where the compiler is able to prove that
+ * the input is non-zero.
+ */
+ if ( value ) {
+ __asm__ ( "bsfl %1, %0"
+ : "=r" ( lsb_minus_one )
+ : "rm" ( value ) );
+ return ( lsb_minus_one + 1 );
+ } else {
+ return 0;
+ }
+}
+
+/**
+ * Find first (i.e. least significant) set bit
+ *
+ * @v value Value
+ * @ret lsb Least significant bit set in value (LSB=1), or zero
+ */
+static inline __attribute__ (( always_inline )) int __ffsll ( long long value ){
+ unsigned long high = ( value >> 32 );
+ unsigned long low = ( value >> 0 );
+
+ if ( low ) {
+ return ( __ffsl ( low ) );
+ } else if ( high ) {
+ return ( 32 + __ffsl ( high ) );
+ } else {
+ return 0;
+ }
+}
/**
* Find last (i.e. most significant) set bit
@@ -13,7 +57,7 @@ static inline __attribute__ (( always_inline )) int __flsl ( long value ) {
long msb_minus_one;
/* If the input value is zero, the BSR instruction returns
- * ZF=1 and leaves an undefined value in the output register.
+ * ZF=0 and leaves an undefined value in the output register.
* Perform this check in C rather than asm so that it can be
* omitted in cases where the compiler is able to prove that
* the input is non-zero.
diff --git a/roms/ipxe/src/arch/i386/include/bits/time.h b/roms/ipxe/src/arch/i386/include/bits/time.h
index 24dd020e9..6a5d63d32 100644
--- a/roms/ipxe/src/arch/i386/include/bits/time.h
+++ b/roms/ipxe/src/arch/i386/include/bits/time.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/rtc_time.h>
diff --git a/roms/ipxe/src/arch/i386/include/bits/timer.h b/roms/ipxe/src/arch/i386/include/bits/timer.h
index 50b676b77..f7d86d78c 100644
--- a/roms/ipxe/src/arch/i386/include/bits/timer.h
+++ b/roms/ipxe/src/arch/i386/include/bits/timer.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/bios_timer.h>
#include <ipxe/rdtsc_timer.h>
diff --git a/roms/ipxe/src/arch/i386/include/bits/uaccess.h b/roms/ipxe/src/arch/i386/include/bits/uaccess.h
index 2bb52e021..aac09ba95 100644
--- a/roms/ipxe/src/arch/i386/include/bits/uaccess.h
+++ b/roms/ipxe/src/arch/i386/include/bits/uaccess.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <librm.h>
diff --git a/roms/ipxe/src/arch/i386/include/bits/umalloc.h b/roms/ipxe/src/arch/i386/include/bits/umalloc.h
index 54fb006f0..113f16fd1 100644
--- a/roms/ipxe/src/arch/i386/include/bits/umalloc.h
+++ b/roms/ipxe/src/arch/i386/include/bits/umalloc.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/memtop_umalloc.h>
diff --git a/roms/ipxe/src/arch/i386/include/bootsector.h b/roms/ipxe/src/arch/i386/include/bootsector.h
index 8730fbfcc..c5d35aae3 100644
--- a/roms/ipxe/src/arch/i386/include/bootsector.h
+++ b/roms/ipxe/src/arch/i386/include/bootsector.h
@@ -6,7 +6,7 @@
* x86 bootsector image format
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
extern int call_bootsector ( unsigned int segment, unsigned int offset,
unsigned int drive );
diff --git a/roms/ipxe/src/arch/i386/include/bzimage.h b/roms/ipxe/src/arch/i386/include/bzimage.h
index 7e42e3188..4933ce5b1 100644
--- a/roms/ipxe/src/arch/i386/include/bzimage.h
+++ b/roms/ipxe/src/arch/i386/include/bzimage.h
@@ -1,7 +1,7 @@
#ifndef _BZIMAGE_H
#define _BZIMAGE_H
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
diff --git a/roms/ipxe/src/arch/i386/include/efi/ipxe/dhcp_arch.h b/roms/ipxe/src/arch/i386/include/efi/ipxe/dhcp_arch.h
index 184177219..c17c1ea5e 100644
--- a/roms/ipxe/src/arch/i386/include/efi/ipxe/dhcp_arch.h
+++ b/roms/ipxe/src/arch/i386/include/efi/ipxe/dhcp_arch.h
@@ -4,7 +4,7 @@
* 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.
+ * 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
@@ -13,7 +13,12 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
#ifndef _DHCP_ARCH_H
@@ -24,7 +29,7 @@
* Architecture-specific DHCP options
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/dhcp.h>
diff --git a/roms/ipxe/src/arch/i386/include/fakee820.h b/roms/ipxe/src/arch/i386/include/fakee820.h
index 9d00fb670..552b1e48d 100644
--- a/roms/ipxe/src/arch/i386/include/fakee820.h
+++ b/roms/ipxe/src/arch/i386/include/fakee820.h
@@ -1,7 +1,7 @@
#ifndef _FAKEE820_H
#define _FAKEE820_H
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
extern void fake_e820 ( void );
extern void unfake_e820 ( void );
diff --git a/roms/ipxe/src/arch/i386/include/initrd.h b/roms/ipxe/src/arch/i386/include/initrd.h
index a5659f43c..ddb3e5a45 100644
--- a/roms/ipxe/src/arch/i386/include/initrd.h
+++ b/roms/ipxe/src/arch/i386/include/initrd.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/uaccess.h>
diff --git a/roms/ipxe/src/arch/i386/include/int13.h b/roms/ipxe/src/arch/i386/include/int13.h
index e337ca1d1..f82a583c6 100644
--- a/roms/ipxe/src/arch/i386/include/int13.h
+++ b/roms/ipxe/src/arch/i386/include/int13.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/list.h>
diff --git a/roms/ipxe/src/arch/i386/include/ipxe/bios_nap.h b/roms/ipxe/src/arch/i386/include/ipxe/bios_nap.h
index 5b684c041..c9b82c1e5 100644
--- a/roms/ipxe/src/arch/i386/include/ipxe/bios_nap.h
+++ b/roms/ipxe/src/arch/i386/include/ipxe/bios_nap.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifdef NAP_PCBIOS
#define NAP_PREFIX_pcbios
diff --git a/roms/ipxe/src/arch/i386/include/ipxe/bios_reboot.h b/roms/ipxe/src/arch/i386/include/ipxe/bios_reboot.h
index a0845328d..3f6df9073 100644
--- a/roms/ipxe/src/arch/i386/include/ipxe/bios_reboot.h
+++ b/roms/ipxe/src/arch/i386/include/ipxe/bios_reboot.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifdef REBOOT_PCBIOS
#define REBOOT_PREFIX_pcbios
diff --git a/roms/ipxe/src/arch/i386/include/ipxe/bios_sanboot.h b/roms/ipxe/src/arch/i386/include/ipxe/bios_sanboot.h
index 689227b70..1a86b7d57 100644
--- a/roms/ipxe/src/arch/i386/include/ipxe/bios_sanboot.h
+++ b/roms/ipxe/src/arch/i386/include/ipxe/bios_sanboot.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifdef SANBOOT_PCBIOS
#define SANBOOT_PREFIX_pcbios
diff --git a/roms/ipxe/src/arch/i386/include/ipxe/bios_smbios.h b/roms/ipxe/src/arch/i386/include/ipxe/bios_smbios.h
index d8c7f648a..9f7f9c8ff 100644
--- a/roms/ipxe/src/arch/i386/include/ipxe/bios_smbios.h
+++ b/roms/ipxe/src/arch/i386/include/ipxe/bios_smbios.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifdef SMBIOS_PCBIOS
#define SMBIOS_PREFIX_pcbios
diff --git a/roms/ipxe/src/arch/i386/include/ipxe/bios_timer.h b/roms/ipxe/src/arch/i386/include/ipxe/bios_timer.h
index f9fc80412..6b88a623c 100644
--- a/roms/ipxe/src/arch/i386/include/ipxe/bios_timer.h
+++ b/roms/ipxe/src/arch/i386/include/ipxe/bios_timer.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifdef TIMER_PCBIOS
#define TIMER_PREFIX_pcbios
@@ -15,7 +15,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define TIMER_PREFIX_pcbios __pcbios_
#endif
-#include <ipxe/timer2.h>
+#include <ipxe/pit8254.h>
/**
* Delay for a fixed number of microseconds
@@ -25,9 +25,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
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
+ * we use the 8254 Programmable Interval Timer.
*/
- timer2_udelay ( usecs );
+ pit8254_udelay ( usecs );
}
/**
diff --git a/roms/ipxe/src/arch/i386/include/ipxe/errno/pcbios.h b/roms/ipxe/src/arch/i386/include/ipxe/errno/pcbios.h
index 3a9eb2495..6312adaa4 100644
--- a/roms/ipxe/src/arch/i386/include/ipxe/errno/pcbios.h
+++ b/roms/ipxe/src/arch/i386/include/ipxe/errno/pcbios.h
@@ -10,7 +10,7 @@
* for the PC-BIOS platform.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <pxe_error.h>
diff --git a/roms/ipxe/src/arch/i386/include/ipxe/guestrpc.h b/roms/ipxe/src/arch/i386/include/ipxe/guestrpc.h
index 72a0f714f..bc3d85506 100644
--- a/roms/ipxe/src/arch/i386/include/ipxe/guestrpc.h
+++ b/roms/ipxe/src/arch/i386/include/ipxe/guestrpc.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/vmware.h>
diff --git a/roms/ipxe/src/arch/i386/include/ipxe/memtop_umalloc.h b/roms/ipxe/src/arch/i386/include/ipxe/memtop_umalloc.h
index 001648fe5..dee055d16 100644
--- a/roms/ipxe/src/arch/i386/include/ipxe/memtop_umalloc.h
+++ b/roms/ipxe/src/arch/i386/include/ipxe/memtop_umalloc.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifdef UMALLOC_MEMTOP
#define UMALLOC_PREFIX_memtop
diff --git a/roms/ipxe/src/arch/i386/include/ipxe/msr.h b/roms/ipxe/src/arch/i386/include/ipxe/msr.h
index c88e26a39..5705318fd 100644
--- a/roms/ipxe/src/arch/i386/include/ipxe/msr.h
+++ b/roms/ipxe/src/arch/i386/include/ipxe/msr.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* Read model-specific register
diff --git a/roms/ipxe/src/arch/i386/include/ipxe/rdtsc_timer.h b/roms/ipxe/src/arch/i386/include/ipxe/rdtsc_timer.h
index 472e14007..598f4bb08 100644
--- a/roms/ipxe/src/arch/i386/include/ipxe/rdtsc_timer.h
+++ b/roms/ipxe/src/arch/i386/include/ipxe/rdtsc_timer.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifdef TIMER_RDTSC
#define TIMER_PREFIX_rdtsc
diff --git a/roms/ipxe/src/arch/i386/include/ipxe/rtc_entropy.h b/roms/ipxe/src/arch/i386/include/ipxe/rtc_entropy.h
index 6c3cf2104..e214745d0 100644
--- a/roms/ipxe/src/arch/i386/include/ipxe/rtc_entropy.h
+++ b/roms/ipxe/src/arch/i386/include/ipxe/rtc_entropy.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
diff --git a/roms/ipxe/src/arch/i386/include/ipxe/rtc_time.h b/roms/ipxe/src/arch/i386/include/ipxe/rtc_time.h
index c0dfe3f88..cb8c7f49e 100644
--- a/roms/ipxe/src/arch/i386/include/ipxe/rtc_time.h
+++ b/roms/ipxe/src/arch/i386/include/ipxe/rtc_time.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifdef TIME_RTC
#define TIME_PREFIX_rtc
diff --git a/roms/ipxe/src/arch/i386/include/ipxe/timer2.h b/roms/ipxe/src/arch/i386/include/ipxe/timer2.h
deleted file mode 100644
index 322a3ed59..000000000
--- a/roms/ipxe/src/arch/i386/include/ipxe/timer2.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef _IPXE_TIMER2_H
-#define _IPXE_TIMER2_H
-
-/** @file
- *
- * Timer chip control
- *
- */
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-extern void timer2_udelay ( unsigned long usecs );
-
-#endif /* _IPXE_TIMER2_H */
diff --git a/roms/ipxe/src/arch/i386/include/ipxe/vesafb.h b/roms/ipxe/src/arch/i386/include/ipxe/vesafb.h
index 48cd6a7b7..efc8f2cb8 100644
--- a/roms/ipxe/src/arch/i386/include/ipxe/vesafb.h
+++ b/roms/ipxe/src/arch/i386/include/ipxe/vesafb.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <realmode.h>
diff --git a/roms/ipxe/src/arch/i386/include/ipxe/vmware.h b/roms/ipxe/src/arch/i386/include/ipxe/vmware.h
index 2ac65f436..24f60a03a 100644
--- a/roms/ipxe/src/arch/i386/include/ipxe/vmware.h
+++ b/roms/ipxe/src/arch/i386/include/ipxe/vmware.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
diff --git a/roms/ipxe/src/arch/i386/include/librm.h b/roms/ipxe/src/arch/i386/include/librm.h
index c8ba72b53..a8a578a39 100644
--- a/roms/ipxe/src/arch/i386/include/librm.h
+++ b/roms/ipxe/src/arch/i386/include/librm.h
@@ -1,7 +1,7 @@
#ifndef LIBRM_H
#define LIBRM_H
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/* Segment selectors as used in our protected-mode GDTs.
*
@@ -170,18 +170,6 @@ extern uint16_t __text16 ( rm_cs );
extern uint16_t __text16 ( rm_ds );
#define rm_ds __use_text16 ( rm_ds )
-/**
- * Convert segment:offset address to user buffer
- *
- * @v segment Real-mode segment
- * @v offset Real-mode offset
- * @ret buffer User buffer
- */
-static inline __always_inline userptr_t
-real_to_user ( unsigned int segment, unsigned int offset ) {
- return ( phys_to_user ( ( segment << 4 ) + offset ) );
-}
-
extern uint16_t copy_user_to_rm_stack ( userptr_t data, size_t size );
extern void remove_user_from_rm_stack ( userptr_t data, size_t size );
diff --git a/roms/ipxe/src/arch/i386/include/limits.h b/roms/ipxe/src/arch/i386/include/limits.h
index 031b6c57a..bb48b75ab 100644
--- a/roms/ipxe/src/arch/i386/include/limits.h
+++ b/roms/ipxe/src/arch/i386/include/limits.h
@@ -1,7 +1,7 @@
#ifndef LIMITS_H
#define LIMITS_H 1
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/* Number of bits in a `char' */
#define CHAR_BIT 8
diff --git a/roms/ipxe/src/arch/i386/include/memsizes.h b/roms/ipxe/src/arch/i386/include/memsizes.h
index 7b217494a..f115f7574 100644
--- a/roms/ipxe/src/arch/i386/include/memsizes.h
+++ b/roms/ipxe/src/arch/i386/include/memsizes.h
@@ -1,7 +1,7 @@
#ifndef _MEMSIZES_H
#define _MEMSIZES_H
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <basemem.h>
diff --git a/roms/ipxe/src/arch/i386/include/multiboot.h b/roms/ipxe/src/arch/i386/include/multiboot.h
index 44614c73a..ae09df6c7 100644
--- a/roms/ipxe/src/arch/i386/include/multiboot.h
+++ b/roms/ipxe/src/arch/i386/include/multiboot.h
@@ -8,7 +8,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
diff --git a/roms/ipxe/src/arch/i386/include/pcbios/ipxe/dhcp_arch.h b/roms/ipxe/src/arch/i386/include/pcbios/ipxe/dhcp_arch.h
index a36d9cfa1..e07e4c192 100644
--- a/roms/ipxe/src/arch/i386/include/pcbios/ipxe/dhcp_arch.h
+++ b/roms/ipxe/src/arch/i386/include/pcbios/ipxe/dhcp_arch.h
@@ -4,7 +4,7 @@
* 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.
+ * 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
@@ -13,7 +13,12 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
#ifndef _DHCP_ARCH_H
@@ -24,7 +29,7 @@
* Architecture-specific DHCP options
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/dhcp.h>
diff --git a/roms/ipxe/src/arch/i386/include/pnpbios.h b/roms/ipxe/src/arch/i386/include/pnpbios.h
index 4c20e73ed..d14873700 100644
--- a/roms/ipxe/src/arch/i386/include/pnpbios.h
+++ b/roms/ipxe/src/arch/i386/include/pnpbios.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/* BIOS segment address */
#define BIOS_SEG 0xf000
diff --git a/roms/ipxe/src/arch/i386/include/pxe.h b/roms/ipxe/src/arch/i386/include/pxe.h
index b95b0cce5..66d752683 100644
--- a/roms/ipxe/src/arch/i386/include/pxe.h
+++ b/roms/ipxe/src/arch/i386/include/pxe.h
@@ -1,7 +1,7 @@
#ifndef PXE_H
#define PXE_H
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include "pxe_types.h"
#include "pxe_error.h"
diff --git a/roms/ipxe/src/arch/i386/include/pxe_api.h b/roms/ipxe/src/arch/i386/include/pxe_api.h
index e4396efb2..3110d26da 100644
--- a/roms/ipxe/src/arch/i386/include/pxe_api.h
+++ b/roms/ipxe/src/arch/i386/include/pxe_api.h
@@ -17,6 +17,10 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ *
* As an alternative, at your option, you may use this file under the
* following terms, known as the "MIT license":
*
@@ -49,7 +53,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include "pxe_types.h"
diff --git a/roms/ipxe/src/arch/i386/include/pxe_call.h b/roms/ipxe/src/arch/i386/include/pxe_call.h
index 45af46549..cbd548318 100644
--- a/roms/ipxe/src/arch/i386/include/pxe_call.h
+++ b/roms/ipxe/src/arch/i386/include/pxe_call.h
@@ -6,7 +6,7 @@
* PXE API entry point
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <pxe_api.h>
#include <realmode.h>
diff --git a/roms/ipxe/src/arch/i386/include/pxe_error.h b/roms/ipxe/src/arch/i386/include/pxe_error.h
index a1398cbd4..51298e665 100644
--- a/roms/ipxe/src/arch/i386/include/pxe_error.h
+++ b/roms/ipxe/src/arch/i386/include/pxe_error.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @defgroup pxeerrors PXE error codes
diff --git a/roms/ipxe/src/arch/i386/include/pxe_types.h b/roms/ipxe/src/arch/i386/include/pxe_types.h
index db8214591..483666e33 100644
--- a/roms/ipxe/src/arch/i386/include/pxe_types.h
+++ b/roms/ipxe/src/arch/i386/include/pxe_types.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <errno.h> /* PXE status codes */
diff --git a/roms/ipxe/src/arch/i386/include/realmode.h b/roms/ipxe/src/arch/i386/include/realmode.h
index dafc5a32a..4defd3b97 100644
--- a/roms/ipxe/src/arch/i386/include/realmode.h
+++ b/roms/ipxe/src/arch/i386/include/realmode.h
@@ -10,7 +10,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/*
* Declaration of variables in .data16
@@ -65,6 +65,18 @@ FILE_LICENCE ( GPL2_OR_LATER );
*/
/**
+ * Convert segment:offset address to user buffer
+ *
+ * @v segment Real-mode segment
+ * @v offset Real-mode offset
+ * @ret buffer User buffer
+ */
+static inline __always_inline userptr_t
+real_to_user ( unsigned int segment, unsigned int offset ) {
+ return ( phys_to_user ( ( segment << 4 ) + offset ) );
+}
+
+/**
* Copy data to base memory
*
* @v dest_seg Destination segment
diff --git a/roms/ipxe/src/arch/i386/include/registers.h b/roms/ipxe/src/arch/i386/include/registers.h
index 06d236524..d9aa3c376 100644
--- a/roms/ipxe/src/arch/i386/include/registers.h
+++ b/roms/ipxe/src/arch/i386/include/registers.h
@@ -10,7 +10,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
diff --git a/roms/ipxe/src/arch/i386/include/rtc.h b/roms/ipxe/src/arch/i386/include/rtc.h
index 2a6abbae5..6294b63e3 100644
--- a/roms/ipxe/src/arch/i386/include/rtc.h
+++ b/roms/ipxe/src/arch/i386/include/rtc.h
@@ -13,7 +13,7 @@
* http://wiki.osdev.org/CMOS
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <pic8259.h>
diff --git a/roms/ipxe/src/arch/i386/include/sdi.h b/roms/ipxe/src/arch/i386/include/sdi.h
index fc486402d..806c3f194 100644
--- a/roms/ipxe/src/arch/i386/include/sdi.h
+++ b/roms/ipxe/src/arch/i386/include/sdi.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** SDI image header */
struct sdi_header {
diff --git a/roms/ipxe/src/arch/i386/include/setjmp.h b/roms/ipxe/src/arch/i386/include/setjmp.h
index 5d3c11b69..fe1a9ef4d 100644
--- a/roms/ipxe/src/arch/i386/include/setjmp.h
+++ b/roms/ipxe/src/arch/i386/include/setjmp.h
@@ -1,40 +1,50 @@
-#ifndef ETHERBOOT_SETJMP_H
-#define ETHERBOOT_SETJMP_H
+#ifndef _SETJMP_H
+#define _SETJMP_H
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <realmode.h>
/** A jump buffer */
typedef struct {
+ /** Saved return address */
uint32_t retaddr;
+ /** Saved stack pointer */
+ uint32_t stack;
+ /** Saved %ebx */
uint32_t ebx;
- uint32_t esp;
- uint32_t ebp;
+ /** Saved %esi */
uint32_t esi;
+ /** Saved %edi */
uint32_t edi;
+ /** Saved %ebp */
+ uint32_t ebp;
} jmp_buf[1];
/** A real-mode-extended jump buffer */
typedef struct {
+ /** Jump buffer */
jmp_buf env;
- uint16_t rm_ss;
- uint16_t rm_sp;
+ /** Real-mode stack pointer */
+ segoff_t rm_stack;
} rmjmp_buf[1];
-extern int __asmcall setjmp ( jmp_buf env );
-extern void __asmcall longjmp ( jmp_buf env, int val );
+extern int __asmcall __attribute__ (( returns_twice ))
+setjmp ( jmp_buf env );
+
+extern void __asmcall __attribute__ (( noreturn ))
+longjmp ( jmp_buf env, int val );
-#define rmsetjmp( _env ) ( { \
- (_env)->rm_ss = rm_ss; \
- (_env)->rm_sp = rm_sp; \
- setjmp ( (_env)->env ); } ) \
+#define rmsetjmp( _env ) ( { \
+ (_env)->rm_stack.segment = rm_ss; \
+ (_env)->rm_stack.offset = rm_sp; \
+ setjmp ( (_env)->env ); } ) \
-#define rmlongjmp( _env, _val ) do { \
- rm_ss = (_env)->rm_ss; \
- rm_sp = (_env)->rm_sp; \
- longjmp ( (_env)->env, (_val) ); \
+#define rmlongjmp( _env, _val ) do { \
+ rm_ss = (_env)->rm_stack.segment; \
+ rm_sp = (_env)->rm_stack.offset; \
+ longjmp ( (_env)->env, (_val) ); \
} while ( 0 )
-#endif /* ETHERBOOT_SETJMP_H */
+#endif /* _SETJMP_H */
diff --git a/roms/ipxe/src/arch/i386/include/undi.h b/roms/ipxe/src/arch/i386/include/undi.h
index 325fcbbf9..7a5624f93 100644
--- a/roms/ipxe/src/arch/i386/include/undi.h
+++ b/roms/ipxe/src/arch/i386/include/undi.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifndef ASSEMBLY
diff --git a/roms/ipxe/src/arch/i386/include/undiload.h b/roms/ipxe/src/arch/i386/include/undiload.h
index 426830e8d..235e7a79e 100644
--- a/roms/ipxe/src/arch/i386/include/undiload.h
+++ b/roms/ipxe/src/arch/i386/include/undiload.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
struct undi_device;
struct undi_rom;
diff --git a/roms/ipxe/src/arch/i386/include/undinet.h b/roms/ipxe/src/arch/i386/include/undinet.h
index c3c17c11a..2798c4466 100644
--- a/roms/ipxe/src/arch/i386/include/undinet.h
+++ b/roms/ipxe/src/arch/i386/include/undinet.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
struct undi_device;
diff --git a/roms/ipxe/src/arch/i386/include/undipreload.h b/roms/ipxe/src/arch/i386/include/undipreload.h
index de9b8fb52..57f493cec 100644
--- a/roms/ipxe/src/arch/i386/include/undipreload.h
+++ b/roms/ipxe/src/arch/i386/include/undipreload.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <realmode.h>
#include <undi.h>
diff --git a/roms/ipxe/src/arch/i386/include/undirom.h b/roms/ipxe/src/arch/i386/include/undirom.h
index 86d7077b5..1c530118d 100644
--- a/roms/ipxe/src/arch/i386/include/undirom.h
+++ b/roms/ipxe/src/arch/i386/include/undirom.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <pxe_types.h>
diff --git a/roms/ipxe/src/arch/i386/interface/pcbios/apm.c b/roms/ipxe/src/arch/i386/interface/pcbios/apm.c
index 3b13e1cd0..50b19cb81 100644
--- a/roms/ipxe/src/arch/i386/interface/pcbios/apm.c
+++ b/roms/ipxe/src/arch/i386/interface/pcbios/apm.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @file
diff --git a/roms/ipxe/src/arch/i386/interface/pcbios/bios_nap.c b/roms/ipxe/src/arch/i386/interface/pcbios/bios_nap.c
index 1e7de756b..f1ba8297b 100644
--- a/roms/ipxe/src/arch/i386/interface/pcbios/bios_nap.c
+++ b/roms/ipxe/src/arch/i386/interface/pcbios/bios_nap.c
@@ -1,7 +1,7 @@
#include <ipxe/nap.h>
#include <realmode.h>
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* Save power by halting the CPU until the next interrupt
diff --git a/roms/ipxe/src/arch/i386/interface/pcbios/bios_reboot.c b/roms/ipxe/src/arch/i386/interface/pcbios/bios_reboot.c
index 68546b2e5..10a1ecb89 100644
--- a/roms/ipxe/src/arch/i386/interface/pcbios/bios_reboot.c
+++ b/roms/ipxe/src/arch/i386/interface/pcbios/bios_reboot.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/arch/i386/interface/pcbios/bios_smbios.c b/roms/ipxe/src/arch/i386/interface/pcbios/bios_smbios.c
index dd7897e29..a8c0fc325 100644
--- a/roms/ipxe/src/arch/i386/interface/pcbios/bios_smbios.c
+++ b/roms/ipxe/src/arch/i386/interface/pcbios/bios_smbios.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <string.h>
diff --git a/roms/ipxe/src/arch/i386/interface/pcbios/bios_timer.c b/roms/ipxe/src/arch/i386/interface/pcbios/bios_timer.c
index 65bbf9e01..3299c9aae 100644
--- a/roms/ipxe/src/arch/i386/interface/pcbios/bios_timer.c
+++ b/roms/ipxe/src/arch/i386/interface/pcbios/bios_timer.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/arch/i386/interface/pcbios/biosint.c b/roms/ipxe/src/arch/i386/interface/pcbios/biosint.c
index a193defa3..3b8e80438 100644
--- a/roms/ipxe/src/arch/i386/interface/pcbios/biosint.c
+++ b/roms/ipxe/src/arch/i386/interface/pcbios/biosint.c
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* Hook INT vector
diff --git a/roms/ipxe/src/arch/i386/interface/pcbios/int13.c b/roms/ipxe/src/arch/i386/interface/pcbios/int13.c
index 1c7a8128f..f0450da90 100644
--- a/roms/ipxe/src/arch/i386/interface/pcbios/int13.c
+++ b/roms/ipxe/src/arch/i386/interface/pcbios/int13.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/arch/i386/interface/pcbios/int13con.c b/roms/ipxe/src/arch/i386/interface/pcbios/int13con.c
new file mode 100644
index 000000000..2414c6909
--- /dev/null
+++ b/roms/ipxe/src/arch/i386/interface/pcbios/int13con.c
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2015 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <ipxe/console.h>
+#include <ipxe/init.h>
+#include <realmode.h>
+#include <int13.h>
+#include <config/console.h>
+
+/** @file
+ *
+ * INT13 disk log console
+ *
+ */
+
+/* Set default console usage if applicable */
+#if ! ( defined ( CONSOLE_INT13 ) && CONSOLE_EXPLICIT ( CONSOLE_INT13 ) )
+#undef CONSOLE_INT13
+#define CONSOLE_INT13 ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_LOG )
+#endif
+
+/** Disk drive number */
+#define INT13CON_DRIVE 0x80
+
+/** Log partition type */
+#define INT13CON_PARTITION_TYPE 0xe0
+
+/** Maximum number of outstanding unwritten characters */
+#define INT13CON_MAX_UNWRITTEN 64
+
+/** Log partition header */
+struct int13con_header {
+ /** Magic signature */
+ char magic[10];
+} __attribute__ (( packed ));
+
+/** Log partition magic signature */
+#define INT13CON_MAGIC "iPXE LOG\n\n"
+
+/** Sector buffer */
+static uint8_t __bss16_array ( int13con_buffer, [INT13_BLKSIZE] );
+#define int13con_buffer __use_data16 ( int13con_buffer )
+
+/** Disk address packet */
+static struct int13_disk_address __bss16 ( int13con_address );
+#define int13con_address __use_data16 ( int13con_address )
+
+/** Current LBA */
+static uint64_t int13con_lba;
+
+/** Maximum LBA */
+static uint64_t int13con_max_lba;
+
+/** Current offset within sector */
+static size_t int13con_offset;
+
+/** Number of unwritten characters */
+static size_t int13con_unwritten;
+
+struct console_driver int13con __console_driver;
+
+/**
+ * Read/write disk sector
+ *
+ * @v op Operation
+ * @v lba Logical block address
+ * @ret rc Return status code
+ */
+static int int13con_rw ( unsigned int op, uint64_t lba ) {
+ uint8_t error;
+
+ /* Construct disk address packet */
+ int13con_address.bufsize = sizeof ( int13con_address );
+ int13con_address.count = 1;
+ int13con_address.buffer.segment = rm_ds;
+ int13con_address.buffer.offset = __from_data16 ( int13con_buffer );
+ int13con_address.lba = lba;
+
+ /* Issue INT13 */
+ __asm__ ( REAL_CODE ( "int $0x13\n\t" )
+ : "=a" ( error )
+ : "0" ( op << 8 ), "d" ( INT13CON_DRIVE ),
+ "S" ( __from_data16 ( &int13con_address ) ) );
+ if ( error ) {
+ DBG ( "INT13CON operation %04x failed: %02x\n",
+ op, error );
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/**
+ * Write character to console
+ *
+ * @v character Character
+ */
+static void int13con_putchar ( int character ) {
+ static int busy;
+ int rc;
+
+ /* Ignore if we are already mid-logging */
+ if ( busy )
+ return;
+ busy = 1;
+
+ /* Write character to buffer */
+ int13con_buffer[int13con_offset++] = character;
+ int13con_unwritten++;
+
+ /* Write sector to disk, if applicable */
+ if ( ( int13con_offset == INT13_BLKSIZE ) ||
+ ( int13con_unwritten == INT13CON_MAX_UNWRITTEN ) ||
+ ( character == '\n' ) ) {
+
+ /* Write sector to disk */
+ if ( ( rc = int13con_rw ( INT13_EXTENDED_WRITE,
+ int13con_lba ) ) != 0 ) {
+ DBG ( "INT13CON could not write log\n" );
+ /* Ignore and continue; there's nothing we can do */
+ }
+
+ /* Reset count of unwritten characters */
+ int13con_unwritten = 0;
+ }
+
+ /* Move to next sector, if applicable */
+ if ( int13con_offset == INT13_BLKSIZE ) {
+
+ /* Disable console if we have run out of space */
+ if ( int13con_lba >= int13con_max_lba )
+ int13con.disabled = 1;
+
+ /* Clear log buffer */
+ memset ( int13con_buffer, 0, sizeof ( int13con_buffer ) );
+ int13con_offset = 0;
+
+ /* Move to next sector */
+ int13con_lba++;
+ }
+
+ /* Clear busy flag */
+ busy = 0;
+}
+
+/**
+ * Find log partition
+ *
+ * @ret rc Return status code
+ */
+static int int13con_find ( void ) {
+ struct master_boot_record *mbr =
+ ( ( struct master_boot_record * ) int13con_buffer );
+ struct int13con_header *hdr =
+ ( ( struct int13con_header * ) int13con_buffer );
+ struct partition_table_entry part[4];
+ unsigned int i;
+ int rc;
+
+ /* Read MBR */
+ if ( ( rc = int13con_rw ( INT13_EXTENDED_READ, 0 ) ) != 0 ) {
+ DBG ( "INT13CON could not read MBR: %s\n", strerror ( rc ) );
+ return rc;
+ }
+
+ /* Check MBR magic */
+ if ( mbr->magic != INT13_MBR_MAGIC ) {
+ DBG ( "INT13CON incorrect MBR magic\n" );
+ DBG2_HDA ( 0, mbr, sizeof ( *mbr ) );
+ return -EINVAL;
+ }
+
+ /* Look for magic partition */
+ memcpy ( part, mbr->partitions, sizeof ( part ) );
+ for ( i = 0 ; i < ( sizeof ( part ) / sizeof ( part[0] ) ) ; i++ ) {
+
+ /* Skip partitions of the wrong type */
+ if ( part[i].type != INT13CON_PARTITION_TYPE )
+ continue;
+
+ /* Read partition header */
+ if ( ( rc = int13con_rw ( INT13_EXTENDED_READ,
+ part[i].start ) ) != 0 ) {
+ DBG ( "INT13CON partition %d could not read header: "
+ "%s\n", ( i + 1 ), strerror ( rc ) );
+ continue;
+ }
+
+ /* Check partition header */
+ if ( memcmp ( hdr->magic, INT13CON_MAGIC,
+ sizeof ( hdr->magic ) ) != 0 ) {
+ DBG ( "INT13CON partition %d bad magic\n", ( i + 1 ) );
+ DBG2_HDA ( 0, hdr, sizeof ( *hdr ) );
+ continue;
+ }
+
+ /* Found log partition */
+ DBG ( "INT13CON partition %d at [%08x,%08x)\n", ( i + 1 ),
+ part[i].start, ( part[i].start + part[i].length ) );
+ int13con_lba = part[i].start;
+ int13con_max_lba = ( part[i].start + part[i].length - 1 );
+
+ /* Initialise log buffer */
+ memset ( &int13con_buffer[ sizeof ( *hdr ) ], 0,
+ ( sizeof ( int13con_buffer ) - sizeof ( *hdr ) ) );
+ int13con_offset = sizeof ( hdr->magic );
+
+ return 0;
+ }
+
+ DBG ( "INT13CON found no log partition\n" );
+ return -ENOENT;
+}
+
+/**
+ * Initialise INT13 console
+ *
+ */
+static void int13con_init ( void ) {
+ uint8_t error;
+ uint16_t check;
+ unsigned int discard_c;
+ unsigned int discard_d;
+ int rc;
+
+ /* Check for INT13 extensions */
+ __asm__ __volatile__ ( REAL_CODE ( "int $0x13\n\t"
+ "setc %%al\n\t" )
+ : "=a" ( error ), "=b" ( check ),
+ "=c" ( discard_c ), "=d" ( discard_d )
+ : "0" ( INT13_EXTENSION_CHECK << 8 ),
+ "1" ( 0x55aa ), "3" ( INT13CON_DRIVE ) );
+ if ( error || ( check != 0xaa55 ) ) {
+ DBG ( "INT13CON missing extensions (%02x,%04x)\n",
+ error, check );
+ return;
+ }
+
+ /* Locate log partition */
+ if ( ( rc = int13con_find() ) != 0)
+ return;
+
+ /* Enable console */
+ int13con.disabled = 0;
+}
+
+/**
+ * INT13 console initialisation function
+ */
+struct init_fn int13con_init_fn __init_fn ( INIT_CONSOLE ) = {
+ .initialise = int13con_init,
+};
+
+/** INT13 console driver */
+struct console_driver int13con __console_driver = {
+ .putchar = int13con_putchar,
+ .disabled = CONSOLE_DISABLED,
+ .usage = CONSOLE_INT13,
+};
diff --git a/roms/ipxe/src/arch/i386/interface/pcbios/memtop_umalloc.c b/roms/ipxe/src/arch/i386/interface/pcbios/memtop_umalloc.c
index c382e3c36..957f8e324 100644
--- a/roms/ipxe/src/arch/i386/interface/pcbios/memtop_umalloc.c
+++ b/roms/ipxe/src/arch/i386/interface/pcbios/memtop_umalloc.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @file
diff --git a/roms/ipxe/src/arch/i386/interface/pcbios/pcibios.c b/roms/ipxe/src/arch/i386/interface/pcbios/pcibios.c
index 61873039f..34efa0b39 100644
--- a/roms/ipxe/src/arch/i386/interface/pcbios/pcibios.c
+++ b/roms/ipxe/src/arch/i386/interface/pcbios/pcibios.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/pci.h>
@@ -38,7 +42,11 @@ static int pcibios_num_bus ( void ) {
int discard_a, discard_D;
uint8_t max_bus;
- __asm__ __volatile__ ( REAL_CODE ( "stc\n\t"
+ /* We issue this call using flat real mode, to work around a
+ * bug in some HP BIOSes.
+ */
+ __asm__ __volatile__ ( REAL_CODE ( "call flatten_real_mode\n\t"
+ "stc\n\t"
"int $0x1a\n\t"
"jnc 1f\n\t"
"xorw %%cx, %%cx\n\t"
diff --git a/roms/ipxe/src/arch/i386/interface/pcbios/rtc_entropy.c b/roms/ipxe/src/arch/i386/interface/pcbios/rtc_entropy.c
index fad421c2a..9aab03c03 100644
--- a/roms/ipxe/src/arch/i386/interface/pcbios/rtc_entropy.c
+++ b/roms/ipxe/src/arch/i386/interface/pcbios/rtc_entropy.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/arch/i386/interface/pcbios/rtc_time.c b/roms/ipxe/src/arch/i386/interface/pcbios/rtc_time.c
index 67041d4ca..cdbeac8d5 100644
--- a/roms/ipxe/src/arch/i386/interface/pcbios/rtc_time.c
+++ b/roms/ipxe/src/arch/i386/interface/pcbios/rtc_time.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/arch/i386/interface/pcbios/vesafb.c b/roms/ipxe/src/arch/i386/interface/pcbios/vesafb.c
index 2adc7b040..9cf2bf29e 100644
--- a/roms/ipxe/src/arch/i386/interface/pcbios/vesafb.c
+++ b/roms/ipxe/src/arch/i386/interface/pcbios/vesafb.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/arch/i386/interface/pxe/pxe_call.c b/roms/ipxe/src/arch/i386/interface/pxe/pxe_call.c
index 657d47b6c..104313666 100644
--- a/roms/ipxe/src/arch/i386/interface/pxe/pxe_call.c
+++ b/roms/ipxe/src/arch/i386/interface/pxe/pxe_call.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/uaccess.h>
#include <ipxe/init.h>
@@ -342,6 +346,7 @@ int pxe_start_nbp ( void ) {
return 0;
}
+REQUIRING_SYMBOL ( pxe_api_call );
REQUIRE_OBJECT ( pxe_preboot );
REQUIRE_OBJECT ( pxe_undi );
REQUIRE_OBJECT ( pxe_udp );
diff --git a/roms/ipxe/src/arch/i386/interface/pxe/pxe_entry.S b/roms/ipxe/src/arch/i386/interface/pxe/pxe_entry.S
index 6274264ff..07852cd50 100644
--- a/roms/ipxe/src/arch/i386/interface/pxe/pxe_entry.S
+++ b/roms/ipxe/src/arch/i386/interface/pxe/pxe_entry.S
@@ -16,9 +16,13 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ *
*/
-FILE_LICENCE ( GPL2_OR_LATER )
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
.arch i386
diff --git a/roms/ipxe/src/arch/i386/interface/pxe/pxe_exit_hook.c b/roms/ipxe/src/arch/i386/interface/pxe/pxe_exit_hook.c
index 9d1896507..f92dae0d1 100644
--- a/roms/ipxe/src/arch/i386/interface/pxe/pxe_exit_hook.c
+++ b/roms/ipxe/src/arch/i386/interface/pxe/pxe_exit_hook.c
@@ -21,9 +21,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <realmode.h>
diff --git a/roms/ipxe/src/arch/i386/interface/pxe/pxe_file.c b/roms/ipxe/src/arch/i386/interface/pxe/pxe_file.c
index 6e9610294..456ffb5fd 100644
--- a/roms/ipxe/src/arch/i386/interface/pxe/pxe_file.c
+++ b/roms/ipxe/src/arch/i386/interface/pxe/pxe_file.c
@@ -31,9 +31,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
FEATURE ( FEATURE_MISC, "PXEXT", DHCP_EB_FEATURE_PXE_EXT, 2 );
diff --git a/roms/ipxe/src/arch/i386/interface/pxe/pxe_loader.c b/roms/ipxe/src/arch/i386/interface/pxe/pxe_loader.c
index 695af3b93..e6a2e072a 100644
--- a/roms/ipxe/src/arch/i386/interface/pxe/pxe_loader.c
+++ b/roms/ipxe/src/arch/i386/interface/pxe/pxe_loader.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/init.h>
#include "pxe.h"
diff --git a/roms/ipxe/src/arch/i386/interface/pxe/pxe_preboot.c b/roms/ipxe/src/arch/i386/interface/pxe/pxe_preboot.c
index 534352b2b..6e09080bc 100644
--- a/roms/ipxe/src/arch/i386/interface/pxe/pxe_preboot.c
+++ b/roms/ipxe/src/arch/i386/interface/pxe/pxe_preboot.c
@@ -22,9 +22,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <string.h>
@@ -174,18 +178,16 @@ pxenv_get_cached_info ( struct s_PXENV_GET_CACHED_INFO *get_cached_info ) {
}
info = &cached_info[idx];
- /* Construct cached version of packet, if not already constructed. */
- if ( ! info->dhcphdr.op ) {
- /* Construct DHCP packet */
- creator = &pxe_dhcp_packet_creators[idx];
- if ( ( rc = creator->create ( pxe_netdev, info,
- sizeof ( *info ) ) ) != 0 ) {
- DBGC ( &pxe_netdev, " failed to build packet: %s\n",
- strerror ( rc ) );
- goto err;
- }
+ /* Construct DHCP packet */
+ creator = &pxe_dhcp_packet_creators[idx];
+ if ( ( rc = creator->create ( pxe_netdev, info,
+ sizeof ( *info ) ) ) != 0 ) {
+ DBGC ( &pxe_netdev, " failed to build packet: %s\n",
+ strerror ( rc ) );
+ goto err;
}
+ /* Copy packet (if applicable) */
len = get_cached_info->BufferSize;
if ( len == 0 ) {
/* Point client at our cached buffer.
diff --git a/roms/ipxe/src/arch/i386/interface/pxe/pxe_tftp.c b/roms/ipxe/src/arch/i386/interface/pxe/pxe_tftp.c
index f4801bad0..068d8a7b2 100644
--- a/roms/ipxe/src/arch/i386/interface/pxe/pxe_tftp.c
+++ b/roms/ipxe/src/arch/i386/interface/pxe/pxe_tftp.c
@@ -21,9 +21,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdlib.h>
#include <stdio.h>
@@ -36,6 +40,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/xfer.h>
#include <ipxe/open.h>
#include <ipxe/process.h>
+#include <ipxe/uri.h>
+#include <realmode.h>
#include <pxe.h>
/** A PXE TFTP connection */
@@ -170,11 +176,10 @@ static struct pxe_tftp_connection pxe_tftp = {
* @v blksize Requested block size
* @ret rc Return status code
*/
-static int pxe_tftp_open ( uint32_t ipaddress, unsigned int port,
- const unsigned char *filename, size_t blksize,
- int sizeonly ) {
- char uri_string[PXE_TFTP_URI_LEN];
+static int pxe_tftp_open ( IP4_t ipaddress, UDP_PORT_t port,
+ UINT8_t *filename, UINT16_t blksize ) {
struct in_addr address;
+ struct uri *uri;
int rc;
/* Reset PXE TFTP connection structure */
@@ -185,19 +190,20 @@ static int pxe_tftp_open ( uint32_t ipaddress, unsigned int port,
pxe_tftp.blksize = blksize;
pxe_tftp.rc = -EINPROGRESS;
- /* Construct URI string */
+ /* Construct URI */
address.s_addr = ipaddress;
- if ( ! port )
- port = htons ( TFTP_PORT );
- snprintf ( uri_string, sizeof ( uri_string ), "tftp%s://%s:%d%s%s",
- sizeonly ? "size" : "", inet_ntoa ( address ),
- ntohs ( port ), ( ( filename[0] == '/' ) ? "" : "/" ),
- filename );
- DBG ( " %s", uri_string );
+ DBG ( " %s", inet_ntoa ( address ) );
+ if ( port )
+ DBG ( ":%d", ntohs ( port ) );
+ DBG ( ":%s", filename );
+ uri = tftp_uri ( address, ntohs ( port ), ( ( char * ) filename ) );
+ if ( ! uri ) {
+ DBG ( " could not create URI\n" );
+ return -ENOMEM;
+ }
/* Open PXE TFTP connection */
- if ( ( rc = xfer_open_uri_string ( &pxe_tftp.xfer,
- uri_string ) ) != 0 ) {
+ if ( ( rc = xfer_open_uri ( &pxe_tftp.xfer, uri ) ) != 0 ) {
DBG ( " could not open (%s)\n", strerror ( rc ) );
return rc;
}
@@ -259,8 +265,7 @@ static PXENV_EXIT_t pxenv_tftp_open ( struct s_PXENV_TFTP_OPEN *tftp_open ) {
if ( ( rc = pxe_tftp_open ( tftp_open->ServerIPAddress,
tftp_open->TFTPPort,
tftp_open->FileName,
- tftp_open->PacketSize,
- 0) ) != 0 ) {
+ tftp_open->PacketSize ) ) != 0 ) {
tftp_open->Status = PXENV_STATUS ( rc );
return PXENV_EXIT_FAILURE;
}
@@ -483,7 +488,7 @@ PXENV_EXIT_t pxenv_tftp_read_file ( struct s_PXENV_TFTP_READ_FILE
/* Open TFTP file */
if ( ( rc = pxe_tftp_open ( tftp_read_file->ServerIPAddress, 0,
- tftp_read_file->FileName, 0, 0 ) ) != 0 ) {
+ tftp_read_file->FileName, 0 ) ) != 0 ) {
tftp_read_file->Status = PXENV_STATUS ( rc );
return PXENV_EXIT_FAILURE;
}
@@ -553,7 +558,7 @@ static PXENV_EXIT_t pxenv_tftp_get_fsize ( struct s_PXENV_TFTP_GET_FSIZE
/* Open TFTP file */
if ( ( rc = pxe_tftp_open ( tftp_get_fsize->ServerIPAddress, 0,
- tftp_get_fsize->FileName, 0, 1 ) ) != 0 ) {
+ tftp_get_fsize->FileName, 0 ) ) != 0 ) {
tftp_get_fsize->Status = PXENV_STATUS ( rc );
return PXENV_EXIT_FAILURE;
}
diff --git a/roms/ipxe/src/arch/i386/interface/pxe/pxe_udp.c b/roms/ipxe/src/arch/i386/interface/pxe/pxe_udp.c
index 32bc39c8e..071cb59db 100644
--- a/roms/ipxe/src/arch/i386/interface/pxe/pxe_udp.c
+++ b/roms/ipxe/src/arch/i386/interface/pxe/pxe_udp.c
@@ -11,6 +11,7 @@
#include <ipxe/udp.h>
#include <ipxe/uaccess.h>
#include <ipxe/process.h>
+#include <realmode.h>
#include <pxe.h>
/*
@@ -30,9 +31,25 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/** A PXE UDP pseudo-header */
+struct pxe_udp_pseudo_header {
+ /** Source IP address */
+ IP4_t src_ip;
+ /** Source port */
+ UDP_PORT_t s_port;
+ /** Destination IP address */
+ IP4_t dest_ip;
+ /** Destination port */
+ UDP_PORT_t d_port;
+} __attribute__ (( packed ));
/** A PXE UDP connection */
struct pxe_udp_connection {
@@ -40,8 +57,8 @@ struct pxe_udp_connection {
struct interface xfer;
/** Local address */
struct sockaddr_in local;
- /** Current PXENV_UDP_READ parameter block */
- struct s_PXENV_UDP_READ *pxenv_udp_read;
+ /** List of received packets */
+ struct list_head list;
};
/**
@@ -58,45 +75,38 @@ struct pxe_udp_connection {
static int pxe_udp_deliver ( struct pxe_udp_connection *pxe_udp,
struct io_buffer *iobuf,
struct xfer_metadata *meta ) {
- struct s_PXENV_UDP_READ *pxenv_udp_read = pxe_udp->pxenv_udp_read;
+ struct pxe_udp_pseudo_header *pshdr;
struct sockaddr_in *sin_src;
struct sockaddr_in *sin_dest;
- userptr_t buffer;
- size_t len;
- int rc = 0;
-
- if ( ! pxenv_udp_read ) {
- DBG ( "PXE discarded UDP packet\n" );
- rc = -ENOBUFS;
- goto done;
- }
-
- /* Copy packet to buffer and record length */
- buffer = real_to_user ( pxenv_udp_read->buffer.segment,
- pxenv_udp_read->buffer.offset );
- len = iob_len ( iobuf );
- if ( len > pxenv_udp_read->buffer_size )
- len = pxenv_udp_read->buffer_size;
- copy_to_user ( buffer, 0, iobuf->data, len );
- pxenv_udp_read->buffer_size = len;
+ int rc;
- /* Fill in source/dest information */
+ /* Extract metadata */
assert ( meta );
sin_src = ( struct sockaddr_in * ) meta->src;
assert ( sin_src );
assert ( sin_src->sin_family == AF_INET );
- pxenv_udp_read->src_ip = sin_src->sin_addr.s_addr;
- pxenv_udp_read->s_port = sin_src->sin_port;
sin_dest = ( struct sockaddr_in * ) meta->dest;
assert ( sin_dest );
assert ( sin_dest->sin_family == AF_INET );
- pxenv_udp_read->dest_ip = sin_dest->sin_addr.s_addr;
- pxenv_udp_read->d_port = sin_dest->sin_port;
- /* Mark as received */
- pxe_udp->pxenv_udp_read = NULL;
+ /* Construct pseudo-header */
+ if ( ( rc = iob_ensure_headroom ( iobuf, sizeof ( *pshdr ) ) ) != 0 ) {
+ DBG ( "PXE could not prepend pseudo-header\n" );
+ rc = -ENOMEM;
+ goto drop;
+ }
+ pshdr = iob_push ( iobuf, sizeof ( *pshdr ) );
+ pshdr->src_ip = sin_src->sin_addr.s_addr;
+ pshdr->s_port = sin_src->sin_port;
+ pshdr->dest_ip = sin_dest->sin_addr.s_addr;
+ pshdr->d_port = sin_dest->sin_port;
- done:
+ /* Add to queue */
+ list_add_tail ( &iobuf->list, &pxe_udp->list );
+
+ return 0;
+
+ drop:
free_iob ( iobuf );
return rc;
}
@@ -116,6 +126,7 @@ static struct pxe_udp_connection pxe_udp = {
.local = {
.sin_family = AF_INET,
},
+ .list = LIST_HEAD_INIT ( pxe_udp.list ),
};
/**
@@ -205,11 +216,20 @@ static PXENV_EXIT_t pxenv_udp_open ( struct s_PXENV_UDP_OPEN *pxenv_udp_open ) {
*/
static PXENV_EXIT_t
pxenv_udp_close ( struct s_PXENV_UDP_CLOSE *pxenv_udp_close ) {
+ struct io_buffer *iobuf;
+ struct io_buffer *tmp;
+
DBG ( "PXENV_UDP_CLOSE\n" );
/* Close UDP connection */
intf_restart ( &pxe_udp.xfer, 0 );
+ /* Discard any received packets */
+ list_for_each_entry_safe ( iobuf, tmp, &pxe_udp.list, list ) {
+ list_del ( &iobuf->list );
+ free_iob ( iobuf );
+ }
+
pxenv_udp_close->Status = PXENV_STATUS_SUCCESS;
return PXENV_EXIT_SUCCESS;
}
@@ -365,20 +385,32 @@ pxenv_udp_write ( struct s_PXENV_UDP_WRITE *pxenv_udp_write ) {
static PXENV_EXIT_t pxenv_udp_read ( struct s_PXENV_UDP_READ *pxenv_udp_read ) {
struct in_addr dest_ip_wanted = { .s_addr = pxenv_udp_read->dest_ip };
struct in_addr dest_ip;
+ struct io_buffer *iobuf;
+ struct pxe_udp_pseudo_header *pshdr;
uint16_t d_port_wanted = pxenv_udp_read->d_port;
uint16_t d_port;
+ userptr_t buffer;
+ size_t len;
+
+ /* Try receiving a packet, if the queue is empty */
+ if ( list_empty ( &pxe_udp.list ) )
+ step();
- /* Try receiving a packet */
- pxe_udp.pxenv_udp_read = pxenv_udp_read;
- step();
- if ( pxe_udp.pxenv_udp_read ) {
+ /* Remove first packet from the queue */
+ iobuf = list_first_entry ( &pxe_udp.list, struct io_buffer, list );
+ if ( ! iobuf ) {
/* No packet received */
DBG2 ( "PXENV_UDP_READ\n" );
- pxe_udp.pxenv_udp_read = NULL;
goto no_packet;
}
- dest_ip.s_addr = pxenv_udp_read->dest_ip;
- d_port = pxenv_udp_read->d_port;
+ list_del ( &iobuf->list );
+
+ /* Strip pseudo-header */
+ assert ( iob_len ( iobuf ) >= sizeof ( *pshdr ) );
+ pshdr = iobuf->data;
+ iob_pull ( iobuf, sizeof ( *pshdr ) );
+ dest_ip.s_addr = pshdr->dest_ip;
+ d_port = pshdr->d_port;
DBG ( "PXENV_UDP_READ" );
/* Filter on destination address and/or port */
@@ -386,14 +418,29 @@ static PXENV_EXIT_t pxenv_udp_read ( struct s_PXENV_UDP_READ *pxenv_udp_read ) {
( dest_ip_wanted.s_addr != dest_ip.s_addr ) ) {
DBG ( " wrong IP %s", inet_ntoa ( dest_ip ) );
DBG ( " (wanted %s)\n", inet_ntoa ( dest_ip_wanted ) );
- goto no_packet;
+ goto drop;
}
if ( d_port_wanted && ( d_port_wanted != d_port ) ) {
DBG ( " wrong port %d", htons ( d_port ) );
DBG ( " (wanted %d)\n", htons ( d_port_wanted ) );
- goto no_packet;
+ goto drop;
}
+ /* Copy packet to buffer and record length */
+ buffer = real_to_user ( pxenv_udp_read->buffer.segment,
+ pxenv_udp_read->buffer.offset );
+ len = iob_len ( iobuf );
+ if ( len > pxenv_udp_read->buffer_size )
+ len = pxenv_udp_read->buffer_size;
+ copy_to_user ( buffer, 0, iobuf->data, len );
+ pxenv_udp_read->buffer_size = len;
+
+ /* Fill in source/dest information */
+ pxenv_udp_read->src_ip = pshdr->src_ip;
+ pxenv_udp_read->s_port = pshdr->s_port;
+ pxenv_udp_read->dest_ip = pshdr->dest_ip;
+ pxenv_udp_read->d_port = pshdr->d_port;
+
DBG ( " %04x:%04x+%x %s:", pxenv_udp_read->buffer.segment,
pxenv_udp_read->buffer.offset, pxenv_udp_read->buffer_size,
inet_ntoa ( *( ( struct in_addr * ) &pxenv_udp_read->src_ip ) ));
@@ -401,9 +448,14 @@ static PXENV_EXIT_t pxenv_udp_read ( struct s_PXENV_UDP_READ *pxenv_udp_read ) {
inet_ntoa ( *( ( struct in_addr * ) &pxenv_udp_read->dest_ip ) ),
ntohs ( pxenv_udp_read->d_port ) );
+ /* Free I/O buffer */
+ free_iob ( iobuf );
+
pxenv_udp_read->Status = PXENV_STATUS_SUCCESS;
return PXENV_EXIT_SUCCESS;
+ drop:
+ free_iob ( iobuf );
no_packet:
pxenv_udp_read->Status = PXENV_STATUS_FAILURE;
return PXENV_EXIT_FAILURE;
diff --git a/roms/ipxe/src/arch/i386/interface/pxe/pxe_undi.c b/roms/ipxe/src/arch/i386/interface/pxe/pxe_undi.c
index 29e586ed2..2eb68178a 100644
--- a/roms/ipxe/src/arch/i386/interface/pxe/pxe_undi.c
+++ b/roms/ipxe/src/arch/i386/interface/pxe/pxe_undi.c
@@ -21,9 +21,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdio.h>
diff --git a/roms/ipxe/src/arch/i386/interface/syslinux/comboot_call.c b/roms/ipxe/src/arch/i386/interface/syslinux/comboot_call.c
index 1854501de..69d94c407 100644
--- a/roms/ipxe/src/arch/i386/interface/syslinux/comboot_call.c
+++ b/roms/ipxe/src/arch/i386/interface/syslinux/comboot_call.c
@@ -41,8 +41,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/image.h>
#include <ipxe/version.h>
#include <usr/imgmgmt.h>
-#include "config/console.h"
-#include "config/serial.h"
/** The "SYSLINUX" version string */
static char __bss16_array ( syslinux_version, [32] );
@@ -86,7 +84,6 @@ rmjmp_buf comboot_return;
/* Mode flags set by INT 22h AX=0017h */
static uint16_t comboot_graphics_mode = 0;
-
/**
* Print a string with a particular terminator
*/
@@ -261,8 +258,10 @@ static __asmcall void int21 ( struct i386_all_regs *ix86 ) {
break;
case 0x04: /* Write Character to Serial Port */
- serial_putc ( ix86->regs.dl );
- ix86->flags &= ~CF;
+ if ( serial_console.base ) {
+ uart_transmit ( &serial_console, ix86->regs.dl );
+ ix86->flags &= ~CF;
+ }
break;
case 0x09: /* Write DOS String to Console */
@@ -455,15 +454,16 @@ static __asmcall void int22 ( struct i386_all_regs *ix86 ) {
break;
case 0x000B: /* Get Serial Console Configuration */
-#if defined(CONSOLE_SERIAL) && !defined(COMPRESERVE)
- ix86->regs.dx = COMCONSOLE;
- ix86->regs.cx = 115200 / COMSPEED;
- ix86->regs.bx = 0;
-#else
- ix86->regs.dx = 0;
-#endif
+ if ( serial_console.base ) {
+ ix86->regs.dx = ( ( intptr_t ) serial_console.base );
+ ix86->regs.cx = serial_console.divisor;
+ ix86->regs.bx = 0;
+ ix86->flags &= ~CF;
+ }
+ break;
- ix86->flags &= ~CF;
+ case 0x000C: /* Perform final cleanup */
+ shutdown_boot();
break;
case 0x000E: /* Get configuration file name */
@@ -712,3 +712,6 @@ void unhook_comboot_interrupts ( ) {
unhook_bios_interrupt ( 0x22, ( unsigned int ) int22_wrapper,
&int22_vector );
}
+
+/* Avoid dragging in serial console support unconditionally */
+struct uart serial_console __attribute__ (( weak ));
diff --git a/roms/ipxe/src/arch/i386/interface/vmware/guestrpc.c b/roms/ipxe/src/arch/i386/interface/vmware/guestrpc.c
index 390fc5545..ef7ee8151 100644
--- a/roms/ipxe/src/arch/i386/interface/vmware/guestrpc.c
+++ b/roms/ipxe/src/arch/i386/interface/vmware/guestrpc.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/arch/i386/interface/vmware/vmconsole.c b/roms/ipxe/src/arch/i386/interface/vmware/vmconsole.c
index c6b9fff12..f7df4f75b 100644
--- a/roms/ipxe/src/arch/i386/interface/vmware/vmconsole.c
+++ b/roms/ipxe/src/arch/i386/interface/vmware/vmconsole.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/arch/i386/interface/vmware/vmware.c b/roms/ipxe/src/arch/i386/interface/vmware/vmware.c
index 8074e6118..a415465fb 100644
--- a/roms/ipxe/src/arch/i386/interface/vmware/vmware.c
+++ b/roms/ipxe/src/arch/i386/interface/vmware/vmware.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/arch/i386/prefix/bootpart.S b/roms/ipxe/src/arch/i386/prefix/bootpart.S
index 968da1a38..6d0c6034a 100644
--- a/roms/ipxe/src/arch/i386/prefix/bootpart.S
+++ b/roms/ipxe/src/arch/i386/prefix/bootpart.S
@@ -1,4 +1,4 @@
-FILE_LICENCE ( GPL2_OR_LATER )
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
#define BOOT_SEG 0x07c0
#define EXEC_SEG 0x0100
diff --git a/roms/ipxe/src/arch/i386/prefix/exeprefix.S b/roms/ipxe/src/arch/i386/prefix/exeprefix.S
index cb61287d3..5c648d51d 100644
--- a/roms/ipxe/src/arch/i386/prefix/exeprefix.S
+++ b/roms/ipxe/src/arch/i386/prefix/exeprefix.S
@@ -16,9 +16,13 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ *
*/
-FILE_LICENCE ( GPL2_OR_LATER )
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
/* Initial temporary stack size */
#define EXE_STACK_SIZE 0x400
diff --git a/roms/ipxe/src/arch/i386/prefix/hdprefix.S b/roms/ipxe/src/arch/i386/prefix/hdprefix.S
index 876bfe1be..1d012d80b 100644
--- a/roms/ipxe/src/arch/i386/prefix/hdprefix.S
+++ b/roms/ipxe/src/arch/i386/prefix/hdprefix.S
@@ -1,4 +1,4 @@
-FILE_LICENCE ( GPL2_OR_LATER )
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
.text
.arch i386
diff --git a/roms/ipxe/src/arch/i386/prefix/isaromprefix.S b/roms/ipxe/src/arch/i386/prefix/isaromprefix.S
index e28208089..fb49819ee 100644
--- a/roms/ipxe/src/arch/i386/prefix/isaromprefix.S
+++ b/roms/ipxe/src/arch/i386/prefix/isaromprefix.S
@@ -16,9 +16,13 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ *
*/
-FILE_LICENCE ( GPL2_OR_LATER )
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
#define BUSTYPE "ISAR"
#define _rom_start _isarom_start
diff --git a/roms/ipxe/src/arch/i386/prefix/kkkpxeprefix.S b/roms/ipxe/src/arch/i386/prefix/kkkpxeprefix.S
index 27ed231e7..6e43cd26a 100644
--- a/roms/ipxe/src/arch/i386/prefix/kkkpxeprefix.S
+++ b/roms/ipxe/src/arch/i386/prefix/kkkpxeprefix.S
@@ -5,12 +5,10 @@
*****************************************************************************
*/
-FILE_LICENCE ( GPL2_OR_LATER )
-
-/* Since we have the whole stack, we can use cached DHCP information */
-REQUIRE_OBJECT ( pxeparent_dhcp )
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
/* Provide the PXENV_FILE_EXIT_HOOK API call */
+REQUIRING_SYMBOL ( _kkkpxe_start )
REQUIRE_OBJECT ( pxe_exit_hook )
#define PXELOADER_KEEP_UNDI
diff --git a/roms/ipxe/src/arch/i386/prefix/kkpxeprefix.S b/roms/ipxe/src/arch/i386/prefix/kkpxeprefix.S
index d177d7d62..3c17dbdb1 100644
--- a/roms/ipxe/src/arch/i386/prefix/kkpxeprefix.S
+++ b/roms/ipxe/src/arch/i386/prefix/kkpxeprefix.S
@@ -3,10 +3,7 @@
*****************************************************************************
*/
-FILE_LICENCE ( GPL2_OR_LATER )
-
-/* Since we have the whole stack, we can use cached DHCP information */
-REQUEST_OBJECT ( pxeparent_dhcp )
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
#define PXELOADER_KEEP_UNDI
#define PXELOADER_KEEP_PXE
diff --git a/roms/ipxe/src/arch/i386/prefix/kpxeprefix.S b/roms/ipxe/src/arch/i386/prefix/kpxeprefix.S
index c75608172..200006d83 100644
--- a/roms/ipxe/src/arch/i386/prefix/kpxeprefix.S
+++ b/roms/ipxe/src/arch/i386/prefix/kpxeprefix.S
@@ -3,7 +3,7 @@
*****************************************************************************
*/
-FILE_LICENCE ( GPL2_OR_LATER )
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
#define PXELOADER_KEEP_UNDI
#define _pxe_start _kpxe_start
diff --git a/roms/ipxe/src/arch/i386/prefix/libprefix.S b/roms/ipxe/src/arch/i386/prefix/libprefix.S
index 7c1ece791..7d5c1ed53 100644
--- a/roms/ipxe/src/arch/i386/prefix/libprefix.S
+++ b/roms/ipxe/src/arch/i386/prefix/libprefix.S
@@ -16,9 +16,13 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ *
*/
-FILE_LICENCE ( GPL2_OR_LATER )
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
.arch i386
@@ -296,11 +300,9 @@ copy_bytes:
* Zero bytes
*
* Parameters:
- * %ds:esi : source address
* %es:edi : destination address
* %ecx : length
* Returns:
- * %ds:esi : next source address
* %es:edi : next destination address
* Corrupts:
* None
@@ -396,8 +398,10 @@ process_bytes:
movw %ax, %fs
movw %ax, %gs
+#ifdef NDEBUG
/* Call memcpy()-like function */
call *%bx
+#endif
/* Return to (flat) real mode */
movl %cr0, %eax
@@ -411,6 +415,20 @@ process_bytes:
popw %fs
popw %gs
+#ifndef NDEBUG
+ /* Call memcpy()-like function in flat real mode (to allow for
+ * debug output via INT 10).
+ */
+ pushw %ds
+ pushw %es
+ xorw %ax, %ax
+ movw %ax, %ds
+ movw %ax, %es
+ call *%bx
+ popw %es
+ popw %ds
+#endif
+
/* Restore GDT */
data32 lgdt -8(%bp)
addw $( 8 /* saved GDT */ + ( PM_DS + 8 ) /* GDT on stack */ ), %sp
@@ -442,11 +460,11 @@ process_bytes:
/* Convert %ds:esi and %es:edi back to physical addresses */
xorl %eax, %eax
- movw %ds, %cx
+ movw %ds, %ax
shll $4, %eax
addl %eax, %esi
xorl %eax, %eax
- movw %es, %cx
+ movw %es, %ax
shll $4, %eax
addl %eax, %edi
@@ -678,12 +696,21 @@ install:
.globl install_prealloc
install_prealloc:
progress "install_prealloc:\n"
- /* Save registers */
+ /* Save registers on external stack */
pushal
pushw %ds
pushw %es
cld /* Sanity: clear the direction flag asap */
+ /* Switch to temporary stack in .bss16 */
+ pushw %ss
+ popw %ds
+ movl %esp, %ecx
+ movw %bx, %ss
+ movl $_data16_memsz, %esp
+ pushw %ds
+ pushl %ecx
+
/* Set up %ds for (read-only) access to .prefix */
pushw %cs
popw %ds
@@ -710,6 +737,7 @@ install_prealloc:
popl %esi
#ifndef KEEP_IT_REAL
+
/* Access high memory by enabling the A20 gate. (We will
* already have 4GB segment limits as a result of calling
* install_block.)
@@ -778,7 +806,7 @@ payload_death_message:
movzwl %bx, %edi
shll $4, %edi
movl $_data16_filesz, %ecx
- movl $_data16_memsz, %edx
+ movl $_data16_filesz, %edx /* do not zero our temporary stack */
call install_block /* .data16 */
/* Set up %ds for access to .data16 */
@@ -787,11 +815,8 @@ payload_death_message:
/* Restore decompression temporary area physical address */
popl %edi
-#ifdef KEEP_IT_REAL
- /* Initialise libkir */
- movw %ax, (init_libkir_vector+2)
- lcall *init_libkir_vector
-#else
+#ifndef KEEP_IT_REAL
+
/* Find a suitable decompression temporary area, if none specified */
pushl %eax
testl %edi, %edi
@@ -823,6 +848,22 @@ payload_death_message:
call install_block
popl %edi
+#endif /* KEEP_IT_REAL */
+
+ /* Switch back to original stack and zero .bss16 */
+ addr32 lss %ss:(%esp), %esp
+ pushl %edi
+ pushw %es
+ movw %bx, %es
+ movl $_data16_filesz, %edi
+ movl $_data16_memsz, %ecx
+ subl %edi, %ecx
+ call zero_bytes
+ popw %es
+ popl %edi
+
+#ifndef KEEP_IT_REAL
+
/* Initialise librm at current location */
progress " init_librm\n"
movw %ax, (init_librm_vector+2)
@@ -834,7 +875,6 @@ payload_death_message:
incb memmap_post
decl %ebp
1:
-
/* Call relocate() to determine target address for relocation.
* relocate() will return with %esi, %edi and %ecx set up
* ready for the copy to the new location.
@@ -857,7 +897,14 @@ payload_death_message:
/* Initialise librm at new location */
progress " init_librm\n"
lcall *init_librm_vector
-#endif
+
+#else /* KEEP_IT_REAL */
+
+ /* Initialise libkir */
+ movw %ax, (init_libkir_vector+2)
+ lcall *init_libkir_vector
+
+#endif /* KEEP_IT_REAL */
/* Close access to payload */
progress " close_payload\n"
diff --git a/roms/ipxe/src/arch/i386/prefix/lkrnprefix.S b/roms/ipxe/src/arch/i386/prefix/lkrnprefix.S
index 259bc6ba5..64135e14b 100644
--- a/roms/ipxe/src/arch/i386/prefix/lkrnprefix.S
+++ b/roms/ipxe/src/arch/i386/prefix/lkrnprefix.S
@@ -1,4 +1,4 @@
-FILE_LICENCE ( GPL_ANY )
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
#define BZI_LOAD_HIGH_ADDR 0x100000
diff --git a/roms/ipxe/src/arch/i386/prefix/mbr.S b/roms/ipxe/src/arch/i386/prefix/mbr.S
index adfe20410..a1e237de8 100644
--- a/roms/ipxe/src/arch/i386/prefix/mbr.S
+++ b/roms/ipxe/src/arch/i386/prefix/mbr.S
@@ -1,3 +1,5 @@
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
+
.text
.arch i386
.section ".prefix", "awx", @progbits
diff --git a/roms/ipxe/src/arch/i386/prefix/mromprefix.S b/roms/ipxe/src/arch/i386/prefix/mromprefix.S
index 4c94457c2..b636b92af 100644
--- a/roms/ipxe/src/arch/i386/prefix/mromprefix.S
+++ b/roms/ipxe/src/arch/i386/prefix/mromprefix.S
@@ -16,9 +16,13 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ *
*/
-FILE_LICENCE ( GPL2_OR_LATER )
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
#define PCIBIOS_READ_CONFIG_WORD 0xb109
#define PCIBIOS_READ_CONFIG_DWORD 0xb10a
@@ -463,6 +467,7 @@ pci_set_mem_access:
.org 0x00
mromheader:
.word 0xaa55 /* BIOS extension signature */
+ .byte 0x01 /* Dummy size (BIOS bug workaround) */
.org 0x18
.word mpciheader
.org 0x1a
diff --git a/roms/ipxe/src/arch/i386/prefix/nbiprefix.S b/roms/ipxe/src/arch/i386/prefix/nbiprefix.S
index 06e7df5b7..16c79566c 100644
--- a/roms/ipxe/src/arch/i386/prefix/nbiprefix.S
+++ b/roms/ipxe/src/arch/i386/prefix/nbiprefix.S
@@ -1,3 +1,5 @@
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
+
.text
.arch i386
.code16
diff --git a/roms/ipxe/src/arch/i386/prefix/nullprefix.S b/roms/ipxe/src/arch/i386/prefix/nullprefix.S
index 032d41e0f..bd0ff339e 100644
--- a/roms/ipxe/src/arch/i386/prefix/nullprefix.S
+++ b/roms/ipxe/src/arch/i386/prefix/nullprefix.S
@@ -1,3 +1,5 @@
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
+
.org 0
.text
.arch i386
diff --git a/roms/ipxe/src/arch/i386/prefix/pciromprefix.S b/roms/ipxe/src/arch/i386/prefix/pciromprefix.S
index 45ba31f50..5a5a49647 100644
--- a/roms/ipxe/src/arch/i386/prefix/pciromprefix.S
+++ b/roms/ipxe/src/arch/i386/prefix/pciromprefix.S
@@ -16,9 +16,13 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ *
*/
-FILE_LICENCE ( GPL2_OR_LATER )
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
#define BUSTYPE "PCIR"
#define _rom_start _pcirom_start
diff --git a/roms/ipxe/src/arch/i386/prefix/pxeprefix.S b/roms/ipxe/src/arch/i386/prefix/pxeprefix.S
index 6e29c7949..465ce4345 100644
--- a/roms/ipxe/src/arch/i386/prefix/pxeprefix.S
+++ b/roms/ipxe/src/arch/i386/prefix/pxeprefix.S
@@ -1,4 +1,4 @@
-FILE_LICENCE ( GPL2_OR_LATER )
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
#define PXENV_UNDI_SHUTDOWN 0x0005
#define PXENV_UNDI_GET_NIC_TYPE 0x0012
diff --git a/roms/ipxe/src/arch/i386/prefix/romprefix.S b/roms/ipxe/src/arch/i386/prefix/romprefix.S
index 7bc4fe8cd..18dda2b37 100644
--- a/roms/ipxe/src/arch/i386/prefix/romprefix.S
+++ b/roms/ipxe/src/arch/i386/prefix/romprefix.S
@@ -6,9 +6,10 @@
* table so using a noticeable amount of stack space is a no-no.
*/
-FILE_LICENCE ( GPL2_OR_LATER )
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
#include <config/general.h>
+#include <config/branding.h>
#define PNP_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'n' << 16 ) + ( 'P' << 24 ) )
#define PMM_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'M' << 16 ) + ( 'M' << 24 ) )
@@ -90,7 +91,7 @@ pciheader:
.ascii "PCIR" /* Signature */
.word pci_vendor_id /* Vendor identification */
.word pci_device_id /* Device identification */
- .word 0x0000 /* Device list pointer */
+ .word ( pci_devlist - pciheader ) /* Device list pointer */
.word pciheader_len /* PCI data structure length */
.byte 0x03 /* PCI data structure revision */
.byte 0x02, 0x00, 0x00 /* Class code */
@@ -106,6 +107,17 @@ pciheader_runtime_length:
.equ pciheader_len, . - pciheader
.size pciheader, . - pciheader
+ /* PCI additional device list (filled in by linker) */
+ .section ".pci_devlist.00000000", "a", @progbits
+pci_devlist:
+ .previous
+ .section ".pci_devlist.ffffffff", "a", @progbits
+pci_devlist_end:
+ .short 0x0000 /* List terminator */
+ .previous
+ /* Ensure that terminator is always present */
+ .reloc pciheader, RELOC_TYPE_NONE, pci_devlist_end
+
.section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
.ascii ZINFO_TYPE_ADxW
.long pciheader_image_length
@@ -573,7 +585,7 @@ get_pmm_decompress_to:
* 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.
+ * strings PRODUCT_NAME and PRODUCT_SHORT_NAME in config/branding.h.
*
* While nothing in the GPL prevents you from removing all references
* to iPXE or http://ipxe.org, we prefer you not to do so.
@@ -589,7 +601,10 @@ init_message:
.ascii "\n"
.ascii PRODUCT_NAME
.ascii "\n"
- .asciz "iPXE (http://ipxe.org)"
+ .ascii PRODUCT_SHORT_NAME
+ .ascii " ("
+ .ascii PRODUCT_URI
+ .asciz ")"
.size init_message, . - init_message
.ifeqs BUSTYPE, "PCIR"
init_message_pci:
@@ -771,7 +786,9 @@ exec: /* Set %ds = %cs */
/* Store PCI bus:dev.fn, if applicable */
.ifeqs BUSTYPE, "PCIR"
+#ifdef AUTOBOOT_ROM_FILTER
movw %ax, autoboot_busdevfn
+#endif /* AUTOBOOT_ROM_FILTER */
.endif
/* Call main() */
@@ -870,3 +887,9 @@ wait_for_tick:
popl %eax
ret
.size wait_for_tick, . - wait_for_tick
+
+/* Drag in objects via _rom_start */
+REQUIRING_SYMBOL ( _rom_start )
+
+/* Drag in ROM configuration */
+REQUIRE_OBJECT ( config_romprefix )
diff --git a/roms/ipxe/src/arch/i386/prefix/undiloader.S b/roms/ipxe/src/arch/i386/prefix/undiloader.S
index 74bb59041..5cace44b7 100644
--- a/roms/ipxe/src/arch/i386/prefix/undiloader.S
+++ b/roms/ipxe/src/arch/i386/prefix/undiloader.S
@@ -1,4 +1,4 @@
-FILE_LICENCE ( GPL2_OR_LATER )
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
.text
.code16
diff --git a/roms/ipxe/src/arch/i386/prefix/unlzma.S b/roms/ipxe/src/arch/i386/prefix/unlzma.S
new file mode 100644
index 000000000..8d4b3c1a8
--- /dev/null
+++ b/roms/ipxe/src/arch/i386/prefix/unlzma.S
@@ -0,0 +1,942 @@
+/*
+ * Copyright (C) 2015 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/****************************************************************************
+ *
+ * This file provides the decompress() and decompress16() functions
+ * which can be called in order to decompress an LZMA-compressed
+ * image. The code is modelled on the public-domain "XZ Embedded"
+ * implementation as used by the Linux kernel. Symbol names are
+ * chosen to match the XZ Embedded implementation where possible, for
+ * ease of reference.
+ *
+ * This code is optimised for size rather than speed, since the amount
+ * of data to be decompressed is trivially small by modern standards.
+ *
+ * The same basic assembly code is used to compile both decompress()
+ * and decompress16().
+ *
+ * Note that these functions require large amounts of stack space.
+ *
+ ****************************************************************************
+ */
+
+ .text
+ .arch i586
+ .section ".prefix.lib", "ax", @progbits
+
+#ifdef CODE16
+#define ADDR16
+#define ADDR32 addr32
+#define decompress decompress16
+ .code16
+#else /* CODE16 */
+#define ADDR16 addr16
+#define ADDR32
+ .code32
+#endif /* CODE16 */
+
+/****************************************************************************
+ * Debugging
+ ****************************************************************************
+ *
+ * This code will usually run in 16-bit protected mode, in which case
+ * only the 0xe9 debug port (present on some virtual machines) can be
+ * used.
+ *
+ * To debug on real hardware, build with DEBUG=libprefix. This will
+ * cause this code to be called in flat real mode, and so DEBUG_INT10
+ * may be used.
+ */
+
+/* Enable debugging via 0xe9 debug port */
+#define DEBUG_E9 0
+
+/* Enable debugging via BIOS INT 10 (works only when in flat real mode) */
+#define DEBUG_INT10 0
+
+#if ( DEBUG_E9 || DEBUG_INT10 )
+ .macro print_character, reg
+ pushfl
+ pushw %ax
+ pushw %bx
+ pushw %bp
+ movb \reg, %al
+ movw $0x0007, %bx
+ movb $0x0e, %ah
+#if DEBUG_E9
+ outb %al, $0xe9
+#endif
+#if DEBUG_INT10
+ cmpb $('\n'), %al
+ jne L\@
+ int $0x10
+ movb $('\r'), %al
+L\@: int $0x10
+#endif
+ popw %bp
+ popw %bx
+ popw %ax
+ popfl
+ .endm
+
+ .macro print_hex_nibble
+ pushfl
+ pushw %ax
+ cmpb $10, %al
+ sbb $0x69, %al
+ das
+ print_character %al
+ popw %ax
+ popfl
+ .endm
+
+ .macro print_hex_byte, reg
+ pushfl
+ pushw %ax
+ movb \reg, %al
+ pushw %ax
+ shrb $4, %al
+ print_hex_nibble
+ popw %ax
+ andb $0x0f, %al
+ print_hex_nibble
+ popw %ax
+ popfl
+ .endm
+
+ .macro print_hex_word, reg
+ pushw %ax
+ movw \reg, %ax
+ print_hex_byte %ah
+ print_hex_byte %al
+ popw %ax
+ .endm
+
+ .macro print_hex_dword, reg
+ pushl %eax
+ movl \reg, %eax
+ rorl $16, %eax
+ print_hex_word %ax
+ rorl $16, %eax
+ print_hex_word %ax
+ popl %eax
+ .endm
+#else
+ .macro print_character, char
+ .endm
+ .macro print_hex_byte, reg
+ .endm
+ .macro print_hex_word, reg
+ .endm
+ .macro print_hex_dword, reg
+ .endm
+#endif
+
+/****************************************************************************
+ * LZMA parameters and data structures
+ ****************************************************************************
+ */
+
+/* LZMA decompressor states (as used in XZ Embedded) */
+#define STATE_LIT_LIT 0x00
+#define STATE_MATCH_LIT_LIT 0x01
+#define STATE_REP_LIT_LIT 0x02
+#define STATE_SHORTREP_LIT_LIT 0x03
+#define STATE_MATCH_LIT 0x04
+#define STATE_REP_LIT 0x05
+#define STATE_SHORTREP_LIT 0x06
+#define STATE_LIT_MATCH 0x07
+#define STATE_LIT_LONGREP 0x08
+#define STATE_LIT_SHORTREP 0x09
+#define STATE_NONLIT_MATCH 0x0a
+#define STATE_NONLIT_REP 0x0b
+
+/* LZMA maximum decompressor state in which most recent symbol was a literal */
+#define STATE_LIT_MAX 0x06
+
+/* LZMA number of literal context bits ("lc=" parameter) */
+#define LZMA_LC 2
+
+ .struct 0
+lzma_len_dec:
+choice: .word 0
+choice2: .word 0
+low: .rept ( 1 << 3 )
+ .word 0
+ .endr
+mid: .rept ( 1 << 3 )
+ .word 0
+ .endr
+high: .rept ( 1 << 8 )
+ .word 0
+ .endr
+ .equ sizeof__lzma_len_dec, . - lzma_len_dec
+ .previous
+
+ .struct 0
+lzma_dec:
+out_start: .long 0
+rc_code: .long 0
+rc_range: .long 0
+len: .word 0
+reps:
+rep0: .long 0
+rep1: .long 0
+rep2: .long 0
+rep3: .long 0
+probs:
+is_match: .word 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+is_rep: .word 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+is_rep0: .word 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+is_rep1: .word 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+is_rep2: .word 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+is_rep0_long: .word 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+dist_slot: .rept ( 4 * ( 1 << 6 ) )
+ .word 0
+ .endr
+dist_special: .rept ( ( 1 << ( 14 / 2 ) ) - 14 )
+ .word 0
+ .endr
+dist_align: .rept ( 1 << 4 )
+ .word 0
+ .endr
+match_len_dec: .space sizeof__lzma_len_dec
+rep_len_dec: .space sizeof__lzma_len_dec
+literal: .rept ( ( 1 << LZMA_LC ) * 0x300 )
+ .word 0
+ .endr
+ .align 4
+ .equ sizeof__lzma_dec, . - lzma_dec
+ .previous
+
+ /* Some binutils versions seem not to handle .struct/.previous */
+ .section ".prefix.lib", "ax", @progbits
+
+/*****************************************************************************
+ * Normalise range encoder
+ *
+ * Parameters:
+ * %ss:%ebp : LZMA parameter block
+ * %ds:%esi : compressed input data pointer
+ * Returns:
+ * %ds:%esi : compressed input data pointer (possibly updated)
+ * %eax : current range
+ *****************************************************************************
+ */
+rc_normalise:
+ /* Check if rc_range is less than 1<<24 */
+ testb $0xff, (rc_range+3)(%ebp)
+ jnz 1f
+ /* If it is, shift in a new byte from the compressed input data */
+ shll $8, rc_range(%ebp)
+ shll $8, rc_code(%ebp)
+ ADDR32 lodsb
+ movb %al, (rc_code+0)(%ebp)
+1: /* Return current range */
+ movl rc_range(%ebp), %eax
+ ret
+ .size rc_normalise, . - rc_normalise
+
+/*****************************************************************************
+ * Decode single range-encoded bit using a probability estimate
+ *
+ * Parameters:
+ * %ss:%ebp : LZMA parameter block
+ * %ds:%esi : compressed input data pointer
+ * %ebx : probability estimate pointer (offset from %ebp)
+ * Returns:
+ * %ds:%esi : compressed input data pointer (possibly updated)
+ * CF : decoded bit
+ * ZF : inverse of decoded bit
+ * Corrupts:
+ * none
+ *****************************************************************************
+ */
+rc_bit:
+ /* Preserve registers */
+ pushl %eax
+ pushl %edx
+ /* Perform normalisation */
+ call rc_normalise
+ /* Calculate bound in %eax and probability estimate in %dx */
+ shrl $11, %eax
+ movzwl (%ebp,%ebx), %edx
+ mul %edx /* will zero %edx */
+ movw (%ebp,%ebx), %dx
+ /* Compare code against bound */
+ cmpl %eax, rc_code(%ebp)
+ jae 2f
+1: /* Code is less than bound */
+ movl %eax, rc_range(%ebp)
+ negw %dx
+ addw $(1<<11), %dx
+ shrw $5, %dx
+ addw %dx, (%ebp,%ebx)
+ xorw %ax, %ax /* Clear CF, set ZF */
+ jmp 99f
+2: /* Code is greater than or equal to bound */
+ subl %eax, rc_range(%ebp)
+ subl %eax, rc_code(%ebp)
+ shrw $5, %dx
+ subw %dx, (%ebp,%ebx)
+ incw %dx /* Clear ZF (%dx is 11-bit; can never wrap) */
+ stc /* Set CF */
+99: /* Restore registers and return */
+ popl %edx
+ popl %eax
+ ret
+ .size rc_bit, . - rc_bit
+
+/*****************************************************************************
+ * Decode MSB-first bittree
+ *
+ * Parameters:
+ * %ss:%ebp : LZMA parameter block
+ * %ds:%esi : compressed input data pointer
+ * %ebx : probability estimate set pointer (offset from %ebp)
+ * %cx : number of bits to decode
+ * Returns:
+ * %ds:%esi : compressed input data pointer (possibly updated)
+ * %eax : decoded bittree
+ * Corrupts:
+ * none
+ *****************************************************************************
+ */
+rc_bittree:
+ /* Preserve registers */
+ pushl %edi
+ pushw %cx
+ movl %ebx, %edi
+ /* Initialise registers */
+ movl $1, %eax
+1: /* Decode bit */
+ leaw (%edi,%eax,2), %bx /* high word always zero anyway */
+ call rc_bit
+ rclw %ax
+ ADDR16 loop 1b
+ /* Restore registers, clear unwanted high bit of result, and return */
+ movl %edi, %ebx
+ popw %cx
+ popl %edi
+ btrw %cx, %ax
+ ret
+ .size rc_bittree, . - rc_bittree
+
+/*****************************************************************************
+ * Decode LSB-first bittree
+ *
+ * Parameters:
+ * %ss:%ebp : LZMA parameter block
+ * %ds:%esi : compressed input data pointer
+ * %ebx : probability estimate set pointer (offset from %ebp)
+ * %cx : number of bits to decode
+ * Returns:
+ * %ds:%esi : compressed input data pointer (possibly updated)
+ * %eax : decoded bittree
+ * Corrupts:
+ * none
+ *****************************************************************************
+ */
+rc_bittree_reverse:
+ /* Preserve registers */
+ pushw %cx
+ /* Decode bittree */
+ call rc_bittree
+1: /* Reverse result */
+ rcrb %al
+ rclb %ah
+ ADDR16 loop 1b
+ shrw $8, %ax
+ /* Restore registers and return */
+ popw %cx
+ ret
+ .size rc_bittree_reverse, . - rc_bittree_reverse
+
+/*****************************************************************************
+ * Decode MSB-first bittree with optional match byte
+ *
+ * Parameters:
+ * %ss:%ebp : LZMA parameter block
+ * %ds:%esi : compressed input data pointer
+ * %ebx : probability estimate set pointer (offset from %ebp)
+ * %cl : match byte
+ * %ch : 1 to use match byte, 0 to ignore match byte
+ * Returns:
+ * %ds:%esi : compressed input data pointer (possibly updated)
+ * %eax : decoded bittree
+ * Corrupts:
+ * none
+ *****************************************************************************
+ */
+rc_bittree_match:
+ /* Preserve registers */
+ pushl %edi
+ pushw %cx
+ pushw %dx
+ movl %ebx, %edi
+ /* Initialise registers */
+ movl $1, %eax
+1: /* Decode bit */
+ rolb $1, %cl
+ movw %cx, %dx
+ andb %dh, %dl /* match_bit in %dl */
+ movw %dx, %bx
+ addb %bl, %bh
+ xorb %bl, %bl
+ addw %ax, %bx /* offset + match_bit + symbol */
+ leaw (%edi,%ebx,2), %bx /* high word always zero anyway */
+ call rc_bit
+ rclw %ax
+ movb %al, %dh
+ notb %dh
+ xorb %dh, %dl
+ andb %dl, %ch /* offset &= ( match_bit ^ bit ) */
+ testb %ah, %ah
+ jz 1b
+ /* Restore registers, clear unwanted high bit of result, and return */
+ movl %edi, %ebx
+ popw %dx
+ popw %cx
+ popl %edi
+ xorb %ah, %ah
+ ret
+ .size rc_bittree_match, . - rc_bittree_match
+
+/*****************************************************************************
+ * Decode direct bits (no probability estimates)
+ *
+ * Parameters:
+ * %ss:%ebp : LZMA parameter block
+ * %ds:%esi : compressed input data pointer
+ * %cx : number of bits to decode
+ * Returns:
+ * %ds:%esi : compressed input data pointer (possibly updated)
+ * %eax : decoded bits
+ * Corrupts:
+ * none
+ *****************************************************************************
+ */
+rc_direct:
+ /* Preserve registers */
+ pushl %ebx
+ pushw %cx
+ pushl %edx
+ /* Initialise registers */
+ xorl %edx, %edx
+1: /* Perform normalisation */
+ call rc_normalise
+ /* Decode bit */
+ shrl $1, %eax
+ movl %eax, rc_range(%ebp)
+ movl rc_code(%ebp), %ebx
+ subl %eax, %ebx
+ js 2f
+ movl %ebx, rc_code(%ebp)
+2: rcll %ebx
+ rcll %edx
+ xorb $1, %dl
+ ADDR16 loop 1b
+ /* Restore registers and return */
+ movl %edx, %eax
+ popl %edx
+ popw %cx
+ popl %ebx
+ ret
+ .size rc_direct, . - rc_direct
+
+/*****************************************************************************
+ * Decode an LZMA literal
+ *
+ * Parameters:
+ * %ss:%ebp : LZMA parameter block
+ * %ds:%esi : compressed input data pointer
+ * %es:%edi : uncompressed output data pointer
+ * %edx : LZMA state
+ * Returns:
+ * %ds:%esi : compressed input data pointer (possibly updated)
+ * %es:%edi : uncompressed output data pointer (updated)
+ * %edx : LZMA state
+ * CF : end of payload marker found (always zero)
+ * Corrupts:
+ * %eax
+ * %ebx
+ * %ecx
+ *****************************************************************************
+ *
+ * Literals are coded as an eight-bit tree, using a match byte if the
+ * previous symbol was not a literal.
+ *
+ */
+lzma_literal:
+ /* Get most recent output byte, if available */
+ xorl %ebx, %ebx
+ cmpl %edi, out_start(%ebp)
+ je 1f
+ movb %es:-1(%edi), %bh
+1: /* Locate probability estimate set */
+ shrb $( 8 - LZMA_LC ), %bh
+ shlb $1, %bh
+ leaw literal(%ebx,%ebx,2), %bx
+ /* Get match byte, if applicable */
+ xorw %cx, %cx
+ cmpb $STATE_LIT_MAX, %dl
+ jbe 1f
+ movl rep0(%ebp), %eax
+ notl %eax
+ movb %es:(%edi,%eax), %cl
+ movb $1, %ch
+1: /* Decode bittree */
+ call rc_bittree_match
+ /* Store output byte */
+ ADDR32 stosb
+ print_hex_byte %al
+ print_character $(' ')
+ /* Update LZMA state */
+ subb $3, %dl
+ jns 1f
+ xorb %dl, %dl
+1: cmpb $7, %dl
+ jb 1f
+ subb $3, %dl
+1: /* Clear CF and return */
+ clc
+ ret
+ .size lzma_literal, . - lzma_literal
+
+/*****************************************************************************
+ * Decode an LZMA length
+ *
+ * Parameters:
+ * %ss:%ebp : LZMA parameter block
+ * %ds:%esi : compressed input data pointer
+ * %ebx : length parameter pointer (offset from %ebp)
+ * Returns:
+ * %ds:%esi : compressed input data pointer (possibly updated)
+ * Corrupts:
+ * %ebx
+ *****************************************************************************
+ *
+ * Lengths are encoded as:
+ *
+ * "0" + 3 bits : lengths 2-9 ("low")
+ * "10" + 3 bits : lengths 10-17 ("mid")
+ * "11" + 8 bits : lengths 18-273 ("high")
+ */
+lzma_len:
+ /* Preserve registers */
+ pushl %eax
+ pushl %ecx
+ pushl %edi
+ movl %ebx, %edi
+ /* Start by assuming three bits and a base length of 2 */
+ movw $3, %cx
+ movw $2, len(%ebp)
+ /* Check low-length choice bit */
+ leal choice(%edi), %ebx
+ call rc_bit
+ leal low(%edi), %ebx
+ jz 1f
+ /* Check high-length choice bit */
+ leal choice2(%edi), %ebx
+ call rc_bit
+ leal mid(%edi), %ebx
+ movb $10, len(%ebp)
+ jz 1f
+ leal high(%edi), %ebx
+ movb $8, %cl
+ movb $18, len(%ebp)
+1: /* Get encoded length */
+ call rc_bittree
+ addw %ax, len(%ebp)
+ /* Restore registers and return */
+ movl %edi, %ebx
+ popl %edi
+ popl %ecx
+ popl %eax
+ ret
+ .size lzma_len, . - lzma_len
+
+/*****************************************************************************
+ * Copy (possibly repeated) matched data
+ *
+ * Parameters:
+ * %ss:%ebp : LZMA parameter block
+ * %ds:%esi : compressed input data pointer
+ * %es:%edi : uncompressed output data pointer
+ * %cl : repeated match distance index (for repeated matches)
+ * %eax : match distance (for non-repeated matches)
+ * Returns:
+ * %ds:%esi : compressed input data pointer (possibly updated)
+ * %es:%edi : uncompressed output data pointer
+ * CF : match distance is out of range
+ * Corrupts:
+ * %eax
+ * %ebx
+ * %ecx
+ *****************************************************************************
+ */
+match: /* Update repeated match list */
+ print_character $('[')
+ movl $3, %ecx
+ jmp 1f
+match_rep:
+ print_character $('[')
+ print_character $('R')
+ print_hex_byte %cl
+ print_character $('=')
+ movzbl %cl, %ecx
+ movl reps(%ebp,%ecx,4), %eax
+ jcxz 2f
+1: movl (reps-4)(%ebp,%ecx,4), %ebx
+ movl %ebx, reps(%ebp,%ecx,4)
+ loop 1b
+ movl %eax, rep0(%ebp)
+2: /* Preserve registers */
+ pushl %esi
+ /* Get stored match length */
+ movzwl len(%ebp), %ecx
+ print_hex_dword %eax
+ print_character $('+')
+ print_hex_word %cx
+ print_character $(']')
+ print_character $(' ')
+ /* Abort with CF set if match distance is out of range */
+ movl out_start(%ebp), %esi
+ negl %esi
+ leal -1(%edi,%esi), %esi
+ cmpl %eax, %esi
+ jc 99f
+ /* Perform copy */
+ notl %eax
+ leal (%edi,%eax), %esi
+ ADDR32 es rep movsb
+99: /* Restore registers and return */
+ popl %esi
+ ret
+ .size match, . - match
+
+/*****************************************************************************
+ * Decode an LZMA match
+ *
+ * Parameters:
+ * %ss:%ebp : LZMA parameter block
+ * %ds:%esi : compressed input data pointer
+ * %es:%edi : uncompressed output data pointer
+ * %edx : LZMA state
+ * Returns:
+ * %ds:%esi : compressed input data pointer (possibly updated)
+ * %es:%edi : uncompressed output data pointer
+ * %edx : LZMA state
+ * CF : end of payload marker found
+ * Corrupts:
+ * %eax
+ * %ebx
+ * %ecx
+ *****************************************************************************
+ *
+ * Matches are encoded as an LZMA length followed by a 6-bit "distance
+ * slot" code, 0-26 fixed-probability bits, and 0-5 context encoded
+ * bits.
+ */
+lzma_match:
+ /* Preserve registers */
+ pushl %edi
+ /* Update LZMA state */
+ cmpb $STATE_LIT_MAX, %dl
+ movb $STATE_LIT_MATCH, %dl
+ jbe 1f
+ movb $STATE_NONLIT_MATCH, %dl
+1: /* Decode length */
+ movl $match_len_dec, %ebx
+ call lzma_len
+ /* Decode distance slot */
+ movw len(%ebp), %bx
+ subw $2, %bx
+ cmpw $4, %bx
+ jb 1f
+ movw $3, %bx
+1: shlw $7, %bx
+ addw $dist_slot, %bx
+ movw $6, %cx
+ call rc_bittree
+ /* Distance slots 0-3 are literal distances */
+ cmpb $4, %al
+ jb 99f
+ /* Determine initial bits: 10/11 for even/odd distance codes */
+ movl %eax, %edi
+ andw $1, %di
+ orw $2, %di
+ /* Determine number of context-encoded bits */
+ movw %ax, %cx
+ shrb $1, %cl
+ decb %cl
+ /* Select context to be used in absence of fixed-probability bits */
+ movl %edi, %ebx
+ shlw %cl, %bx
+ subw %ax, %bx
+ leaw (dist_special-2)(%ebx,%ebx), %bx
+ /* Decode fixed-probability bits, if any */
+ cmpb $6, %cl
+ jb 1f
+ subb $4, %cl
+ shll %cl, %edi
+ call rc_direct
+ orl %eax, %edi
+ /* Select context to be used in presence of fixed-probability bits */
+ movb $4, %cl
+ movl $dist_align, %ebx
+1: /* Decode context-encoded bits */
+ shll %cl, %edi
+ call rc_bittree_reverse
+ orl %edi, %eax
+99: /* Restore registers and tail-call */
+ popl %edi
+ jmp match
+ .size lzma_match, . - lzma_match
+
+/*****************************************************************************
+ * Decode an LZMA repeated match
+ *
+ * Parameters:
+ * %ss:%ebp : LZMA parameter block
+ * %ds:%esi : compressed input data pointer
+ * %es:%edi : uncompressed output data pointer
+ * %edx : LZMA state
+ * Returns:
+ * %ds:%esi : compressed input data pointer (possibly updated)
+ * %es:%edi : uncompressed output data pointer
+ * %edx : LZMA state
+ * CF : end of payload marker found
+ * Corrupts:
+ * %eax
+ * %ebx
+ * %ecx
+ *****************************************************************************
+ *
+ * Repeated matches are encoded as:
+ *
+ * "00" : shortrep0 (implicit length 1)
+ * "01" + len : longrep0
+ * "10" + len : longrep1
+ * "110" + len : longrep2
+ * "111" + len : longrep3
+ */
+lzma_rep_match:
+ /* Initially assume longrep0 */
+ movw $(STATE_LIT_LONGREP << 8), %cx
+ /* Get is_rep0 bit */
+ leal is_rep0(,%edx,2), %ebx
+ call rc_bit
+ jnz 1f
+ /* Get is_rep0_long bit */
+ leal is_rep0_long(,%edx,2), %ebx
+ call rc_bit
+ jnz 98f
+ movw $1, len(%ebp)
+ movb $STATE_LIT_SHORTREP, %ch
+ jmp 99f
+1: /* Get is_rep1 bit */
+ incb %cl
+ leal is_rep1(,%edx,2), %ebx
+ call rc_bit
+ jz 98f
+ /* Get is_rep2 bit */
+ incb %cl
+ leal is_rep2(,%edx,2), %ebx
+ call rc_bit
+ adcb $0, %cl
+98: /* Decode length */
+ movl $rep_len_dec, %ebx
+ call lzma_len
+99: /* Update LZMA state */
+ cmpb $STATE_LIT_MAX, %dl
+ movb %ch, %dl
+ jbe 1f
+ movb $STATE_NONLIT_REP, %dl
+1: /* Tail call */
+ jmp match_rep
+ .size lzma_match, . - lzma_match
+
+/*****************************************************************************
+ * Decode one LZMA symbol
+ *
+ * Parameters:
+ * %ss:%ebp : LZMA parameter block
+ * %ds:%esi : compressed input data pointer
+ * %es:%edi : uncompressed output data pointer
+ * %edx : LZMA state
+ * Returns:
+ * %ds:%esi : compressed input data pointer (possibly updated)
+ * %es:%edi : uncompressed output data pointer (updated)
+ * %edx : LZMA state
+ * CF : end of payload marker found
+ * Corrupts:
+ * %eax
+ * %ebx
+ * %ecx
+ *****************************************************************************
+ */
+lzma_decode:
+ /* Get is_match bit */
+ leal is_match(,%edx,2), %ebx
+ call rc_bit
+ jz lzma_literal
+ /* Get is_rep bit */
+ leal is_rep(,%edx,2), %ebx
+ call rc_bit
+ jz lzma_match
+ jmp lzma_rep_match
+ .size lzma_decode, . - lzma_decode
+
+/****************************************************************************
+ * Undo effect of branch-call-jump (BCJ) filter
+ *
+ * Parameters:
+ * %es:%esi : start of uncompressed output data (note %es)
+ * %es:%edi : end of uncompressed output data
+ * Returns:
+ * Corrupts:
+ * %eax
+ * %ebx
+ * %ecx
+ * %edx
+ * %esi
+ *****************************************************************************
+ */
+bcj_filter:
+ /* Store (negative) start of data in %edx */
+ movl %esi, %edx
+ negl %edx
+ /* Calculate limit in %ecx */
+ leal -5(%edi,%edx), %ecx
+1: /* Calculate offset in %ebx */
+ leal (%esi,%edx), %ebx
+ /* Check for end of data */
+ cmpl %ecx, %ebx
+ ja 99f
+ /* Check for an opcode which would be followed by a rel32 address */
+ ADDR32 es lodsb
+ andb $0xfe, %al
+ cmpb $0xe8, %al
+ jne 1b
+ /* Get current jump target value in %eax */
+ ADDR32 es lodsl
+ /* Convert absolute addresses in the range [0,limit) back to
+ * relative addresses in the range [-offset,limit-offset).
+ */
+ cmpl %ecx, %eax
+ jae 2f
+ subl %ebx,%es:-4(%esi)
+2: /* Convert negative numbers in the range [-offset,0) back to
+ * positive numbers in the range [limit-offset,limit).
+ */
+ notl %eax /* Range is now [0,offset) */
+ cmpl %ebx, %eax
+ jae 1b
+ addl %ecx,%es:-4(%esi)
+ jmp 1b
+99: /* Return */
+ ret
+ .size bcj_filter, . - bcj_filter
+
+/****************************************************************************
+ * decompress (real-mode or 16/32-bit protected-mode near call)
+ *
+ * Decompress data
+ *
+ * Parameters (passed via registers):
+ * %ds:%esi : Start of compressed input data
+ * %es:%edi : Start of output buffer
+ * Returns:
+ * %ds:%esi - End of compressed input data
+ * %es:%edi - End of decompressed output data
+ * All other registers are preserved
+ *
+ * NOTE: It would be possible to build a smaller version of the
+ * decompression code for -DKEEP_IT_REAL by using 16-bit registers
+ * where possible.
+ ****************************************************************************
+ */
+ .globl decompress
+decompress:
+ /* Preserve registers */
+ pushl %eax
+ pushl %ebx
+ pushl %ecx
+ pushl %edx
+ pushl %ebp
+ /* Allocate parameter block */
+ subl $sizeof__lzma_dec, %esp
+ movl %esp, %ebp
+ /* Zero parameter block and set all probabilities to 0.5 */
+ pushl %edi
+ pushw %es
+ pushw %ss
+ popw %es
+ movl %ebp, %edi
+ xorl %eax, %eax
+ movl $( sizeof__lzma_dec / 4 ), %ecx
+ ADDR32 rep stosl
+ leal probs(%ebp), %edi
+ movw $( ( 1 << 11 ) / 2 ), %ax
+ movl $( ( sizeof__lzma_dec - probs ) / 2 ), %ecx
+ ADDR32 rep stosw
+ popw %es
+ popl %edi
+ /* Initialise remaining parameters */
+ movl %edi, out_start(%ebp)
+ print_character $('\n')
+ ADDR32 lodsb /* discard initial byte */
+ print_hex_byte %al
+ ADDR32 lodsl
+ bswapl %eax
+ print_hex_dword %eax
+ print_character $('\n')
+ movl %eax, rc_code(%ebp)
+ decl rc_range(%ebp)
+ movl $STATE_LIT_LIT, %edx
+1: /* Decompress until we reach end of buffer */
+ call lzma_decode
+ jnc 1b
+ call rc_normalise
+ print_character $('\n')
+ /* Undo BCJ filter */
+ pushl %esi
+ movl out_start(%ebp), %esi
+ call bcj_filter
+ popl %esi
+ /* Restore registers and return */
+ addl $sizeof__lzma_dec, %esp
+ popl %ebp
+ popl %edx
+ popl %ecx
+ popl %ebx
+ popl %eax
+ ret
+
+ /* Specify minimum amount of stack space required */
+ .globl _min_decompress_stack
+ .equ _min_decompress_stack, ( sizeof__lzma_dec + 512 /* margin */ )
diff --git a/roms/ipxe/src/arch/i386/prefix/unnrv2b16.S b/roms/ipxe/src/arch/i386/prefix/unlzma16.S
index b24c2846f..32b43f0dc 100644
--- a/roms/ipxe/src/arch/i386/prefix/unnrv2b16.S
+++ b/roms/ipxe/src/arch/i386/prefix/unlzma16.S
@@ -3,7 +3,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER )
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
#define CODE16
-#include "unnrv2b.S"
+#include "unlzma.S"
diff --git a/roms/ipxe/src/arch/i386/prefix/unnrv2b.S b/roms/ipxe/src/arch/i386/prefix/unnrv2b.S
deleted file mode 100644
index f5724c134..000000000
--- a/roms/ipxe/src/arch/i386/prefix/unnrv2b.S
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright (C) 1996-2002 Markus Franz Xaver Johannes Oberhumer
- *
- * This file 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.
- *
- * Originally this code was part of ucl the data compression library
- * for upx the ``Ultimate Packer of eXecutables''.
- *
- * - Converted to gas assembly, and refitted to work with etherboot.
- * Eric Biederman 20 Aug 2002
- *
- * - Structure modified to be a subroutine call rather than an
- * executable prefix.
- * Michael Brown 30 Mar 2004
- *
- * - Modified to be compilable as either 16-bit or 32-bit code.
- * Michael Brown 9 Mar 2005
- */
-
-FILE_LICENCE ( GPL2_OR_LATER )
-
-/****************************************************************************
- * This file provides the decompress() and decompress16() functions
- * which can be called in order to decompress an image compressed with
- * the nrv2b utility in src/util.
- *
- * These functions are designed to be called by the prefix. They are
- * position-independent code.
- *
- * The same basic assembly code is used to compile both
- * decompress() and decompress16().
- ****************************************************************************
- */
-
- .text
- .arch i386
- .section ".prefix.lib", "ax", @progbits
-
-#ifdef CODE16
-/****************************************************************************
- * decompress16 (real-mode near call, position independent)
- *
- * Decompress data in 16-bit mode
- *
- * Parameters (passed via registers):
- * %ds:%esi - Start of compressed input data
- * %es:%edi - Start of output buffer
- * Returns:
- * %ds:%esi - End of compressed input data
- * %es:%edi - End of decompressed output data
- * All other registers are preserved
- *
- * NOTE: It would be possible to build a smaller version of the
- * decompression code for -DKEEP_IT_REAL by using
- * #define REG(x) x
- * to use 16-bit registers where possible. This would impose limits
- * that the compressed data size must be in the range [1,65533-%si]
- * and the uncompressed data size must be in the range [1,65536-%di]
- * (where %si and %di are the input values for those registers). Note
- * particularly that the lower limit is 1, not 0, and that the upper
- * limit on the input (compressed) data really is 65533, since the
- * algorithm may read up to three bytes beyond the end of the input
- * data, since it reads dwords.
- ****************************************************************************
- */
-
-#define REG(x) e ## x
-#define ADDR32 addr32
-
- .code16
- .globl decompress16
-decompress16:
-
-#else /* CODE16 */
-
-/****************************************************************************
- * decompress (32-bit protected-mode near call, position independent)
- *
- * Parameters (passed via registers):
- * %ds:%esi - Start of compressed input data
- * %es:%edi - Start of output buffer
- * Returns:
- * %ds:%esi - End of compressed input data
- * %es:%edi - End of decompressed output data
- * All other registers are preserved
- ****************************************************************************
- */
-
-#define REG(x) e ## x
-#define ADDR32
-
- .code32
- .globl decompress
-decompress:
-
-#endif /* CODE16 */
-
-#define xAX REG(ax)
-#define xCX REG(cx)
-#define xBP REG(bp)
-#define xSI REG(si)
-#define xDI REG(di)
-
- /* Save registers */
- push %xAX
- pushl %ebx
- push %xCX
- push %xBP
- /* Do the decompression */
- cld
- xor %xBP, %xBP
- dec %xBP /* last_m_off = -1 */
- jmp dcl1_n2b
-
-decompr_literals_n2b:
- ADDR32 movsb
-decompr_loop_n2b:
- addl %ebx, %ebx
- jnz dcl2_n2b
-dcl1_n2b:
- call getbit32
-dcl2_n2b:
- jc decompr_literals_n2b
- xor %xAX, %xAX
- inc %xAX /* m_off = 1 */
-loop1_n2b:
- call getbit1
- adc %xAX, %xAX /* m_off = m_off*2 + getbit() */
- call getbit1
- jnc loop1_n2b /* while(!getbit()) */
- sub $3, %xAX
- jb decompr_ebpeax_n2b /* if (m_off == 2) goto decompr_ebpeax_n2b ? */
- shl $8, %xAX
- ADDR32 movb (%xSI), %al /* m_off = (m_off - 3)*256 + src[ilen++] */
- inc %xSI
- xor $-1, %xAX
- jz decompr_end_n2b /* if (m_off == 0xffffffff) goto decomp_end_n2b */
- mov %xAX, %xBP /* last_m_off = m_off ?*/
-decompr_ebpeax_n2b:
- xor %xCX, %xCX
- call getbit1
- adc %xCX, %xCX /* m_len = getbit() */
- call getbit1
- adc %xCX, %xCX /* m_len = m_len*2 + getbit()) */
- jnz decompr_got_mlen_n2b /* if (m_len == 0) goto decompr_got_mlen_n2b */
- inc %xCX /* m_len++ */
-loop2_n2b:
- call getbit1
- adc %xCX, %xCX /* m_len = m_len*2 + getbit() */
- call getbit1
- jnc loop2_n2b /* while(!getbit()) */
- inc %xCX
- inc %xCX /* m_len += 2 */
-decompr_got_mlen_n2b:
- cmp $-0xd00, %xBP
- adc $1, %xCX /* m_len = m_len + 1 + (last_m_off > 0xd00) */
- push %xSI
- ADDR32 lea (%xBP,%xDI), %xSI /* m_pos = dst + olen + -m_off */
- rep
- es ADDR32 movsb /* dst[olen++] = *m_pos++ while(m_len > 0) */
- pop %xSI
- jmp decompr_loop_n2b
-
-
-getbit1:
- addl %ebx, %ebx
- jnz 1f
-getbit32:
- ADDR32 movl (%xSI), %ebx
- sub $-4, %xSI /* sets carry flag */
- adcl %ebx, %ebx
-1:
- ret
-
-decompr_end_n2b:
- /* Restore registers and return */
- pop %xBP
- pop %xCX
- popl %ebx
- pop %xAX
- ret
diff --git a/roms/ipxe/src/arch/i386/prefix/usbdisk.S b/roms/ipxe/src/arch/i386/prefix/usbdisk.S
index fa7d1956e..9676406e2 100644
--- a/roms/ipxe/src/arch/i386/prefix/usbdisk.S
+++ b/roms/ipxe/src/arch/i386/prefix/usbdisk.S
@@ -1,3 +1,5 @@
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
+
.text
.arch i386
.section ".prefix", "awx", @progbits
@@ -6,18 +8,27 @@
#include "mbr.S"
-/* Partition table: ZIP-compatible partition 4, 64 heads, 32 sectors/track */
+/* Partition table: 64 heads, 32 sectors/track (ZIP-drive compatible) */
.org 446
.space 16
.space 16
- .space 16
- .byte 0x80, 0x01, 0x01, 0x00
- .byte 0xeb, 0x3f, 0x20, 0x01
+ /* Partition 3: log partition (for CONSOLE_INT13) */
+ .byte 0x00, 0x01, 0x01, 0x00
+ .byte 0xe0, 0x3f, 0x20, 0x00
.long 0x00000020
- .long 0x00000fe0
+ .long 0x000007e0
+ /* Partition 4: boot partition */
+ .byte 0x80, 0x00, 0x01, 0x01
+ .byte 0xeb, 0x3f, 0x20, 0x02
+ .long 0x00000800
+ .long 0x00001000
.org 510
.byte 0x55, 0xaa
-/* Skip to start of partition */
+/* Skip to start of log partition */
.org 32 * 512
+ .ascii "iPXE LOG\n\n"
+
+/* Skip to start of boot partition */
+ .org 2048 * 512
diff --git a/roms/ipxe/src/arch/i386/scripts/i386.lds b/roms/ipxe/src/arch/i386/scripts/i386.lds
index 98f95cb23..38c89e14b 100644
--- a/roms/ipxe/src/arch/i386/scripts/i386.lds
+++ b/roms/ipxe/src/arch/i386/scripts/i386.lds
@@ -27,6 +27,13 @@ SECTIONS {
PROVIDE ( _max_align = 16 );
/*
+ * Allow decompressor to require a minimum amount of temporary stack
+ * space.
+ *
+ */
+ PROVIDE ( _min_decompress_stack = 0 );
+
+ /*
* The prefix
*
*/
@@ -34,6 +41,7 @@ SECTIONS {
.prefix 0x0 : AT ( _prefix_lma ) {
_prefix = .;
*(.prefix)
+ *(SORT(.pci_devlist.*))
*(.prefix.*)
_mprefix = .;
} .bss.prefix (NOLOAD) : AT ( _end_lma ) {
@@ -87,6 +95,7 @@ SECTIONS {
*(.bss16.*)
*(.stack16)
*(.stack16.*)
+ . = MAX ( ., _mdata16 + _min_decompress_stack );
_edata16 = .;
}
_data16_filesz = ABSOLUTE ( _mdata16 ) - ABSOLUTE ( _data16 );
diff --git a/roms/ipxe/src/arch/i386/transitions/liba20.S b/roms/ipxe/src/arch/i386/transitions/liba20.S
index 684697525..6c1e1f62f 100644
--- a/roms/ipxe/src/arch/i386/transitions/liba20.S
+++ b/roms/ipxe/src/arch/i386/transitions/liba20.S
@@ -16,9 +16,13 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ *
*/
-FILE_LICENCE ( GPL2_OR_LATER )
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
.arch i386
diff --git a/roms/ipxe/src/arch/i386/transitions/libkir.S b/roms/ipxe/src/arch/i386/transitions/libkir.S
index 1176fcced..fa9459d52 100644
--- a/roms/ipxe/src/arch/i386/transitions/libkir.S
+++ b/roms/ipxe/src/arch/i386/transitions/libkir.S
@@ -5,7 +5,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER )
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
/****************************************************************************
* This file defines libkir: an interface between external and
diff --git a/roms/ipxe/src/arch/i386/transitions/librm.S b/roms/ipxe/src/arch/i386/transitions/librm.S
index 2e447b030..863e22415 100644
--- a/roms/ipxe/src/arch/i386/transitions/librm.S
+++ b/roms/ipxe/src/arch/i386/transitions/librm.S
@@ -5,7 +5,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER )
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
/* Drag in local definitions */
#include "librm.h"
diff --git a/roms/ipxe/src/arch/i386/transitions/librm_mgmt.c b/roms/ipxe/src/arch/i386/transitions/librm_mgmt.c
index cc4765de2..becb02677 100644
--- a/roms/ipxe/src/arch/i386/transitions/librm_mgmt.c
+++ b/roms/ipxe/src/arch/i386/transitions/librm_mgmt.c
@@ -5,7 +5,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/profile.h>
@@ -103,7 +103,7 @@ void init_idt ( void ) {
( uint32_t ) vec->next );
set_interrupt_vector ( intr, vec );
}
- DBGC ( &intr_vec[0], "INTn vector at %p+%xn (phys %#lx+%xn)\n",
+ DBGC ( &intr_vec[0], "INTn vector at %p+%zxn (phys %#lx+%zxn)\n",
intr_vec, sizeof ( intr_vec[0] ),
virt_to_phys ( intr_vec ), sizeof ( intr_vec[0] ) );
diff --git a/roms/ipxe/src/arch/i386/transitions/librm_test.c b/roms/ipxe/src/arch/i386/transitions/librm_test.c
index e07cfccdd..f1a517eda 100644
--- a/roms/ipxe/src/arch/i386/transitions/librm_test.c
+++ b/roms/ipxe/src/arch/i386/transitions/librm_test.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
@@ -114,4 +118,5 @@ struct self_test librm_test __self_test = {
.exec = librm_test_exec,
};
+REQUIRING_SYMBOL ( librm_test );
REQUIRE_OBJECT ( test );
diff --git a/roms/ipxe/src/arch/x86/Makefile b/roms/ipxe/src/arch/x86/Makefile
index e555587df..98c49b98d 100644
--- a/roms/ipxe/src/arch/x86/Makefile
+++ b/roms/ipxe/src/arch/x86/Makefile
@@ -9,9 +9,14 @@ SRCDIRS += arch/x86/interface/efi
SRCDIRS += arch/x86/prefix
SRCDIRS += arch/x86/hci/commands
SRCDIRS += arch/x86/drivers/xen
+SRCDIRS += arch/x86/drivers/hyperv
# breaks building some of the linux-related objects
CFLAGS += -Ulinux
# disable valgrind
CFLAGS += -DNVALGRIND
+
+# Include Hyper-V driver in the all-drivers build
+#
+DRIVERS_hyperv += hyperv
diff --git a/roms/ipxe/src/arch/x86/Makefile.efi b/roms/ipxe/src/arch/x86/Makefile.efi
index 13a69d9f7..f73bc7d5d 100644
--- a/roms/ipxe/src/arch/x86/Makefile.efi
+++ b/roms/ipxe/src/arch/x86/Makefile.efi
@@ -17,7 +17,7 @@ NON_AUTO_MEDIA += efirom
# Include SNP driver in the all-drivers build
#
-DRIVERS += snp
+DRIVERS_net += snp
# Rules for building EFI files
#
diff --git a/roms/ipxe/src/arch/x86/core/cpuid.c b/roms/ipxe/src/arch/x86/core/cpuid.c
index 5908f4419..bc5a6c68c 100644
--- a/roms/ipxe/src/arch/x86/core/cpuid.c
+++ b/roms/ipxe/src/arch/x86/core/cpuid.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <ipxe/cpuid.h>
diff --git a/roms/ipxe/src/arch/x86/core/cpuid_settings.c b/roms/ipxe/src/arch/x86/core/cpuid_settings.c
index 42dea9336..08bd3918a 100644
--- a/roms/ipxe/src/arch/x86/core/cpuid_settings.c
+++ b/roms/ipxe/src/arch/x86/core/cpuid_settings.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <errno.h>
diff --git a/roms/ipxe/src/arch/x86/core/debugcon.c b/roms/ipxe/src/arch/x86/core/debugcon.c
index 263cb4af1..60de61f55 100644
--- a/roms/ipxe/src/arch/x86/core/debugcon.c
+++ b/roms/ipxe/src/arch/x86/core/debugcon.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/arch/x86/core/pcidirect.c b/roms/ipxe/src/arch/x86/core/pcidirect.c
index dbc8317b8..9b8e6b1d9 100644
--- a/roms/ipxe/src/arch/x86/core/pcidirect.c
+++ b/roms/ipxe/src/arch/x86/core/pcidirect.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/io.h>
#include <ipxe/pci.h>
diff --git a/roms/ipxe/src/arch/i386/core/pic8259.c b/roms/ipxe/src/arch/x86/core/pic8259.c
index 0a9ea2e03..0a9ea2e03 100644
--- a/roms/ipxe/src/arch/i386/core/pic8259.c
+++ b/roms/ipxe/src/arch/x86/core/pic8259.c
diff --git a/roms/ipxe/src/arch/x86/core/pit8254.c b/roms/ipxe/src/arch/x86/core/pit8254.c
new file mode 100644
index 000000000..da2099263
--- /dev/null
+++ b/roms/ipxe/src/arch/x86/core/pit8254.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2015 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <assert.h>
+#include <ipxe/io.h>
+#include <ipxe/pit8254.h>
+
+/** @file
+ *
+ * 8254 Programmable Interval Timer
+ *
+ */
+
+/**
+ * Delay for a fixed number of timer ticks using the speaker channel
+ *
+ * @v ticks Number of timer ticks for which to delay
+ */
+void pit8254_speaker_delay ( unsigned int ticks ) {
+ uint8_t spkr;
+ uint8_t cmd;
+ uint8_t low;
+ uint8_t high;
+
+ /* Sanity check */
+ assert ( ticks <= 0xffff );
+
+ /* Disable speaker, set speaker channel gate input high */
+ spkr = inb ( PIT8254_SPKR );
+ spkr &= ~PIT8254_SPKR_ENABLE;
+ spkr |= PIT8254_SPKR_GATE;
+ outb ( spkr, PIT8254_SPKR );
+
+ /* Program speaker channel to "interrupt" on terminal count */
+ cmd = ( PIT8254_CMD_CHANNEL ( PIT8254_CH_SPKR ) |
+ PIT8254_CMD_ACCESS_LOHI | PIT8254_CMD_OP_TERMINAL |
+ PIT8254_CMD_BINARY );
+ low = ( ( ticks >> 0 ) & 0xff );
+ high = ( ( ticks >> 8 ) & 0xff );
+ outb ( cmd, PIT8254_CMD );
+ outb ( low, PIT8254_DATA ( PIT8254_CH_SPKR ) );
+ outb ( high, PIT8254_DATA ( PIT8254_CH_SPKR ) );
+
+ /* Wait for channel to "interrupt" */
+ do {
+ spkr = inb ( PIT8254_SPKR );
+ } while ( ! ( spkr & PIT8254_SPKR_OUT ) );
+}
diff --git a/roms/ipxe/src/arch/x86/core/vram_settings.c b/roms/ipxe/src/arch/x86/core/vram_settings.c
new file mode 100644
index 000000000..9c169b40c
--- /dev/null
+++ b/roms/ipxe/src/arch/x86/core/vram_settings.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <ipxe/uaccess.h>
+#include <ipxe/settings.h>
+
+/** @file
+ *
+ * Video RAM dump
+ *
+ */
+
+/** Video RAM base address */
+#define VRAM_BASE 0xb8000
+
+/** Video RAM length */
+#define VRAM_LEN \
+ ( 80 /* columns */ * 25 /* rows */ * 2 /* bytes per character */ )
+
+/**
+ * Fetch video RAM setting
+ *
+ * @v data Buffer to fill with setting data
+ * @v len Length of buffer
+ * @ret len Length of setting data, or negative error
+ */
+static int vram_fetch ( void *data, size_t len ) {
+ userptr_t vram = phys_to_user ( VRAM_BASE );
+
+ /* Copy video RAM */
+ if ( len > VRAM_LEN )
+ len = VRAM_LEN;
+ copy_from_user ( data, vram, 0, len );
+
+ return VRAM_LEN;
+}
+
+/** Video RAM setting */
+const struct setting vram_setting __setting ( SETTING_MISC, vram ) = {
+ .name = "vram",
+ .description = "Video RAM",
+ .type = &setting_type_base64,
+ .scope = &builtin_scope,
+};
+
+/** Video RAM built-in setting */
+struct builtin_setting vram_builtin_setting __builtin_setting = {
+ .setting = &vram_setting,
+ .fetch = vram_fetch,
+};
diff --git a/roms/ipxe/src/arch/x86/core/x86_bigint.c b/roms/ipxe/src/arch/x86/core/x86_bigint.c
index 418ac2309..6413b2fa8 100644
--- a/roms/ipxe/src/arch/x86/core/x86_bigint.c
+++ b/roms/ipxe/src/arch/x86/core/x86_bigint.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <string.h>
diff --git a/roms/ipxe/src/arch/x86/core/x86_io.c b/roms/ipxe/src/arch/x86/core/x86_io.c
index 9b2d2d935..3081fa8b9 100644
--- a/roms/ipxe/src/arch/x86/core/x86_io.c
+++ b/roms/ipxe/src/arch/x86/core/x86_io.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/io.h>
#include <ipxe/x86_io.h>
diff --git a/roms/ipxe/src/arch/x86/core/x86_string.c b/roms/ipxe/src/arch/x86/core/x86_string.c
index d48347c96..7d5e4a5f1 100644
--- a/roms/ipxe/src/arch/x86/core/x86_string.c
+++ b/roms/ipxe/src/arch/x86/core/x86_string.c
@@ -15,6 +15,10 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
/** @file
@@ -23,7 +27,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
@@ -104,87 +108,3 @@ void * __memmove ( void *dest, const void *src, size_t len ) {
return __memcpy_reverse ( dest, src, len );
}
}
-
-/**
- * Swap memory areas
- *
- * @v dest Destination address
- * @v src Source address
- * @v len Length
- * @ret dest Destination address
- */
-void * memswap ( void *dest, void *src, size_t len ) {
- size_t discard_c;
- int discard;
-
- __asm__ __volatile__ ( "\n1:\n\t"
- "dec %2\n\t"
- "js 2f\n\t"
- "movb (%0,%2), %b3\n\t"
- "xchgb (%1,%2), %b3\n\t"
- "movb %b3, (%0,%2)\n\t"
- "jmp 1b\n\t"
- "2:\n\t"
- : "=r" ( src ), "=r" ( dest ),
- "=&c" ( discard_c ), "=&q" ( discard )
- : "0" ( src ), "1" ( dest ), "2" ( len )
- : "memory" );
-
- return dest;
-}
-
-/**
- * Calculate length of string
- *
- * @v string String
- * @ret len Length (excluding NUL)
- */
-size_t strlen ( const char *string ) {
- const char *discard_D;
- size_t len_plus_one;
-
- __asm__ __volatile__ ( "repne scasb\n\t"
- "not %1\n\t"
- : "=&D" ( discard_D ), "=&c" ( len_plus_one )
- : "0" ( string ), "1" ( -1UL ), "a" ( 0 ) );
-
- return ( len_plus_one - 1 );
-}
-
-/**
- * Compare strings (up to a specified length)
- *
- * @v str1 First string
- * @v str2 Second string
- * @v len Maximum length
- * @ret diff Difference
- */
-int strncmp ( const char *str1, const char *str2, size_t len ) {
- const void *discard_S;
- const void *discard_D;
- size_t discard_c;
- int diff;
-
- __asm__ __volatile__ ( "\n1:\n\t"
- "dec %2\n\t"
- "js 2f\n\t"
- "lodsb\n\t"
- "scasb\n\t"
- "jne 3f\n\t"
- "testb %b3, %b3\n\t"
- "jnz 1b\n\t"
- /* Equal */
- "\n2:\n\t"
- "xor %3, %3\n\t"
- "jmp 4f\n\t"
- /* Not equal; CF indicates difference */
- "\n3:\n\t"
- "sbb %3, %3\n\t"
- "orb $1, %b3\n\t"
- "\n4:\n\t"
- : "=&S" ( discard_S ), "=&D" ( discard_D ),
- "=&c" ( discard_c ), "=&a" ( diff )
- : "0" ( str1 ), "1" ( str2 ), "2" ( len ) );
-
- return diff;
-}
diff --git a/roms/ipxe/src/arch/x86/core/x86_tcpip.c b/roms/ipxe/src/arch/x86/core/x86_tcpip.c
index 8a4ce5152..88042f5f7 100644
--- a/roms/ipxe/src/arch/x86/core/x86_tcpip.c
+++ b/roms/ipxe/src/arch/x86/core/x86_tcpip.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/arch/x86/core/x86_uart.c b/roms/ipxe/src/arch/x86/core/x86_uart.c
new file mode 100644
index 000000000..e455775bf
--- /dev/null
+++ b/roms/ipxe/src/arch/x86/core/x86_uart.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/** @file
+ *
+ * 16550-compatible UART
+ *
+ */
+
+#include <errno.h>
+#include <ipxe/uart.h>
+
+/** UART port bases */
+static uint16_t uart_base[] = {
+ [COM1] = 0x3f8,
+ [COM2] = 0x2f8,
+ [COM3] = 0x3e8,
+ [COM4] = 0x2e8,
+};
+
+/**
+ * Select UART port
+ *
+ * @v uart UART
+ * @v port Port number, or 0 to disable
+ * @ret rc Return status code
+ */
+int uart_select ( struct uart *uart, unsigned int port ) {
+ int rc;
+
+ /* Set new UART base */
+ if ( port >= ( sizeof ( uart_base ) / sizeof ( uart_base[0] ) ) ) {
+ rc = -ENODEV;
+ goto err;
+ }
+ uart->base = ( ( void * ) ( intptr_t ) uart_base[port] );
+
+ /* Check that UART exists */
+ if ( ( rc = uart_exists ( uart ) ) != 0 )
+ goto err;
+
+ return 0;
+
+ err:
+ uart->base = NULL;
+ return rc;
+}
diff --git a/roms/ipxe/src/arch/x86/drivers/hyperv/hyperv.c b/roms/ipxe/src/arch/x86/drivers/hyperv/hyperv.c
new file mode 100644
index 000000000..f73829bd5
--- /dev/null
+++ b/roms/ipxe/src/arch/x86/drivers/hyperv/hyperv.c
@@ -0,0 +1,597 @@
+/*
+ * Copyright (C) 2014 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/** @file
+ *
+ * Hyper-V driver
+ *
+ */
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <pic8259.h>
+#include <ipxe/malloc.h>
+#include <ipxe/device.h>
+#include <ipxe/cpuid.h>
+#include <ipxe/msr.h>
+#include <ipxe/hyperv.h>
+#include <ipxe/vmbus.h>
+#include "hyperv.h"
+
+/** Maximum time to wait for a message response
+ *
+ * This is a policy decision.
+ */
+#define HV_MESSAGE_MAX_WAIT_MS 1000
+
+/**
+ * Convert a Hyper-V status code to an iPXE status code
+ *
+ * @v status Hyper-V status code
+ * @ret rc iPXE status code (before negation)
+ */
+#define EHV( status ) EPLATFORM ( EINFO_EPLATFORM, (status) )
+
+/**
+ * Allocate zeroed pages
+ *
+ * @v hv Hyper-V hypervisor
+ * @v ... Page addresses to fill in, terminated by NULL
+ * @ret rc Return status code
+ */
+__attribute__ (( sentinel )) int
+hv_alloc_pages ( struct hv_hypervisor *hv, ... ) {
+ va_list args;
+ void **page;
+ int i;
+
+ /* Allocate and zero pages */
+ va_start ( args, hv );
+ for ( i = 0 ; ( ( page = va_arg ( args, void ** ) ) != NULL ); i++ ) {
+ *page = malloc_dma ( PAGE_SIZE, PAGE_SIZE );
+ if ( ! *page )
+ goto err_alloc;
+ memset ( *page, 0, PAGE_SIZE );
+ }
+ va_end ( args );
+
+ return 0;
+
+ err_alloc:
+ va_end ( args );
+ va_start ( args, hv );
+ for ( ; i >= 0 ; i-- ) {
+ page = va_arg ( args, void ** );
+ free_dma ( *page, PAGE_SIZE );
+ }
+ va_end ( args );
+ return -ENOMEM;
+}
+
+/**
+ * Free pages
+ *
+ * @v hv Hyper-V hypervisor
+ * @v ... Page addresses, terminated by NULL
+ */
+__attribute__ (( sentinel )) void
+hv_free_pages ( struct hv_hypervisor *hv, ... ) {
+ va_list args;
+ void *page;
+
+ va_start ( args, hv );
+ while ( ( page = va_arg ( args, void * ) ) != NULL )
+ free_dma ( page, PAGE_SIZE );
+ va_end ( args );
+}
+
+/**
+ * Allocate message buffer
+ *
+ * @v hv Hyper-V hypervisor
+ * @ret rc Return status code
+ */
+static int hv_alloc_message ( struct hv_hypervisor *hv ) {
+
+ /* Allocate buffer. Must be aligned to at least 8 bytes and
+ * must not cross a page boundary, so align on its own size.
+ */
+ hv->message = malloc_dma ( sizeof ( *hv->message ),
+ sizeof ( *hv->message ) );
+ if ( ! hv->message )
+ return -ENOMEM;
+
+ return 0;
+}
+
+/**
+ * Free message buffer
+ *
+ * @v hv Hyper-V hypervisor
+ */
+static void hv_free_message ( struct hv_hypervisor *hv ) {
+
+ /* Free buffer */
+ free_dma ( hv->message, sizeof ( *hv->message ) );
+}
+
+/**
+ * Check whether or not we are running in Hyper-V
+ *
+ * @v hv Hyper-V hypervisor
+ * @ret rc Return status code
+ */
+static int hv_check_hv ( struct hv_hypervisor *hv ) {
+ struct x86_features features;
+ uint32_t interface_id;
+ uint32_t discard_ebx;
+ uint32_t discard_ecx;
+ uint32_t discard_edx;
+ uint32_t available;
+ uint32_t permissions;
+
+ /* Check for presence of a hypervisor (not necessarily Hyper-V) */
+ x86_features ( &features );
+ if ( ! ( features.intel.ecx & CPUID_FEATURES_INTEL_ECX_HYPERVISOR ) ) {
+ DBGC ( hv, "HV %p not running in a hypervisor\n", hv );
+ return -ENODEV;
+ }
+
+ /* Check that hypervisor is Hyper-V */
+ cpuid ( HV_CPUID_INTERFACE_ID, &interface_id, &discard_ebx,
+ &discard_ecx, &discard_edx );
+ if ( interface_id != HV_INTERFACE_ID ) {
+ DBGC ( hv, "HV %p not running in Hyper-V (interface ID "
+ "%#08x)\n", hv, interface_id );
+ return -ENODEV;
+ }
+
+ /* Check that required features and privileges are available */
+ cpuid ( HV_CPUID_FEATURES, &available, &permissions, &discard_ecx,
+ &discard_edx );
+ if ( ! ( available & HV_FEATURES_AVAIL_HYPERCALL_MSR ) ) {
+ DBGC ( hv, "HV %p has no hypercall MSRs (features %08x:%08x)\n",
+ hv, available, permissions );
+ return -ENODEV;
+ }
+ if ( ! ( available & HV_FEATURES_AVAIL_SYNIC_MSR ) ) {
+ DBGC ( hv, "HV %p has no SynIC MSRs (features %08x:%08x)\n",
+ hv, available, permissions );
+ return -ENODEV;
+ }
+ if ( ! ( permissions & HV_FEATURES_PERM_POST_MESSAGES ) ) {
+ DBGC ( hv, "HV %p cannot post messages (features %08x:%08x)\n",
+ hv, available, permissions );
+ return -EACCES;
+ }
+ if ( ! ( permissions & HV_FEATURES_PERM_SIGNAL_EVENTS ) ) {
+ DBGC ( hv, "HV %p cannot signal events (features %08x:%08x)",
+ hv, available, permissions );
+ return -EACCES;
+ }
+
+ return 0;
+}
+
+/**
+ * Map hypercall page
+ *
+ * @v hv Hyper-V hypervisor
+ * @ret rc Return status code
+ */
+static int hv_map_hypercall ( struct hv_hypervisor *hv ) {
+ union {
+ struct {
+ uint32_t ebx;
+ uint32_t ecx;
+ uint32_t edx;
+ } __attribute__ (( packed ));
+ char text[ 13 /* "bbbbccccdddd" + NUL */ ];
+ } vendor_id;
+ uint32_t build;
+ uint32_t version;
+ uint32_t discard_eax;
+ uint32_t discard_ecx;
+ uint32_t discard_edx;
+ uint64_t guest_os_id;
+ uint64_t hypercall;
+
+ /* Report guest OS identity */
+ guest_os_id = rdmsr ( HV_X64_MSR_GUEST_OS_ID );
+ if ( guest_os_id != 0 ) {
+ DBGC ( hv, "HV %p guest OS ID MSR already set to %#08llx\n",
+ hv, guest_os_id );
+ return -EBUSY;
+ }
+ guest_os_id = HV_GUEST_OS_ID_IPXE;
+ DBGC2 ( hv, "HV %p guest OS ID MSR is %#08llx\n", hv, guest_os_id );
+ wrmsr ( HV_X64_MSR_GUEST_OS_ID, guest_os_id );
+
+ /* Get hypervisor system identity (for debugging) */
+ cpuid ( HV_CPUID_VENDOR_ID, &discard_eax, &vendor_id.ebx,
+ &vendor_id.ecx, &vendor_id.edx );
+ vendor_id.text[ sizeof ( vendor_id.text ) - 1 ] = '\0';
+ cpuid ( HV_CPUID_HYPERVISOR_ID, &build, &version, &discard_ecx,
+ &discard_edx );
+ DBGC ( hv, "HV %p detected \"%s\" version %d.%d build %d\n", hv,
+ vendor_id.text, ( version >> 16 ), ( version & 0xffff ), build );
+
+ /* Map hypercall page */
+ hypercall = rdmsr ( HV_X64_MSR_HYPERCALL );
+ hypercall &= ( PAGE_SIZE - 1 );
+ hypercall |= ( virt_to_phys ( hv->hypercall ) | HV_HYPERCALL_ENABLE );
+ DBGC2 ( hv, "HV %p hypercall MSR is %#08llx\n", hv, hypercall );
+ wrmsr ( HV_X64_MSR_HYPERCALL, hypercall );
+
+ return 0;
+}
+
+/**
+ * Unmap hypercall page
+ *
+ * @v hv Hyper-V hypervisor
+ */
+static void hv_unmap_hypercall ( struct hv_hypervisor *hv ) {
+ uint64_t hypercall;
+ uint64_t guest_os_id;
+
+ /* Unmap the hypercall page */
+ hypercall = rdmsr ( HV_X64_MSR_HYPERCALL );
+ hypercall &= ( ( PAGE_SIZE - 1 ) & ~HV_HYPERCALL_ENABLE );
+ DBGC2 ( hv, "HV %p hypercall MSR is %#08llx\n", hv, hypercall );
+ wrmsr ( HV_X64_MSR_HYPERCALL, hypercall );
+
+ /* Reset the guest OS identity */
+ guest_os_id = 0;
+ DBGC2 ( hv, "HV %p guest OS ID MSR is %#08llx\n", hv, guest_os_id );
+ wrmsr ( HV_X64_MSR_GUEST_OS_ID, guest_os_id );
+}
+
+/**
+ * Map synthetic interrupt controller
+ *
+ * @v hv Hyper-V hypervisor
+ * @ret rc Return status code
+ */
+static int hv_map_synic ( struct hv_hypervisor *hv ) {
+ uint64_t simp;
+ uint64_t siefp;
+ uint64_t scontrol;
+
+ /* Map SynIC message page */
+ simp = rdmsr ( HV_X64_MSR_SIMP );
+ simp &= ( PAGE_SIZE - 1 );
+ simp |= ( virt_to_phys ( hv->synic.message ) | HV_SIMP_ENABLE );
+ DBGC2 ( hv, "HV %p SIMP MSR is %#08llx\n", hv, simp );
+ wrmsr ( HV_X64_MSR_SIMP, simp );
+
+ /* Map SynIC event page */
+ siefp = rdmsr ( HV_X64_MSR_SIEFP );
+ siefp &= ( PAGE_SIZE - 1 );
+ siefp |= ( virt_to_phys ( hv->synic.event ) | HV_SIEFP_ENABLE );
+ DBGC2 ( hv, "HV %p SIEFP MSR is %#08llx\n", hv, siefp );
+ wrmsr ( HV_X64_MSR_SIEFP, siefp );
+
+ /* Enable SynIC */
+ scontrol = rdmsr ( HV_X64_MSR_SCONTROL );
+ scontrol |= HV_SCONTROL_ENABLE;
+ DBGC2 ( hv, "HV %p SCONTROL MSR is %#08llx\n", hv, scontrol );
+ wrmsr ( HV_X64_MSR_SCONTROL, scontrol );
+
+ return 0;
+}
+
+/**
+ * Unmap synthetic interrupt controller
+ *
+ * @v hv Hyper-V hypervisor
+ */
+static void hv_unmap_synic ( struct hv_hypervisor *hv ) {
+ uint64_t scontrol;
+ uint64_t siefp;
+ uint64_t simp;
+
+ /* Disable SynIC */
+ scontrol = rdmsr ( HV_X64_MSR_SCONTROL );
+ scontrol &= ~HV_SCONTROL_ENABLE;
+ DBGC2 ( hv, "HV %p SCONTROL MSR is %#08llx\n", hv, scontrol );
+ wrmsr ( HV_X64_MSR_SCONTROL, scontrol );
+
+ /* Unmap SynIC event page */
+ siefp = rdmsr ( HV_X64_MSR_SIEFP );
+ siefp &= ( ( PAGE_SIZE - 1 ) & ~HV_SIEFP_ENABLE );
+ DBGC2 ( hv, "HV %p SIEFP MSR is %#08llx\n", hv, siefp );
+ wrmsr ( HV_X64_MSR_SIEFP, siefp );
+
+ /* Unmap SynIC message page */
+ simp = rdmsr ( HV_X64_MSR_SIMP );
+ simp &= ( ( PAGE_SIZE - 1 ) & ~HV_SIMP_ENABLE );
+ DBGC2 ( hv, "HV %p SIMP MSR is %#08llx\n", hv, simp );
+ wrmsr ( HV_X64_MSR_SIMP, simp );
+}
+
+/**
+ * Enable synthetic interrupt
+ *
+ * @v hv Hyper-V hypervisor
+ * @v sintx Synthetic interrupt number
+ */
+void hv_enable_sint ( struct hv_hypervisor *hv, unsigned int sintx ) {
+ unsigned long msr = HV_X64_MSR_SINT ( sintx );
+ uint64_t sint;
+
+ /* Enable synthetic interrupt
+ *
+ * We have to enable the interrupt, otherwise messages will
+ * not be delivered (even though the documentation implies
+ * that polling for messages is possible). We enable AutoEOI
+ * and hook the interrupt to the obsolete IRQ13 (FPU
+ * exception) vector, which will be implemented as a no-op.
+ */
+ sint = rdmsr ( msr );
+ sint &= ~( HV_SINT_MASKED | HV_SINT_VECTOR_MASK );
+ sint |= ( HV_SINT_AUTO_EOI |
+ HV_SINT_VECTOR ( IRQ_INT ( 13 /* See comment above */ ) ) );
+ DBGC2 ( hv, "HV %p SINT%d MSR is %#08llx\n", hv, sintx, sint );
+ wrmsr ( msr, sint );
+}
+
+/**
+ * Disable synthetic interrupt
+ *
+ * @v hv Hyper-V hypervisor
+ * @v sintx Synthetic interrupt number
+ */
+void hv_disable_sint ( struct hv_hypervisor *hv, unsigned int sintx ) {
+ unsigned long msr = HV_X64_MSR_SINT ( sintx );
+ uint64_t sint;
+
+ /* Disable synthetic interrupt */
+ sint = rdmsr ( msr );
+ sint &= ~HV_SINT_AUTO_EOI;
+ sint |= HV_SINT_MASKED;
+ DBGC2 ( hv, "HV %p SINT%d MSR is %#08llx\n", hv, sintx, sint );
+ wrmsr ( msr, sint );
+}
+
+/**
+ * Post message
+ *
+ * @v hv Hyper-V hypervisor
+ * @v id Connection ID
+ * @v type Message type
+ * @v data Message
+ * @v len Length of message
+ * @ret rc Return status code
+ */
+int hv_post_message ( struct hv_hypervisor *hv, unsigned int id,
+ unsigned int type, const void *data, size_t len ) {
+ struct hv_post_message *msg = &hv->message->posted;
+ int status;
+ int rc;
+
+ /* Sanity check */
+ assert ( len <= sizeof ( msg->data ) );
+
+ /* Construct message */
+ memset ( msg, 0, sizeof ( *msg ) );
+ msg->id = cpu_to_le32 ( id );
+ msg->type = cpu_to_le32 ( type );
+ msg->len = cpu_to_le32 ( len );
+ memcpy ( msg->data, data, len );
+ DBGC2 ( hv, "HV %p connection %d posting message type %#08x:\n",
+ hv, id, type );
+ DBGC2_HDA ( hv, 0, msg->data, len );
+
+ /* Post message */
+ if ( ( status = hv_call ( hv, HV_POST_MESSAGE, msg, NULL ) ) != 0 ) {
+ rc = -EHV ( status );
+ DBGC ( hv, "HV %p could not post message to %#08x: %s\n",
+ hv, id, strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Wait for received message
+ *
+ * @v hv Hyper-V hypervisor
+ * @v sintx Synthetic interrupt number
+ * @ret rc Return status code
+ */
+int hv_wait_for_message ( struct hv_hypervisor *hv, unsigned int sintx ) {
+ struct hv_message *msg = &hv->message->received;
+ struct hv_message *src = &hv->synic.message[sintx];
+ unsigned int retries;
+ size_t len;
+
+ /* Wait for message to arrive */
+ for ( retries = 0 ; retries < HV_MESSAGE_MAX_WAIT_MS ; retries++ ) {
+
+ /* Check for message */
+ if ( src->type ) {
+
+ /* Copy message */
+ memset ( msg, 0, sizeof ( *msg ) );
+ len = src->len;
+ assert ( len <= sizeof ( *msg ) );
+ memcpy ( msg, src,
+ ( offsetof ( typeof ( *msg ), data ) + len ) );
+ DBGC2 ( hv, "HV %p SINT%d received message type "
+ "%#08x:\n", hv, sintx,
+ le32_to_cpu ( msg->type ) );
+ DBGC2_HDA ( hv, 0, msg->data, len );
+
+ /* Consume message */
+ src->type = 0;
+
+ return 0;
+ }
+
+ /* Trigger message delivery */
+ wrmsr ( HV_X64_MSR_EOM, 0 );
+
+ /* Delay */
+ mdelay ( 1 );
+ }
+
+ DBGC ( hv, "HV %p SINT%d timed out waiting for message\n",
+ hv, sintx );
+ return -ETIMEDOUT;
+}
+
+/**
+ * Signal event
+ *
+ * @v hv Hyper-V hypervisor
+ * @v id Connection ID
+ * @v flag Flag number
+ * @ret rc Return status code
+ */
+int hv_signal_event ( struct hv_hypervisor *hv, unsigned int id,
+ unsigned int flag ) {
+ struct hv_signal_event *event = &hv->message->signalled;
+ int status;
+ int rc;
+
+ /* Construct event */
+ memset ( event, 0, sizeof ( *event ) );
+ event->id = cpu_to_le32 ( id );
+ event->flag = cpu_to_le16 ( flag );
+
+ /* Signal event */
+ if ( ( status = hv_call ( hv, HV_SIGNAL_EVENT, event, NULL ) ) != 0 ) {
+ rc = -EHV ( status );
+ DBGC ( hv, "HV %p could not signal event to %#08x: %s\n",
+ hv, id, strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Probe root device
+ *
+ * @v rootdev Root device
+ * @ret rc Return status code
+ */
+static int hv_probe ( struct root_device *rootdev ) {
+ struct hv_hypervisor *hv;
+ int rc;
+
+ /* Allocate and initialise structure */
+ hv = zalloc ( sizeof ( *hv ) );
+ if ( ! hv ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+
+ /* Check we are running in Hyper-V */
+ if ( ( rc = hv_check_hv ( hv ) ) != 0 )
+ goto err_check_hv;
+
+ /* Allocate pages */
+ if ( ( rc = hv_alloc_pages ( hv, &hv->hypercall, &hv->synic.message,
+ &hv->synic.event, NULL ) ) != 0 )
+ goto err_alloc_pages;
+
+ /* Allocate message buffer */
+ if ( ( rc = hv_alloc_message ( hv ) ) != 0 )
+ goto err_alloc_message;
+
+ /* Map hypercall page */
+ if ( ( rc = hv_map_hypercall ( hv ) ) != 0 )
+ goto err_map_hypercall;
+
+ /* Map synthetic interrupt controller */
+ if ( ( rc = hv_map_synic ( hv ) ) != 0 )
+ goto err_map_synic;
+
+ /* Probe Hyper-V devices */
+ if ( ( rc = vmbus_probe ( hv, &rootdev->dev ) ) != 0 )
+ goto err_vmbus_probe;
+
+ rootdev_set_drvdata ( rootdev, hv );
+ return 0;
+
+ vmbus_remove ( hv, &rootdev->dev );
+ err_vmbus_probe:
+ hv_unmap_synic ( hv );
+ err_map_synic:
+ hv_unmap_hypercall ( hv );
+ err_map_hypercall:
+ hv_free_message ( hv );
+ err_alloc_message:
+ hv_free_pages ( hv, hv->hypercall, hv->synic.message, hv->synic.event,
+ NULL );
+ err_alloc_pages:
+ err_check_hv:
+ free ( hv );
+ err_alloc:
+ return rc;
+}
+
+/**
+ * Remove root device
+ *
+ * @v rootdev Root device
+ */
+static void hv_remove ( struct root_device *rootdev ) {
+ struct hv_hypervisor *hv = rootdev_get_drvdata ( rootdev );
+
+ vmbus_remove ( hv, &rootdev->dev );
+ hv_unmap_synic ( hv );
+ hv_unmap_hypercall ( hv );
+ hv_free_message ( hv );
+ hv_free_pages ( hv, hv->hypercall, hv->synic.message, hv->synic.event,
+ NULL );
+ free ( hv );
+}
+
+/** Hyper-V root device driver */
+static struct root_driver hv_root_driver = {
+ .probe = hv_probe,
+ .remove = hv_remove,
+};
+
+/** Hyper-V root device */
+struct root_device hv_root_device __root_device = {
+ .dev = { .name = "Hyper-V" },
+ .driver = &hv_root_driver,
+};
+
+/* Drag in objects via hv_root_device */
+REQUIRING_SYMBOL ( hv_root_device );
+
+/* Drag in netvsc driver */
+REQUIRE_OBJECT ( netvsc );
diff --git a/roms/ipxe/src/arch/x86/drivers/hyperv/hyperv.h b/roms/ipxe/src/arch/x86/drivers/hyperv/hyperv.h
new file mode 100644
index 000000000..0d09beb44
--- /dev/null
+++ b/roms/ipxe/src/arch/x86/drivers/hyperv/hyperv.h
@@ -0,0 +1,57 @@
+#ifndef _HYPERV_H
+#define _HYPERV_H
+
+/** @file
+ *
+ * Hyper-V driver
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/** Get vendor identification */
+#define HV_CPUID_VENDOR_ID 0x40000000UL
+
+/** Get interface identification */
+#define HV_CPUID_INTERFACE_ID 0x40000001UL
+
+/** Get hypervisor identification */
+#define HV_CPUID_HYPERVISOR_ID 0x40000002UL
+
+/** Get hypervisor features */
+#define HV_CPUID_FEATURES 0x40000003UL
+
+/** SynIC MSRs are available */
+#define HV_FEATURES_AVAIL_SYNIC_MSR 0x00000004UL
+
+/** Hypercall MSRs are available */
+#define HV_FEATURES_AVAIL_HYPERCALL_MSR 0x00000020UL
+
+/** Guest may post messages */
+#define HV_FEATURES_PERM_POST_MESSAGES 0x00000010UL
+
+/** Guest may signal events */
+#define HV_FEATURES_PERM_SIGNAL_EVENTS 0x00000020UL
+
+/** Guest OS identity MSR */
+#define HV_X64_MSR_GUEST_OS_ID 0x40000000UL
+
+/** Hypercall page MSR */
+#define HV_X64_MSR_HYPERCALL 0x40000001UL
+
+/** SynIC control MSR */
+#define HV_X64_MSR_SCONTROL 0x40000080UL
+
+/** SynIC event flags page MSR */
+#define HV_X64_MSR_SIEFP 0x40000082UL
+
+/** SynIC message page MSR */
+#define HV_X64_MSR_SIMP 0x40000083UL
+
+/** SynIC end of message MSR */
+#define HV_X64_MSR_EOM 0x40000084UL
+
+/** SynIC interrupt source MSRs */
+#define HV_X64_MSR_SINT(x) ( 0x40000090UL + (x) )
+
+#endif /* _HYPERV_H */
diff --git a/roms/ipxe/src/arch/x86/drivers/xen/hvm.c b/roms/ipxe/src/arch/x86/drivers/xen/hvm.c
index 7406ca68d..7ac32d54c 100644
--- a/roms/ipxe/src/arch/x86/drivers/xen/hvm.c
+++ b/roms/ipxe/src/arch/x86/drivers/xen/hvm.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdio.h>
@@ -492,5 +496,8 @@ struct pci_driver hvm_driver __pci_driver = {
.remove = hvm_remove,
};
+/* Drag in objects via hvm_driver */
+REQUIRING_SYMBOL ( hvm_driver );
+
/* Drag in netfront driver */
REQUIRE_OBJECT ( netfront );
diff --git a/roms/ipxe/src/arch/x86/drivers/xen/hvm.h b/roms/ipxe/src/arch/x86/drivers/xen/hvm.h
index 325d20d66..72ed94f6d 100644
--- a/roms/ipxe/src/arch/x86/drivers/xen/hvm.h
+++ b/roms/ipxe/src/arch/x86/drivers/xen/hvm.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/xen.h>
diff --git a/roms/ipxe/src/arch/x86/hci/commands/cpuid_cmd.c b/roms/ipxe/src/arch/x86/hci/commands/cpuid_cmd.c
index c4e35d179..d73ce2a3e 100644
--- a/roms/ipxe/src/arch/x86/hci/commands/cpuid_cmd.c
+++ b/roms/ipxe/src/arch/x86/hci/commands/cpuid_cmd.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdio.h>
diff --git a/roms/ipxe/src/arch/x86/include/bits/bigint.h b/roms/ipxe/src/arch/x86/include/bits/bigint.h
index d3449af5a..c9bb6ea45 100644
--- a/roms/ipxe/src/arch/x86/include/bits/bigint.h
+++ b/roms/ipxe/src/arch/x86/include/bits/bigint.h
@@ -6,7 +6,7 @@
* Big integer support
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <string.h>
diff --git a/roms/ipxe/src/arch/x86/include/bits/endian.h b/roms/ipxe/src/arch/x86/include/bits/endian.h
new file mode 100644
index 000000000..85718cfdd
--- /dev/null
+++ b/roms/ipxe/src/arch/x86/include/bits/endian.h
@@ -0,0 +1,8 @@
+#ifndef _BITS_ENDIAN_H
+#define _BITS_ENDIAN_H
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#define __BYTE_ORDER __LITTLE_ENDIAN
+
+#endif /* _BITS_ENDIAN_H */
diff --git a/roms/ipxe/src/arch/x86/include/bits/errfile.h b/roms/ipxe/src/arch/x86/include/bits/errfile.h
index 624575621..0d1617d20 100644
--- a/roms/ipxe/src/arch/x86/include/bits/errfile.h
+++ b/roms/ipxe/src/arch/x86/include/bits/errfile.h
@@ -1,7 +1,7 @@
#ifndef _BITS_ERRFILE_H
#define _BITS_ERRFILE_H
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @addtogroup errfile Error file identifiers
@@ -21,6 +21,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define ERRFILE_guestinfo ( ERRFILE_ARCH | ERRFILE_CORE | 0x000a0000 )
#define ERRFILE_apm ( ERRFILE_ARCH | ERRFILE_CORE | 0x000b0000 )
#define ERRFILE_vesafb ( ERRFILE_ARCH | ERRFILE_CORE | 0x000c0000 )
+#define ERRFILE_int13con ( ERRFILE_ARCH | ERRFILE_CORE | 0x000d0000 )
#define ERRFILE_bootsector ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00000000 )
#define ERRFILE_bzimage ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00010000 )
@@ -46,9 +47,12 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define ERRFILE_timer_rdtsc ( ERRFILE_ARCH | ERRFILE_DRIVER | 0x00000000 )
#define ERRFILE_timer_bios ( ERRFILE_ARCH | ERRFILE_DRIVER | 0x00010000 )
#define ERRFILE_hvm ( ERRFILE_ARCH | ERRFILE_DRIVER | 0x00020000 )
+#define ERRFILE_hyperv ( ERRFILE_ARCH | ERRFILE_DRIVER | 0x00030000 )
+#define ERRFILE_x86_uart ( ERRFILE_ARCH | ERRFILE_DRIVER | 0x00040000 )
#define ERRFILE_cpuid_cmd ( ERRFILE_ARCH | ERRFILE_OTHER | 0x00000000 )
#define ERRFILE_cpuid_settings ( ERRFILE_ARCH | ERRFILE_OTHER | 0x00010000 )
+#define ERRFILE_efi_entropy ( ERRFILE_ARCH | ERRFILE_OTHER | 0x00020000 )
/** @} */
diff --git a/roms/ipxe/src/arch/x86/include/bits/io.h b/roms/ipxe/src/arch/x86/include/bits/io.h
index cb1b67a6f..60c2e3edf 100644
--- a/roms/ipxe/src/arch/x86/include/bits/io.h
+++ b/roms/ipxe/src/arch/x86/include/bits/io.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/x86_io.h>
diff --git a/roms/ipxe/src/arch/x86/include/bits/pci_io.h b/roms/ipxe/src/arch/x86/include/bits/pci_io.h
index 01b12326e..b41e562ee 100644
--- a/roms/ipxe/src/arch/x86/include/bits/pci_io.h
+++ b/roms/ipxe/src/arch/x86/include/bits/pci_io.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/pcibios.h>
#include <ipxe/pcidirect.h>
diff --git a/roms/ipxe/src/arch/x86/include/bits/string.h b/roms/ipxe/src/arch/x86/include/bits/string.h
index dce994983..c26fe30d5 100644
--- a/roms/ipxe/src/arch/x86/include/bits/string.h
+++ b/roms/ipxe/src/arch/x86/include/bits/string.h
@@ -18,9 +18,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
@@ -28,8 +32,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
*/
-#define __HAVE_ARCH_MEMCPY
-
extern void * __memcpy ( void *dest, const void *src, size_t len );
extern void * __memcpy_reverse ( void *dest, const void *src, size_t len );
@@ -169,8 +171,6 @@ memcpy ( void *dest, const void *src, size_t len ) {
}
}
-#define __HAVE_ARCH_MEMMOVE
-
extern void * __memmove ( void *dest, const void *src, size_t len );
/**
@@ -196,8 +196,6 @@ memmove ( void *dest, const void *src, size_t len ) {
}
}
-#define __HAVE_ARCH_MEMSET
-
/**
* Fill memory region
*
@@ -206,7 +204,8 @@ memmove ( void *dest, const void *src, size_t len ) {
* @v len Length
* @ret dest Destination address
*/
-static inline void * memset ( void *dest, int fill, size_t len ) {
+static inline __attribute__ (( always_inline )) void *
+__memset ( void *dest, int fill, size_t len ) {
void *discard_D;
size_t discard_c;
@@ -217,16 +216,129 @@ static inline void * memset ( void *dest, int fill, size_t len ) {
return dest;
}
-#define __HAVE_ARCH_MEMSWAP
+/**
+ * Fill memory region with zero (where length is a compile-time constant)
+ *
+ * @v dest Destination address
+ * @v len Length
+ * @ret dest Destination address
+ */
+static inline __attribute__ (( always_inline )) void *
+__constant_memset_zero ( void *dest, size_t len ) {
+ union {
+ uint32_t u32[2];
+ uint16_t u16[4];
+ uint8_t u8[8];
+ } __attribute__ (( __may_alias__ )) *dest_u = dest;
+ void *edi;
+ uint32_t eax;
+
+ switch ( len ) {
+ case 0 : /* 0 bytes */
+ return dest;
+
+ /* Single-register moves. Almost certainly better than a
+ * string operation. We can avoid clobbering any registers,
+ * we can reuse a zero that happens to already be in a
+ * register, and we can optimise away the code entirely if the
+ * memset() is used to clear a region which then gets
+ * immediately overwritten.
+ */
+ case 1 : /* 3 bytes */
+ dest_u->u8[0] = 0;
+ return dest;
+ case 2: /* 5 bytes */
+ dest_u->u16[0] = 0;
+ return dest;
+ case 4: /* 6 bytes */
+ dest_u->u32[0] = 0;
+ return dest;
+
+ /* Double-register moves. Very probably better than a string
+ * operation.
+ */
+ case 3 : /* 9 bytes */
+ dest_u->u16[0] = 0;
+ dest_u->u8[2] = 0;
+ return dest;
+ case 5 : /* 10 bytes */
+ dest_u->u32[0] = 0;
+ dest_u->u8[4] = 0;
+ return dest;
+ case 6 : /* 12 bytes */
+ dest_u->u32[0] = 0;
+ dest_u->u16[2] = 0;
+ return dest;
+ case 8 : /* 13 bytes */
+ dest_u->u32[0] = 0;
+ dest_u->u32[1] = 0;
+ return dest;
+ }
+
+ /* As with memcpy(), we can potentially save space by using
+ * multiple single-byte "stos" instructions instead of loading
+ * up ecx and using "rep stosb".
+ *
+ * "load ecx, rep movsb" is 7 bytes, plus an average of 1 byte
+ * to allow for saving/restoring ecx 50% of the time.
+ *
+ * "stosl" and "stosb" are 1 byte each, "stosw" is two bytes.
+ *
+ * The calculations are therefore the same as for memcpy(),
+ * giving a cutoff point of around 26 bytes.
+ */
-extern void * memswap ( void *dest, void *src, size_t len );
+ edi = dest;
+ eax = 0;
+
+ if ( len >= 26 )
+ return __memset ( dest, 0, len );
-#define __HAVE_ARCH_STRNCMP
+ if ( len >= 6*4 )
+ __asm__ __volatile__ ( "stosl" : "=&D" ( edi ), "=&a" ( eax )
+ : "0" ( edi ), "1" ( eax ) : "memory" );
+ if ( len >= 5*4 )
+ __asm__ __volatile__ ( "stosl" : "=&D" ( edi ), "=&a" ( eax )
+ : "0" ( edi ), "1" ( eax ) : "memory" );
+ if ( len >= 4*4 )
+ __asm__ __volatile__ ( "stosl" : "=&D" ( edi ), "=&a" ( eax )
+ : "0" ( edi ), "1" ( eax ) : "memory" );
+ if ( len >= 3*4 )
+ __asm__ __volatile__ ( "stosl" : "=&D" ( edi ), "=&a" ( eax )
+ : "0" ( edi ), "1" ( eax ) : "memory" );
+ if ( len >= 2*4 )
+ __asm__ __volatile__ ( "stosl" : "=&D" ( edi ), "=&a" ( eax )
+ : "0" ( edi ), "1" ( eax ) : "memory" );
+ if ( len >= 1*4 )
+ __asm__ __volatile__ ( "stosl" : "=&D" ( edi ), "=&a" ( eax )
+ : "0" ( edi ), "1" ( eax ) : "memory" );
+ if ( ( len % 4 ) >= 2 )
+ __asm__ __volatile__ ( "stosw" : "=&D" ( edi ), "=&a" ( eax )
+ : "0" ( edi ), "1" ( eax ) : "memory" );
+ if ( ( len % 2 ) >= 1 )
+ __asm__ __volatile__ ( "stosb" : "=&D" ( edi ), "=&a" ( eax )
+ : "0" ( edi ), "1" ( eax ) : "memory" );
-extern int strncmp ( const char *str1, const char *str2, size_t len );
+ return dest;
+}
-#define __HAVE_ARCH_STRLEN
+/**
+ * Fill memory region
+ *
+ * @v dest Destination address
+ * @v fill Fill pattern
+ * @v len Length
+ * @ret dest Destination address
+ */
+static inline __attribute__ (( always_inline )) void *
+memset ( void *dest, int fill, size_t len ) {
-extern size_t strlen ( const char *string );
+ if ( __builtin_constant_p ( fill ) && ( fill == 0 ) &&
+ __builtin_constant_p ( len ) ) {
+ return __constant_memset_zero ( dest, len );
+ } else {
+ return __memset ( dest, fill, len );
+ }
+}
#endif /* X86_BITS_STRING_H */
diff --git a/roms/ipxe/src/arch/x86/include/bits/tcpip.h b/roms/ipxe/src/arch/x86/include/bits/tcpip.h
index a4b335eb1..5c2baffcf 100644
--- a/roms/ipxe/src/arch/x86/include/bits/tcpip.h
+++ b/roms/ipxe/src/arch/x86/include/bits/tcpip.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
extern uint16_t x86_tcpip_continue_chksum ( uint16_t partial,
const void *data, size_t len );
diff --git a/roms/ipxe/src/arch/x86/include/bits/uart.h b/roms/ipxe/src/arch/x86/include/bits/uart.h
new file mode 100644
index 000000000..e09cd3f4c
--- /dev/null
+++ b/roms/ipxe/src/arch/x86/include/bits/uart.h
@@ -0,0 +1,41 @@
+#ifndef _BITS_UART_H
+#define _BITS_UART_H
+
+/** @file
+ *
+ * 16550-compatible UART
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
+#include <ipxe/io.h>
+
+/**
+ * Write to UART register
+ *
+ * @v uart UART
+ * @v addr Register address
+ * @v data Data
+ */
+static inline __attribute__ (( always_inline )) void
+uart_write ( struct uart *uart, unsigned int addr, uint8_t data ) {
+ outb ( data, ( uart->base + addr ) );
+}
+
+/**
+ * Read from UART register
+ *
+ * @v uart UART
+ * @v addr Register address
+ * @ret data Data
+ */
+static inline __attribute__ (( always_inline )) uint8_t
+uart_read ( struct uart *uart, unsigned int addr ) {
+ return inb ( uart->base + addr );
+}
+
+extern int uart_select ( struct uart *uart, unsigned int port );
+
+#endif /* _BITS_UART_H */
diff --git a/roms/ipxe/src/arch/x86/include/bits/xen.h b/roms/ipxe/src/arch/x86/include/bits/xen.h
index dbccf1b77..fc065ea38 100644
--- a/roms/ipxe/src/arch/x86/include/bits/xen.h
+++ b/roms/ipxe/src/arch/x86/include/bits/xen.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/* Hypercall registers */
#ifdef __x86_64__
@@ -161,4 +161,23 @@ xen_hypercall_5 ( struct xen_hypervisor *xen, unsigned int hypercall,
return retval;
}
+/**
+ * Test and clear pending event
+ *
+ * @v xen Xen hypervisor
+ * @v port Event channel port
+ * @ret pending Event was pending
+ */
+static inline __attribute__ (( always_inline )) uint8_t
+xenevent_pending ( struct xen_hypervisor *xen, evtchn_port_t port ) {
+ uint8_t pending;
+
+ __asm__ __volatile__ ( "lock btr %2, %0\n\t"
+ "setc %1\n\t"
+ : "+m" ( xen->shared->evtchn_pending ),
+ "=a" ( pending )
+ : "Ir" ( port ) );
+ return pending;
+}
+
#endif /* _BITS_XEN_H */
diff --git a/roms/ipxe/src/arch/x86/include/ipxe/cpuid.h b/roms/ipxe/src/arch/x86/include/ipxe/cpuid.h
index 2f78dfca1..da85d0b88 100644
--- a/roms/ipxe/src/arch/x86/include/ipxe/cpuid.h
+++ b/roms/ipxe/src/arch/x86/include/ipxe/cpuid.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
@@ -39,6 +39,9 @@ struct x86_features {
/** Get standard features */
#define CPUID_FEATURES 0x00000001UL
+/** Hypervisor is present */
+#define CPUID_FEATURES_INTEL_ECX_HYPERVISOR 0x80000000UL
+
/** Get largest extended function */
#define CPUID_AMD_MAX_FN 0x80000000UL
diff --git a/roms/ipxe/src/arch/x86/include/ipxe/efi/efix86_nap.h b/roms/ipxe/src/arch/x86/include/ipxe/efi/efix86_nap.h
index e85a272b3..1a391c9b6 100644
--- a/roms/ipxe/src/arch/x86/include/ipxe/efi/efix86_nap.h
+++ b/roms/ipxe/src/arch/x86/include/ipxe/efi/efix86_nap.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifdef NAP_EFIX86
#define NAP_PREFIX_efix86
diff --git a/roms/ipxe/src/arch/x86/include/ipxe/pcibios.h b/roms/ipxe/src/arch/x86/include/ipxe/pcibios.h
index 36af7fcde..7e1bcd814 100644
--- a/roms/ipxe/src/arch/x86/include/ipxe/pcibios.h
+++ b/roms/ipxe/src/arch/x86/include/ipxe/pcibios.h
@@ -9,7 +9,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifdef PCIAPI_PCBIOS
#define PCIAPI_PREFIX_pcbios
diff --git a/roms/ipxe/src/arch/x86/include/ipxe/pcidirect.h b/roms/ipxe/src/arch/x86/include/ipxe/pcidirect.h
index 7fa7c4fa7..d924f2f20 100644
--- a/roms/ipxe/src/arch/x86/include/ipxe/pcidirect.h
+++ b/roms/ipxe/src/arch/x86/include/ipxe/pcidirect.h
@@ -1,7 +1,7 @@
#ifndef _PCIDIRECT_H
#define _PCIDIRECT_H
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/io.h>
diff --git a/roms/ipxe/src/arch/x86/include/ipxe/pit8254.h b/roms/ipxe/src/arch/x86/include/ipxe/pit8254.h
new file mode 100644
index 000000000..00b0ab164
--- /dev/null
+++ b/roms/ipxe/src/arch/x86/include/ipxe/pit8254.h
@@ -0,0 +1,81 @@
+#ifndef _IPXE_PIT8254_H
+#define _IPXE_PIT8254_H
+
+/** @file
+ *
+ * 8254 Programmable Interval Timer
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/** IRQ0 channel */
+#define PIT8254_CH_IRQ0 0
+
+/** PC speaker channel */
+#define PIT8254_CH_SPKR 2
+
+/** Timer frequency (1.193182MHz) */
+#define PIT8254_HZ 1193182UL
+
+/** Data port */
+#define PIT8254_DATA(channel) ( 0x40 + (channel) )
+
+/** Mode/command register */
+#define PIT8254_CMD 0x43
+
+/** Select channel */
+#define PIT8254_CMD_CHANNEL(channel) ( (channel) << 6 )
+
+/** Access modes */
+#define PIT8254_CMD_ACCESS_LATCH 0x00 /**< Latch count value command */
+#define PIT8254_CMD_ACCESS_LO 0x10 /**< Low byte only */
+#define PIT8254_CMD_ACCESS_HI 0x20 /**< High byte only */
+#define PIT8254_CMD_ACCESS_LOHI 0x30 /**< Low-byte, high-byte pair */
+
+/* Operating modes */
+#define PIT8254_CMD_OP_TERMINAL 0x00 /**< Interrupt on terminal count */
+#define PIT8254_CMD_OP_ONESHOT 0x02 /**< Hardware re-triggerable one-shot */
+#define PIT8254_CMD_OP_RATE 0x04 /**< Rate generator */
+#define PIT8254_CMD_OP_SQUARE 0x06 /**< Square wave generator */
+#define PIT8254_CMD_OP_SWSTROBE 0x08 /**< Software triggered strobe */
+#define PIT8254_CMD_OP_HWSTROBE 0x0a /**< Hardware triggered strobe */
+#define PIT8254_CMD_OP_RATE2 0x0c /**< Rate generator (duplicate) */
+#define PIT8254_CMD_OP_SQUARE2 0x0e /**< Square wave generator (duplicate)*/
+
+/** Binary mode */
+#define PIT8254_CMD_BINARY 0x00
+
+/** BCD mode */
+#define PIT8254_CMD_BCD 0x01
+
+/** PC speaker control register */
+#define PIT8254_SPKR 0x61
+
+/** PC speaker channel gate */
+#define PIT8254_SPKR_GATE 0x01
+
+/** PC speaker enabled */
+#define PIT8254_SPKR_ENABLE 0x02
+
+/** PC speaker channel output */
+#define PIT8254_SPKR_OUT 0x20
+
+extern void pit8254_speaker_delay ( unsigned int ticks );
+
+/**
+ * Delay for a fixed number of microseconds
+ *
+ * @v usecs Number of microseconds for which to delay
+ */
+static inline __attribute__ (( always_inline )) void
+pit8254_udelay ( unsigned long usecs ) {
+
+ /* Delays are invariably compile-time constants; force the
+ * multiplication and division to take place at compilation
+ * time rather than runtime.
+ */
+ pit8254_speaker_delay ( ( usecs * PIT8254_HZ ) / 1000000 );
+}
+
+#endif /* _IPXE_PIT8254_H */
diff --git a/roms/ipxe/src/arch/x86/include/ipxe/x86_io.h b/roms/ipxe/src/arch/x86/include/ipxe/x86_io.h
index 9e68f4e78..5214e9fbb 100644
--- a/roms/ipxe/src/arch/x86/include/ipxe/x86_io.h
+++ b/roms/ipxe/src/arch/x86/include/ipxe/x86_io.h
@@ -15,7 +15,7 @@
* physically fit into a machine with such an old CPU anyway.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifdef IOAPI_X86
#define IOAPI_PREFIX_x86
diff --git a/roms/ipxe/src/arch/x86/include/linux/ipxe/dhcp_arch.h b/roms/ipxe/src/arch/x86/include/linux/ipxe/dhcp_arch.h
index e83fd9d87..d60905f22 100644
--- a/roms/ipxe/src/arch/x86/include/linux/ipxe/dhcp_arch.h
+++ b/roms/ipxe/src/arch/x86/include/linux/ipxe/dhcp_arch.h
@@ -4,7 +4,7 @@
* 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.
+ * 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
@@ -13,7 +13,12 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
#ifndef _LINUX_DHCP_ARCH_H
@@ -24,7 +29,7 @@
* Architecture-specific DHCP options
*/
-FILE_LICENCE(GPL2_OR_LATER);
+FILE_LICENCE(GPL2_OR_LATER_OR_UBDL);
#include <ipxe/dhcp.h>
diff --git a/roms/ipxe/src/arch/i386/include/pic8259.h b/roms/ipxe/src/arch/x86/include/pic8259.h
index a07e97d30..f02e62909 100644
--- a/roms/ipxe/src/arch/i386/include/pic8259.h
+++ b/roms/ipxe/src/arch/x86/include/pic8259.h
@@ -4,16 +4,13 @@
* Initially written by Michael Brown (mcb30).
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifndef PIC8259_H
#define PIC8259_H
#include <ipxe/io.h>
-/* For segoff_t */
-#include "realmode.h"
-
#define IRQ_PIC_CUTOFF 8
/* 8259 register locations */
diff --git a/roms/ipxe/src/arch/x86/interface/efi/efi_entropy.c b/roms/ipxe/src/arch/x86/interface/efi/efi_entropy.c
new file mode 100644
index 000000000..a54bd12e6
--- /dev/null
+++ b/roms/ipxe/src/arch/x86/interface/efi/efi_entropy.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2015 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <errno.h>
+#include <ipxe/entropy.h>
+#include <ipxe/crc32.h>
+#include <ipxe/efi/efi.h>
+#include <ipxe/efi/Protocol/Rng.h>
+
+/** @file
+ *
+ * EFI entropy source
+ *
+ */
+
+/** Random number generator protocol */
+static EFI_RNG_PROTOCOL *efirng;
+EFI_REQUEST_PROTOCOL ( EFI_RNG_PROTOCOL, &efirng );
+
+/** Minimum number of bytes to request from RNG
+ *
+ * The UEFI spec states (for no apparently good reason) that "When a
+ * Deterministic Random Bit Generator (DRBG) is used on the output of
+ * a (raw) entropy source, its security level must be at least 256
+ * bits." The EDK2 codebase (mis)interprets this to mean that the
+ * call to GetRNG() should fail if given a buffer less than 32 bytes.
+ *
+ * Incidentally, nothing in the EFI RNG protocol provides any way to
+ * report the actual amount of entropy returned by GetRNG().
+ */
+#define EFI_ENTROPY_RNG_LEN 32
+
+/** Time (in 100ns units) to delay waiting for timer tick
+ *
+ * In theory, UEFI allows us to specify a trigger time of zero to
+ * simply wait for the next timer tick. In practice, specifying zero
+ * seems to often return immediately, which produces almost no
+ * entropy. Specify a delay of 1000ns to try to force an existent
+ * delay.
+ */
+#define EFI_ENTROPY_TRIGGER_TIME 10
+
+/** Event used to wait for timer tick */
+static EFI_EVENT tick;
+
+/**
+ * Enable entropy gathering
+ *
+ * @ret rc Return status code
+ */
+static int efi_entropy_enable ( void ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_STATUS efirc;
+ int rc;
+
+ DBGC ( &tick, "ENTROPY %s RNG protocol\n",
+ ( efirng ? "has" : "has no" ) );
+
+ /* Create timer tick event */
+ if ( ( efirc = bs->CreateEvent ( EVT_TIMER, TPL_NOTIFY, NULL, NULL,
+ &tick ) ) != 0 ) {
+ rc = -EEFI ( efirc );
+ DBGC ( &tick, "ENTROPY could not create event: %s\n",
+ strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Disable entropy gathering
+ *
+ */
+static void efi_entropy_disable ( void ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+
+ /* Close timer tick event */
+ bs->CloseEvent ( tick );
+}
+
+/**
+ * Wait for a timer tick
+ *
+ * @ret low TSC low-order bits, or negative error
+ */
+static int efi_entropy_tick ( void ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ UINTN index;
+ uint16_t low;
+ uint32_t discard_d;
+ EFI_STATUS efirc;
+ int rc;
+
+ /* Wait for next timer tick */
+ if ( ( efirc = bs->SetTimer ( tick, TimerRelative,
+ EFI_ENTROPY_TRIGGER_TIME ) ) != 0 ) {
+ rc = -EEFI ( efirc );
+ DBGC ( &tick, "ENTROPY could not set timer: %s\n",
+ strerror ( rc ) );
+ return rc;
+ }
+ if ( ( efirc = bs->WaitForEvent ( 1, &tick, &index ) ) != 0 ) {
+ rc = -EEFI ( efirc );
+ DBGC ( &tick, "ENTROPY could not wait for timer tick: %s\n",
+ strerror ( rc ) );
+ return rc;
+ }
+
+ /* Get current TSC low-order bits */
+ __asm__ __volatile__ ( "rdtsc" : "=a" ( low ), "=d" ( discard_d ) );
+
+ return low;
+}
+
+/**
+ * Get noise sample from timer ticks
+ *
+ * @ret noise Noise sample
+ * @ret rc Return status code
+ */
+static int efi_get_noise_ticks ( noise_sample_t *noise ) {
+ int before;
+ int after;
+ int rc;
+
+ /* Wait for a timer tick */
+ before = efi_entropy_tick();
+ if ( before < 0 ) {
+ rc = before;
+ return rc;
+ }
+
+ /* Wait for another timer tick */
+ after = efi_entropy_tick();
+ if ( after < 0 ) {
+ rc = after;
+ return rc;
+ }
+
+ /* Use TSC delta as noise sample */
+ *noise = ( after - before );
+
+ return 0;
+}
+
+/**
+ * Get noise sample from RNG protocol
+ *
+ * @ret noise Noise sample
+ * @ret rc Return status code
+ */
+static int efi_get_noise_rng ( noise_sample_t *noise ) {
+ uint8_t buf[EFI_ENTROPY_RNG_LEN];
+ EFI_STATUS efirc;
+ int rc;
+
+ /* Fail if we have no EFI RNG protocol */
+ if ( ! efirng )
+ return -ENOTSUP;
+
+ /* Get the minimum allowed number of random bytes */
+ if ( ( efirc = efirng->GetRNG ( efirng, NULL, EFI_ENTROPY_RNG_LEN,
+ buf ) ) != 0 ) {
+ rc = -EEFI ( efirc );
+ DBGC ( &tick, "ENTROPY could not read from RNG: %s\n",
+ strerror ( rc ) );
+ return rc;
+ }
+
+ /* Reduce random bytes to a single noise sample. This seems
+ * like overkill, but we have no way of knowing how much
+ * entropy is actually present in the bytes returned by the
+ * RNG protocol.
+ */
+ *noise = crc32_le ( 0, buf, sizeof ( buf ) );
+
+ return 0;
+}
+
+/**
+ * Get noise sample
+ *
+ * @ret noise Noise sample
+ * @ret rc Return status code
+ */
+static int efi_get_noise ( noise_sample_t *noise ) {
+ int rc;
+
+ /* Try RNG first, falling back to timer ticks */
+ if ( ( ( rc = efi_get_noise_rng ( noise ) ) != 0 ) &&
+ ( ( rc = efi_get_noise_ticks ( noise ) ) != 0 ) )
+ return rc;
+
+ return 0;
+}
+
+PROVIDE_ENTROPY_INLINE ( efi, min_entropy_per_sample );
+PROVIDE_ENTROPY ( efi, entropy_enable, efi_entropy_enable );
+PROVIDE_ENTROPY ( efi, entropy_disable, efi_entropy_disable );
+PROVIDE_ENTROPY ( efi, get_noise, efi_get_noise );
diff --git a/roms/ipxe/src/arch/x86/interface/efi/efix86_nap.c b/roms/ipxe/src/arch/x86/interface/efi/efix86_nap.c
index b05421fab..3ebf0bd68 100644
--- a/roms/ipxe/src/arch/x86/interface/efi/efix86_nap.c
+++ b/roms/ipxe/src/arch/x86/interface/efi/efix86_nap.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/nap.h>
#include <ipxe/efi/efi.h>
diff --git a/roms/ipxe/src/arch/x86/prefix/efidrvprefix.c b/roms/ipxe/src/arch/x86/prefix/efidrvprefix.c
index 3daefd00a..4fbb19ff7 100644
--- a/roms/ipxe/src/arch/x86/prefix/efidrvprefix.c
+++ b/roms/ipxe/src/arch/x86/prefix/efidrvprefix.c
@@ -21,7 +21,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <stdlib.h>
#include <ipxe/init.h>
+#include <ipxe/device.h>
#include <ipxe/efi/efi.h>
+#include <ipxe/efi/efi_driver.h>
/**
* EFI entry point
@@ -44,3 +46,36 @@ EFI_STATUS EFIAPI _efidrv_start ( EFI_HANDLE image_handle,
return 0;
}
+
+/**
+ * Probe EFI root bus
+ *
+ * @v rootdev EFI root device
+ */
+static int efi_probe ( struct root_device *rootdev __unused ) {
+
+ /* Do nothing */
+ return 0;
+}
+
+/**
+ * Remove EFI root bus
+ *
+ * @v rootdev EFI root device
+ */
+static void efi_remove ( struct root_device *rootdev __unused ) {
+
+ efi_driver_disconnect_all();
+}
+
+/** EFI root device driver */
+static struct root_driver efi_root_driver = {
+ .probe = efi_probe,
+ .remove = efi_remove,
+};
+
+/** EFI root device */
+struct root_device efi_root_device __root_device = {
+ .dev = { .name = "EFI" },
+ .driver = &efi_root_driver,
+};
diff --git a/roms/ipxe/src/arch/x86/prefix/efiprefix.c b/roms/ipxe/src/arch/x86/prefix/efiprefix.c
index b0bf99c65..18b931e68 100644
--- a/roms/ipxe/src/arch/x86/prefix/efiprefix.c
+++ b/roms/ipxe/src/arch/x86/prefix/efiprefix.c
@@ -26,6 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/efi/efi_driver.h>
#include <ipxe/efi/efi_snp.h>
#include <ipxe/efi/efi_autoboot.h>
+#include <ipxe/efi/efi_watchdog.h>
/**
* EFI entry point
@@ -49,6 +50,9 @@ EFI_STATUS EFIAPI _efi_start ( EFI_HANDLE image_handle,
/* Claim SNP devices for use by iPXE */
efi_snp_claim();
+ /* Start watchdog holdoff timer */
+ efi_watchdog_start();
+
/* Call to main() */
if ( ( rc = main() ) != 0 ) {
efirc = EFIRC ( rc );
@@ -56,6 +60,7 @@ EFI_STATUS EFIAPI _efi_start ( EFI_HANDLE image_handle,
}
err_main:
+ efi_watchdog_stop();
efi_snp_release();
efi_loaded_image->Unload ( image_handle );
efi_driver_reconnect_all();
diff --git a/roms/ipxe/src/arch/x86_64/Makefile b/roms/ipxe/src/arch/x86_64/Makefile
index b687f3407..48c0aa1af 100644
--- a/roms/ipxe/src/arch/x86_64/Makefile
+++ b/roms/ipxe/src/arch/x86_64/Makefile
@@ -40,6 +40,7 @@ endif
# x86_64-specific directories containing source files
#
+SRCDIRS += arch/x86_64/core
SRCDIRS += arch/x86_64/prefix
# Include common x86 Makefile
diff --git a/roms/ipxe/src/arch/x86_64/core/setjmp.S b/roms/ipxe/src/arch/x86_64/core/setjmp.S
new file mode 100644
index 000000000..e43200d7b
--- /dev/null
+++ b/roms/ipxe/src/arch/x86_64/core/setjmp.S
@@ -0,0 +1,65 @@
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
+
+ .text
+ .code64
+
+ /* Must match jmp_buf structure layout */
+ .struct 0
+env_retaddr: .quad 0
+env_stack: .quad 0
+env_rbx: .quad 0
+env_rbp: .quad 0
+env_r12: .quad 0
+env_r13: .quad 0
+env_r14: .quad 0
+env_r15: .quad 0
+ .previous
+
+/*
+ * Save stack context for non-local goto
+ */
+ .globl setjmp
+setjmp:
+ /* Save return address */
+ movq 0(%rsp), %rax
+ movq %rax, env_retaddr(%rdi)
+ /* Save stack pointer */
+ movq %rsp, env_stack(%rdi)
+ /* Save other registers */
+ movq %rbx, env_rbx(%rdi)
+ movq %rbp, env_rbp(%rdi)
+ movq %r12, env_r12(%rdi)
+ movq %r13, env_r13(%rdi)
+ movq %r14, env_r14(%rdi)
+ movq %r15, env_r15(%rdi)
+ /* Return 0 when returning as setjmp() */
+ xorq %rax, %rax
+ ret
+ .size setjmp, . - setjmp
+
+/*
+ * Non-local jump to a saved stack context
+ */
+ .globl longjmp
+longjmp:
+ /* Get result in %rax */
+ movq %rsi, %rax
+ /* Force result to non-zero */
+ testq %rax, %rax
+ jnz 1f
+ incq %rax
+1: /* Restore stack pointer */
+ movq env_stack(%rdi), %rsp
+ /* Restore other registers */
+ movq env_rbx(%rdi), %rbx
+ movq env_rbp(%rdi), %rbp
+ movq env_r12(%rdi), %r12
+ movq env_r13(%rdi), %r13
+ movq env_r14(%rdi), %r14
+ movq env_r15(%rdi), %r15
+ /* Replace return address on the new stack */
+ popq %rcx /* discard */
+ pushq env_retaddr(%rdi)
+ /* Return to setjmp() caller */
+ ret
+ .size longjmp, . - longjmp
diff --git a/roms/ipxe/src/arch/x86_64/include/bits/byteswap.h b/roms/ipxe/src/arch/x86_64/include/bits/byteswap.h
index 2e472d98a..d8c5098ef 100644
--- a/roms/ipxe/src/arch/x86_64/include/bits/byteswap.h
+++ b/roms/ipxe/src/arch/x86_64/include/bits/byteswap.h
@@ -9,7 +9,7 @@
#include <stdint.h>
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
static inline __attribute__ (( always_inline, const )) uint16_t
__bswap_variable_16 ( uint16_t x ) {
diff --git a/roms/ipxe/src/arch/x86_64/include/bits/compiler.h b/roms/ipxe/src/arch/x86_64/include/bits/compiler.h
index 51a7eaae2..f70b2e517 100644
--- a/roms/ipxe/src/arch/x86_64/include/bits/compiler.h
+++ b/roms/ipxe/src/arch/x86_64/include/bits/compiler.h
@@ -1,6 +1,9 @@
#ifndef _BITS_COMPILER_H
#define _BITS_COMPILER_H
+/** Dummy relocation type */
+#define RELOC_TYPE_NONE R_X86_64_NONE
+
#ifndef ASSEMBLY
/** Declare a function with standard calling conventions */
diff --git a/roms/ipxe/src/arch/x86_64/include/bits/endian.h b/roms/ipxe/src/arch/x86_64/include/bits/endian.h
deleted file mode 100644
index 413e702db..000000000
--- a/roms/ipxe/src/arch/x86_64/include/bits/endian.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef ETHERBOOT_BITS_ENDIAN_H
-#define ETHERBOOT_BITS_ENDIAN_H
-
-#define __BYTE_ORDER __LITTLE_ENDIAN
-
-#endif /* ETHERBOOT_BITS_ENDIAN_H */
diff --git a/roms/ipxe/src/arch/x86_64/include/bits/entropy.h b/roms/ipxe/src/arch/x86_64/include/bits/entropy.h
index 9c64c833b..a9b3bc10e 100644
--- a/roms/ipxe/src/arch/x86_64/include/bits/entropy.h
+++ b/roms/ipxe/src/arch/x86_64/include/bits/entropy.h
@@ -7,6 +7,6 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#endif /* _BITS_ENTROPY_H */
diff --git a/roms/ipxe/src/arch/x86_64/include/bits/hyperv.h b/roms/ipxe/src/arch/x86_64/include/bits/hyperv.h
new file mode 100644
index 000000000..845c182f7
--- /dev/null
+++ b/roms/ipxe/src/arch/x86_64/include/bits/hyperv.h
@@ -0,0 +1,75 @@
+#ifndef _BITS_HYPERV_H
+#define _BITS_HYPERV_H
+
+/** @file
+ *
+ * Hyper-V interface
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stddef.h>
+#include <stdint.h>
+#include <ipxe/io.h>
+
+/**
+ * Issue hypercall
+ *
+ * @v hv Hyper-V hypervisor
+ * @v code Call code
+ * @v in Input parameters
+ * @v out Output parameters
+ * @ret status Status code
+ */
+static inline __attribute__ (( always_inline )) int
+hv_call ( struct hv_hypervisor *hv, unsigned int code, const void *in,
+ void *out ) {
+ void *hypercall = hv->hypercall;
+ register uint64_t rcx asm ( "rcx" );
+ register uint64_t rdx asm ( "rdx" );
+ register uint64_t r8 asm ( "r8" );
+ uint64_t in_phys;
+ uint64_t out_phys;
+ uint16_t result;
+
+ in_phys = ( ( __builtin_constant_p ( in ) && ( in == NULL ) )
+ ? 0 : virt_to_phys ( in ) );
+ out_phys = ( ( __builtin_constant_p ( out ) && ( out == NULL ) )
+ ? 0 : virt_to_phys ( out ) );
+ rcx = code;
+ rdx = in_phys;
+ r8 = out_phys;
+ __asm__ __volatile__ ( "call *%4"
+ : "=a" ( result ), "+r" ( rcx ), "+r" ( rdx ),
+ "+r" ( r8 )
+ : "m" ( hypercall )
+ : "r9", "r10", "r11", "xmm0", "xmm1", "xmm2",
+ "xmm3", "xmm4", "xmm5" );
+ return result;
+}
+
+/**
+ * Set bit atomically
+ *
+ * @v bits Bit field
+ * @v bit Bit to set
+ */
+static inline __attribute__ (( always_inline )) void
+hv_set_bit ( void *bits, unsigned int bit ) {
+ struct {
+ uint64_t qword[ ( bit / 64 ) + 1 ];
+ } *qwords = bits;
+
+ /* Set bit using "lock bts". Inform compiler that any memory
+ * from the start of the bit field up to and including the
+ * qword containing this bit may be modified. (This is
+ * overkill but shouldn't matter in practice since we're
+ * unlikely to subsequently read other bits from the same bit
+ * field.)
+ */
+ __asm__ __volatile__ ( "lock bts %1, %0"
+ : "+m" ( *qwords ) : "Ir" ( bit ) );
+}
+
+#endif /* _BITS_HYPERV_H */
diff --git a/roms/ipxe/src/arch/x86_64/include/bits/profile.h b/roms/ipxe/src/arch/x86_64/include/bits/profile.h
index 6fc16d84b..b7c74fbe7 100644
--- a/roms/ipxe/src/arch/x86_64/include/bits/profile.h
+++ b/roms/ipxe/src/arch/x86_64/include/bits/profile.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
diff --git a/roms/ipxe/src/arch/x86_64/include/bits/reboot.h b/roms/ipxe/src/arch/x86_64/include/bits/reboot.h
index f1bce0540..f9bcd6a7b 100644
--- a/roms/ipxe/src/arch/x86_64/include/bits/reboot.h
+++ b/roms/ipxe/src/arch/x86_64/include/bits/reboot.h
@@ -7,6 +7,6 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#endif /* _BITS_REBOOT_H */
diff --git a/roms/ipxe/src/arch/x86_64/include/bits/sanboot.h b/roms/ipxe/src/arch/x86_64/include/bits/sanboot.h
index d33d03cbe..dcab830f6 100644
--- a/roms/ipxe/src/arch/x86_64/include/bits/sanboot.h
+++ b/roms/ipxe/src/arch/x86_64/include/bits/sanboot.h
@@ -7,6 +7,6 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#endif /* _BITS_SANBOOT_H */
diff --git a/roms/ipxe/src/arch/x86_64/include/bits/strings.h b/roms/ipxe/src/arch/x86_64/include/bits/strings.h
index 6ee99a500..3b7911f3b 100644
--- a/roms/ipxe/src/arch/x86_64/include/bits/strings.h
+++ b/roms/ipxe/src/arch/x86_64/include/bits/strings.h
@@ -1,7 +1,43 @@
#ifndef _BITS_STRINGS_H
#define _BITS_STRINGS_H
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/**
+ * Find first (i.e. least significant) set bit
+ *
+ * @v value Value
+ * @ret lsb Least significant bit set in value (LSB=1), or zero
+ */
+static inline __attribute__ (( always_inline )) int __ffsll ( long long value ){
+ long long lsb_minus_one;
+
+ /* If the input value is zero, the BSF instruction returns
+ * ZF=0 and leaves an undefined value in the output register.
+ * Perform this check in C rather than asm so that it can be
+ * omitted in cases where the compiler is able to prove that
+ * the input is non-zero.
+ */
+ if ( value ) {
+ __asm__ ( "bsfq %1, %0"
+ : "=r" ( lsb_minus_one )
+ : "rm" ( value ) );
+ return ( lsb_minus_one + 1 );
+ } else {
+ return 0;
+ }
+}
+
+/**
+ * Find first (i.e. least significant) set bit
+ *
+ * @v value Value
+ * @ret lsb Least significant bit set in value (LSB=1), or zero
+ */
+static inline __attribute__ (( always_inline )) int __ffsl ( long value ) {
+
+ return __ffsll ( value );
+}
/**
* Find last (i.e. most significant) set bit
@@ -13,7 +49,7 @@ static inline __attribute__ (( always_inline )) int __flsll ( long long value ){
long long msb_minus_one;
/* If the input value is zero, the BSR instruction returns
- * ZF=1 and leaves an undefined value in the output register.
+ * ZF=0 and leaves an undefined value in the output register.
* Perform this check in C rather than asm so that it can be
* omitted in cases where the compiler is able to prove that
* the input is non-zero.
diff --git a/roms/ipxe/src/arch/x86_64/include/bits/time.h b/roms/ipxe/src/arch/x86_64/include/bits/time.h
index 59b355359..aa74fac8c 100644
--- a/roms/ipxe/src/arch/x86_64/include/bits/time.h
+++ b/roms/ipxe/src/arch/x86_64/include/bits/time.h
@@ -7,6 +7,6 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#endif /* _BITS_TIME_H */
diff --git a/roms/ipxe/src/arch/x86_64/include/efi/ipxe/dhcp_arch.h b/roms/ipxe/src/arch/x86_64/include/efi/ipxe/dhcp_arch.h
index 9a4790fdc..6511c1ad3 100644
--- a/roms/ipxe/src/arch/x86_64/include/efi/ipxe/dhcp_arch.h
+++ b/roms/ipxe/src/arch/x86_64/include/efi/ipxe/dhcp_arch.h
@@ -4,7 +4,7 @@
* 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.
+ * 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
@@ -13,7 +13,12 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
#ifndef _DHCP_ARCH_H
@@ -24,7 +29,7 @@
* Architecture-specific DHCP options
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/dhcp.h>
diff --git a/roms/ipxe/src/arch/x86_64/include/ipxe/msr.h b/roms/ipxe/src/arch/x86_64/include/ipxe/msr.h
index a5816ac35..316243b69 100644
--- a/roms/ipxe/src/arch/x86_64/include/ipxe/msr.h
+++ b/roms/ipxe/src/arch/x86_64/include/ipxe/msr.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* Read model-specific register
diff --git a/roms/ipxe/src/arch/x86_64/include/setjmp.h b/roms/ipxe/src/arch/x86_64/include/setjmp.h
new file mode 100644
index 000000000..69835d9fa
--- /dev/null
+++ b/roms/ipxe/src/arch/x86_64/include/setjmp.h
@@ -0,0 +1,34 @@
+#ifndef _SETJMP_H
+#define _SETJMP_H
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
+
+/** A jump buffer */
+typedef struct {
+ /** Saved return address */
+ uint64_t retaddr;
+ /** Saved stack pointer */
+ uint64_t stack;
+ /** Saved %rbx */
+ uint64_t rbx;
+ /** Saved %rbp */
+ uint64_t rbp;
+ /** Saved %r12 */
+ uint64_t r12;
+ /** Saved %r13 */
+ uint64_t r13;
+ /** Saved %r14 */
+ uint64_t r14;
+ /** Saved %r15 */
+ uint64_t r15;
+} jmp_buf[1];
+
+extern int __asmcall __attribute__ (( returns_twice ))
+setjmp ( jmp_buf env );
+
+extern void __asmcall __attribute__ (( noreturn ))
+longjmp ( jmp_buf env, int val );
+
+#endif /* _SETJMP_H */
diff --git a/roms/ipxe/src/config/.gitignore b/roms/ipxe/src/config/.gitignore
deleted file mode 100644
index 8e94f32fe..000000000
--- a/roms/ipxe/src/config/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-.buildserial.*
diff --git a/roms/ipxe/src/config/branding.h b/roms/ipxe/src/config/branding.h
new file mode 100644
index 000000000..73f00af95
--- /dev/null
+++ b/roms/ipxe/src/config/branding.h
@@ -0,0 +1,174 @@
+#ifndef CONFIG_BRANDING_H
+#define CONFIG_BRANDING_H
+
+/** @file
+ *
+ * Branding configuration
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <config/defaults.h>
+
+/*
+ * Branding
+ *
+ * Vendors may use these strings to add their own branding to iPXE.
+ * PRODUCT_NAME is displayed prior to any iPXE 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
+ * "iPXE".
+ *
+ */
+#define PRODUCT_NAME ""
+#define PRODUCT_SHORT_NAME "iPXE"
+#define PRODUCT_URI "http://ipxe.org"
+
+/*
+ * Tag line
+ *
+ * If your PRODUCT_SHORT_NAME is longer than the four characters used
+ * by "iPXE", then the standard tag line "Open Source Network Boot
+ * Firmware" is unlikely to fit neatly onto the screen.
+ */
+#define PRODUCT_TAG_LINE "Open Source Network Boot Firmware"
+
+/*
+ * Error messages
+ *
+ * iPXE error messages comprise a summary error message
+ * (e.g. "Permission denied") and a 32-bit error number. This number
+ * is incorporated into an error URI such as
+ *
+ * "No such file or directory (http://ipxe.org/2d0c613b)"
+ *
+ * or
+ *
+ * "Operation not supported (http://ipxe.org/3c092003)"
+ *
+ * Users may browse to the URI within the error message, which is
+ * provided by a database running on the iPXE web site
+ * (http://ipxe.org). This database provides details for all possible
+ * errors generated by iPXE, including:
+ *
+ * - the detailed error message (e.g. "Not an OCSP signing
+ * certificate") to complement the summary message (e.g. "Permission
+ * denied") which is compiled into the iPXE binary.
+ *
+ * - an instruction to the user to upgrade, if the error cannot be
+ * generated by the latest version of iPXE.
+ *
+ * - hints on how to fix the error (e.g. "This error indicates that
+ * the file was not found on the TFTP server. Check that you can
+ * retrieve the file using an alternative TFTP client, such as
+ * tftp-hpa on Linux.")
+ *
+ * - details of which source file within the iPXE codebase generated
+ * the error.
+ *
+ * - a direct link to the line(s) of code which generated the error.
+ *
+ * If you have a customer support team and would like your customers
+ * to contact your support team for all problems, instead of using the
+ * existing support infrastructure provided by http://ipxe.org, then
+ * you may define a custom URI to be included within error messages.
+ *
+ * Note that the custom URI is a printf() format string which must
+ * include a format specifier for the 32-bit error number.
+ */
+#define PRODUCT_ERROR_URI "http://ipxe.org/%08x"
+
+/*
+ * Command help messages
+ *
+ * iPXE command help messages include a URI constructed from the
+ * command name, such as
+ *
+ * "See http://ipxe.org/cmd/vcreate for further information"
+ *
+ * The iPXE web site includes documentation for the commands provided
+ * by the iPXE shell, including:
+ *
+ * - details of the command syntax (e.g. "vcreate --tag <tag>
+ * [--priority <priority>] <trunk interface>").
+ *
+ * - example usages of the command (e.g. "vcreate --tag 123 net0")
+ *
+ * - a formal description of the command (e.g. "Create a VLAN network
+ * interface on an existing trunk network interface. The new network
+ * interface will be named by appending a hyphen and the VLAN tag
+ * value to the trunk network interface name.")
+ *
+ * - details of the possible exit statuses from the command.
+ *
+ * - links to documentation for related commands (e.g. "vdestroy")
+ *
+ * - links to documentation for relevant build options (e.g. "VLAN_CMD").
+ *
+ * - general hints and tips on using the command.
+ *
+ * If you want to provide your own documentation for all of the
+ * commands provided by the iPXE shell, rather than using the existing
+ * support infrastructure provided by http://ipxe.org, then you may
+ * define a custom URI to be included within command help messages.
+ *
+ * Note that the custom URI is a printf() format string which must
+ * include a format specifier for the command name.
+ *
+ * [ Please also note that the existing documentation is licensed
+ * under Creative Commons terms which require attribution to the
+ * iPXE project and prohibit the alteration or removal of any
+ * references to "iPXE". ]
+ */
+#define PRODUCT_COMMAND_URI "http://ipxe.org/cmd/%s"
+
+/*
+ * Setting help messages
+ *
+ * iPXE setting help messages include a URI constructed from the
+ * setting name, such as
+ *
+ * "http://ipxe.org/cfg/initiator-iqn"
+ *
+ * The iPXE web site includes documentation for the settings used by
+ * iPXE, including:
+ *
+ * - details of the corresponding DHCP option number.
+ *
+ * - details of the corresponding ISC dhcpd option name.
+ *
+ * - examples of using the setting from the iPXE command line, or in
+ * iPXE scripts.
+ *
+ * - examples of configuring the setting via a DHCP server.
+ *
+ * - a formal description of the setting.
+ *
+ * - links to documentation for related settings.
+ *
+ * - links to documentation for relevant build options.
+ *
+ * - general notes about the setting.
+ *
+ * If you want to provide your own documentation for all of the
+ * settings used by iPXE, rather than using the existing support
+ * infrastructure provided by http://ipxe.org, then you may define a
+ * custom URI to be included within setting help messages.
+ *
+ * Note that the custom URI is a printf() format string which must
+ * include a format specifier for the setting name.
+ *
+ * [ Please also note that the existing documentation is licensed
+ * under Creative Commons terms which require attribution to the
+ * iPXE project and prohibit the alteration or removal of any
+ * references to "iPXE". ]
+ */
+#define PRODUCT_SETTING_URI "http://ipxe.org/cfg/%s"
+
+#include <config/local/branding.h>
+
+#endif /* CONFIG_BRANDING_H */
diff --git a/roms/ipxe/src/config/colour.h b/roms/ipxe/src/config/colour.h
index 57d20c1db..98198f12f 100644
--- a/roms/ipxe/src/config/colour.h
+++ b/roms/ipxe/src/config/colour.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define COLOR_NORMAL_FG COLOR_WHITE
#define COLOR_NORMAL_BG COLOR_BLUE
diff --git a/roms/ipxe/src/config/config.c b/roms/ipxe/src/config/config.c
index 6c8b9551a..1dd912c1d 100644
--- a/roms/ipxe/src/config/config.c
+++ b/roms/ipxe/src/config/config.c
@@ -1,11 +1,25 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2, or (at
- * your option) any later version.
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <config/general.h>
#include <config/console.h>
@@ -30,33 +44,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
* in the final iPXE executable built.
*/
-/*
- * Build ID string calculations
- *
- */
-#undef XSTR
-#undef STR
-#define XSTR(s) STR(s)
-#define STR(s) #s
-
-#ifdef BUILD_SERIAL
-#include "config/.buildserial.h"
-#define BUILD_SERIAL_STR " #" XSTR(BUILD_SERIAL_NUM)
-#else
-#define BUILD_SERIAL_STR ""
-#endif
-
-#ifdef BUILD_ID
-#define BUILD_ID_STR " " BUILD_ID
-#else
-#define BUILD_ID_STR ""
-#endif
-
-#if defined(BUILD_ID) || defined(BUILD_SERIAL)
-#define BUILD_STRING " [build" BUILD_ID_STR BUILD_SERIAL_STR "]"
-#else
-#define BUILD_STRING ""
-#endif
+PROVIDE_REQUIRING_SYMBOL();
/*
* Drag in all requested console types
@@ -67,7 +55,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
REQUIRE_OBJECT ( bios_console );
#endif
#ifdef CONSOLE_SERIAL
-REQUIRE_OBJECT ( serial_console );
+REQUIRE_OBJECT ( serial );
#endif
#ifdef CONSOLE_DIRECT_VGA
REQUIRE_OBJECT ( video_subr );
@@ -96,6 +84,9 @@ REQUIRE_OBJECT ( debugcon );
#ifdef CONSOLE_VESAFB
REQUIRE_OBJECT ( vesafb );
#endif
+#ifdef CONSOLE_INT13
+REQUIRE_OBJECT ( int13con );
+#endif
/*
* Drag in all requested network protocols
@@ -149,6 +140,9 @@ REQUIRE_OBJECT ( slam );
#ifdef SANBOOT_PROTO_ISCSI
REQUIRE_OBJECT ( iscsi );
#endif
+#ifdef SANBOOT_PROTO_HTTP
+REQUIRE_OBJECT ( httpblock );
+#endif
/*
* Drag in all requested resolvers
@@ -349,6 +343,9 @@ REQUIRE_OBJECT ( cpuid_settings );
#ifdef MEMMAP_SETTINGS
REQUIRE_OBJECT ( memmap_settings );
#endif
+#ifdef VRAM_SETTINGS
+REQUIRE_OBJECT ( vram_settings );
+#endif
/*
* Drag in selected keyboard map
diff --git a/roms/ipxe/src/config/config_crypto.c b/roms/ipxe/src/config/config_crypto.c
new file mode 100644
index 000000000..1e125d8ab
--- /dev/null
+++ b/roms/ipxe/src/config/config_crypto.c
@@ -0,0 +1,76 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <config/crypto.h>
+
+/** @file
+ *
+ * Cryptographic configuration
+ *
+ * Cryptographic configuration is slightly messy since we need to drag
+ * in objects based on combinations of build options.
+ */
+
+PROVIDE_REQUIRING_SYMBOL();
+
+/* RSA and MD5 */
+#if defined ( CRYPTO_PUBKEY_RSA ) && defined ( CRYPTO_DIGEST_MD5 )
+REQUIRE_OBJECT ( rsa_md5 );
+#endif
+
+/* RSA and SHA-1 */
+#if defined ( CRYPTO_PUBKEY_RSA ) && defined ( CRYPTO_DIGEST_SHA1 )
+REQUIRE_OBJECT ( rsa_sha1 );
+#endif
+
+/* RSA and SHA-224 */
+#if defined ( CRYPTO_PUBKEY_RSA ) && defined ( CRYPTO_DIGEST_SHA224 )
+REQUIRE_OBJECT ( rsa_sha224 );
+#endif
+
+/* RSA and SHA-256 */
+#if defined ( CRYPTO_PUBKEY_RSA ) && defined ( CRYPTO_DIGEST_SHA256 )
+REQUIRE_OBJECT ( rsa_sha256 );
+#endif
+
+/* RSA and SHA-384 */
+#if defined ( CRYPTO_PUBKEY_RSA ) && defined ( CRYPTO_DIGEST_SHA384 )
+REQUIRE_OBJECT ( rsa_sha384 );
+#endif
+
+/* RSA and SHA-512 */
+#if defined ( CRYPTO_PUBKEY_RSA ) && defined ( CRYPTO_DIGEST_SHA512 )
+REQUIRE_OBJECT ( rsa_sha512 );
+#endif
+
+/* RSA, AES-CBC, and SHA-1 */
+#if defined ( CRYPTO_PUBKEY_RSA ) && defined ( CRYPTO_CIPHER_AES_CBC ) && \
+ defined ( CRYPTO_DIGEST_SHA1 )
+REQUIRE_OBJECT ( rsa_aes_cbc_sha1 );
+#endif
+
+/* RSA, AES-CBC, and SHA-256 */
+#if defined ( CRYPTO_PUBKEY_RSA ) && defined ( CRYPTO_CIPHER_AES_CBC ) && \
+ defined ( CRYPTO_DIGEST_SHA256 )
+REQUIRE_OBJECT ( rsa_aes_cbc_sha256 );
+#endif
diff --git a/roms/ipxe/src/config/config_ethernet.c b/roms/ipxe/src/config/config_ethernet.c
index d13bd6144..de7a07c57 100644
--- a/roms/ipxe/src/config/config_ethernet.c
+++ b/roms/ipxe/src/config/config_ethernet.c
@@ -1,11 +1,25 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2, or (at
- * your option) any later version.
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <config/general.h>
@@ -15,6 +29,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
*/
+PROVIDE_REQUIRING_SYMBOL();
+
/*
* Drag in Ethernet-specific protocols
*/
@@ -24,3 +40,6 @@ REQUIRE_OBJECT ( aoe );
#ifdef NET_PROTO_FCOE
REQUIRE_OBJECT ( fcoe );
#endif
+#ifdef NET_PROTO_STP
+REQUIRE_OBJECT ( stp );
+#endif
diff --git a/roms/ipxe/src/config/config_fc.c b/roms/ipxe/src/config/config_fc.c
index 414646994..33fc9462a 100644
--- a/roms/ipxe/src/config/config_fc.c
+++ b/roms/ipxe/src/config/config_fc.c
@@ -1,11 +1,25 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2, or (at
- * your option) any later version.
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <config/general.h>
@@ -15,6 +29,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
*/
+PROVIDE_REQUIRING_SYMBOL();
+
/*
* Drag in Fibre Channel-specific commands
*
diff --git a/roms/ipxe/src/config/config_http.c b/roms/ipxe/src/config/config_http.c
new file mode 100644
index 000000000..3f198d228
--- /dev/null
+++ b/roms/ipxe/src/config/config_http.c
@@ -0,0 +1,45 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <config/general.h>
+
+/** @file
+ *
+ * HTTP extensions
+ *
+ */
+
+PROVIDE_REQUIRING_SYMBOL();
+
+/*
+ * Drag in HTTP extensions
+ */
+#ifdef HTTP_AUTH_BASIC
+REQUIRE_OBJECT ( httpbasic );
+#endif
+#ifdef HTTP_AUTH_DIGEST
+REQUIRE_OBJECT ( httpdigest );
+#endif
+#ifdef HTTP_ENC_PEERDIST
+REQUIRE_OBJECT ( peerdist );
+#endif
diff --git a/roms/ipxe/src/config/config_infiniband.c b/roms/ipxe/src/config/config_infiniband.c
index 432e621d0..a742e7559 100644
--- a/roms/ipxe/src/config/config_infiniband.c
+++ b/roms/ipxe/src/config/config_infiniband.c
@@ -1,11 +1,25 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2, or (at
- * your option) any later version.
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <config/general.h>
@@ -15,6 +29,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
*/
+PROVIDE_REQUIRING_SYMBOL();
+
/*
* Drag in Infiniband-specific protocols
*/
diff --git a/roms/ipxe/src/config/config_net80211.c b/roms/ipxe/src/config/config_net80211.c
index b33c363b1..343617548 100644
--- a/roms/ipxe/src/config/config_net80211.c
+++ b/roms/ipxe/src/config/config_net80211.c
@@ -1,8 +1,18 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2, or (at
- * your option) any later version.
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
@@ -15,6 +25,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
*/
+PROVIDE_REQUIRING_SYMBOL();
+
/*
* Drag in 802.11-specific commands
*
diff --git a/roms/ipxe/src/config/config_romprefix.c b/roms/ipxe/src/config/config_romprefix.c
index 85f1e78ab..21921b867 100644
--- a/roms/ipxe/src/config/config_romprefix.c
+++ b/roms/ipxe/src/config/config_romprefix.c
@@ -1,11 +1,25 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2, or (at
- * your option) any later version.
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <config/general.h>
@@ -15,6 +29,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
*/
+PROVIDE_REQUIRING_SYMBOL();
+
/*
* Provide UNDI loader if PXE stack is requested
*
diff --git a/roms/ipxe/src/config/config_route.c b/roms/ipxe/src/config/config_route.c
index 33e18cdd3..c0b4ee91d 100644
--- a/roms/ipxe/src/config/config_route.c
+++ b/roms/ipxe/src/config/config_route.c
@@ -1,11 +1,25 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2, or (at
- * your option) any later version.
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <config/general.h>
@@ -15,6 +29,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
*/
+PROVIDE_REQUIRING_SYMBOL();
+
/*
* Drag in routing management for relevant protocols
*
diff --git a/roms/ipxe/src/config/config_usb.c b/roms/ipxe/src/config/config_usb.c
new file mode 100644
index 000000000..dc0e6e6af
--- /dev/null
+++ b/roms/ipxe/src/config/config_usb.c
@@ -0,0 +1,52 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <config/usb.h>
+
+/** @file
+ *
+ * USB configuration options
+ *
+ */
+
+PROVIDE_REQUIRING_SYMBOL();
+
+/*
+ * Drag in USB controllers
+ */
+#ifdef USB_HCD_XHCI
+REQUIRE_OBJECT ( xhci );
+#endif
+#ifdef USB_HCD_EHCI
+REQUIRE_OBJECT ( ehci );
+#endif
+#ifdef USB_HCD_UHCI
+REQUIRE_OBJECT ( uhci );
+#endif
+
+/*
+ * Drag in USB peripherals
+ */
+#ifdef USB_KEYBOARD
+REQUIRE_OBJECT ( usbkbd );
+#endif
diff --git a/roms/ipxe/src/config/console.h b/roms/ipxe/src/config/console.h
index 908ec5a0b..ffa5cf50d 100644
--- a/roms/ipxe/src/config/console.h
+++ b/roms/ipxe/src/config/console.h
@@ -10,7 +10,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <config/defaults.h>
@@ -23,6 +23,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
//#define CONSOLE_VMWARE /* VMware logfile console */
//#define CONSOLE_DEBUGCON /* Debug port console */
//#define CONSOLE_VESAFB /* VESA framebuffer console */
+//#define CONSOLE_INT13 /* INT13 disk log console */
#define KEYBOARD_MAP us
diff --git a/roms/ipxe/src/config/crypto.h b/roms/ipxe/src/config/crypto.h
index 1e021b0fb..bccfc04b8 100644
--- a/roms/ipxe/src/config/crypto.h
+++ b/roms/ipxe/src/config/crypto.h
@@ -7,7 +7,40 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/** RSA public-key algorithm */
+#define CRYPTO_PUBKEY_RSA
+
+/** AES-CBC block cipher */
+#define CRYPTO_CIPHER_AES_CBC
+
+/** MD5 digest algorithm
+ *
+ * Note that use of MD5 is implicit when using TLSv1.1 or earlier.
+ */
+#define CRYPTO_DIGEST_MD5
+
+/** SHA-1 digest algorithm
+ *
+ * Note that use of SHA-1 is implicit when using TLSv1.1 or earlier.
+ */
+#define CRYPTO_DIGEST_SHA1
+
+/** SHA-224 digest algorithm */
+#define CRYPTO_DIGEST_SHA224
+
+/** SHA-256 digest algorithm
+ *
+ * Note that use of SHA-256 is implicit when using TLSv1.2.
+ */
+#define CRYPTO_DIGEST_SHA256
+
+/** SHA-384 digest algorithm */
+#define CRYPTO_DIGEST_SHA384
+
+/** SHA-512 digest algorithm */
+#define CRYPTO_DIGEST_SHA512
/** Margin of error (in seconds) allowed in signed timestamps
*
diff --git a/roms/ipxe/src/config/defaults.h b/roms/ipxe/src/config/defaults.h
index 389c0b07b..32d6dbcce 100644
--- a/roms/ipxe/src/config/defaults.h
+++ b/roms/ipxe/src/config/defaults.h
@@ -1,7 +1,7 @@
#ifndef CONFIG_DEFAULTS_H
#define CONFIG_DEFAULTS_H
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define CONFIG_DEFAULTS(_platform) <config/defaults/_platform.h>
diff --git a/roms/ipxe/src/config/defaults/efi.h b/roms/ipxe/src/config/defaults/efi.h
index 4276d9366..cdf41c54d 100644
--- a/roms/ipxe/src/config/defaults/efi.h
+++ b/roms/ipxe/src/config/defaults/efi.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define UACCESS_EFI
#define IOAPI_X86
@@ -19,8 +19,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define SMBIOS_EFI
#define SANBOOT_NULL
#define BOFM_EFI
-#define ENTROPY_NULL
-#define TIME_NULL
+#define ENTROPY_EFI
+#define TIME_EFI
#define REBOOT_EFI
#define IMAGE_EFI /* EFI image support */
diff --git a/roms/ipxe/src/config/defaults/pcbios.h b/roms/ipxe/src/config/defaults/pcbios.h
index 7debc8d2f..3ed8343ce 100644
--- a/roms/ipxe/src/config/defaults/pcbios.h
+++ b/roms/ipxe/src/config/defaults/pcbios.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define UACCESS_LIBRM
#define IOAPI_X86
@@ -35,6 +35,12 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define SANBOOT_PROTO_AOE /* AoE protocol */
#define SANBOOT_PROTO_IB_SRP /* Infiniband SCSI RDMA protocol */
#define SANBOOT_PROTO_FCP /* Fibre Channel protocol */
+#define SANBOOT_PROTO_HTTP /* HTTP SAN protocol */
+
+#define USB_HCD_XHCI /* xHCI USB host controller */
+#define USB_HCD_EHCI /* EHCI USB host controller */
+#define USB_HCD_UHCI /* UHCI USB host controller */
+#define USB_KEYBOARD /* USB keyboards */
#define REBOOT_CMD /* Reboot command */
#define CPUID_CMD /* x86 CPU feature detection command */
diff --git a/roms/ipxe/src/config/dhcp.h b/roms/ipxe/src/config/dhcp.h
new file mode 100644
index 000000000..49fe16b92
--- /dev/null
+++ b/roms/ipxe/src/config/dhcp.h
@@ -0,0 +1,87 @@
+#ifndef CONFIG_DHCP_H
+#define CONFIG_DHCP_H
+
+/** @file
+ *
+ * DHCP configuration
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <config/defaults.h>
+
+/*
+ * DHCP and PXE Boot Server timeout parameters
+ *
+ * Initial and final timeout for DHCP discovery
+ *
+ * The PXE spec indicates discover request are sent 4 times, with
+ * timeouts of 4, 8, 16, 32 seconds. iPXE by default uses 1, 2, 4, 8.
+ */
+#define DHCP_DISC_START_TIMEOUT_SEC 1
+#define DHCP_DISC_END_TIMEOUT_SEC 10
+//#define DHCP_DISC_START_TIMEOUT_SEC 4 /* as per PXE spec */
+//#define DHCP_DISC_END_TIMEOUT_SEC 32 /* as per PXE spec */
+
+/*
+ * ProxyDHCP offers are given precedence by continue to wait for them
+ * after a valid DHCPOFFER is received. We'll wait through this
+ * timeout for it. The PXE spec indicates waiting through the 4 & 8
+ * second timeouts, iPXE by default stops after 2.
+ */
+#define DHCP_DISC_PROXY_TIMEOUT_SEC 2
+//#define DHCP_DISC_PROXY_TIMEOUT_SEC 11 /* as per PXE spec */
+
+/*
+ * Per the PXE spec, requests are also tried 4 times, but at timeout
+ * intervals of 1, 2, 3, 4 seconds. To adapt this to an exponential
+ * backoff timer, we can either do 1, 2, 4, 8, ie. 4 retires with a
+ * longer interval or start at 0 (0.25s) for 0.25, 0.5, 1, 2, 4,
+ * ie. one extra try and shorter initial timeouts. iPXE by default
+ * does a combination of both, starting at 0 and going through the 8
+ * second timeout.
+ */
+#define DHCP_REQ_START_TIMEOUT_SEC 0
+#define DHCP_REQ_END_TIMEOUT_SEC 10
+//#define DHCP_REQ_END_TIMEOUT_SEC 4 /* as per PXE spec */
+
+/*
+ * A ProxyDHCP offer without PXE options also goes through a request
+ * phase using these same parameters, but note the early break below.
+ */
+#define DHCP_PROXY_START_TIMEOUT_SEC 0
+#define DHCP_PROXY_END_TIMEOUT_SEC 10
+//#define DHCP_PROXY_END_TIMEOUT_SEC 8 /* as per PXE spec */
+
+/*
+ * A ProxyDHCP request timeout should not induce a failure condition,
+ * so we always want to break before the above set of timers expire.
+ * The iPXE default value of 2 breaks at the first timeout after 2
+ * seconds, which will be after the 2 second timeout.
+ */
+#define DHCP_REQ_PROXY_TIMEOUT_SEC 2
+//#define DHCP_REQ_PROXY_TIMEOUT_SEC 7 /* as per PXE spec */
+
+/*
+ * Per the PXE spec, a PXE boot server request is also be retried 4
+ * times at timeouts of 1, 2, 3, 4. iPXE uses the same timeouts as
+ * discovery, 1, 2, 4, 8, but will move on to the next server if
+ * available after an elapsed time greater than 3 seconds, therefore
+ * effectively only sending 3 tries at timeouts of 1, 2, 4.
+ */
+#define PXEBS_START_TIMEOUT_SEC 1
+#define PXEBS_END_TIMEOUT_SEC 10
+//#define PXEBS_START_TIMEOUT_SEC 0 /* as per PXE spec */
+//#define PXEBS_END_TIMEOUT_SEC 8 /* as per PXE spec */
+
+/*
+ * Increment to the next PXE Boot server, if available, after this
+ * this much time has elapsed.
+ */
+#define PXEBS_MAX_TIMEOUT_SEC 3
+//#define PXEBS_MAX_TIMEOUT_SEC 7 /* as per PXE spec */
+
+#include <config/local/dhcp.h>
+
+#endif /* CONFIG_DHCP_H */
diff --git a/roms/ipxe/src/config/entropy.h b/roms/ipxe/src/config/entropy.h
index 7de2f6737..c79060fd5 100644
--- a/roms/ipxe/src/config/entropy.h
+++ b/roms/ipxe/src/config/entropy.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <config/defaults.h>
diff --git a/roms/ipxe/src/config/fault.h b/roms/ipxe/src/config/fault.h
new file mode 100644
index 000000000..5024a8ff3
--- /dev/null
+++ b/roms/ipxe/src/config/fault.h
@@ -0,0 +1,34 @@
+#ifndef CONFIG_FAULT_H
+#define CONFIG_FAULT_H
+
+/** @file
+ *
+ * Fault injection
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <config/defaults.h>
+
+/* Drop every N transmitted or received network packets */
+#define NETDEV_DISCARD_RATE 0
+
+/* Drop every N transmitted or received PeerDist discovery packets */
+#define PEERDISC_DISCARD_RATE 0
+
+/* Annul every N PeerDist download attempts */
+#define PEERBLK_ANNUL_RATE 0
+
+/* Stall every N PeerDist download attempts */
+#define PEERBLK_STALL_RATE 0
+
+/* Abort every N PeerDist download attempts */
+#define PEERBLK_ABORT_RATE 0
+
+/* Corrupt every N received PeerDist packets */
+#define PEERBLK_CORRUPT_RATE 0
+
+#include <config/local/fault.h>
+
+#endif /* CONFIG_FAULT_H */
diff --git a/roms/ipxe/src/config/general.h b/roms/ipxe/src/config/general.h
index 539203457..ee15f6bf1 100644
--- a/roms/ipxe/src/config/general.h
+++ b/roms/ipxe/src/config/general.h
@@ -7,27 +7,11 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <config/defaults.h>
/*
- * Branding
- *
- * Vendors may use these strings to add their own branding to iPXE.
- * PRODUCT_NAME is displayed prior to any iPXE 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
- * "iPXE".
- *
- */
-#define PRODUCT_NAME ""
-#define PRODUCT_SHORT_NAME "iPXE"
-
-/*
* Banner timeout configuration
*
* This controls the timeout for the "Press Ctrl-B for the iPXE
@@ -53,6 +37,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define NET_PROTO_IPV4 /* IPv4 protocol */
#undef NET_PROTO_IPV6 /* IPv6 protocol */
#undef NET_PROTO_FCOE /* Fibre Channel over Ethernet protocol */
+#define NET_PROTO_STP /* Spanning Tree protocol */
/*
* PXE support
@@ -82,6 +67,15 @@ FILE_LICENCE ( GPL2_OR_LATER );
//#undef SANBOOT_PROTO_AOE /* AoE protocol */
//#undef SANBOOT_PROTO_IB_SRP /* Infiniband SCSI RDMA protocol */
//#undef SANBOOT_PROTO_FCP /* Fibre Channel protocol */
+//#undef SANBOOT_PROTO_HTTP /* HTTP SAN protocol */
+
+/*
+ * HTTP extensions
+ *
+ */
+#define HTTP_AUTH_BASIC /* Basic authentication */
+#define HTTP_AUTH_DIGEST /* Digest authentication */
+//#define HTTP_ENC_PEERDIST /* PeerDist content encoding */
/*
* 802.11 cryptosystems and handshaking protocols
@@ -156,6 +150,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
*/
#undef NONPNP_HOOK_INT19 /* Hook INT19 on non-PnP BIOSes */
+#define AUTOBOOT_ROM_FILTER /* Autoboot only devices matching our ROM */
/*
* Error message tables to include
@@ -170,7 +165,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
*/
-#define NETDEV_DISCARD_RATE 0 /* Drop every N packets (0=>no drop) */
#undef BUILD_SERIAL /* Include an automatic build serial
* number. Add "bs" to the list of
* make targets. For example:
@@ -181,6 +175,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#undef GDBSERIAL /* Remote GDB debugging over serial */
#undef GDBUDP /* Remote GDB debugging over UDP
* (both may be set) */
+//#define EFI_DOWNGRADE_UX /* Downgrade UEFI user experience */
#include <config/named.h>
#include NAMED_CONFIG(general.h)
diff --git a/roms/ipxe/src/config/ioapi.h b/roms/ipxe/src/config/ioapi.h
index ce19c6d71..abe5a50ce 100644
--- a/roms/ipxe/src/config/ioapi.h
+++ b/roms/ipxe/src/config/ioapi.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <config/defaults.h>
diff --git a/roms/ipxe/src/config/named.h b/roms/ipxe/src/config/named.h
index 36efdabdd..ddde6f0a6 100644
--- a/roms/ipxe/src/config/named.h
+++ b/roms/ipxe/src/config/named.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/* config/<name>/<header>.h */
#ifdef CONFIG
diff --git a/roms/ipxe/src/config/nap.h b/roms/ipxe/src/config/nap.h
index 187af4289..e4fe97964 100644
--- a/roms/ipxe/src/config/nap.h
+++ b/roms/ipxe/src/config/nap.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <config/defaults.h>
diff --git a/roms/ipxe/src/config/qemu/colour.h b/roms/ipxe/src/config/qemu/colour.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/roms/ipxe/src/config/qemu/colour.h
diff --git a/roms/ipxe/src/config/qemu/console.h b/roms/ipxe/src/config/qemu/console.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/roms/ipxe/src/config/qemu/console.h
diff --git a/roms/ipxe/src/config/qemu/crypto.h b/roms/ipxe/src/config/qemu/crypto.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/roms/ipxe/src/config/qemu/crypto.h
diff --git a/roms/ipxe/src/config/qemu/general.h b/roms/ipxe/src/config/qemu/general.h
new file mode 100644
index 000000000..30f60d3f7
--- /dev/null
+++ b/roms/ipxe/src/config/qemu/general.h
@@ -0,0 +1,10 @@
+/* Disable entry during POST */
+#undef ROM_BANNER_TIMEOUT
+#define ROM_BANNER_TIMEOUT 0
+
+/* Extend banner timeout */
+#undef BANNER_TIMEOUT
+#define BANNER_TIMEOUT 30
+
+/* Work around missing EFI_PXE_BASE_CODE_PROTOCOL */
+#define EFI_DOWNGRADE_UX
diff --git a/roms/ipxe/src/config/qemu/serial.h b/roms/ipxe/src/config/qemu/serial.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/roms/ipxe/src/config/qemu/serial.h
diff --git a/roms/ipxe/src/config/qemu/settings.h b/roms/ipxe/src/config/qemu/settings.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/roms/ipxe/src/config/qemu/settings.h
diff --git a/roms/ipxe/src/config/qemu/sideband.h b/roms/ipxe/src/config/qemu/sideband.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/roms/ipxe/src/config/qemu/sideband.h
diff --git a/roms/ipxe/src/config/qemu/usb.h b/roms/ipxe/src/config/qemu/usb.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/roms/ipxe/src/config/qemu/usb.h
diff --git a/roms/ipxe/src/config/reboot.h b/roms/ipxe/src/config/reboot.h
index 240ef87be..2d1648e7b 100644
--- a/roms/ipxe/src/config/reboot.h
+++ b/roms/ipxe/src/config/reboot.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <config/defaults.h>
diff --git a/roms/ipxe/src/config/sanboot.h b/roms/ipxe/src/config/sanboot.h
index 1d7f5f177..ccc4bda1f 100644
--- a/roms/ipxe/src/config/sanboot.h
+++ b/roms/ipxe/src/config/sanboot.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <config/defaults.h>
diff --git a/roms/ipxe/src/config/serial.h b/roms/ipxe/src/config/serial.h
index 08368efdb..27040dc54 100644
--- a/roms/ipxe/src/config/serial.h
+++ b/roms/ipxe/src/config/serial.h
@@ -13,11 +13,6 @@
FILE_LICENCE ( GPL2_OR_LATER );
-#define COM1 0x3f8
-#define COM2 0x2f8
-#define COM3 0x3e8
-#define COM4 0x2e8
-
#define COMCONSOLE COM1 /* I/O port address */
/* Keep settings from a previous user of the serial port (e.g. lilo or
diff --git a/roms/ipxe/src/config/settings.h b/roms/ipxe/src/config/settings.h
index 42fe9cc81..01feaaa87 100644
--- a/roms/ipxe/src/config/settings.h
+++ b/roms/ipxe/src/config/settings.h
@@ -7,12 +7,13 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define PCI_SETTINGS /* PCI device settings */
//#define CPUID_SETTINGS /* CPUID settings */
//#define MEMMAP_SETTINGS /* Memory map settings */
//#define VMWARE_SETTINGS /* VMware GuestInfo settings */
+//#define VRAM_SETTINGS /* Video RAM dump settings */
#include <config/named.h>
#include NAMED_CONFIG(settings.h)
diff --git a/roms/ipxe/src/config/sideband.h b/roms/ipxe/src/config/sideband.h
index 039bb5d09..dd704f9bb 100644
--- a/roms/ipxe/src/config/sideband.h
+++ b/roms/ipxe/src/config/sideband.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
//#define CONFIG_BOFM /* IBM's BladeCenter Open Fabric Manager */
diff --git a/roms/ipxe/src/config/time.h b/roms/ipxe/src/config/time.h
index 0576211fd..678f6f864 100644
--- a/roms/ipxe/src/config/time.h
+++ b/roms/ipxe/src/config/time.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <config/defaults.h>
diff --git a/roms/ipxe/src/config/timer.h b/roms/ipxe/src/config/timer.h
index abd669851..5a54d398c 100644
--- a/roms/ipxe/src/config/timer.h
+++ b/roms/ipxe/src/config/timer.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <config/defaults.h>
diff --git a/roms/ipxe/src/config/umalloc.h b/roms/ipxe/src/config/umalloc.h
index 245c6b4aa..832dd21d1 100644
--- a/roms/ipxe/src/config/umalloc.h
+++ b/roms/ipxe/src/config/umalloc.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <config/defaults.h>
diff --git a/roms/ipxe/src/config/usb.h b/roms/ipxe/src/config/usb.h
new file mode 100644
index 000000000..52e82eaad
--- /dev/null
+++ b/roms/ipxe/src/config/usb.h
@@ -0,0 +1,33 @@
+#ifndef CONFIG_USB_H
+#define CONFIG_USB_H
+
+/** @file
+ *
+ * USB configuration
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <config/defaults.h>
+
+/*
+ * USB host controllers (all enabled by default)
+ *
+ */
+//#undef USB_HCD_XHCI /* xHCI USB host controller */
+//#undef USB_HCD_EHCI /* EHCI USB host controller */
+//#undef USB_HCD_UHCI /* UHCI USB host controller */
+
+/*
+ * USB peripherals
+ *
+ */
+//#undef USB_KEYBOARD /* USB keyboards */
+
+#include <config/named.h>
+#include NAMED_CONFIG(usb.h)
+#include <config/local/usb.h>
+#include LOCAL_NAMED_CONFIG(usb.h)
+
+#endif /* CONFIG_USB_H */
diff --git a/roms/ipxe/src/config/vbox/general.h b/roms/ipxe/src/config/vbox/general.h
index 27d15daf2..06b45f1a8 100644
--- a/roms/ipxe/src/config/vbox/general.h
+++ b/roms/ipxe/src/config/vbox/general.h
@@ -1,25 +1,17 @@
/* Disabled from config/defaults/pcbios.h */
-#undef IMAGE_ELF
#undef SANBOOT_PROTO_ISCSI
#undef SANBOOT_PROTO_AOE
#undef SANBOOT_PROTO_IB_SRP
#undef SANBOOT_PROTO_FCP
-#undef REBOOT_CMD
-#undef CPUID_CMD
/* Disabled from config/general.h */
-#undef DOWNLOAD_PROTO_HTTP
#undef CRYPTO_80211_WEP
#undef CRYPTO_80211_WPA
#undef CRYPTO_80211_WPA2
#undef IWMGMT_CMD
-#undef FCMGMT_CMD
-#undef SANBOOT_CMD
#undef MENU_CMD
-#undef LOGIN_CMD
-#undef SYNC_CMD
/* Ensure ROM banner is not displayed */
diff --git a/roms/ipxe/src/config/vbox/usb.h b/roms/ipxe/src/config/vbox/usb.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/roms/ipxe/src/config/vbox/usb.h
diff --git a/roms/ipxe/src/core/acpi.c b/roms/ipxe/src/core/acpi.c
index 330f50631..b0ccfa78d 100644
--- a/roms/ipxe/src/core/acpi.c
+++ b/roms/ipxe/src/core/acpi.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <errno.h>
#include <ipxe/acpi.h>
diff --git a/roms/ipxe/src/core/ansicol.c b/roms/ipxe/src/core/ansicol.c
index 142a00f8d..ddf9ba77c 100644
--- a/roms/ipxe/src/core/ansicol.c
+++ b/roms/ipxe/src/core/ansicol.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdio.h>
#include <errno.h>
diff --git a/roms/ipxe/src/core/ansicoldef.c b/roms/ipxe/src/core/ansicoldef.c
index dd89f3b70..6d8598e11 100644
--- a/roms/ipxe/src/core/ansicoldef.c
+++ b/roms/ipxe/src/core/ansicoldef.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdio.h>
#include <errno.h>
diff --git a/roms/ipxe/src/core/ansiesc.c b/roms/ipxe/src/core/ansiesc.c
index ca9a73ce0..7f545db0e 100644
--- a/roms/ipxe/src/core/ansiesc.c
+++ b/roms/ipxe/src/core/ansiesc.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <assert.h>
diff --git a/roms/ipxe/src/core/asprintf.c b/roms/ipxe/src/core/asprintf.c
index 03cf45cfc..00edf8e11 100644
--- a/roms/ipxe/src/core/asprintf.c
+++ b/roms/ipxe/src/core/asprintf.c
@@ -4,7 +4,7 @@
#include <stdio.h>
#include <errno.h>
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* Write a formatted string to newly allocated memory.
diff --git a/roms/ipxe/src/core/assert.c b/roms/ipxe/src/core/assert.c
index 0791ea7b9..294e766be 100644
--- a/roms/ipxe/src/core/assert.c
+++ b/roms/ipxe/src/core/assert.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/core/base16.c b/roms/ipxe/src/core/base16.c
index bf9cc21bb..f9e0f3364 100644
--- a/roms/ipxe/src/core/base16.c
+++ b/roms/ipxe/src/core/base16.c
@@ -15,14 +15,20 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
-#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
+#include <assert.h>
+#include <ipxe/string.h>
+#include <ipxe/vsprintf.h>
#include <ipxe/base16.h>
/** @file
@@ -32,48 +38,42 @@ FILE_LICENCE ( GPL2_OR_LATER );
*/
/**
- * Base16-encode data
+ * Encode hexadecimal string (with optional byte separator character)
*
+ * @v separator Byte separator character, or 0 for no separator
* @v raw Raw data
- * @v len Length of raw data
- * @v encoded Buffer for encoded string
- *
- * The buffer must be the correct length for the encoded string. Use
- * something like
- *
- * char buf[ base16_encoded_len ( len ) + 1 ];
- *
- * (the +1 is for the terminating NUL) to provide a buffer of the
- * correct size.
+ * @v raw_len Length of raw data
+ * @v data Buffer
+ * @v len Length of buffer
+ * @ret len Encoded length
*/
-void base16_encode ( const uint8_t *raw, size_t len, char *encoded ) {
- const uint8_t *raw_bytes = raw;
- char *encoded_bytes = encoded;
- size_t remaining = len;
-
- /* Encode each byte */
- for ( ; remaining-- ; encoded_bytes += 2 ) {
- sprintf ( encoded_bytes, "%02x", *(raw_bytes++) );
+size_t hex_encode ( char separator, const void *raw, size_t raw_len,
+ char *data, size_t len ) {
+ const uint8_t *bytes = raw;
+ const char delimiter[2] = { separator, '\0' };
+ size_t used = 0;
+ unsigned int i;
+
+ if ( len )
+ data[0] = 0; /* Ensure that a terminating NUL exists */
+ for ( i = 0 ; i < raw_len ; i++ ) {
+ used += ssnprintf ( ( data + used ), ( len - used ),
+ "%s%02x", ( used ? delimiter : "" ),
+ bytes[i] );
}
-
- /* Ensure terminating NUL exists even if length was zero */
- *encoded_bytes = '\0';
-
- DBG ( "Base16-encoded to \"%s\":\n", encoded );
- DBG_HDA ( 0, raw, len );
- assert ( strlen ( encoded ) == base16_encoded_len ( len ) );
+ return used;
}
/**
- * Decode hexadecimal string
+ * Decode hexadecimal string (with optional byte separator character)
*
- * @v encoded Encoded string
* @v separator Byte separator character, or 0 for no separator
+ * @v encoded Encoded string
* @v data Buffer
* @v len Length of buffer
* @ret len Length of data, or negative error
*/
-int hex_decode ( const char *encoded, char separator, void *data, size_t len ) {
+int hex_decode ( char separator, const char *encoded, void *data, size_t len ) {
uint8_t *out = data;
unsigned int count = 0;
unsigned int sixteens;
@@ -87,13 +87,13 @@ int hex_decode ( const char *encoded, char separator, void *data, size_t len ) {
/* Extract digits. Note that either digit may be NUL,
* which would be interpreted as an invalid value by
- * strtoul_charval(); there is therefore no need for an
+ * digit_value(); there is therefore no need for an
* explicit end-of-string check.
*/
- sixteens = strtoul_charval ( *(encoded++) );
+ sixteens = digit_value ( *(encoded++) );
if ( sixteens >= 16 )
return -EINVAL;
- units = strtoul_charval ( *(encoded++) );
+ units = digit_value ( *(encoded++) );
if ( units >= 16 )
return -EINVAL;
@@ -105,31 +105,3 @@ int hex_decode ( const char *encoded, char separator, void *data, size_t len ) {
}
return count;
}
-
-/**
- * Base16-decode data
- *
- * @v encoded Encoded string
- * @v raw Raw data
- * @ret len Length of raw data, or negative error
- *
- * The buffer must be large enough to contain the decoded data. Use
- * something like
- *
- * char buf[ base16_decoded_max_len ( encoded ) ];
- *
- * to provide a buffer of the correct size.
- */
-int base16_decode ( const char *encoded, uint8_t *raw ) {
- int len;
-
- len = hex_decode ( encoded, 0, raw, -1UL );
- if ( len < 0 )
- return len;
-
- DBG ( "Base16-decoded \"%s\" to:\n", encoded );
- DBG_HDA ( 0, raw, len );
- assert ( len <= ( int ) base16_decoded_max_len ( encoded ) );
-
- return len;
-}
diff --git a/roms/ipxe/src/core/base64.c b/roms/ipxe/src/core/base64.c
index bdaf70957..e452f7d41 100644
--- a/roms/ipxe/src/core/base64.c
+++ b/roms/ipxe/src/core/base64.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <string.h>
@@ -39,80 +43,73 @@ static const char base64[64] =
* Base64-encode data
*
* @v raw Raw data
- * @v len Length of raw data
- * @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 ( len ) + 1 ];
- *
- * (the +1 is for the terminating NUL) to provide a buffer of the
- * correct size.
+ * @v raw_len Length of raw data
+ * @v data Buffer
+ * @v len Length of buffer
+ * @ret len Encoded length
*/
-void base64_encode ( const uint8_t *raw, size_t len, char *encoded ) {
+size_t base64_encode ( const void *raw, size_t raw_len, char *data,
+ size_t len ) {
const uint8_t *raw_bytes = ( ( const uint8_t * ) raw );
- uint8_t *encoded_bytes = ( ( uint8_t * ) encoded );
- size_t raw_bit_len = ( 8 * len );
+ size_t raw_bit_len = ( 8 * raw_len );
+ size_t used = 0;
unsigned int bit;
unsigned int byte;
unsigned int shift;
unsigned int tmp;
- for ( bit = 0 ; bit < raw_bit_len ; bit += 6 ) {
+ for ( bit = 0 ; bit < raw_bit_len ; bit += 6, used++ ) {
byte = ( bit / 8 );
shift = ( bit % 8 );
tmp = ( raw_bytes[byte] << shift );
- if ( ( byte + 1 ) < len )
+ if ( ( byte + 1 ) < raw_len )
tmp |= ( raw_bytes[ byte + 1 ] >> ( 8 - shift ) );
tmp = ( ( tmp >> 2 ) & 0x3f );
- *(encoded_bytes++) = base64[tmp];
+ if ( used < len )
+ data[used] = base64[tmp];
+ }
+ for ( ; ( bit % 8 ) != 0 ; bit += 6, used++ ) {
+ if ( used < len )
+ data[used] = '=';
}
- for ( ; ( bit % 8 ) != 0 ; bit += 6 )
- *(encoded_bytes++) = '=';
- *(encoded_bytes++) = '\0';
+ if ( used < len )
+ data[used] = '\0';
+ if ( len )
+ data[ len - 1 ] = '\0'; /* Ensure terminator exists */
- DBG ( "Base64-encoded to \"%s\":\n", encoded );
- DBG_HDA ( 0, raw, len );
- assert ( strlen ( encoded ) == base64_encoded_len ( len ) );
+ return used;
}
/**
* Base64-decode string
*
* @v encoded Encoded string
- * @v raw Raw data
- * @ret len Length of raw data, or negative error
- *
- * The buffer must be large enough to contain the decoded data. Use
- * something like
- *
- * char buf[ base64_decoded_max_len ( encoded ) ];
- *
- * to provide a buffer of the correct size.
+ * @v data Buffer
+ * @v len Length of buffer
+ * @ret len Length of data, or negative error
*/
-int base64_decode ( const char *encoded, uint8_t *raw ) {
- const uint8_t *encoded_bytes = ( ( const uint8_t * ) encoded );
- uint8_t *raw_bytes = ( ( uint8_t * ) raw );
- uint8_t encoded_byte;
+int base64_decode ( const char *encoded, void *data, size_t len ) {
+ const char *in = encoded;
+ uint8_t *out = data;
+ uint8_t in_char;
char *match;
- int decoded;
+ int in_bits;
unsigned int bit = 0;
unsigned int pad_count = 0;
- size_t len;
+ size_t offset;
- /* Zero the raw data */
- memset ( raw, 0, base64_decoded_max_len ( encoded ) );
+ /* Zero the output buffer */
+ memset ( data, 0, len );
/* Decode string */
- while ( ( encoded_byte = *(encoded_bytes++) ) ) {
+ while ( ( in_char = *(in++) ) ) {
/* Ignore whitespace characters */
- if ( isspace ( encoded_byte ) )
+ if ( isspace ( in_char ) )
continue;
/* Process pad characters */
- if ( encoded_byte == '=' ) {
+ if ( in_char == '=' ) {
if ( pad_count >= 2 ) {
DBG ( "Base64-encoded string \"%s\" has too "
"many pad characters\n", encoded );
@@ -129,18 +126,22 @@ int base64_decode ( const char *encoded, uint8_t *raw ) {
}
/* Process normal characters */
- match = strchr ( base64, encoded_byte );
+ match = strchr ( base64, in_char );
if ( ! match ) {
DBG ( "Base64-encoded string \"%s\" contains invalid "
- "character '%c'\n", encoded, encoded_byte );
+ "character '%c'\n", encoded, in_char );
return -EINVAL;
}
- decoded = ( match - base64 );
+ in_bits = ( match - base64 );
/* Add to raw data */
- decoded <<= 2;
- raw_bytes[ bit / 8 ] |= ( decoded >> ( bit % 8 ) );
- raw_bytes[ bit / 8 + 1 ] |= ( decoded << ( 8 - ( bit % 8 ) ) );
+ in_bits <<= 2;
+ offset = ( bit / 8 );
+ if ( offset < len )
+ out[offset] |= ( in_bits >> ( bit % 8 ) );
+ offset++;
+ if ( offset < len )
+ out[offset] |= ( in_bits << ( 8 - ( bit % 8 ) ) );
bit += 6;
}
@@ -150,12 +151,7 @@ int base64_decode ( const char *encoded, uint8_t *raw ) {
"%d\n", encoded, bit );
return -EINVAL;
}
- len = ( bit / 8 );
-
- DBG ( "Base64-decoded \"%s\" to:\n", encoded );
- DBG_HDA ( 0, raw, len );
- assert ( len <= base64_decoded_max_len ( encoded ) );
/* Return length in bytes */
- return ( len );
+ return ( bit / 8 );
}
diff --git a/roms/ipxe/src/core/basename.c b/roms/ipxe/src/core/basename.c
index b534a7886..f4f929517 100644
--- a/roms/ipxe/src/core/basename.c
+++ b/roms/ipxe/src/core/basename.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @file
diff --git a/roms/ipxe/src/core/bitmap.c b/roms/ipxe/src/core/bitmap.c
index 0d1152327..2aac33870 100644
--- a/roms/ipxe/src/core/bitmap.c
+++ b/roms/ipxe/src/core/bitmap.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <errno.h>
#include <ipxe/bitmap.h>
diff --git a/roms/ipxe/src/core/blockdev.c b/roms/ipxe/src/core/blockdev.c
index 9d118cb2f..c219d9673 100644
--- a/roms/ipxe/src/core/blockdev.c
+++ b/roms/ipxe/src/core/blockdev.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <errno.h>
#include <ipxe/interface.h>
diff --git a/roms/ipxe/src/core/blocktrans.c b/roms/ipxe/src/core/blocktrans.c
new file mode 100644
index 000000000..3f32f9cf8
--- /dev/null
+++ b/roms/ipxe/src/core/blocktrans.c
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/**
+ * @file
+ *
+ * Block device translator
+ *
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/xfer.h>
+#include <ipxe/blockdev.h>
+#include <ipxe/blocktrans.h>
+
+/**
+ * Reallocate block device translator data buffer
+ *
+ * @v xferbuf Data transfer buffer
+ * @v len New length (or zero to free buffer)
+ * @ret rc Return status code
+ */
+static int blktrans_xferbuf_realloc ( struct xfer_buffer *xferbuf,
+ size_t len ) {
+ struct block_translator *blktrans =
+ container_of ( xferbuf, struct block_translator, xferbuf );
+
+ /* Record length, if applicable */
+ if ( blktrans->buffer ) {
+
+ /* We have a (non-reallocatable) data buffer */
+ return -ENOTSUP;
+
+ } else {
+
+ /* Record length (for block device capacity) */
+ xferbuf->len = len;
+ return 0;
+ }
+}
+
+/**
+ * Write data to block device translator data buffer
+ *
+ * @v xferbuf Data transfer buffer
+ * @v offset Starting offset
+ * @v data Data to copy
+ * @v len Length of data
+ */
+static void blktrans_xferbuf_write ( struct xfer_buffer *xferbuf, size_t offset,
+ const void *data, size_t len ) {
+ struct block_translator *blktrans =
+ container_of ( xferbuf, struct block_translator, xferbuf );
+
+ /* Write data to buffer, if applicable */
+ if ( blktrans->buffer ) {
+
+ /* Write data to buffer */
+ copy_to_user ( blktrans->buffer, offset, data, len );
+
+ } else {
+
+ /* Sanity check */
+ assert ( len == 0 );
+ }
+}
+
+/**
+ * Read data from block device translator data buffer
+ *
+ * @v xferbuf Data transfer buffer
+ * @v offset Starting offset
+ * @v data Data to read
+ * @v len Length of data
+ */
+static void blktrans_xferbuf_read ( struct xfer_buffer *xferbuf, size_t offset,
+ void *data, size_t len ) {
+ struct block_translator *blktrans =
+ container_of ( xferbuf, struct block_translator, xferbuf );
+
+ /* Read data from buffer, if applicable */
+ if ( blktrans->buffer ) {
+
+ /* Read data from buffer */
+ copy_from_user ( data, blktrans->buffer, offset, len );
+
+ } else {
+
+ /* Sanity check */
+ assert ( len == 0 );
+ }
+}
+
+/** Block device translator data transfer buffer operations */
+static struct xfer_buffer_operations blktrans_xferbuf_operations = {
+ .realloc = blktrans_xferbuf_realloc,
+ .write = blktrans_xferbuf_write,
+ .read = blktrans_xferbuf_read,
+};
+
+/**
+ * Close block device translator
+ *
+ * @v blktrans Block device translator
+ * @v rc Reason for close
+ */
+static void blktrans_close ( struct block_translator *blktrans, int rc ) {
+ struct block_device_capacity capacity;
+
+ /* Report block device capacity, if applicable */
+ if ( ( rc == 0 ) && ( blktrans->blksize ) ) {
+
+ /* Construct block device capacity */
+ capacity.blocks =
+ ( blktrans->xferbuf.len / blktrans->blksize );
+ capacity.blksize = blktrans->blksize;
+ capacity.max_count = -1U;
+
+ /* Report block device capacity */
+ block_capacity ( &blktrans->block, &capacity );
+ }
+
+ /* Shut down interfaces */
+ intf_shutdown ( &blktrans->xfer, rc );
+ intf_shutdown ( &blktrans->block, rc );
+}
+
+/**
+ * Deliver data
+ *
+ * @v blktrans Block device translator
+ * @v iobuf I/O buffer
+ * @v meta Data transfer metadata
+ * @ret rc Return status code
+ */
+static int blktrans_deliver ( struct block_translator *blktrans,
+ struct io_buffer *iobuf,
+ struct xfer_metadata *meta ) {
+ int rc;
+
+ /* Deliver to buffer */
+ if ( ( rc = xferbuf_deliver ( &blktrans->xferbuf, iob_disown ( iobuf ),
+ meta ) ) != 0 ) {
+ DBGC ( blktrans, "BLKTRANS %p could not deliver: %s\n",
+ blktrans, strerror ( rc ) );
+ goto err;
+ }
+
+ return 0;
+
+ err:
+ blktrans_close ( blktrans, rc );
+ return rc;
+}
+
+/**
+ * Get underlying data transfer buffer
+ *
+ * @v blktrans Block device translator
+ * @ret xferbuf Data transfer buffer
+ */
+static struct xfer_buffer *
+blktrans_buffer ( struct block_translator *blktrans ) {
+
+ return &blktrans->xferbuf;
+}
+
+/** Block device translator block device interface operations */
+static struct interface_operation blktrans_block_operations[] = {
+ INTF_OP ( intf_close, struct block_translator *, blktrans_close ),
+};
+
+/** Block device translator block device interface descriptor */
+static struct interface_descriptor blktrans_block_desc =
+ INTF_DESC_PASSTHRU ( struct block_translator, block,
+ blktrans_block_operations, xfer );
+
+/** Block device translator data transfer interface operations */
+static struct interface_operation blktrans_xfer_operations[] = {
+ INTF_OP ( xfer_deliver, struct block_translator *, blktrans_deliver ),
+ INTF_OP ( xfer_buffer, struct block_translator *, blktrans_buffer ),
+ INTF_OP ( intf_close, struct block_translator *, blktrans_close ),
+};
+
+/** Block device translator data transfer interface descriptor */
+static struct interface_descriptor blktrans_xfer_desc =
+ INTF_DESC_PASSTHRU ( struct block_translator, xfer,
+ blktrans_xfer_operations, block );
+
+/**
+ * Insert block device translator
+ *
+ * @v block Block device interface
+ * @v buffer Data buffer (or UNULL)
+ * @v size Length of data buffer, or block size
+ * @ret rc Return status code
+ */
+int block_translate ( struct interface *block, userptr_t buffer, size_t size ) {
+ struct block_translator *blktrans;
+ int rc;
+
+ /* Allocate and initialise structure */
+ blktrans = zalloc ( sizeof ( *blktrans ) );
+ if ( ! blktrans ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ ref_init ( &blktrans->refcnt, NULL );
+ intf_init ( &blktrans->block, &blktrans_block_desc, &blktrans->refcnt );
+ intf_init ( &blktrans->xfer, &blktrans_xfer_desc, &blktrans->refcnt );
+ blktrans->xferbuf.op = &blktrans_xferbuf_operations;
+ blktrans->buffer = buffer;
+ if ( buffer ) {
+ blktrans->xferbuf.len = size;
+ } else {
+ blktrans->blksize = size;
+ }
+
+ /* Attach to interfaces, mortalise self, and return */
+ assert ( block->dest != &null_intf );
+ intf_plug_plug ( &blktrans->xfer, block->dest );
+ intf_plug_plug ( &blktrans->block, block );
+ ref_put ( &blktrans->refcnt );
+
+ DBGC2 ( blktrans, "BLKTRANS %p created", blktrans );
+ if ( buffer ) {
+ DBGC2 ( blktrans, " for %#lx+%#zx",
+ user_to_phys ( buffer, 0 ), size );
+ }
+ DBGC2 ( blktrans, "\n" );
+ return 0;
+
+ ref_put ( &blktrans->refcnt );
+ err_alloc:
+ return rc;
+}
diff --git a/roms/ipxe/src/core/console.c b/roms/ipxe/src/core/console.c
index 141d8f0f0..7fd00036f 100644
--- a/roms/ipxe/src/core/console.c
+++ b/roms/ipxe/src/core/console.c
@@ -5,7 +5,7 @@
/** @file */
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** Current console usage */
int console_usage = CONSOLE_USAGE_STDOUT;
diff --git a/roms/ipxe/src/core/cpio.c b/roms/ipxe/src/core/cpio.c
index 3a5f4d2b6..080c72daf 100644
--- a/roms/ipxe/src/core/cpio.c
+++ b/roms/ipxe/src/core/cpio.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/core/ctype.c b/roms/ipxe/src/core/ctype.c
index c812346a0..891af71ea 100644
--- a/roms/ipxe/src/core/ctype.c
+++ b/roms/ipxe/src/core/ctype.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @file
@@ -31,11 +35,12 @@ FILE_LICENCE ( GPL2_OR_LATER );
/**
* Check to see if character is a space
*
- * @v c Character
+ * @v character Character
* @ret isspace Character is a space
*/
-int isspace ( int c ) {
- switch ( c ) {
+int isspace ( int character ) {
+
+ switch ( character ) {
case ' ' :
case '\f' :
case '\n' :
diff --git a/roms/ipxe/src/core/cwuri.c b/roms/ipxe/src/core/cwuri.c
index 5865552a0..612f0b179 100644
--- a/roms/ipxe/src/core/cwuri.c
+++ b/roms/ipxe/src/core/cwuri.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <ipxe/uri.h>
diff --git a/roms/ipxe/src/core/debug.c b/roms/ipxe/src/core/debug.c
index 7ded47089..def5d8b09 100644
--- a/roms/ipxe/src/core/debug.c
+++ b/roms/ipxe/src/core/debug.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdio.h>
#include <stdint.h>
diff --git a/roms/ipxe/src/core/debug_md5.c b/roms/ipxe/src/core/debug_md5.c
index f049ac757..d0dbad9ed 100644
--- a/roms/ipxe/src/core/debug_md5.c
+++ b/roms/ipxe/src/core/debug_md5.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdio.h>
#include <stdint.h>
diff --git a/roms/ipxe/src/core/device.c b/roms/ipxe/src/core/device.c
index 330f95c5a..77d7b719b 100644
--- a/roms/ipxe/src/core/device.c
+++ b/roms/ipxe/src/core/device.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <ipxe/list.h>
diff --git a/roms/ipxe/src/core/downloader.c b/roms/ipxe/src/core/downloader.c
index ec69db6b1..d745f3617 100644
--- a/roms/ipxe/src/core/downloader.c
+++ b/roms/ipxe/src/core/downloader.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdlib.h>
#include <errno.h>
@@ -29,7 +33,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/uaccess.h>
#include <ipxe/umalloc.h>
#include <ipxe/image.h>
-#include <ipxe/profile.h>
+#include <ipxe/xferbuf.h>
#include <ipxe/downloader.h>
/** @file
@@ -38,14 +42,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
*/
-/** Receive profiler */
-static struct profiler downloader_rx_profiler __profiler =
- { .name = "downloader.rx" };
-
-/** Data copy profiler */
-static struct profiler downloader_copy_profiler __profiler =
- { .name = "downloader.copy" };
-
/** A downloader */
struct downloader {
/** Reference count for this object */
@@ -58,8 +54,8 @@ struct downloader {
/** Image to contain downloaded file */
struct image *image;
- /** Current position within image buffer */
- size_t pos;
+ /** Data transfer buffer */
+ struct xfer_buffer buffer;
};
/**
@@ -92,42 +88,14 @@ static void downloader_finished ( struct downloader *downloader, int rc ) {
downloader->image->name, strerror ( rc ) );
}
+ /* Update image length */
+ downloader->image->len = downloader->buffer.len;
+
/* Shut down interfaces */
intf_shutdown ( &downloader->xfer, rc );
intf_shutdown ( &downloader->job, rc );
}
-/**
- * Ensure that download buffer is large enough for the specified size
- *
- * @v downloader Downloader
- * @v len Required minimum size
- * @ret rc Return status code
- */
-static int downloader_ensure_size ( struct downloader *downloader,
- size_t len ) {
- userptr_t new_buffer;
-
- /* If buffer is already large enough, do nothing */
- if ( len <= downloader->image->len )
- return 0;
-
- DBGC ( downloader, "Downloader %p extending to %zd bytes\n",
- downloader, len );
-
- /* Extend buffer */
- new_buffer = urealloc ( downloader->image->data, len );
- if ( ! new_buffer ) {
- DBGC ( downloader, "Downloader %p could not extend buffer to "
- "%zd bytes\n", downloader, len );
- return -ENOSPC;
- }
- downloader->image->data = new_buffer;
- downloader->image->len = len;
-
- return 0;
-}
-
/****************************************************************************
*
* Job control interface
@@ -148,8 +116,8 @@ static int downloader_progress ( struct downloader *downloader,
* arrive out of order (e.g. with multicast protocols), but
* it's a reasonable first approximation.
*/
- progress->completed = downloader->pos;
- progress->total = downloader->image->len;
+ progress->completed = downloader->buffer.pos;
+ progress->total = downloader->buffer.len;
return 0;
}
@@ -171,44 +139,37 @@ static int downloader_progress ( struct downloader *downloader,
static int downloader_xfer_deliver ( struct downloader *downloader,
struct io_buffer *iobuf,
struct xfer_metadata *meta ) {
- size_t len;
- size_t max;
int rc;
- /* Start profiling */
- profile_start ( &downloader_rx_profiler );
-
- /* Calculate new buffer position */
- if ( meta->flags & XFER_FL_ABS_OFFSET )
- downloader->pos = 0;
- downloader->pos += meta->offset;
-
- /* Ensure that we have enough buffer space for this data */
- len = iob_len ( iobuf );
- max = ( downloader->pos + len );
- if ( ( rc = downloader_ensure_size ( downloader, max ) ) != 0 )
- goto done;
-
- /* Copy data to buffer */
- profile_start ( &downloader_copy_profiler );
- copy_to_user ( downloader->image->data, downloader->pos,
- iobuf->data, len );
- profile_stop ( &downloader_copy_profiler );
-
- /* Update current buffer position */
- downloader->pos += len;
-
- done:
- free_iob ( iobuf );
- if ( rc != 0 )
- downloader_finished ( downloader, rc );
- profile_stop ( &downloader_rx_profiler );
+ /* Add data to buffer */
+ if ( ( rc = xferbuf_deliver ( &downloader->buffer, iob_disown ( iobuf ),
+ meta ) ) != 0 )
+ goto err_deliver;
+
+ return 0;
+
+ err_deliver:
+ downloader_finished ( downloader, rc );
return rc;
}
+/**
+ * Get underlying data transfer buffer
+ *
+ * @v downloader Downloader
+ * @ret xferbuf Data transfer buffer, or NULL on error
+ */
+static struct xfer_buffer *
+downloader_xfer_buffer ( struct downloader *downloader ) {
+
+ /* Provide direct access to underlying data transfer buffer */
+ return &downloader->buffer;
+}
+
/** Downloader data transfer interface operations */
static struct interface_operation downloader_xfer_operations[] = {
INTF_OP ( xfer_deliver, struct downloader *, downloader_xfer_deliver ),
+ INTF_OP ( xfer_buffer, struct downloader *, downloader_xfer_buffer ),
INTF_OP ( intf_close, struct downloader *, downloader_finished ),
};
@@ -262,6 +223,7 @@ int create_downloader ( struct interface *job, struct image *image ) {
intf_init ( &downloader->xfer, &downloader_xfer_desc,
&downloader->refcnt );
downloader->image = image_get ( image );
+ xferbuf_umalloc_init ( &downloader->buffer, &image->data );
/* Instantiate child objects and attach to our interfaces */
if ( ( rc = xfer_open_uri ( &downloader->xfer, image->uri ) ) != 0 )
diff --git a/roms/ipxe/src/core/edd.c b/roms/ipxe/src/core/edd.c
index d574ea6c0..a50b74ab1 100644
--- a/roms/ipxe/src/core/edd.c
+++ b/roms/ipxe/src/core/edd.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <errno.h>
#include <ipxe/interface.h>
diff --git a/roms/ipxe/src/core/errno.c b/roms/ipxe/src/core/errno.c
index 06905561f..5de15bb92 100644
--- a/roms/ipxe/src/core/errno.c
+++ b/roms/ipxe/src/core/errno.c
@@ -1,6 +1,6 @@
#include <errno.h>
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/core/exec.c b/roms/ipxe/src/core/exec.c
index 1c85705ae..2c2ade0a5 100644
--- a/roms/ipxe/src/core/exec.c
+++ b/roms/ipxe/src/core/exec.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <string.h>
diff --git a/roms/ipxe/src/core/fault.c b/roms/ipxe/src/core/fault.c
new file mode 100644
index 000000000..63d3ccacf
--- /dev/null
+++ b/roms/ipxe/src/core/fault.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2015 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdlib.h>
+#include <errno.h>
+#include <ipxe/fault.h>
+
+/** @file
+ *
+ * Fault injection
+ *
+ */
+
+/**
+ * Inject fault with a specified probability
+ *
+ * @v rate Reciprocal of fault probability (must be non-zero)
+ * @ret rc Return status code
+ */
+int inject_fault_nonzero ( unsigned int rate ) {
+
+ /* Do nothing unless we want to inject a fault now */
+ if ( ( random() % rate ) != 0 )
+ return 0;
+
+ /* Generate error number here so that faults can be injected
+ * into files that don't themselves have error file
+ * identifiers (via errfile.h).
+ */
+ return -EFAULT;
+}
+
+/**
+ * Corrupt data with a specified probability
+ *
+ * @v rate Reciprocal of fault probability (must be non-zero)
+ * @v data Data
+ * @v len Length of data
+ * @ret rc Return status code
+ */
+void inject_corruption_nonzero ( unsigned int rate, const void *data,
+ size_t len ) {
+ uint8_t *writable;
+ size_t offset;
+
+ /* Do nothing if we have no data to corrupt */
+ if ( ! len )
+ return;
+
+ /* Do nothing unless we want to inject a fault now */
+ if ( ! inject_fault_nonzero ( rate ) )
+ return;
+
+ /* Get a writable pointer to the nominally read-only data */
+ writable = ( ( uint8_t * ) data );
+
+ /* Pick a random victim byte and zap it */
+ offset = ( random() % len );
+ writable[offset] ^= random();
+}
diff --git a/roms/ipxe/src/core/fbcon.c b/roms/ipxe/src/core/fbcon.c
index 72d6a6789..6d8b0086d 100644
--- a/roms/ipxe/src/core/fbcon.c
+++ b/roms/ipxe/src/core/fbcon.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/core/fnrec.c b/roms/ipxe/src/core/fnrec.c
index 3453c8b6a..0430817f8 100644
--- a/roms/ipxe/src/core/fnrec.c
+++ b/roms/ipxe/src/core/fnrec.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdlib.h>
#include <stdio.h>
diff --git a/roms/ipxe/src/core/gdbserial.c b/roms/ipxe/src/core/gdbserial.c
index 6f78c88bf..0983f2557 100644
--- a/roms/ipxe/src/core/gdbserial.c
+++ b/roms/ipxe/src/core/gdbserial.c
@@ -15,35 +15,105 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <assert.h>
-#include <ipxe/serial.h>
+#include <ipxe/uart.h>
#include <ipxe/gdbstub.h>
#include <ipxe/gdbserial.h>
+#include <config/serial.h>
+
+/* UART port number */
+#ifdef COMCONSOLE
+#define GDBSERIAL_PORT COMCONSOLE
+#else
+#define GDBSERIAL_PORT 0
+#endif
+
+/* UART baud rate */
+#ifdef COMPRESERVE
+#define GDBSERIAL_BAUD 0
+#else
+#define GDBSERIAL_BAUD COMSPEED
+#endif
+
+/* UART line control register value */
+#ifdef COMPRESERVE
+#define GDBSERIAL_LCR 0
+#else
+#define GDBSERIAL_LCR UART_LCR_WPS ( COMDATA, COMPARITY, COMSTOP )
+#endif
+
+/** GDB serial UART */
+static struct uart gdbserial_uart;
struct gdb_transport serial_gdb_transport __gdb_transport;
static size_t gdbserial_recv ( char *buf, size_t len ) {
+
assert ( len > 0 );
- buf [ 0 ] = serial_getc();
+ while ( ! uart_data_ready ( &gdbserial_uart ) ) {}
+ buf[0] = uart_receive ( &gdbserial_uart );
return 1;
}
static void gdbserial_send ( const char *buf, size_t len ) {
+
while ( len-- > 0 ) {
- serial_putc ( *buf++ );
+ uart_transmit ( &gdbserial_uart, *buf++ );
}
}
+static int gdbserial_init ( int argc, char **argv ) {
+ unsigned int port;
+ char *endp;
+
+ if ( argc == 0 ) {
+ port = GDBSERIAL_PORT;
+ } else if ( argc == 1 ) {
+ port = strtoul ( argv[0], &endp, 10 );
+ if ( *endp ) {
+ printf ( "serial: invalid port\n" );
+ return 1;
+ }
+ } else {
+ printf ( "serial: syntax <port>\n" );
+ return 1;
+ }
+
+ if ( ! gdbserial_configure ( port, GDBSERIAL_BAUD, GDBSERIAL_LCR ) ) {
+ printf ( "serial: unable to configure\n" );
+ return 1;
+ }
+
+ return 0;
+}
+
struct gdb_transport serial_gdb_transport __gdb_transport = {
.name = "serial",
+ .init = gdbserial_init,
.recv = gdbserial_recv,
.send = gdbserial_send,
};
-struct gdb_transport *gdbserial_configure ( void ) {
+struct gdb_transport * gdbserial_configure ( unsigned int port,
+ unsigned int baud, uint8_t lcr ) {
+ int rc;
+
+ if ( ( rc = uart_select ( &gdbserial_uart, port ) ) != 0 )
+ return NULL;
+
+ if ( ( rc = uart_init ( &gdbserial_uart, baud, lcr ) ) != 0 )
+ return NULL;
+
return &serial_gdb_transport;
}
diff --git a/roms/ipxe/src/core/gdbstub.c b/roms/ipxe/src/core/gdbstub.c
index af06118b2..6ad52d1a6 100644
--- a/roms/ipxe/src/core/gdbstub.c
+++ b/roms/ipxe/src/core/gdbstub.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @file
diff --git a/roms/ipxe/src/core/gdbudp.c b/roms/ipxe/src/core/gdbudp.c
index 5977547c8..e4613d137 100644
--- a/roms/ipxe/src/core/gdbudp.c
+++ b/roms/ipxe/src/core/gdbudp.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdio.h>
#include <string.h>
diff --git a/roms/ipxe/src/core/getkey.c b/roms/ipxe/src/core/getkey.c
index d69cfb44b..0f0f8b7c3 100644
--- a/roms/ipxe/src/core/getkey.c
+++ b/roms/ipxe/src/core/getkey.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ctype.h>
#include <ipxe/console.h>
diff --git a/roms/ipxe/src/core/getopt.c b/roms/ipxe/src/core/getopt.c
index abc1edd6c..e6c3948d1 100644
--- a/roms/ipxe/src/core/getopt.c
+++ b/roms/ipxe/src/core/getopt.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <string.h>
diff --git a/roms/ipxe/src/core/image.c b/roms/ipxe/src/core/image.c
index ec4480238..529e3d72c 100644
--- a/roms/ipxe/src/core/image.c
+++ b/roms/ipxe/src/core/image.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <string.h>
@@ -154,6 +158,32 @@ int image_set_cmdline ( struct image *image, const char *cmdline ) {
}
/**
+ * Determine image type
+ *
+ * @v image Executable image
+ * @ret rc Return status code
+ */
+static int image_probe ( struct image *image ) {
+ struct image_type *type;
+ int rc;
+
+ /* Try each type in turn */
+ for_each_table_entry ( type, IMAGE_TYPES ) {
+ if ( ( rc = type->probe ( image ) ) == 0 ) {
+ image->type = type;
+ DBGC ( image, "IMAGE %s is %s\n",
+ image->name, type->name );
+ break;
+ }
+ DBGC ( image, "IMAGE %s is not %s: %s\n", image->name,
+ type->name, strerror ( rc ) );
+ }
+
+ DBGC ( image, "IMAGE %s format not recognised\n", image->name );
+ return -ENOTSUP;
+}
+
+/**
* Register executable image
*
* @v image Executable image
@@ -185,6 +215,14 @@ int register_image ( struct image *image ) {
image->name, user_to_phys ( image->data, 0 ),
user_to_phys ( image->data, image->len ) );
+ /* Try to detect image type, if applicable. Ignore failures,
+ * since we expect to handle some unrecognised images
+ * (e.g. kernel initrds, multiboot modules, random files
+ * provided via our EFI virtual filesystem, etc).
+ */
+ if ( ! image->type )
+ image_probe ( image );
+
return 0;
}
@@ -223,36 +261,6 @@ struct image * find_image ( const char *name ) {
}
/**
- * Determine image type
- *
- * @v image Executable image
- * @ret rc Return status code
- */
-int image_probe ( struct image *image ) {
- struct image_type *type;
- int rc;
-
- /* Succeed if we already have a type */
- if ( image->type )
- return 0;
-
- /* Try each type in turn */
- for_each_table_entry ( type, IMAGE_TYPES ) {
- if ( ( rc = type->probe ( image ) ) == 0 ) {
- image->type = type;
- DBGC ( image, "IMAGE %s is %s\n",
- image->name, type->name );
- return 0;
- }
- DBGC ( image, "IMAGE %s is not %s: %s\n", image->name,
- type->name, strerror ( rc ) );
- }
-
- DBGC ( image, "IMAGE %s format not recognised\n", image->name );
- return -ENOEXEC;
-}
-
-/**
* Execute image
*
* @v image Executable image
@@ -284,9 +292,11 @@ int image_exec ( struct image *image ) {
*/
current_image = image_get ( image );
- /* Check that this image can be selected for execution */
- if ( ( rc = image_select ( image ) ) != 0 )
+ /* Check that this image can be executed */
+ if ( ! ( image->type && image->type->exec ) ) {
+ rc = -ENOEXEC;
goto err;
+ }
/* Check that image is trusted (if applicable) */
if ( require_trusted_images && ! ( image->flags & IMAGE_TRUSTED ) ) {
@@ -378,8 +388,8 @@ int image_replace ( struct image *replacement ) {
}
/* Check that the replacement image can be executed */
- if ( ( rc = image_probe ( replacement ) ) != 0 )
- return rc;
+ if ( ! ( replacement->type && replacement->type->exec ) )
+ return -ENOEXEC;
/* Clear any existing replacement */
image_put ( image->replacement );
@@ -400,16 +410,13 @@ int image_replace ( struct image *replacement ) {
*/
int image_select ( struct image *image ) {
struct image *tmp;
- int rc;
/* Unselect all other images */
for_each_image ( tmp )
tmp->flags &= ~IMAGE_SELECTED;
/* Check that this image can be executed */
- if ( ( rc = image_probe ( image ) ) != 0 )
- return rc;
- if ( ! image->type->exec )
+ if ( ! ( image->type && image->type->exec ) )
return -ENOEXEC;
/* Mark image as selected */
@@ -468,9 +475,7 @@ int image_pixbuf ( struct image *image, struct pixel_buffer **pixbuf ) {
int rc;
/* Check that this image can be used to create a pixel buffer */
- if ( ( rc = image_probe ( image ) ) != 0 )
- return rc;
- if ( ! image->type->pixbuf )
+ if ( ! ( image->type && image->type->pixbuf ) )
return -ENOTSUP;
/* Try creating pixel buffer */
diff --git a/roms/ipxe/src/core/init.c b/roms/ipxe/src/core/init.c
index 7ea0730fa..d91e44669 100644
--- a/roms/ipxe/src/core/init.c
+++ b/roms/ipxe/src/core/init.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/device.h>
#include <ipxe/console.h>
diff --git a/roms/ipxe/src/core/interface.c b/roms/ipxe/src/core/interface.c
index 62f4621db..ba148c13d 100644
--- a/roms/ipxe/src/core/interface.c
+++ b/roms/ipxe/src/core/interface.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <ipxe/interface.h>
@@ -307,3 +311,28 @@ void intf_restart ( struct interface *intf, int rc ) {
*/
intf->desc = desc;
}
+
+/**
+ * Poke an object interface
+ *
+ * @v intf Object interface
+ * @v type Operation type
+ *
+ * This is a helper function to implement methods which take no
+ * parameters and return nothing.
+ */
+void intf_poke ( struct interface *intf,
+ void ( type ) ( struct interface *intf ) ) {
+ struct interface *dest;
+ intf_poke_TYPE ( void * ) *op =
+ intf_get_dest_op_untyped ( intf, type, &dest );
+ void *object = intf_object ( dest );
+
+ if ( op ) {
+ op ( object );
+ } else {
+ /* Default is to do nothing */
+ }
+
+ intf_put ( dest );
+}
diff --git a/roms/ipxe/src/core/iobuf.c b/roms/ipxe/src/core/iobuf.c
index afc91d150..3e52ada4f 100644
--- a/roms/ipxe/src/core/iobuf.c
+++ b/roms/ipxe/src/core/iobuf.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <strings.h>
@@ -200,3 +204,33 @@ struct io_buffer * iob_concatenate ( struct list_head *list ) {
return concatenated;
}
+
+/**
+ * Split I/O buffer
+ *
+ * @v iobuf I/O buffer
+ * @v len Length to split into a new I/O buffer
+ * @ret split New I/O buffer, or NULL on allocation failure
+ *
+ * Split the first @c len bytes of the existing I/O buffer into a
+ * separate I/O buffer. The resulting buffers are likely to have no
+ * headroom or tailroom.
+ *
+ * If this call fails, then the original buffer will be unmodified.
+ */
+struct io_buffer * iob_split ( struct io_buffer *iobuf, size_t len ) {
+ struct io_buffer *split;
+
+ /* Sanity checks */
+ assert ( len <= iob_len ( iobuf ) );
+
+ /* Allocate new I/O buffer */
+ split = alloc_iob ( len );
+ if ( ! split )
+ return NULL;
+
+ /* Copy in data */
+ memcpy ( iob_put ( split, len ), iobuf->data, len );
+ iob_pull ( iobuf, len );
+ return split;
+}
diff --git a/roms/ipxe/src/core/isqrt.c b/roms/ipxe/src/core/isqrt.c
index 35c918d19..c4d0571e7 100644
--- a/roms/ipxe/src/core/isqrt.c
+++ b/roms/ipxe/src/core/isqrt.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/core/job.c b/roms/ipxe/src/core/job.c
index 674bec8b5..65df80056 100644
--- a/roms/ipxe/src/core/job.c
+++ b/roms/ipxe/src/core/job.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <errno.h>
diff --git a/roms/ipxe/src/core/linebuf.c b/roms/ipxe/src/core/linebuf.c
index 8fb2f86a7..c197e383c 100644
--- a/roms/ipxe/src/core/linebuf.c
+++ b/roms/ipxe/src/core/linebuf.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @file
@@ -39,7 +43,18 @@ FILE_LICENCE ( GPL2_OR_LATER );
* @ret line Buffered line, or NULL if no line ready to read
*/
char * buffered_line ( struct line_buffer *linebuf ) {
- return ( linebuf->ready ? linebuf->data : NULL );
+ char *line = &linebuf->data[ linebuf->len ];
+
+ /* Fail unless we have a newly completed line to retrieve */
+ if ( ( linebuf->len == 0 ) || ( linebuf->consumed == 0 ) ||
+ ( *(--line) != '\0' ) )
+ return NULL;
+
+ /* Identify start of line */
+ while ( ( line > linebuf->data ) && ( line[-1] != '\0' ) )
+ line--;
+
+ return line;
}
/**
@@ -48,10 +63,11 @@ char * buffered_line ( struct line_buffer *linebuf ) {
* @v linebuf Line buffer
*/
void empty_line_buffer ( struct line_buffer *linebuf ) {
+
free ( linebuf->data );
linebuf->data = NULL;
linebuf->len = 0;
- linebuf->ready = 0;
+ linebuf->consumed = 0;
}
/**
@@ -72,16 +88,13 @@ void empty_line_buffer ( struct line_buffer *linebuf ) {
* should call empty_line_buffer() before freeing a @c struct @c
* line_buffer.
*/
-ssize_t line_buffer ( struct line_buffer *linebuf,
- const char *data, size_t len ) {
+int line_buffer ( struct line_buffer *linebuf, const char *data, size_t len ) {
const char *eol;
size_t consume;
size_t new_len;
char *new_data;
-
- /* Free any completed line from previous iteration */
- if ( linebuf->ready )
- empty_line_buffer ( linebuf );
+ char *lf;
+ char *cr;
/* Search for line terminator */
if ( ( eol = memchr ( data, '\n', len ) ) ) {
@@ -90,6 +103,10 @@ ssize_t line_buffer ( struct line_buffer *linebuf,
consume = len;
}
+ /* Reject any embedded NULs within the data to be consumed */
+ if ( memchr ( data, '\0', consume ) )
+ return -EINVAL;
+
/* Reallocate data buffer and copy in new data */
new_len = ( linebuf->len + consume );
new_data = realloc ( linebuf->data, ( new_len + 1 ) );
@@ -100,13 +117,27 @@ ssize_t line_buffer ( struct line_buffer *linebuf,
linebuf->data = new_data;
linebuf->len = new_len;
- /* If we have reached end of line, trim the line and mark as ready */
+ /* If we have reached end of line, terminate the line */
if ( eol ) {
- linebuf->data[--linebuf->len] = '\0'; /* trim NL */
- if ( linebuf->data[linebuf->len - 1] == '\r' )
- linebuf->data[--linebuf->len] = '\0'; /* trim CR */
- linebuf->ready = 1;
+
+ /* Overwrite trailing LF (which must exist at this point) */
+ assert ( linebuf->len > 0 );
+ lf = &linebuf->data[ linebuf->len - 1 ];
+ assert ( *lf == '\n' );
+ *lf = '\0';
+
+ /* Trim (and overwrite) trailing CR, if present */
+ if ( linebuf->len > 1 ) {
+ cr = ( lf - 1 );
+ if ( *cr == '\r' ) {
+ linebuf->len--;
+ *cr = '\0';
+ }
+ }
}
+ /* Record consumed length */
+ linebuf->consumed = consume;
+
return consume;
}
diff --git a/roms/ipxe/src/core/lineconsole.c b/roms/ipxe/src/core/lineconsole.c
index 1b6791cf3..bb3bfafc9 100644
--- a/roms/ipxe/src/core/lineconsole.c
+++ b/roms/ipxe/src/core/lineconsole.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/core/list.c b/roms/ipxe/src/core/list.c
index 77579d69a..5175c84ec 100644
--- a/roms/ipxe/src/core/list.c
+++ b/roms/ipxe/src/core/list.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/core/log.c b/roms/ipxe/src/core/log.c
index f160b4fc8..c08e4bb9b 100644
--- a/roms/ipxe/src/core/log.c
+++ b/roms/ipxe/src/core/log.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/core/main.c b/roms/ipxe/src/core/main.c
index db09e4c39..638dea9cf 100644
--- a/roms/ipxe/src/core/main.c
+++ b/roms/ipxe/src/core/main.c
@@ -12,7 +12,7 @@ Literature dealing with the network protocols:
**************************************************************************/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <stdio.h>
@@ -26,6 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
* @ret rc Return status code
*/
__asmcall int main ( void ) {
+ int rc;
/* Perform one-time-only initialisation (e.g. heap) */
initialise();
@@ -35,9 +36,11 @@ __asmcall int main ( void ) {
startup();
printf ( "ok\n" );
- ipxe ( NULL );
+ /* Attempt to boot */
+ if ( ( rc = ipxe ( NULL ) ) != 0 )
+ goto err_ipxe;
+ err_ipxe:
shutdown_exit();
-
- return 0;
+ return rc;
}
diff --git a/roms/ipxe/src/core/malloc.c b/roms/ipxe/src/core/malloc.c
index d9c07495d..b120c0325 100644
--- a/roms/ipxe/src/core/malloc.c
+++ b/roms/ipxe/src/core/malloc.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <stdint.h>
@@ -106,6 +110,7 @@ static char heap[HEAP_SIZE] __attribute__ (( aligned ( __alignof__(void *) )));
static inline void valgrind_make_blocks_defined ( void ) {
struct memory_block *block;
+ /* Do nothing unless running under Valgrind */
if ( RUNNING_ON_VALGRIND <= 0 )
return;
@@ -147,6 +152,7 @@ static inline void valgrind_make_blocks_noaccess ( void ) {
struct memory_block *block;
struct memory_block *prev = NULL;
+ /* Do nothing unless running under Valgrind */
if ( RUNNING_ON_VALGRIND <= 0 )
return;
@@ -267,24 +273,25 @@ static void discard_all_cache ( void ) {
void * alloc_memblock ( size_t size, size_t align, size_t offset ) {
struct memory_block *block;
size_t align_mask;
+ size_t actual_size;
size_t pre_size;
ssize_t post_size;
struct memory_block *pre;
struct memory_block *post;
- struct memory_block *ptr;
+ void *ptr;
/* Sanity checks */
assert ( size != 0 );
assert ( ( align == 0 ) || ( ( align & ( align - 1 ) ) == 0 ) );
-
valgrind_make_blocks_defined();
check_blocks();
/* Round up size to multiple of MIN_MEMBLOCK_SIZE and
* calculate alignment mask.
*/
- size = ( size + MIN_MEMBLOCK_SIZE - 1 ) & ~( MIN_MEMBLOCK_SIZE - 1 );
- align_mask = ( align - 1 ) | ( MIN_MEMBLOCK_SIZE - 1 );
+ actual_size = ( ( size + MIN_MEMBLOCK_SIZE - 1 ) &
+ ~( MIN_MEMBLOCK_SIZE - 1 ) );
+ align_mask = ( ( align - 1 ) | ( MIN_MEMBLOCK_SIZE - 1 ) );
DBGC2 ( &heap, "Allocating %#zx (aligned %#zx+%zx)\n",
size, align, offset );
@@ -293,7 +300,7 @@ void * alloc_memblock ( size_t size, size_t align, size_t offset ) {
list_for_each_entry ( block, &free_blocks, list ) {
pre_size = ( ( offset - virt_to_phys ( block ) )
& align_mask );
- post_size = ( block->size - pre_size - size );
+ post_size = ( block->size - pre_size - actual_size );
if ( post_size >= 0 ) {
/* Split block into pre-block, block, and
* post-block. After this split, the "pre"
@@ -302,7 +309,7 @@ void * alloc_memblock ( size_t size, size_t align, size_t offset ) {
*/
pre = block;
block = ( ( ( void * ) pre ) + pre_size );
- post = ( ( ( void * ) block ) + size );
+ post = ( ( ( void * ) block ) + actual_size );
DBGC2 ( &heap, "[%p,%p) -> [%p,%p) + [%p,%p)\n",
pre, ( ( ( void * ) pre ) + pre->size ),
pre, block, post,
@@ -313,8 +320,8 @@ void * alloc_memblock ( size_t size, size_t align, size_t offset ) {
* the heap).
*/
if ( (size_t) post_size >= MIN_MEMBLOCK_SIZE ) {
- VALGRIND_MAKE_MEM_DEFINED ( post,
- sizeof ( *post ) );
+ VALGRIND_MAKE_MEM_UNDEFINED
+ ( post, sizeof ( *post ) );
post->size = post_size;
list_add ( &post->list, &pre->list );
}
@@ -328,14 +335,18 @@ void * alloc_memblock ( size_t size, size_t align, size_t offset ) {
* it is too small, which can happen only at
* the very start of the heap.
*/
- if ( pre_size < MIN_MEMBLOCK_SIZE )
+ if ( pre_size < MIN_MEMBLOCK_SIZE ) {
list_del ( &pre->list );
+ VALGRIND_MAKE_MEM_NOACCESS
+ ( pre, sizeof ( *pre ) );
+ }
/* Update total free memory */
- freemem -= size;
+ freemem -= actual_size;
/* Return allocated block */
DBGC2 ( &heap, "Allocated [%p,%p)\n", block,
( ( ( void * ) block ) + size ) );
ptr = block;
+ VALGRIND_MAKE_MEM_UNDEFINED ( ptr, size );
goto done;
}
}
@@ -368,13 +379,16 @@ void free_memblock ( void *ptr, size_t size ) {
struct memory_block *freeing;
struct memory_block *block;
struct memory_block *tmp;
+ size_t actual_size;
ssize_t gap_before;
ssize_t gap_after = -1;
/* Allow for ptr==NULL */
if ( ! ptr )
return;
+ VALGRIND_MAKE_MEM_NOACCESS ( ptr, size );
+ /* Sanity checks */
valgrind_make_blocks_defined();
check_blocks();
@@ -382,9 +396,10 @@ void free_memblock ( void *ptr, size_t size ) {
* would have used.
*/
assert ( size != 0 );
- size = ( size + MIN_MEMBLOCK_SIZE - 1 ) & ~( MIN_MEMBLOCK_SIZE - 1 );
+ actual_size = ( ( size + MIN_MEMBLOCK_SIZE - 1 ) &
+ ~( MIN_MEMBLOCK_SIZE - 1 ) );
freeing = ptr;
- VALGRIND_MAKE_MEM_DEFINED ( freeing, sizeof ( *freeing ) );
+ VALGRIND_MAKE_MEM_UNDEFINED ( freeing, sizeof ( *freeing ) );
DBGC2 ( &heap, "Freeing [%p,%p)\n",
freeing, ( ( ( void * ) freeing ) + size ) );
@@ -392,7 +407,7 @@ void free_memblock ( void *ptr, size_t size ) {
if ( ASSERTING ) {
list_for_each_entry ( block, &free_blocks, list ) {
if ( ( ( ( void * ) block ) <
- ( ( void * ) freeing + size ) ) &&
+ ( ( void * ) freeing + actual_size ) ) &&
( ( void * ) freeing <
( ( void * ) block + block->size ) ) ) {
assert ( 0 );
@@ -407,7 +422,7 @@ void free_memblock ( void *ptr, size_t size ) {
}
/* Insert/merge into free list */
- freeing->size = size;
+ freeing->size = actual_size;
list_for_each_entry_safe ( block, tmp, &free_blocks, list ) {
/* Calculate gaps before and after the "freeing" block */
gap_before = ( ( ( void * ) freeing ) -
@@ -421,8 +436,10 @@ void free_memblock ( void *ptr, size_t size ) {
( ( ( void * ) freeing ) + freeing->size ),
block,
( ( ( void * ) freeing ) + freeing->size ) );
- block->size += size;
+ block->size += actual_size;
list_del ( &block->list );
+ VALGRIND_MAKE_MEM_NOACCESS ( freeing,
+ sizeof ( *freeing ) );
freeing = block;
}
/* Stop processing as soon as we reach a following block */
@@ -444,10 +461,11 @@ void free_memblock ( void *ptr, size_t size ) {
( ( ( void * ) block ) + block->size ) );
freeing->size += block->size;
list_del ( &block->list );
+ VALGRIND_MAKE_MEM_NOACCESS ( block, sizeof ( *block ) );
}
/* Update free memory counter */
- freemem += size;
+ freemem += actual_size;
check_blocks();
valgrind_make_blocks_noaccess();
@@ -490,9 +508,9 @@ void * realloc ( void *old_ptr, size_t new_size ) {
new_block = alloc_memblock ( new_total_size, 1, 0 );
if ( ! new_block )
return NULL;
- VALGRIND_MAKE_MEM_UNDEFINED ( new_block, offsetof ( struct autosized_block, data ) );
new_block->size = new_total_size;
- VALGRIND_MAKE_MEM_NOACCESS ( new_block, offsetof ( struct autosized_block, data ) );
+ VALGRIND_MAKE_MEM_NOACCESS ( &new_block->size,
+ sizeof ( new_block->size ) );
new_ptr = &new_block->data;
VALGRIND_MALLOCLIKE_BLOCK ( new_ptr, new_size, 0, 0 );
}
@@ -505,16 +523,16 @@ void * realloc ( void *old_ptr, size_t new_size ) {
if ( old_ptr && ( old_ptr != NOWHERE ) ) {
old_block = container_of ( old_ptr, struct autosized_block,
data );
- VALGRIND_MAKE_MEM_DEFINED ( old_block, offsetof ( struct autosized_block, data ) );
+ VALGRIND_MAKE_MEM_DEFINED ( &old_block->size,
+ sizeof ( old_block->size ) );
old_total_size = old_block->size;
assert ( old_total_size != 0 );
old_size = ( old_total_size -
offsetof ( struct autosized_block, data ) );
memcpy ( new_ptr, old_ptr,
( ( old_size < new_size ) ? old_size : new_size ) );
- free_memblock ( old_block, old_total_size );
- VALGRIND_MAKE_MEM_NOACCESS ( old_block, offsetof ( struct autosized_block, data ) );
VALGRIND_FREELIKE_BLOCK ( old_ptr, 0 );
+ free_memblock ( old_block, old_total_size );
}
if ( ASSERTED ) {
@@ -611,6 +629,7 @@ void mpopulate ( void *start, size_t len ) {
*/
static void init_heap ( void ) {
VALGRIND_MAKE_MEM_NOACCESS ( heap, sizeof ( heap ) );
+ VALGRIND_MAKE_MEM_NOACCESS ( &free_blocks, sizeof ( free_blocks ) );
mpopulate ( heap, sizeof ( heap ) );
}
diff --git a/roms/ipxe/src/core/memblock.c b/roms/ipxe/src/core/memblock.c
index 1fd89b871..aecddc22c 100644
--- a/roms/ipxe/src/core/memblock.c
+++ b/roms/ipxe/src/core/memblock.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/core/memmap_settings.c b/roms/ipxe/src/core/memmap_settings.c
index 0f6d0abf5..fab3e5f3a 100644
--- a/roms/ipxe/src/core/memmap_settings.c
+++ b/roms/ipxe/src/core/memmap_settings.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <errno.h>
diff --git a/roms/ipxe/src/core/menu.c b/roms/ipxe/src/core/menu.c
index 8d42e1f83..ab5b0c7f5 100644
--- a/roms/ipxe/src/core/menu.c
+++ b/roms/ipxe/src/core/menu.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/core/misc.c b/roms/ipxe/src/core/misc.c
deleted file mode 100644
index eaceddfea..000000000
--- a/roms/ipxe/src/core/misc.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/**************************************************************************
-MISC Support Routines
-**************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#include <stdlib.h>
-#include <ctype.h>
-#include <byteswap.h>
-#include <ipxe/in.h>
-#include <ipxe/timer.h>
-
-/**************************************************************************
-INET_ATON - Convert an ascii x.x.x.x to binary form
-**************************************************************************/
-int inet_aton ( const char *cp, struct in_addr *inp ) {
- const char *p = cp;
- const char *digits_start;
- unsigned long ip = 0;
- unsigned long val;
- int j;
- for(j = 0; j <= 3; j++) {
- digits_start = p;
- val = strtoul(p, ( char ** ) &p, 10);
- if ((p == digits_start) || (val > 255)) return 0;
- if ( ( j < 3 ) && ( *(p++) != '.' ) ) return 0;
- ip = (ip << 8) | val;
- }
- if ( *p == '\0' ) {
- inp->s_addr = htonl(ip);
- return 1;
- }
- return 0;
-}
-
-unsigned int strtoul_charval ( unsigned int charval ) {
-
- if ( charval >= 'a' ) {
- charval = ( charval - 'a' + 10 );
- } else if ( charval >= 'A' ) {
- charval = ( charval - 'A' + 10 );
- } else if ( charval <= '9' ) {
- charval = ( charval - '0' );
- }
-
- return charval;
-}
-
-unsigned long strtoul ( const char *p, char **endp, int base ) {
- unsigned long ret = 0;
- int negative = 0;
- unsigned int charval;
-
- while ( isspace ( *p ) )
- p++;
-
- if ( *p == '-' ) {
- negative = 1;
- p++;
- }
-
- base = strtoul_base ( &p, base );
-
- while ( 1 ) {
- charval = strtoul_charval ( *p );
- if ( charval >= ( unsigned int ) base )
- break;
- ret = ( ( ret * base ) + charval );
- p++;
- }
-
- if ( negative )
- ret = -ret;
-
- if ( endp )
- *endp = ( char * ) p;
-
- return ( ret );
-}
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/roms/ipxe/src/core/monojob.c b/roms/ipxe/src/core/monojob.c
index 820fa31dc..817f21b2c 100644
--- a/roms/ipxe/src/core/monojob.c
+++ b/roms/ipxe/src/core/monojob.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <stdio.h>
diff --git a/roms/ipxe/src/core/null_reboot.c b/roms/ipxe/src/core/null_reboot.c
index a3d5b2ef8..7be5612a3 100644
--- a/roms/ipxe/src/core/null_reboot.c
+++ b/roms/ipxe/src/core/null_reboot.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @file
diff --git a/roms/ipxe/src/core/null_sanboot.c b/roms/ipxe/src/core/null_sanboot.c
index 18c0dea84..2f7522c6c 100644
--- a/roms/ipxe/src/core/null_sanboot.c
+++ b/roms/ipxe/src/core/null_sanboot.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <errno.h>
#include <ipxe/sanboot.h>
diff --git a/roms/ipxe/src/core/null_time.c b/roms/ipxe/src/core/null_time.c
index 506c70b52..90041a456 100644
--- a/roms/ipxe/src/core/null_time.c
+++ b/roms/ipxe/src/core/null_time.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/core/nvo.c b/roms/ipxe/src/core/nvo.c
index e135d2b41..d2c9b5e73 100644
--- a/roms/ipxe/src/core/nvo.c
+++ b/roms/ipxe/src/core/nvo.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/core/open.c b/roms/ipxe/src/core/open.c
index b479c2975..9d665ffda 100644
--- a/roms/ipxe/src/core/open.c
+++ b/roms/ipxe/src/core/open.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdarg.h>
#include <string.h>
diff --git a/roms/ipxe/src/core/params.c b/roms/ipxe/src/core/params.c
index 93b834419..e1f66acca 100644
--- a/roms/ipxe/src/core/params.c
+++ b/roms/ipxe/src/core/params.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/core/parseopt.c b/roms/ipxe/src/core/parseopt.c
index d268c0594..66f60158c 100644
--- a/roms/ipxe/src/core/parseopt.c
+++ b/roms/ipxe/src/core/parseopt.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <stdint.h>
@@ -32,6 +36,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/params.h>
#include <ipxe/timer.h>
#include <ipxe/parseopt.h>
+#include <config/branding.h>
/** @file
*
@@ -343,7 +348,7 @@ void print_usage ( struct command_descriptor *cmd, char **argv ) {
}
if ( cmd->usage )
printf ( " %s", cmd->usage );
- printf ( "\n\nSee http://ipxe.org/cmd/%s for further information\n",
+ printf ( "\n\nSee " PRODUCT_COMMAND_URI " for further information\n",
argv[0] );
}
diff --git a/roms/ipxe/src/core/pending.c b/roms/ipxe/src/core/pending.c
index 7bb0c2e00..96d0cf197 100644
--- a/roms/ipxe/src/core/pending.c
+++ b/roms/ipxe/src/core/pending.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <errno.h>
#include <ipxe/process.h>
diff --git a/roms/ipxe/src/core/pinger.c b/roms/ipxe/src/core/pinger.c
index 31ea2ce1c..0ff7bb9f2 100644
--- a/roms/ipxe/src/core/pinger.c
+++ b/roms/ipxe/src/core/pinger.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdlib.h>
#include <string.h>
diff --git a/roms/ipxe/src/core/pixbuf.c b/roms/ipxe/src/core/pixbuf.c
index 48f8e9f9a..41e18f8dc 100644
--- a/roms/ipxe/src/core/pixbuf.c
+++ b/roms/ipxe/src/core/pixbuf.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/core/pool.c b/roms/ipxe/src/core/pool.c
new file mode 100644
index 000000000..0163405f7
--- /dev/null
+++ b/roms/ipxe/src/core/pool.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/**
+ * @file
+ *
+ * Pooled connections
+ *
+ */
+
+#include <assert.h>
+#include <ipxe/pool.h>
+
+/**
+ * Recycle this connection after closing
+ *
+ * @v intf Data transfer interface
+ */
+void pool_recycle ( struct interface *intf ) {
+
+ intf_poke ( intf, pool_recycle );
+}
+
+/**
+ * Reopen a defunct connection
+ *
+ * @v intf Data transfer interface
+ */
+void pool_reopen ( struct interface *intf ) {
+
+ intf_poke ( intf, pool_reopen );
+}
+
+/**
+ * Add connection to pool
+ *
+ * @v pool Pooled connection
+ * @v list List of pooled connections
+ * @v expiry Expiry time
+ */
+void pool_add ( struct pooled_connection *pool, struct list_head *list,
+ unsigned long expiry ) {
+
+ /* Sanity check */
+ assert ( list_empty ( &pool->list ) );
+ assert ( ! timer_running ( &pool->timer ) );
+
+ /* Add to list of pooled connections */
+ list_add_tail ( &pool->list, list );
+
+ /* Start expiry timer */
+ start_timer_fixed ( &pool->timer, expiry );
+}
+
+/**
+ * Remove connection from pool
+ *
+ * @v pool Pooled connection
+ */
+void pool_del ( struct pooled_connection *pool ) {
+
+ /* Remove from list of pooled connections */
+ list_del ( &pool->list );
+ INIT_LIST_HEAD ( &pool->list );
+
+ /* Stop expiry timer */
+ stop_timer ( &pool->timer );
+
+ /* Mark as a freshly recycled connection */
+ pool->flags = POOL_RECYCLED;
+}
+
+/**
+ * Close expired pooled connection
+ *
+ * @v timer Expiry timer
+ * @v over Failure indicator
+ */
+void pool_expired ( struct retry_timer *timer, int over __unused ) {
+ struct pooled_connection *pool =
+ container_of ( timer, struct pooled_connection, timer );
+
+ /* Sanity check */
+ assert ( ! list_empty ( &pool->list ) );
+
+ /* Remove from connection pool */
+ list_del ( &pool->list );
+ INIT_LIST_HEAD ( &pool->list );
+
+ /* Close expired connection */
+ pool->expired ( pool );
+}
diff --git a/roms/ipxe/src/core/posix_io.c b/roms/ipxe/src/core/posix_io.c
index 8460d0f51..35b52beeb 100644
--- a/roms/ipxe/src/core/posix_io.c
+++ b/roms/ipxe/src/core/posix_io.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdlib.h>
#include <string.h>
diff --git a/roms/ipxe/src/core/process.c b/roms/ipxe/src/core/process.c
index d341a2c37..69852c416 100644
--- a/roms/ipxe/src/core/process.c
+++ b/roms/ipxe/src/core/process.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/list.h>
#include <ipxe/init.h>
diff --git a/roms/ipxe/src/core/profile.c b/roms/ipxe/src/core/profile.c
index 150e6b273..1075047b9 100644
--- a/roms/ipxe/src/core/profile.c
+++ b/roms/ipxe/src/core/profile.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdio.h>
diff --git a/roms/ipxe/src/core/random.c b/roms/ipxe/src/core/random.c
index 8824dca3a..a74175a79 100644
--- a/roms/ipxe/src/core/random.c
+++ b/roms/ipxe/src/core/random.c
@@ -4,7 +4,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdlib.h>
#include <ipxe/timer.h>
diff --git a/roms/ipxe/src/core/refcnt.c b/roms/ipxe/src/core/refcnt.c
index 68a86120e..47c975a0b 100644
--- a/roms/ipxe/src/core/refcnt.c
+++ b/roms/ipxe/src/core/refcnt.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdlib.h>
#include <ipxe/refcnt.h>
diff --git a/roms/ipxe/src/core/resolv.c b/roms/ipxe/src/core/resolv.c
index d59a8c0ad..1e3182b0b 100644
--- a/roms/ipxe/src/core/resolv.c
+++ b/roms/ipxe/src/core/resolv.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/core/serial.c b/roms/ipxe/src/core/serial.c
index 7e4460ab9..4ce025519 100644
--- a/roms/ipxe/src/core/serial.c
+++ b/roms/ipxe/src/core/serial.c
@@ -1,259 +1,184 @@
/*
- * The serial port interface routines implement a simple polled i/o
- * interface to a standard serial port. Due to the space restrictions
- * for the boot blocks, no BIOS support is used (since BIOS requires
- * expensive real/protected mode switches), instead the rudimentary
- * BIOS support is duplicated here.
+ * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
*
- * The base address and speed for the i/o port are passed from the
- * Makefile in the COMCONSOLE and CONSPEED preprocessor macros. The
- * line control parameters are currently hard-coded to 8 bits, no
- * parity, 1 stop bit (8N1). This can be changed in init_serial().
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/** @file
+ *
+ * Serial console
+ *
+ */
-#include "stddef.h"
+#include <stddef.h>
#include <ipxe/init.h>
-#include <ipxe/io.h>
-#include <unistd.h>
+#include <ipxe/uart.h>
+#include <ipxe/console.h>
#include <ipxe/serial.h>
-#include "config/serial.h"
-
-/* Set default values if none specified */
+#include <config/console.h>
+#include <config/serial.h>
-#ifndef COMCONSOLE
-#define COMCONSOLE 0x3f8
+/* Set default console usage if applicable */
+#if ! ( defined ( CONSOLE_SERIAL ) && CONSOLE_EXPLICIT ( CONSOLE_SERIAL ) )
+#undef CONSOLE_SERIAL
+#define CONSOLE_SERIAL ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_LOG )
#endif
-#ifndef COMSPEED
-#define COMSPEED 9600
-#endif
-
-#ifndef COMDATA
-#define COMDATA 8
+/* UART port number */
+#ifdef COMCONSOLE
+#define CONSOLE_PORT COMCONSOLE
+#else
+#define CONSOLE_PORT 0
#endif
-#ifndef COMPARITY
-#define COMPARITY 0
+/* UART baud rate */
+#ifdef COMPRESERVE
+#define CONSOLE_BAUD 0
+#else
+#define CONSOLE_BAUD COMSPEED
#endif
-#ifndef COMSTOP
-#define COMSTOP 1
+/* UART line control register value */
+#ifdef COMPRESERVE
+#define CONSOLE_LCR 0
+#else
+#define CONSOLE_LCR UART_LCR_WPS ( COMDATA, COMPARITY, COMSTOP )
#endif
-#undef UART_BASE
-#define UART_BASE ( COMCONSOLE )
-
-#undef UART_BAUD
-#define UART_BAUD ( COMSPEED )
+/** Serial console UART */
+struct uart serial_console;
-#if ((115200%UART_BAUD) != 0)
-#error Bad ttys0 baud rate
-#endif
-
-#define COMBRD (115200/UART_BAUD)
+/**
+ * Print a character to serial console
+ *
+ * @v character Character to be printed
+ */
+static void serial_putchar ( int character ) {
-/* Line Control Settings */
-#define UART_LCS ( ( ( (COMDATA) - 5 ) << 0 ) | \
- ( ( (COMPARITY) ) << 3 ) | \
- ( ( (COMSTOP) - 1 ) << 2 ) )
+ /* Do nothing if we have no UART */
+ if ( ! serial_console.base )
+ return;
-/* Data */
-#define UART_RBR 0x00
-#define UART_TBR 0x00
+ /* Transmit character */
+ uart_transmit ( &serial_console, character );
+}
-/* Control */
-#define UART_IER 0x01
-#define UART_IIR 0x02
-#define UART_FCR 0x02
-#define UART_LCR 0x03
-#define UART_MCR 0x04
-#define UART_DLL 0x00
-#define UART_DLM 0x01
+/**
+ * Get character from serial console
+ *
+ * @ret character Character read from console
+ */
+static int serial_getchar ( void ) {
+ uint8_t data;
-/* Status */
-#define UART_LSR 0x05
-#define UART_LSR_TEMPT 0x40 /* Transmitter empty */
-#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
-#define UART_LSR_BI 0x10 /* Break interrupt indicator */
-#define UART_LSR_FE 0x08 /* Frame error indicator */
-#define UART_LSR_PE 0x04 /* Parity error indicator */
-#define UART_LSR_OE 0x02 /* Overrun error indicator */
-#define UART_LSR_DR 0x01 /* Receiver data ready */
+ /* Do nothing if we have no UART */
+ if ( ! serial_console.base )
+ return 0;
-#define UART_MSR 0x06
-#define UART_SCR 0x07
+ /* Wait for data to be ready */
+ while ( ! uart_data_ready ( &serial_console ) ) {}
-#if defined(UART_MEM)
-#define uart_readb(addr) readb((addr))
-#define uart_writeb(val,addr) writeb((val),(addr))
-#else
-#define uart_readb(addr) inb((addr))
-#define uart_writeb(val,addr) outb((val),(addr))
-#endif
+ /* Receive data */
+ data = uart_receive ( &serial_console );
-/* Boolean for the state of serial driver initialization */
-int serial_initialized = 0;
+ /* Strip any high bit and convert DEL to backspace */
+ data &= 0x7f;
+ if ( data == 0x7f )
+ data = 0x08;
-/*
- * void serial_putc(int ch);
- * Write character `ch' to port UART_BASE.
- */
-void serial_putc ( int ch ) {
- int i;
- int status;
- i = 1000; /* timeout */
- while(--i > 0) {
- status = uart_readb(UART_BASE + UART_LSR);
- if (status & UART_LSR_THRE) {
- /* TX buffer emtpy */
- uart_writeb(ch, UART_BASE + UART_TBR);
- break;
- }
- mdelay(2);
- }
+ return data;
}
-/*
- * int serial_getc(void);
- * Read a character from port UART_BASE.
- */
-int serial_getc ( void ) {
- int status;
- int ch;
- do {
- status = uart_readb(UART_BASE + UART_LSR);
- } while((status & 1) == 0);
- ch = uart_readb(UART_BASE + UART_RBR); /* fetch (first) character */
- ch &= 0x7f; /* remove any parity bits we get */
- if (ch == 0x7f) { /* Make DEL... look like BS */
- ch = 0x08;
- }
- return ch;
-}
-
-/*
- * int serial_ischar(void);
- * If there is a character in the input buffer of port UART_BASE,
- * return nonzero; otherwise return 0.
+/**
+ * Check for character ready to read from serial console
+ *
+ * @ret True Character available to read
+ * @ret False No character available to read
*/
-int serial_ischar ( void ) {
- int status;
- status = uart_readb(UART_BASE + UART_LSR); /* line status reg; */
- return status & 1; /* rx char available */
-}
+static int serial_iskey ( void ) {
-/*
- * int serial_init(void);
- * Initialize port UART_BASE to speed COMSPEED, line settings 8N1.
- */
-static void serial_init ( void ) {
- int status;
- int divisor, lcs;
+ /* Do nothing if we have no UART */
+ if ( ! serial_console.base )
+ return 0;
- DBG ( "Serial port %#x initialising\n", UART_BASE );
+ /* Check UART */
+ return uart_data_ready ( &serial_console );
+}
- divisor = COMBRD;
- lcs = UART_LCS;
+/** Serial console */
+struct console_driver serial_console_driver __console_driver = {
+ .putchar = serial_putchar,
+ .getchar = serial_getchar,
+ .iskey = serial_iskey,
+ .usage = CONSOLE_SERIAL,
+};
+/** Initialise serial console */
+static void serial_init ( void ) {
+ int rc;
-#ifdef COMPRESERVE
- lcs = uart_readb(UART_BASE + UART_LCR) & 0x7f;
- uart_writeb(0x80 | lcs, UART_BASE + UART_LCR);
- divisor = (uart_readb(UART_BASE + UART_DLM) << 8) | uart_readb(UART_BASE + UART_DLL);
- uart_writeb(lcs, UART_BASE + UART_LCR);
-#endif
+ /* Do nothing if we have no default port */
+ if ( ! CONSOLE_PORT )
+ return;
- /* Set Baud Rate Divisor to COMSPEED, and test to see if the
- * serial port appears to be present.
- */
- uart_writeb(0x80 | lcs, UART_BASE + UART_LCR);
- uart_writeb(0xaa, UART_BASE + UART_DLL);
- if (uart_readb(UART_BASE + UART_DLL) != 0xaa) {
- DBG ( "Serial port %#x UART_DLL failed\n", UART_BASE );
- goto out;
- }
- uart_writeb(0x55, UART_BASE + UART_DLL);
- if (uart_readb(UART_BASE + UART_DLL) != 0x55) {
- DBG ( "Serial port %#x UART_DLL failed\n", UART_BASE );
- goto out;
+ /* Select UART */
+ if ( ( rc = uart_select ( &serial_console, CONSOLE_PORT ) ) != 0 ) {
+ DBG ( "Could not select UART %d: %s\n",
+ CONSOLE_PORT, strerror ( rc ) );
+ return;
}
- uart_writeb(divisor & 0xff, UART_BASE + UART_DLL);
- if (uart_readb(UART_BASE + UART_DLL) != (divisor & 0xff)) {
- DBG ( "Serial port %#x UART_DLL failed\n", UART_BASE );
- goto out;
- }
- uart_writeb(0xaa, UART_BASE + UART_DLM);
- if (uart_readb(UART_BASE + UART_DLM) != 0xaa) {
- DBG ( "Serial port %#x UART_DLM failed\n", UART_BASE );
- goto out;
- }
- uart_writeb(0x55, UART_BASE + UART_DLM);
- if (uart_readb(UART_BASE + UART_DLM) != 0x55) {
- DBG ( "Serial port %#x UART_DLM failed\n", UART_BASE );
- goto out;
- }
- uart_writeb((divisor >> 8) & 0xff, UART_BASE + UART_DLM);
- if (uart_readb(UART_BASE + UART_DLM) != ((divisor >> 8) & 0xff)) {
- DBG ( "Serial port %#x UART_DLM failed\n", UART_BASE );
- goto out;
- }
- uart_writeb(lcs, UART_BASE + UART_LCR);
-
- /* disable interrupts */
- uart_writeb(0x0, UART_BASE + UART_IER);
- /* enable fifos */
- uart_writeb(0x01, UART_BASE + UART_FCR);
+ /* Initialise UART */
+ if ( ( rc = uart_init ( &serial_console, CONSOLE_BAUD,
+ CONSOLE_LCR ) ) != 0 ) {
+ DBG ( "Could not initialise UART %d baud %d LCR %#02x: %s\n",
+ CONSOLE_PORT, CONSOLE_BAUD, CONSOLE_LCR, strerror ( rc ));
+ return;
+ }
+}
- /* Set clear to send, so flow control works... */
- uart_writeb((1<<1), UART_BASE + UART_MCR);
+/**
+ * Shut down serial console
+ *
+ * @v flags Shutdown flags
+ */
+static void serial_shutdown ( int flags __unused ) {
- /* Flush the input buffer. */
- do {
- /* rx buffer reg
- * throw away (unconditionally the first time)
- */
- (void) uart_readb(UART_BASE + UART_RBR);
- /* line status reg */
- status = uart_readb(UART_BASE + UART_LSR);
- } while(status & UART_LSR_DR);
+ /* Do nothing if we have no UART */
+ if ( ! serial_console.base )
+ return;
- /* Note that serial support has been initialized */
- serial_initialized = 1;
- out:
- return;
-}
+ /* Flush any pending output */
+ uart_flush ( &serial_console );
-/*
- * void serial_fini(void);
- * Cleanup our use of the serial port, in particular flush the
- * output buffer so we don't accidentially lose characters.
- */
-static void serial_fini ( int flags __unused ) {
- int i, status;
- /* Flush the output buffer to avoid dropping characters,
- * if we are reinitializing the serial port.
- */
- i = 10000; /* timeout */
- do {
- status = uart_readb(UART_BASE + UART_LSR);
- } while((--i > 0) && !(status & UART_LSR_TEMPT));
- /* Don't mark it as disabled; it's still usable */
+ /* Leave console enabled; it's still usable */
}
-/**
- * Serial driver initialisation function
- *
- * Initialise serial port early on so that it is available to capture
- * early debug messages.
- */
-struct init_fn serial_init_fn __init_fn ( INIT_SERIAL ) = {
+/** Serial console initialisation function */
+struct init_fn serial_console_init_fn __init_fn ( INIT_CONSOLE ) = {
.initialise = serial_init,
};
-/** Serial driver startup function */
+/** Serial console startup function */
struct startup_fn serial_startup_fn __startup_fn ( STARTUP_EARLY ) = {
- .shutdown = serial_fini,
+ .shutdown = serial_shutdown,
};
diff --git a/roms/ipxe/src/core/serial_console.c b/roms/ipxe/src/core/serial_console.c
deleted file mode 100644
index de9b84ca7..000000000
--- a/roms/ipxe/src/core/serial_console.c
+++ /dev/null
@@ -1,42 +0,0 @@
-#include <ipxe/init.h>
-#include <ipxe/serial.h>
-#include <ipxe/console.h>
-#include <config/console.h>
-
-/** @file
- *
- * Serial console
- *
- */
-
-/* Set default console usage if applicable */
-#if ! ( defined ( CONSOLE_SERIAL ) && CONSOLE_EXPLICIT ( CONSOLE_SERIAL ) )
-#undef CONSOLE_SERIAL
-#define CONSOLE_SERIAL ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_LOG )
-#endif
-
-struct console_driver serial_console __console_driver;
-
-static void serial_console_init ( void ) {
- /*
- * Check if serial driver initialization is done.
- * If so, it's time to enable the serial console.
- */
- if ( serial_initialized )
- serial_console.disabled = 0;
-}
-
-struct console_driver serial_console __console_driver = {
- .putchar = serial_putc,
- .getchar = serial_getc,
- .iskey = serial_ischar,
- .disabled = CONSOLE_DISABLED,
- .usage = CONSOLE_SERIAL,
-};
-
-/**
- * Serial console initialisation function
- */
-struct init_fn serial_console_init_fn __init_fn ( INIT_CONSOLE ) = {
- .initialise = serial_console_init,
-};
diff --git a/roms/ipxe/src/core/settings.c b/roms/ipxe/src/core/settings.c
index 5e16b27d0..12e6c7d61 100644
--- a/roms/ipxe/src/core/settings.c
+++ b/roms/ipxe/src/core/settings.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
@@ -35,6 +39,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/uuid.h>
#include <ipxe/uri.h>
#include <ipxe/base16.h>
+#include <ipxe/base64.h>
#include <ipxe/pci.h>
#include <ipxe/init.h>
#include <ipxe/version.h>
@@ -337,17 +342,20 @@ struct settings * autovivify_child_settings ( struct settings *parent,
*/
const char * settings_name ( struct settings *settings ) {
static char buf[16];
- char tmp[ sizeof ( buf ) ];
+ char tmp[ 1 /* '.' */ + sizeof ( buf ) ];
/* Find target settings block */
settings = settings_target ( settings );
/* Construct name */
- for ( buf[2] = buf[0] = 0 ; settings ; settings = settings->parent ) {
- memcpy ( tmp, buf, sizeof ( tmp ) );
- snprintf ( buf, sizeof ( buf ), ".%s%s", settings->name, tmp );
+ buf[0] = '\0';
+ tmp[0] = '\0';
+ for ( ; settings->parent ; settings = settings->parent ) {
+ memcpy ( ( tmp + 1 ), buf, ( sizeof ( tmp ) - 1 ) );
+ snprintf ( buf, sizeof ( buf ), "%s%s", settings->name, tmp );
+ tmp[0] = '.';
}
- return ( buf + 2 );
+ return buf;
}
/**
@@ -499,10 +507,10 @@ int register_settings ( struct settings *settings, struct settings *parent,
*/
void unregister_settings ( struct settings *settings ) {
struct settings *child;
- struct settings *tmp;
/* Unregister child settings */
- list_for_each_entry_safe ( child, tmp, &settings->children, siblings ) {
+ while ( ( child = list_first_entry ( &settings->children,
+ struct settings, siblings ) ) ) {
unregister_settings ( child );
}
@@ -1999,32 +2007,6 @@ const struct setting_type setting_type_uint32 __setting_type =
SETTING_TYPE_UINT ( SETTING_TYPE_INT32 );
/**
- * Format hex string setting value
- *
- * @v delimiter Byte delimiter
- * @v raw Raw setting value
- * @v raw_len Length of raw setting value
- * @v buf Buffer to contain formatted value
- * @v len Length of buffer
- * @ret len Length of formatted value, or negative error
- */
-static int format_hex_setting ( const char *delimiter, const void *raw,
- size_t raw_len, char *buf, size_t len ) {
- const uint8_t *bytes = raw;
- int used = 0;
- unsigned int i;
-
- if ( len )
- buf[0] = 0; /* Ensure that a terminating NUL exists */
- for ( i = 0 ; i < raw_len ; i++ ) {
- used += ssnprintf ( ( buf + used ), ( len - used ),
- "%s%02x", ( used ? delimiter : "" ),
- bytes[i] );
- }
- return used;
-}
-
-/**
* Parse hex string setting value (using colon delimiter)
*
* @v type Setting type
@@ -2036,7 +2018,7 @@ static int format_hex_setting ( const char *delimiter, const void *raw,
*/
static int parse_hex_setting ( const struct setting_type *type __unused,
const char *value, void *buf, size_t len ) {
- return hex_decode ( value, ':', buf, len );
+ return hex_decode ( ':', value, buf, len );
}
/**
@@ -2052,7 +2034,7 @@ static int parse_hex_setting ( const struct setting_type *type __unused,
static int format_hex_colon_setting ( const struct setting_type *type __unused,
const void *raw, size_t raw_len,
char *buf, size_t len ) {
- return format_hex_setting ( ":", raw, raw_len, buf, len );
+ return hex_encode ( ':', raw, raw_len, buf, len );
}
/**
@@ -2068,7 +2050,7 @@ static int format_hex_colon_setting ( const struct setting_type *type __unused,
static int parse_hex_hyphen_setting ( const struct setting_type *type __unused,
const char *value, void *buf,
size_t len ) {
- return hex_decode ( value, '-', buf, len );
+ return hex_decode ( '-', value, buf, len );
}
/**
@@ -2084,7 +2066,7 @@ static int parse_hex_hyphen_setting ( const struct setting_type *type __unused,
static int format_hex_hyphen_setting ( const struct setting_type *type __unused,
const void *raw, size_t raw_len,
char *buf, size_t len ) {
- return format_hex_setting ( "-", raw, raw_len, buf, len );
+ return hex_encode ( '-', raw, raw_len, buf, len );
}
/**
@@ -2099,7 +2081,7 @@ static int format_hex_hyphen_setting ( const struct setting_type *type __unused,
*/
static int parse_hex_raw_setting ( const struct setting_type *type __unused,
const char *value, void *buf, size_t len ) {
- return hex_decode ( value, 0, buf, len );
+ return hex_decode ( 0, value, buf, len );
}
/**
@@ -2115,7 +2097,7 @@ static int parse_hex_raw_setting ( const struct setting_type *type __unused,
static int format_hex_raw_setting ( const struct setting_type *type __unused,
const void *raw, size_t raw_len,
char *buf, size_t len ) {
- return format_hex_setting ( "", raw, raw_len, buf, len );
+ return hex_encode ( 0, raw, raw_len, buf, len );
}
/** A hex-string setting (colon-delimited) */
@@ -2140,6 +2122,46 @@ const struct setting_type setting_type_hexraw __setting_type = {
};
/**
+ * Parse Base64-encoded setting value
+ *
+ * @v type Setting type
+ * @v value Formatted setting value
+ * @v buf Buffer to contain raw value
+ * @v len Length of buffer
+ * @v size Integer size, in bytes
+ * @ret len Length of raw value, or negative error
+ */
+static int parse_base64_setting ( const struct setting_type *type __unused,
+ const char *value, void *buf, size_t len ) {
+
+ return base64_decode ( value, buf, len );
+}
+
+/**
+ * Format Base64-encoded setting value
+ *
+ * @v type Setting type
+ * @v raw Raw setting value
+ * @v raw_len Length of raw setting value
+ * @v buf Buffer to contain formatted value
+ * @v len Length of buffer
+ * @ret len Length of formatted value, or negative error
+ */
+static int format_base64_setting ( const struct setting_type *type __unused,
+ const void *raw, size_t raw_len,
+ char *buf, size_t len ) {
+
+ return base64_encode ( raw, raw_len, buf, len );
+}
+
+/** A Base64-encoded setting */
+const struct setting_type setting_type_base64 __setting_type = {
+ .name = "base64",
+ .parse = parse_base64_setting,
+ .format = format_base64_setting,
+};
+
+/**
* Format UUID setting value
*
* @v type Setting type
diff --git a/roms/ipxe/src/core/string.c b/roms/ipxe/src/core/string.c
index e53c283c2..3e658e54e 100644
--- a/roms/ipxe/src/core/string.c
+++ b/roms/ipxe/src/core/string.c
@@ -1,353 +1,501 @@
/*
- * Copyright (C) 1991, 1992 Linus Torvalds
- * Copyright (C) 2004 Tobias Lorenz
+ * Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
*
- * string handling functions
- * based on linux/lib/string.c
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-FILE_LICENCE ( GPL2_ONLY );
-
-/*
- * stupid library routines.. The optimized versions should generally be found
- * as inline code in <asm-xx/string.h>
+ * 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.
*
- * These are buggy as well..
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
*
- * * Fri Jun 25 1999, Ingo Oeser <ioe@informatik.tu-chemnitz.de>
- * - Added strsep() which will replace strtok() soon (because strsep() is
- * reentrant and should be faster). Use only strsep() in new code, please.
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
-/* *** FROM string.c *** */
+/** @file
+ *
+ * String functions
+ *
+ */
-#ifndef __HAVE_ARCH_STRCPY
/**
- * strcpy - Copy a %NUL terminated string
- * @dest: Where to copy the string to
- * @src: Where to copy the string from
+ * Fill memory region
+ *
+ * @v dest Destination region
+ * @v character Fill character
+ * @v len Length
+ * @ret dest Destination region
*/
-char * strcpy(char * dest,const char *src)
-{
- char *tmp = dest;
+void * generic_memset ( void *dest, int character, size_t len ) {
+ uint8_t *dest_bytes = dest;
- while ((*dest++ = *src++) != '\0')
- /* nothing */;
- return tmp;
+ while ( len-- )
+ *(dest_bytes++) = character;
+ return dest;
}
-#endif
-#ifndef __HAVE_ARCH_STRNCPY
/**
- * strncpy - Copy a length-limited, %NUL-terminated string
- * @dest: Where to copy the string to
- * @src: Where to copy the string from
- * @count: The maximum number of bytes to copy
+ * Copy memory region
*
- * Note that unlike userspace strncpy, this does not %NUL-pad the buffer.
- * However, the result is not %NUL-terminated if the source exceeds
- * @count bytes.
+ * @v dest Destination region
+ * @v src Source region
+ * @v len Length
+ * @ret dest Destination region
*/
-char * strncpy(char * dest,const char *src,size_t count)
-{
- char *tmp = dest;
-
- while (count-- && (*dest++ = *src++) != '\0')
- /* nothing */;
+void * generic_memcpy ( void *dest, const void *src, size_t len ) {
+ const uint8_t *src_bytes = src;
+ uint8_t *dest_bytes = dest;
- return tmp;
+ while ( len-- )
+ *(dest_bytes++) = *(src_bytes++);
+ return dest;
}
-#endif
-#ifndef __HAVE_ARCH_STRCAT
/**
- * strcat - Append one %NUL-terminated string to another
- * @dest: The string to be appended to
- * @src: The string to append to it
+ * Copy (possibly overlapping) memory region
+ *
+ * @v dest Destination region
+ * @v src Source region
+ * @v len Length
+ * @ret dest Destination region
*/
-char * strcat(char * dest, const char * src)
-{
- char *tmp = dest;
-
- while (*dest)
- dest++;
- while ((*dest++ = *src++) != '\0')
- ;
+void * generic_memmove ( void *dest, const void *src, size_t len ) {
+ const uint8_t *src_bytes = ( src + len );
+ uint8_t *dest_bytes = ( dest + len );
+
+ if ( dest < src )
+ return memcpy ( dest, src, len );
+ while ( len-- )
+ *(--dest_bytes) = *(--src_bytes);
+ return dest;
+}
- return tmp;
+/**
+ * Compare memory regions
+ *
+ * @v first First region
+ * @v second Second region
+ * @v len Length
+ * @ret diff Difference
+ */
+int memcmp ( const void *first, const void *second, size_t len ) {
+ const uint8_t *first_bytes = first;
+ const uint8_t *second_bytes = second;
+ int diff;
+
+ while ( len-- ) {
+ diff = ( *(second_bytes++) - *(first_bytes++) );
+ if ( diff )
+ return diff;
+ }
+ return 0;
}
-#endif
-#ifndef __HAVE_ARCH_STRCMP
/**
- * strcmp - Compare two strings
- * @cs: One string
- * @ct: Another string
+ * Find character within a memory region
+ *
+ * @v src Source region
+ * @v character Character to find
+ * @v len Length
+ * @ret found Found character, or NULL if not found
*/
-int strcmp(const char * cs,const char * ct)
-{
- register signed char __res;
+void * memchr ( const void *src, int character, size_t len ) {
+ const uint8_t *src_bytes = src;
- while (1) {
- if ((__res = *cs - *ct++) != 0 || !*cs++)
- break;
+ for ( ; len-- ; src_bytes++ ) {
+ if ( *src_bytes == character )
+ return ( ( void * ) src_bytes );
}
-
- return __res;
+ return NULL;
}
-#endif
-#ifndef __HAVE_ARCH_STRNCMP
/**
- * strncmp - Compare two length-limited strings
- * @cs: One string
- * @ct: Another string
- * @count: The maximum number of bytes to compare
+ * Swap memory regions
+ *
+ * @v first First region
+ * @v second Second region
+ * @v len Length
+ * @ret first First region
*/
-int strncmp(const char * cs,const char * ct,size_t count)
-{
- register signed char __res = 0;
-
- while (count) {
- if ((__res = *cs - *ct++) != 0 || !*cs++)
- break;
- count--;
+void * memswap ( void *first, void *second, size_t len ) {
+ uint8_t *first_bytes = first;
+ uint8_t *second_bytes = second;
+ uint8_t temp;
+
+ for ( ; len-- ; first_bytes++, second_bytes++ ) {
+ temp = *first_bytes;
+ *first_bytes = *second_bytes;
+ *second_bytes = temp;
}
+ return first;
+}
+
+/**
+ * Compare strings
+ *
+ * @v first First string
+ * @v second Second string
+ * @ret diff Difference
+ */
+int strcmp ( const char *first, const char *second ) {
- return __res;
+ return strncmp ( first, second, ~( ( size_t ) 0 ) );
}
-#endif
-#ifndef __HAVE_ARCH_STRCASECMP
-int strcasecmp(const char *a, const char *b)
-{
- while (*a && *b && (*a & ~0x20) == (*b & ~0x20)) {a++; b++; }
- return((*a & ~0x20) - (*b & ~0x20));
+/**
+ * Compare strings
+ *
+ * @v first First string
+ * @v second Second string
+ * @v max Maximum length to compare
+ * @ret diff Difference
+ */
+int strncmp ( const char *first, const char *second, size_t max ) {
+ const uint8_t *first_bytes = ( ( const uint8_t * ) first );
+ const uint8_t *second_bytes = ( ( const uint8_t * ) second );
+ int diff;
+
+ for ( ; max-- ; first_bytes++, second_bytes++ ) {
+ diff = ( *second_bytes - *first_bytes );
+ if ( diff )
+ return diff;
+ if ( ! *first_bytes )
+ return 0;
+ }
+ return 0;
}
-#endif
-#ifndef __HAVE_ARCH_STRCHR
/**
- * strchr - Find the first occurrence of a character in a string
- * @s: The string to be searched
- * @c: The character to search for
+ * Compare case-insensitive strings
+ *
+ * @v first First string
+ * @v second Second string
+ * @ret diff Difference
*/
-char * strchr(const char * s, int c)
-{
- for(; *s != (char) c; ++s)
- if (*s == '\0')
- return NULL;
- return (char *) s;
+int strcasecmp ( const char *first, const char *second ) {
+ const uint8_t *first_bytes = ( ( const uint8_t * ) first );
+ const uint8_t *second_bytes = ( ( const uint8_t * ) second );
+ int diff;
+
+ for ( ; ; first_bytes++, second_bytes++ ) {
+ diff = ( toupper ( *second_bytes ) -
+ toupper ( *first_bytes ) );
+ if ( diff )
+ return diff;
+ if ( ! *first_bytes )
+ return 0;
+ }
}
-#endif
-#ifndef __HAVE_ARCH_STRRCHR
/**
- * strrchr - Find the last occurrence of a character in a string
- * @s: The string to be searched
- * @c: The character to search for
+ * Get length of string
+ *
+ * @v src String
+ * @ret len Length
*/
-char * strrchr(const char * s, int c)
-{
- const char *p = s + strlen(s);
- do {
- if (*p == (char)c)
- return (char *)p;
- } while (--p >= s);
- return NULL;
+size_t strlen ( const char *src ) {
+
+ return strnlen ( src, ~( ( size_t ) 0 ) );
}
-#endif
-#ifndef __HAVE_ARCH_STRLEN
/**
- * strlen - Find the length of a string
- * @s: The string to be sized
+ * Get length of string
+ *
+ * @v src String
+ * @v max Maximum length
+ * @ret len Length
*/
-size_t strlen(const char * s)
-{
- const char *sc;
+size_t strnlen ( const char *src, size_t max ) {
+ const uint8_t *src_bytes = ( ( const uint8_t * ) src );
+ size_t len = 0;
- for (sc = s; *sc != '\0'; ++sc)
- /* nothing */;
- return sc - s;
+ while ( max-- && *(src_bytes++) )
+ len++;
+ return len;
}
-#endif
-#ifndef __HAVE_ARCH_STRNLEN
/**
- * strnlen - Find the length of a length-limited string
- * @s: The string to be sized
- * @count: The maximum number of bytes to search
+ * Find character within a string
+ *
+ * @v src String
+ * @v character Character to find
+ * @ret found Found character, or NULL if not found
*/
-size_t strnlen(const char * s, size_t count)
-{
- const char *sc;
+char * strchr ( const char *src, int character ) {
+ const uint8_t *src_bytes = ( ( const uint8_t * ) src );
- for (sc = s; count-- && *sc != '\0'; ++sc)
- /* nothing */;
- return sc - s;
+ for ( ; ; src_bytes++ ) {
+ if ( *src_bytes == character )
+ return ( ( char * ) src_bytes );
+ if ( ! *src_bytes )
+ return NULL;
+ }
}
-#endif
-#ifndef __HAVE_ARCH_MEMSET
/**
- * memset - Fill a region of memory with the given value
- * @s: Pointer to the start of the area.
- * @c: The byte to fill the area with
- * @count: The size of the area.
+ * Find rightmost character within a string
*
- * Do not use memset() to access IO space, use memset_io() instead.
+ * @v src String
+ * @v character Character to find
+ * @ret found Found character, or NULL if not found
*/
-void * memset(void * s,int c,size_t count)
-{
- char *xs = (char *) s;
+char * strrchr ( const char *src, int character ) {
+ const uint8_t *src_bytes = ( ( const uint8_t * ) src );
+ const uint8_t *start = src_bytes;
+
+ while ( *src_bytes )
+ src_bytes++;
+ for ( src_bytes-- ; src_bytes >= start ; src_bytes-- ) {
+ if ( *src_bytes == character )
+ return ( ( char * ) src_bytes );
+ }
+ return NULL;
+}
- while (count--)
- *xs++ = c;
+/**
+ * Find substring
+ *
+ * @v haystack String
+ * @v needle Substring
+ * @ret found Found substring, or NULL if not found
+ */
+char * strstr ( const char *haystack, const char *needle ) {
+ size_t len = strlen ( needle );
- return s;
+ for ( ; *haystack ; haystack++ ) {
+ if ( memcmp ( haystack, needle, len ) == 0 )
+ return ( ( char * ) haystack );
+ }
+ return NULL;
}
-#endif
-#ifndef __HAVE_ARCH_MEMCPY
/**
- * memcpy - Copy one area of memory to another
- * @dest: Where to copy to
- * @src: Where to copy from
- * @count: The size of the area.
+ * Copy string
*
- * You should not use this function to access IO space, use memcpy_toio()
- * or memcpy_fromio() instead.
+ * @v dest Destination string
+ * @v src Source string
+ * @ret dest Destination string
*/
-void * memcpy(void * dest,const void *src,size_t count)
-{
- char *tmp = (char *) dest, *s = (char *) src;
+char * strcpy ( char *dest, const char *src ) {
+ const uint8_t *src_bytes = ( ( const uint8_t * ) src );
+ uint8_t *dest_bytes = ( ( uint8_t * ) dest );
+
+ /* We cannot use strncpy(), since that would pad the destination */
+ for ( ; ; src_bytes++, dest_bytes++ ) {
+ *dest_bytes = *src_bytes;
+ if ( ! *dest_bytes )
+ break;
+ }
+ return dest;
+}
- while (count--)
- *tmp++ = *s++;
+/**
+ * Copy string
+ *
+ * @v dest Destination string
+ * @v src Source string
+ * @v max Maximum length
+ * @ret dest Destination string
+ */
+char * strncpy ( char *dest, const char *src, size_t max ) {
+ const uint8_t *src_bytes = ( ( const uint8_t * ) src );
+ uint8_t *dest_bytes = ( ( uint8_t * ) dest );
+ for ( ; max ; max--, src_bytes++, dest_bytes++ ) {
+ *dest_bytes = *src_bytes;
+ if ( ! *dest_bytes )
+ break;
+ }
+ while ( max-- )
+ *(dest_bytes++) = '\0';
return dest;
}
-#endif
-#ifndef __HAVE_ARCH_MEMMOVE
/**
- * memmove - Copy one area of memory to another
- * @dest: Where to copy to
- * @src: Where to copy from
- * @count: The size of the area.
+ * Concatenate string
*
- * Unlike memcpy(), memmove() copes with overlapping areas.
+ * @v dest Destination string
+ * @v src Source string
+ * @ret dest Destination string
*/
-void * memmove(void * dest,const void *src,size_t count)
-{
- char *tmp, *s;
-
- if (dest <= src) {
- tmp = (char *) dest;
- s = (char *) src;
- while (count--)
- *tmp++ = *s++;
- }
- else {
- tmp = (char *) dest + count;
- s = (char *) src + count;
- while (count--)
- *--tmp = *--s;
- }
+char * strcat ( char *dest, const char *src ) {
+ strcpy ( ( dest + strlen ( dest ) ), src );
return dest;
}
-#endif
-#ifndef __HAVE_ARCH_MEMCMP
/**
- * memcmp - Compare two areas of memory
- * @cs: One area of memory
- * @ct: Another area of memory
- * @count: The size of the area.
+ * Duplicate string
+ *
+ * @v src Source string
+ * @ret dup Duplicated string, or NULL if allocation failed
*/
-int memcmp(const void * cs,const void * ct,size_t count)
-{
- const unsigned char *su1, *su2;
- int res = 0;
+char * strdup ( const char *src ) {
- for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
- if ((res = *su1 - *su2) != 0)
- break;
- return res;
+ return strndup ( src, ~( ( size_t ) 0 ) );
}
-#endif
-#ifndef __HAVE_ARCH_STRSTR
/**
- * strstr - Find the first substring in a %NUL terminated string
- * @s1: The string to be searched
- * @s2: The string to search for
+ * Duplicate string
+ *
+ * @v src Source string
+ * @v max Maximum length
+ * @ret dup Duplicated string, or NULL if allocation failed
*/
-char * strstr(const char * s1,const char * s2)
-{
- int l1, l2;
-
- l2 = strlen(s2);
- if (!l2)
- return (char *) s1;
- l1 = strlen(s1);
- while (l1 >= l2) {
- l1--;
- if (!memcmp(s1,s2,l2))
- return (char *) s1;
- s1++;
- }
- return NULL;
+char * strndup ( const char *src, size_t max ) {
+ size_t len = strnlen ( src, max );
+ char *dup;
+
+ dup = malloc ( len + 1 /* NUL */ );
+ if ( dup ) {
+ memcpy ( dup, src, len );
+ dup[len] = '\0';
+ }
+ return dup;
+}
+
+/**
+ * Calculate digit value
+ *
+ * @v character Digit character
+ * @ret digit Digit value
+ *
+ * Invalid digits will be returned as a value greater than or equal to
+ * the numeric base.
+ */
+unsigned int digit_value ( unsigned int character ) {
+
+ if ( character >= 'a' )
+ return ( character - ( 'a' - 10 ) );
+ if ( character >= 'A' )
+ return ( character - ( 'A' - 10 ) );
+ if ( character <= '9' )
+ return ( character - '0' );
+ return character;
}
-#endif
-#ifndef __HAVE_ARCH_MEMCHR
/**
- * memchr - Find a character in an area of memory.
- * @s: The memory area
- * @c: The byte to search for
- * @n: The size of the area.
+ * Preprocess string for strtoul() or strtoull()
*
- * returns the address of the first occurrence of @c, or %NULL
- * if @c is not found
+ * @v string String
+ * @v negate Final value should be negated
+ * @v base Numeric base
+ * @ret string Remaining string
*/
-void * memchr(const void *s, int c, size_t n)
-{
- const unsigned char *p = s;
- while (n-- != 0) {
- if ((unsigned char)c == *p++) {
- return (void *)(p-1);
+static const char * strtoul_pre ( const char *string, int *negate, int *base ) {
+
+ /* Skip any leading whitespace */
+ while ( isspace ( *string ) )
+ string++;
+
+ /* Process arithmetic sign, if present */
+ *negate = 0;
+ if ( *string == '-' ) {
+ string++;
+ *negate = 1;
+ } else if ( *string == '+' ) {
+ string++;
+ }
+
+ /* Process base, if present */
+ if ( *base == 0 ) {
+ *base = 10;
+ if ( *string == '0' ) {
+ string++;
+ *base = 8;
+ if ( ( *string & ~0x20 ) == 'X' ) {
+ string++;
+ *base = 16;
+ }
}
}
- return NULL;
+
+ return string;
}
-#endif
+/**
+ * Convert string to numeric value
+ *
+ * @v string String
+ * @v endp End pointer (or NULL)
+ * @v base Numeric base (or zero to autodetect)
+ * @ret value Numeric value
+ */
+unsigned long strtoul ( const char *string, char **endp, int base ) {
+ unsigned long value = 0;
+ unsigned int digit;
+ int negate;
+
+ /* Preprocess string */
+ string = strtoul_pre ( string, &negate, &base );
+
+ /* Process digits */
+ for ( ; ; string++ ) {
+ digit = digit_value ( *string );
+ if ( digit >= ( unsigned int ) base )
+ break;
+ value = ( ( value * base ) + digit );
+ }
+
+ /* Negate value if, applicable */
+ if ( negate )
+ value = -value;
-char * strndup(const char *s, size_t n)
-{
- size_t len = strnlen(s,n);
- char *new;
+ /* Fill in end pointer, if applicable */
+ if ( endp )
+ *endp = ( ( char * ) string );
- new = malloc(len+1);
- if (new) {
- new[len] = '\0';
- memcpy(new,s,len);
- }
- return new;
+ return value;
}
-char * strdup(const char *s) {
- return strndup(s, ~((size_t)0));
+/**
+ * Convert string to numeric value
+ *
+ * @v string String
+ * @v endp End pointer (or NULL)
+ * @v base Numeric base (or zero to autodetect)
+ * @ret value Numeric value
+ */
+unsigned long long strtoull ( const char *string, char **endp, int base ) {
+ unsigned long long value = 0;
+ unsigned int digit;
+ int negate;
+
+ /* Preprocess string */
+ string = strtoul_pre ( string, &negate, &base );
+
+ /* Process digits */
+ for ( ; ; string++ ) {
+ digit = digit_value ( *string );
+ if ( digit >= ( unsigned int ) base )
+ break;
+ value = ( ( value * base ) + digit );
+ }
+
+ /* Negate value if, applicable */
+ if ( negate )
+ value = -value;
+
+ /* Fill in end pointer, if applicable */
+ if ( endp )
+ *endp = ( ( char * ) string );
+
+ return value;
}
diff --git a/roms/ipxe/src/core/stringextra.c b/roms/ipxe/src/core/stringextra.c
index 0a509852e..18ffc6301 100644
--- a/roms/ipxe/src/core/stringextra.c
+++ b/roms/ipxe/src/core/stringextra.c
@@ -38,122 +38,6 @@ FILE_LICENCE ( GPL2_ONLY );
/* *** FROM string.c *** */
-#ifndef __HAVE_ARCH_STRNICMP
-/**
- * strnicmp - Case insensitive, length-limited string comparison
- * @s1: One string
- * @s2: The other string
- * @len: the maximum number of characters to compare
- */
-int strnicmp(const char *s1, const char *s2, size_t len)
-{
- /* Yes, Virginia, it had better be unsigned */
- unsigned char c1, c2;
-
- c1 = 0; c2 = 0;
- if (len) {
- do {
- c1 = *s1; c2 = *s2;
- s1++; s2++;
- if (!c1)
- break;
- if (!c2)
- break;
- if (c1 == c2)
- continue;
- c1 = tolower(c1);
- c2 = tolower(c2);
- if (c1 != c2)
- break;
- } while (--len);
- }
- return (int)c1 - (int)c2;
-}
-#endif
-
-char * ___strtok;
-
-#ifndef __HAVE_ARCH_STRNCAT
-/**
- * strncat - Append a length-limited, %NUL-terminated string to another
- * @dest: The string to be appended to
- * @src: The string to append to it
- * @count: The maximum numbers of bytes to copy
- *
- * Note that in contrast to strncpy, strncat ensures the result is
- * terminated.
- */
-char * strncat(char *dest, const char *src, size_t count)
-{
- char *tmp = dest;
-
- if (count) {
- while (*dest)
- dest++;
- while ((*dest++ = *src++)) {
- if (--count == 0) {
- *dest = '\0';
- break;
- }
- }
- }
-
- return tmp;
-}
-#endif
-
-#ifndef __HAVE_ARCH_STRSPN
-/**
- * strspn - Calculate the length of the initial substring of @s which only
- * contain letters in @accept
- * @s: The string to be searched
- * @accept: The string to search for
- */
-size_t strspn(const char *s, const char *accept)
-{
- const char *p;
- const char *a;
- size_t count = 0;
-
- for (p = s; *p != '\0'; ++p) {
- for (a = accept; *a != '\0'; ++a) {
- if (*p == *a)
- break;
- }
- if (*a == '\0')
- return count;
- ++count;
- }
-
- return count;
-}
-#endif
-
-#ifndef __HAVE_ARCH_STRCSPN
-/**
- * strcspn - Calculate the length of the initial substring of @s which only
- * contain letters not in @reject
- * @s: The string to be searched
- * @accept: The string to search for
- */
-size_t strcspn(const char *s, const char *reject)
-{
- const char *p;
- const char *r;
- size_t count = 0;
-
- for (p = s; *p != '\0'; ++p) {
- for (r = reject; *r != '\0'; ++r) {
- if (*p == *r)
- return count;
- }
- ++count;
- }
-
- return count;
-}
-#endif
-
#ifndef __HAVE_ARCH_STRPBRK
/**
* strpbrk - Find the first occurrence of a set of characters
@@ -174,35 +58,6 @@ char * strpbrk(const char * cs,const char * ct)
}
#endif
-#ifndef __HAVE_ARCH_STRTOK
-/**
- * strtok - Split a string into tokens
- * @s: The string to be searched
- * @ct: The characters to search for
- *
- * WARNING: strtok is deprecated, use strsep instead.
- */
-char * strtok(char * s,const char * ct)
-{
- char *sbegin, *send;
-
- sbegin = s ? s : ___strtok;
- if (!sbegin) {
- return NULL;
- }
- sbegin += strspn(sbegin,ct);
- if (*sbegin == '\0') {
- ___strtok = NULL;
- return( NULL );
- }
- send = strpbrk( sbegin, ct);
- if (send && *send != '\0')
- *send++ = '\0';
- ___strtok = send;
- return (sbegin);
-}
-#endif
-
#ifndef __HAVE_ARCH_STRSEP
/**
* strsep - Split a string into tokens
@@ -230,46 +85,3 @@ char * strsep(char **s, const char *ct)
return sbegin;
}
#endif
-
-#ifndef __HAVE_ARCH_BCOPY
-/**
- * bcopy - Copy one area of memory to another
- * @src: Where to copy from
- * @dest: Where to copy to
- * @count: The size of the area.
- *
- * Note that this is the same as memcpy(), with the arguments reversed.
- * memcpy() is the standard, bcopy() is a legacy BSD function.
- *
- * You should not use this function to access IO space, use memcpy_toio()
- * or memcpy_fromio() instead.
- */
-char * bcopy(const char * src, char * dest, int count)
-{
- return memmove(dest,src,count);
-}
-#endif
-
-#ifndef __HAVE_ARCH_MEMSCAN
-/**
- * memscan - Find a character in an area of memory.
- * @addr: The memory area
- * @c: The byte to search for
- * @size: The size of the area.
- *
- * returns the address of the first occurrence of @c, or 1 byte past
- * the area if @c is not found
- */
-void * memscan(const void * addr, int c, size_t size)
-{
- unsigned char * p = (unsigned char *) addr;
-
- while (size) {
- if (*p == c)
- return (void *) p;
- p++;
- size--;
- }
- return (void *) p;
-}
-#endif
diff --git a/roms/ipxe/src/core/strtoull.c b/roms/ipxe/src/core/strtoull.c
deleted file mode 100644
index 00986eef0..000000000
--- a/roms/ipxe/src/core/strtoull.c
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>
- * Copyright (C) 2010 Piotr Jaroszyński <p.jaroszynski@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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#include <stdlib.h>
-#include <ctype.h>
-
-/*
- * Despite being exactly the same as strtoul() except the long long instead of
- * long it ends up being much bigger so provide a separate implementation in a
- * separate object so that it won't be linked in if not used.
- */
-unsigned long long strtoull ( const char *p, char **endp, int base ) {
- unsigned long long ret = 0;
- int negative = 0;
- unsigned int charval;
-
- while ( isspace ( *p ) )
- p++;
-
- if ( *p == '-' ) {
- negative = 1;
- p++;
- }
-
- base = strtoul_base ( &p, base );
-
- while ( 1 ) {
- charval = strtoul_charval ( *p );
- if ( charval >= ( unsigned int ) base )
- break;
- ret = ( ( ret * base ) + charval );
- p++;
- }
-
- if ( negative )
- ret = -ret;
-
- if ( endp )
- *endp = ( char * ) p;
-
- return ( ret );
-}
diff --git a/roms/ipxe/src/core/time.c b/roms/ipxe/src/core/time.c
index f70e1981d..29a924ebe 100644
--- a/roms/ipxe/src/core/time.c
+++ b/roms/ipxe/src/core/time.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <time.h>
diff --git a/roms/ipxe/src/core/timer.c b/roms/ipxe/src/core/timer.c
index 18c2b2849..dbd89f12b 100644
--- a/roms/ipxe/src/core/timer.c
+++ b/roms/ipxe/src/core/timer.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <unistd.h>
diff --git a/roms/ipxe/src/core/uart.c b/roms/ipxe/src/core/uart.c
new file mode 100644
index 000000000..b85fe0767
--- /dev/null
+++ b/roms/ipxe/src/core/uart.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/** @file
+ *
+ * 16550-compatible UART
+ *
+ */
+
+#include <unistd.h>
+#include <errno.h>
+#include <ipxe/uart.h>
+
+/** Timeout for transmit holding register to become empty */
+#define UART_THRE_TIMEOUT_MS 100
+
+/** Timeout for transmitter to become empty */
+#define UART_TEMT_TIMEOUT_MS 1000
+
+/**
+ * Transmit data
+ *
+ * @v uart UART
+ * @v data Data
+ */
+void uart_transmit ( struct uart *uart, uint8_t data ) {
+ unsigned int i;
+ uint8_t lsr;
+
+ /* Wait for transmitter holding register to become empty */
+ for ( i = 0 ; i < UART_THRE_TIMEOUT_MS ; i++ ) {
+ lsr = uart_read ( uart, UART_LSR );
+ if ( lsr & UART_LSR_THRE )
+ break;
+ mdelay ( 1 );
+ }
+
+ /* Transmit data (even if we timed out) */
+ uart_write ( uart, UART_THR, data );
+}
+
+/**
+ * Flush data
+ *
+ * @v uart UART
+ */
+void uart_flush ( struct uart *uart ) {
+ unsigned int i;
+ uint8_t lsr;
+
+ /* Wait for transmitter and receiver to become empty */
+ for ( i = 0 ; i < UART_TEMT_TIMEOUT_MS ; i++ ) {
+ uart_read ( uart, UART_RBR );
+ lsr = uart_read ( uart, UART_LSR );
+ if ( ( lsr & UART_LSR_TEMT ) && ! ( lsr & UART_LSR_DR ) )
+ break;
+ }
+}
+
+/**
+ * Check for existence of UART
+ *
+ * @v uart UART
+ * @ret rc Return status code
+ */
+int uart_exists ( struct uart *uart ) {
+
+ /* Fail if no UART port is defined */
+ if ( ! uart->base )
+ return -ENODEV;
+
+ /* Fail if UART scratch register seems not to be present */
+ uart_write ( uart, UART_SCR, 0x18 );
+ if ( uart_read ( uart, UART_SCR ) != 0x18 )
+ return -ENODEV;
+ uart_write ( uart, UART_SCR, 0xae );
+ if ( uart_read ( uart, UART_SCR ) != 0xae )
+ return -ENODEV;
+
+ return 0;
+}
+
+/**
+ * Initialise UART
+ *
+ * @v uart UART
+ * @v baud Baud rate, or zero to leave unchanged
+ * @v lcr Line control register value, or zero to leave unchanged
+ * @ret rc Return status code
+ */
+int uart_init ( struct uart *uart, unsigned int baud, uint8_t lcr ) {
+ uint8_t dlm;
+ uint8_t dll;
+ int rc;
+
+ /* Check for existence of UART */
+ if ( ( rc = uart_exists ( uart ) ) != 0 )
+ return rc;
+
+ /* Configure divisor and line control register, if applicable */
+ if ( ! lcr )
+ lcr = uart_read ( uart, UART_LCR );
+ uart->lcr = lcr;
+ uart_write ( uart, UART_LCR, ( lcr | UART_LCR_DLAB ) );
+ if ( baud ) {
+ uart->divisor = ( UART_MAX_BAUD / baud );
+ dlm = ( ( uart->divisor >> 8 ) & 0xff );
+ dll = ( ( uart->divisor >> 0 ) & 0xff );
+ uart_write ( uart, UART_DLM, dlm );
+ uart_write ( uart, UART_DLL, dll );
+ } else {
+ dlm = uart_read ( uart, UART_DLM );
+ dll = uart_read ( uart, UART_DLL );
+ uart->divisor = ( ( dlm << 8 ) | dll );
+ }
+ uart_write ( uart, UART_LCR, ( lcr & ~UART_LCR_DLAB ) );
+
+ /* Disable interrupts */
+ uart_write ( uart, UART_IER, 0 );
+
+ /* Enable FIFOs */
+ uart_write ( uart, UART_FCR, UART_FCR_FE );
+
+ /* Assert DTR and RTS */
+ uart_write ( uart, UART_MCR, ( UART_MCR_DTR | UART_MCR_RTS ) );
+
+ /* Flush any stale data */
+ uart_flush ( uart );
+
+ return 0;
+}
diff --git a/roms/ipxe/src/core/uri.c b/roms/ipxe/src/core/uri.c
index 9ec21cee4..3b5f270fe 100644
--- a/roms/ipxe/src/core/uri.c
+++ b/roms/ipxe/src/core/uri.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
@@ -661,6 +665,7 @@ struct uri * resolve_uri ( const struct uri *base_uri,
* Construct TFTP URI from next-server and filename
*
* @v next_server Next-server address
+ * @v port Port number, or zero to use the default port
* @v filename Filename
* @ret uri URI, or NULL on failure
*
@@ -669,12 +674,18 @@ struct uri * resolve_uri ( const struct uri *base_uri,
* generic URI parser. We provide a mechanism for directly
* constructing a TFTP URI from the next-server and filename.
*/
-struct uri * tftp_uri ( struct in_addr next_server, const char *filename ) {
+struct uri * tftp_uri ( struct in_addr next_server, unsigned int port,
+ const char *filename ) {
+ char buf[ 6 /* "65535" + NUL */ ];
struct uri uri;
memset ( &uri, 0, sizeof ( uri ) );
uri.scheme = "tftp";
uri.host = inet_ntoa ( next_server );
+ if ( port ) {
+ snprintf ( buf, sizeof ( buf ), "%d", port );
+ uri.port = buf;
+ }
uri.path = filename;
return uri_dup ( &uri );
}
diff --git a/roms/ipxe/src/core/uuid.c b/roms/ipxe/src/core/uuid.c
index 27a249da8..b8d21de17 100644
--- a/roms/ipxe/src/core/uuid.c
+++ b/roms/ipxe/src/core/uuid.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdio.h>
diff --git a/roms/ipxe/src/core/version.c b/roms/ipxe/src/core/version.c
index 1e1e9daca..c984335c2 100644
--- a/roms/ipxe/src/core/version.c
+++ b/roms/ipxe/src/core/version.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
@@ -29,6 +33,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/features.h>
#include <ipxe/version.h>
#include <config/general.h>
+#include <config/branding.h>
/**
* Create wide-character version of string
diff --git a/roms/ipxe/src/core/vsprintf.c b/roms/ipxe/src/core/vsprintf.c
index 54811b11b..cb3bec5dd 100644
--- a/roms/ipxe/src/core/vsprintf.c
+++ b/roms/ipxe/src/core/vsprintf.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <stdarg.h>
diff --git a/roms/ipxe/src/core/wchar.c b/roms/ipxe/src/core/wchar.c
index 7fabca470..860322820 100644
--- a/roms/ipxe/src/core/wchar.c
+++ b/roms/ipxe/src/core/wchar.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @file
diff --git a/roms/ipxe/src/core/xfer.c b/roms/ipxe/src/core/xfer.c
index 8d4bc9f53..112fee1bf 100644
--- a/roms/ipxe/src/core/xfer.c
+++ b/roms/ipxe/src/core/xfer.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <stdlib.h>
@@ -134,18 +138,8 @@ size_t xfer_window ( struct interface *intf ) {
* generating an xfer_window_changed() message.
*/
void xfer_window_changed ( struct interface *intf ) {
- struct interface *dest;
- xfer_window_changed_TYPE ( void * ) *op =
- intf_get_dest_op ( intf, xfer_window_changed, &dest );
- void *object = intf_object ( dest );
- if ( op ) {
- op ( object );
- } else {
- /* Default is to do nothing */
- }
-
- intf_put ( dest );
+ intf_poke ( intf, xfer_window_changed );
}
/**
@@ -365,3 +359,34 @@ int xfer_seek ( struct interface *intf, off_t offset ) {
return xfer_deliver ( intf, iobuf, &meta );
}
+
+/**
+ * Check that data is delivered strictly in order
+ *
+ * @v meta Data transfer metadata
+ * @v pos Current position
+ * @v len Length of data
+ * @ret rc Return status code
+ */
+int xfer_check_order ( struct xfer_metadata *meta, size_t *pos, size_t len ) {
+ size_t new_pos;
+
+ /* Allow out-of-order zero-length packets (as used by xfer_seek()) */
+ if ( len == 0 )
+ return 0;
+
+ /* Calculate position of this delivery */
+ new_pos = *pos;
+ if ( meta->flags & XFER_FL_ABS_OFFSET )
+ new_pos = 0;
+ new_pos += meta->offset;
+
+ /* Fail if delivery position is not equal to current position */
+ if ( new_pos != *pos )
+ return -EPROTO;
+
+ /* Update current position */
+ *pos += len;
+
+ return 0;
+}
diff --git a/roms/ipxe/src/core/xferbuf.c b/roms/ipxe/src/core/xferbuf.c
index a0457feee..240118557 100644
--- a/roms/ipxe/src/core/xferbuf.c
+++ b/roms/ipxe/src/core/xferbuf.c
@@ -15,15 +15,21 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <ipxe/xfer.h>
#include <ipxe/iobuf.h>
+#include <ipxe/umalloc.h>
+#include <ipxe/profile.h>
#include <ipxe/xferbuf.h>
/** @file
@@ -32,14 +38,26 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
*/
+/** Data delivery profiler */
+static struct profiler xferbuf_deliver_profiler __profiler =
+ { .name = "xferbuf.deliver" };
+
+/** Data write profiler */
+static struct profiler xferbuf_write_profiler __profiler =
+ { .name = "xferbuf.write" };
+
+/** Data read profiler */
+static struct profiler xferbuf_read_profiler __profiler =
+ { .name = "xferbuf.read" };
+
/**
- * Finish using data transfer buffer
+ * Free data transfer buffer
*
* @v xferbuf Data transfer buffer
*/
-void xferbuf_done ( struct xfer_buffer *xferbuf ) {
- free ( xferbuf->data );
- xferbuf->data = NULL;
+void xferbuf_free ( struct xfer_buffer *xferbuf ) {
+
+ xferbuf->op->realloc ( xferbuf, 0 );
xferbuf->len = 0;
xferbuf->pos = 0;
}
@@ -52,26 +70,78 @@ void xferbuf_done ( struct xfer_buffer *xferbuf ) {
* @ret rc Return status code
*/
static int xferbuf_ensure_size ( struct xfer_buffer *xferbuf, size_t len ) {
- void *new_data;
+ int rc;
/* If buffer is already large enough, do nothing */
if ( len <= xferbuf->len )
return 0;
/* Extend buffer */
- new_data = realloc ( xferbuf->data, len );
- if ( ! new_data ) {
+ if ( ( rc = xferbuf->op->realloc ( xferbuf, len ) ) != 0 ) {
DBGC ( xferbuf, "XFERBUF %p could not extend buffer to "
- "%zd bytes\n", xferbuf, len );
- return -ENOSPC;
+ "%zd bytes: %s\n", xferbuf, len, strerror ( rc ) );
+ return rc;
}
- xferbuf->data = new_data;
xferbuf->len = len;
return 0;
}
/**
+ * Write to data transfer buffer
+ *
+ * @v xferbuf Data transfer buffer
+ * @v offset Starting offset
+ * @v data Data to write
+ * @v len Length of data
+ */
+int xferbuf_write ( struct xfer_buffer *xferbuf, size_t offset,
+ const void *data, size_t len ) {
+ size_t max_len;
+ int rc;
+
+ /* Check for overflow */
+ max_len = ( offset + len );
+ if ( max_len < offset )
+ return -EOVERFLOW;
+
+ /* Ensure buffer is large enough to contain this write */
+ if ( ( rc = xferbuf_ensure_size ( xferbuf, max_len ) ) != 0 )
+ return rc;
+
+ /* Copy data to buffer */
+ profile_start ( &xferbuf_write_profiler );
+ xferbuf->op->write ( xferbuf, offset, data, len );
+ profile_stop ( &xferbuf_write_profiler );
+
+ return 0;
+}
+
+/**
+ * Read from data transfer buffer
+ *
+ * @v xferbuf Data transfer buffer
+ * @v offset Starting offset
+ * @v data Data to write
+ * @v len Length of data
+ */
+int xferbuf_read ( struct xfer_buffer *xferbuf, size_t offset,
+ void *data, size_t len ) {
+
+ /* Check that read is within buffer range */
+ if ( ( offset > xferbuf->len ) ||
+ ( len > ( xferbuf->len - offset ) ) )
+ return -ENOENT;
+
+ /* Copy data from buffer */
+ profile_start ( &xferbuf_read_profiler );
+ xferbuf->op->read ( xferbuf, offset, data, len );
+ profile_stop ( &xferbuf_read_profiler );
+
+ return 0;
+}
+
+/**
* Add received data to data transfer buffer
*
* @v xferbuf Data transfer buffer
@@ -81,28 +151,174 @@ static int xferbuf_ensure_size ( struct xfer_buffer *xferbuf, size_t len ) {
*/
int xferbuf_deliver ( struct xfer_buffer *xferbuf, struct io_buffer *iobuf,
struct xfer_metadata *meta ) {
- size_t len;
- size_t max;
+ size_t len = iob_len ( iobuf );
+ size_t pos;
int rc;
+ /* Start profiling */
+ profile_start ( &xferbuf_deliver_profiler );
+
/* Calculate new buffer position */
+ pos = xferbuf->pos;
if ( meta->flags & XFER_FL_ABS_OFFSET )
- xferbuf->pos = 0;
- xferbuf->pos += meta->offset;
+ pos = 0;
+ pos += meta->offset;
- /* Ensure that we have enough buffer space for this data */
- len = iob_len ( iobuf );
- max = ( xferbuf->pos + len );
- if ( ( rc = xferbuf_ensure_size ( xferbuf, max ) ) != 0 )
+ /* Write data to buffer */
+ if ( ( rc = xferbuf_write ( xferbuf, pos, iobuf->data, len ) ) != 0 )
goto done;
- /* Copy data to buffer */
- memcpy ( ( xferbuf->data + xferbuf->pos ), iobuf->data, len );
-
/* Update current buffer position */
- xferbuf->pos += len;
+ xferbuf->pos = ( pos + len );
done:
free_iob ( iobuf );
+ profile_stop ( &xferbuf_deliver_profiler );
return rc;
}
+
+/**
+ * Reallocate malloc()-based data buffer
+ *
+ * @v xferbuf Data transfer buffer
+ * @v len New length (or zero to free buffer)
+ * @ret rc Return status code
+ */
+static int xferbuf_malloc_realloc ( struct xfer_buffer *xferbuf, size_t len ) {
+ void *new_data;
+
+ new_data = realloc ( xferbuf->data, len );
+ if ( ! new_data )
+ return -ENOSPC;
+ xferbuf->data = new_data;
+ return 0;
+}
+
+/**
+ * Write data to malloc()-based data buffer
+ *
+ * @v xferbuf Data transfer buffer
+ * @v offset Starting offset
+ * @v data Data to copy
+ * @v len Length of data
+ */
+static void xferbuf_malloc_write ( struct xfer_buffer *xferbuf, size_t offset,
+ const void *data, size_t len ) {
+
+ memcpy ( ( xferbuf->data + offset ), data, len );
+}
+
+/**
+ * Read data from malloc()-based data buffer
+ *
+ * @v xferbuf Data transfer buffer
+ * @v offset Starting offset
+ * @v data Data to read
+ * @v len Length of data
+ */
+static void xferbuf_malloc_read ( struct xfer_buffer *xferbuf, size_t offset,
+ void *data, size_t len ) {
+
+ memcpy ( data, ( xferbuf->data + offset ), len );
+}
+
+/** malloc()-based data buffer operations */
+struct xfer_buffer_operations xferbuf_malloc_operations = {
+ .realloc = xferbuf_malloc_realloc,
+ .write = xferbuf_malloc_write,
+ .read = xferbuf_malloc_read,
+};
+
+/**
+ * Reallocate umalloc()-based data buffer
+ *
+ * @v xferbuf Data transfer buffer
+ * @v len New length (or zero to free buffer)
+ * @ret rc Return status code
+ */
+static int xferbuf_umalloc_realloc ( struct xfer_buffer *xferbuf, size_t len ) {
+ userptr_t *udata = xferbuf->data;
+ userptr_t new_udata;
+
+ new_udata = urealloc ( *udata, len );
+ if ( ! new_udata )
+ return -ENOSPC;
+ *udata = new_udata;
+ return 0;
+}
+
+/**
+ * Write data to umalloc()-based data buffer
+ *
+ * @v xferbuf Data transfer buffer
+ * @v offset Starting offset
+ * @v data Data to copy
+ * @v len Length of data
+ */
+static void xferbuf_umalloc_write ( struct xfer_buffer *xferbuf, size_t offset,
+ const void *data, size_t len ) {
+ userptr_t *udata = xferbuf->data;
+
+ copy_to_user ( *udata, offset, data, len );
+}
+
+/**
+ * Read data from umalloc()-based data buffer
+ *
+ * @v xferbuf Data transfer buffer
+ * @v offset Starting offset
+ * @v data Data to read
+ * @v len Length of data
+ */
+static void xferbuf_umalloc_read ( struct xfer_buffer *xferbuf, size_t offset,
+ void *data, size_t len ) {
+ userptr_t *udata = xferbuf->data;
+
+ copy_from_user ( data, *udata, offset, len );
+}
+
+/** umalloc()-based data buffer operations */
+struct xfer_buffer_operations xferbuf_umalloc_operations = {
+ .realloc = xferbuf_umalloc_realloc,
+ .write = xferbuf_umalloc_write,
+ .read = xferbuf_umalloc_read,
+};
+
+/**
+ * Get underlying data transfer buffer
+ *
+ * @v interface Data transfer interface
+ * @ret xferbuf Data transfer buffer, or NULL on error
+ *
+ * This call will check that the xfer_buffer() handler belongs to the
+ * destination interface which also provides xfer_deliver() for this
+ * interface.
+ *
+ * This is done to prevent accidental accesses to a data transfer
+ * buffer which may be located behind a non-transparent datapath via a
+ * series of pass-through interfaces.
+ */
+struct xfer_buffer * xfer_buffer ( struct interface *intf ) {
+ struct interface *dest;
+ xfer_buffer_TYPE ( void * ) *op =
+ intf_get_dest_op ( intf, xfer_buffer, &dest );
+ void *object = intf_object ( dest );
+ struct interface *xfer_deliver_dest;
+ struct xfer_buffer *xferbuf;
+
+ /* Check that this operation is provided by the same interface
+ * which handles xfer_deliver().
+ */
+ ( void ) intf_get_dest_op ( intf, xfer_deliver, &xfer_deliver_dest );
+
+ if ( op && ( dest == xfer_deliver_dest ) ) {
+ xferbuf = op ( object );
+ } else {
+ /* Default is to not have a data transfer buffer */
+ xferbuf = NULL;
+ }
+
+ intf_put ( xfer_deliver_dest );
+ intf_put ( dest );
+ return xferbuf;
+}
diff --git a/roms/ipxe/src/crypto/aes.c b/roms/ipxe/src/crypto/aes.c
new file mode 100644
index 000000000..b9e206bfb
--- /dev/null
+++ b/roms/ipxe/src/crypto/aes.c
@@ -0,0 +1,808 @@
+/*
+ * Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/** @file
+ *
+ * AES algorithm
+ *
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <ipxe/rotate.h>
+#include <ipxe/crypto.h>
+#include <ipxe/ecb.h>
+#include <ipxe/cbc.h>
+#include <ipxe/aes.h>
+
+/** AES strides
+ *
+ * These are the strides (modulo 16) used to walk through the AES
+ * input state bytes in order of byte position after [Inv]ShiftRows.
+ */
+enum aes_stride {
+ /** Input stride for ShiftRows
+ *
+ * 0 4 8 c
+ * \ \ \
+ * 1 5 9 d
+ * \ \ \
+ * 2 6 a e
+ * \ \ \
+ * 3 7 b f
+ */
+ AES_STRIDE_SHIFTROWS = +5,
+ /** Input stride for InvShiftRows
+ *
+ * 0 4 8 c
+ * / / /
+ * 1 5 9 d
+ * / / /
+ * 2 6 a e
+ * / / /
+ * 3 7 b f
+ */
+ AES_STRIDE_INVSHIFTROWS = -3,
+};
+
+/** A single AES lookup table entry
+ *
+ * This represents the product (in the Galois field GF(2^8)) of an
+ * eight-byte vector multiplier with a single scalar multiplicand.
+ *
+ * The vector multipliers used for AES will be {1,1,1,3,2,1,1,3} for
+ * MixColumns and {1,9,13,11,14,9,13,11} for InvMixColumns. This
+ * allows for the result of multiplying any single column of the
+ * [Inv]MixColumns matrix by a scalar value to be obtained simply by
+ * extracting the relevant four-byte subset from the lookup table
+ * entry.
+ *
+ * For example, to find the result of multiplying the second column of
+ * the MixColumns matrix by the scalar value 0x80:
+ *
+ * MixColumns column[0]: { 2, 1, 1, 3 }
+ * MixColumns column[1]: { 3, 2, 1, 1 }
+ * MixColumns column[2]: { 1, 3, 2, 1 }
+ * MixColumns column[3]: { 1, 1, 3, 2 }
+ * Vector multiplier: { 1, 1, 1, 3, 2, 1, 1, 3 }
+ * Scalar multiplicand: 0x80
+ * Lookup table entry: { 0x80, 0x80, 0x80, 0x9b, 0x1b, 0x80, 0x80, 0x9b }
+ *
+ * The second column of the MixColumns matrix is {3,2,1,1}. The
+ * product of this column with the scalar value 0x80 can be obtained
+ * by extracting the relevant four-byte subset of the lookup table
+ * entry:
+ *
+ * MixColumns column[1]: { 3, 2, 1, 1 }
+ * Vector multiplier: { 1, 1, 1, 3, 2, 1, 1, 3 }
+ * Lookup table entry: { 0x80, 0x80, 0x80, 0x9b, 0x1b, 0x80, 0x80, 0x9b }
+ * Product: { 0x9b, 0x1b, 0x80, 0x80 }
+ *
+ * The column lookups require only seven bytes of the eight-byte
+ * entry: the remaining (first) byte is used to hold the scalar
+ * multiplicand itself (i.e. the first byte of the vector multiplier
+ * is always chosen to be 1).
+ */
+union aes_table_entry {
+ /** Viewed as an array of bytes */
+ uint8_t byte[8];
+} __attribute__ (( packed ));
+
+/** An AES lookup table
+ *
+ * This represents the products (in the Galois field GF(2^8)) of a
+ * constant eight-byte vector multiplier with all possible 256 scalar
+ * multiplicands.
+ *
+ * The entries are indexed by the AES [Inv]SubBytes S-box output
+ * values (denoted S(N)). This allows for the result of multiplying
+ * any single column of the [Inv]MixColumns matrix by S(N) to be
+ * obtained simply by extracting the relevant four-byte subset from
+ * the Nth table entry. For example:
+ *
+ * Input byte (N): 0x3a
+ * SubBytes output S(N): 0x80
+ * MixColumns column[1]: { 3, 2, 1, 1 }
+ * Vector multiplier: { 1, 1, 1, 3, 2, 1, 1, 3 }
+ * Table entry[0x3a]: { 0x80, 0x80, 0x80, 0x9b, 0x1b, 0x80, 0x80, 0x9b }
+ * Product: { 0x9b, 0x1b, 0x80, 0x80 }
+ *
+ * Since the first byte of the eight-byte vector multiplier is always
+ * chosen to be 1, the value of S(N) may be lookup up by extracting
+ * the first byte of the Nth table entry.
+ */
+struct aes_table {
+ /** Table entries, indexed by S(N) */
+ union aes_table_entry entry[256];
+} __attribute__ (( aligned ( 8 ) ));
+
+/** AES MixColumns lookup table */
+static struct aes_table aes_mixcolumns;
+
+/** AES InvMixColumns lookup table */
+static struct aes_table aes_invmixcolumns;
+
+/**
+ * Multiply [Inv]MixColumns matrix column by scalar multiplicand
+ *
+ * @v entry AES lookup table entry for scalar multiplicand
+ * @v column [Inv]MixColumns matrix column index
+ * @ret product Product of matrix column with scalar multiplicand
+ */
+static inline __attribute__ (( always_inline )) uint32_t
+aes_entry_column ( const union aes_table_entry *entry, unsigned int column ) {
+ const union {
+ uint8_t byte;
+ uint32_t column;
+ } __attribute__ (( may_alias )) *product;
+
+ /* Locate relevant four-byte subset */
+ product = container_of ( &entry->byte[ 4 - column ],
+ typeof ( *product ), byte );
+
+ /* Extract this four-byte subset */
+ return product->column;
+}
+
+/**
+ * Multiply [Inv]MixColumns matrix column by S-boxed input byte
+ *
+ * @v table AES lookup table
+ * @v stride AES row shift stride
+ * @v in AES input state
+ * @v offset Output byte offset (after [Inv]ShiftRows)
+ * @ret product Product of matrix column with S(input byte)
+ *
+ * Note that the specified offset is not the offset of the input byte;
+ * it is the offset of the output byte which corresponds to the input
+ * byte. This output byte offset is used to calculate both the input
+ * byte offset and to select the appropriate matric column.
+ *
+ * With a compile-time constant offset, this function will optimise
+ * down to a single "movzbl" (to extract the input byte) and will
+ * generate a single x86 memory reference expression which can then be
+ * used directly within a single "xorl" instruction.
+ */
+static inline __attribute__ (( always_inline )) uint32_t
+aes_column ( const struct aes_table *table, size_t stride,
+ const union aes_matrix *in, size_t offset ) {
+ const union aes_table_entry *entry;
+ unsigned int byte;
+
+ /* Extract input byte corresponding to this output byte offset
+ * (i.e. perform [Inv]ShiftRows).
+ */
+ byte = in->byte[ ( stride * offset ) & 0xf ];
+
+ /* Locate lookup table entry for this input byte (i.e. perform
+ * [Inv]SubBytes).
+ */
+ entry = &table->entry[byte];
+
+ /* Multiply appropriate matrix column by this input byte
+ * (i.e. perform [Inv]MixColumns).
+ */
+ return aes_entry_column ( entry, ( offset & 0x3 ) );
+}
+
+/**
+ * Calculate intermediate round output column
+ *
+ * @v table AES lookup table
+ * @v stride AES row shift stride
+ * @v in AES input state
+ * @v key AES round key
+ * @v column Column index
+ * @ret output Output column value
+ */
+static inline __attribute__ (( always_inline )) uint32_t
+aes_output ( const struct aes_table *table, size_t stride,
+ const union aes_matrix *in, const union aes_matrix *key,
+ unsigned int column ) {
+ size_t offset = ( column * 4 );
+
+ /* Perform [Inv]ShiftRows, [Inv]SubBytes, [Inv]MixColumns, and
+ * AddRoundKey for this column. The loop is unrolled to allow
+ * for the required compile-time constant optimisations.
+ */
+ return ( aes_column ( table, stride, in, ( offset + 0 ) ) ^
+ aes_column ( table, stride, in, ( offset + 1 ) ) ^
+ aes_column ( table, stride, in, ( offset + 2 ) ) ^
+ aes_column ( table, stride, in, ( offset + 3 ) ) ^
+ key->column[column] );
+}
+
+/**
+ * Perform a single intermediate round
+ *
+ * @v table AES lookup table
+ * @v stride AES row shift stride
+ * @v in AES input state
+ * @v out AES output state
+ * @v key AES round key
+ */
+static inline __attribute__ (( always_inline )) void
+aes_round ( const struct aes_table *table, size_t stride,
+ const union aes_matrix *in, union aes_matrix *out,
+ const union aes_matrix *key ) {
+
+ /* Perform [Inv]ShiftRows, [Inv]SubBytes, [Inv]MixColumns, and
+ * AddRoundKey for all columns. The loop is unrolled to allow
+ * for the required compile-time constant optimisations.
+ */
+ out->column[0] = aes_output ( table, stride, in, key, 0 );
+ out->column[1] = aes_output ( table, stride, in, key, 1 );
+ out->column[2] = aes_output ( table, stride, in, key, 2 );
+ out->column[3] = aes_output ( table, stride, in, key, 3 );
+}
+
+/**
+ * Perform encryption intermediate rounds
+ *
+ * @v in AES input state
+ * @v out AES output state
+ * @v key Round keys
+ * @v rounds Number of rounds (must be odd)
+ *
+ * This function is deliberately marked as non-inlinable to ensure
+ * maximal availability of registers for GCC's register allocator,
+ * which has a tendency to otherwise spill performance-critical
+ * registers to the stack.
+ */
+static __attribute__ (( noinline )) void
+aes_encrypt_rounds ( union aes_matrix *in, union aes_matrix *out,
+ const union aes_matrix *key, unsigned int rounds ) {
+ union aes_matrix *tmp;
+
+ /* Perform intermediate rounds */
+ do {
+ /* Perform one intermediate round */
+ aes_round ( &aes_mixcolumns, AES_STRIDE_SHIFTROWS,
+ in, out, key++ );
+
+ /* Swap input and output states for next round */
+ tmp = in;
+ in = out;
+ out = tmp;
+
+ } while ( --rounds );
+}
+
+/**
+ * Perform decryption intermediate rounds
+ *
+ * @v in AES input state
+ * @v out AES output state
+ * @v key Round keys
+ * @v rounds Number of rounds (must be odd)
+ *
+ * As with aes_encrypt_rounds(), this function is deliberately marked
+ * as non-inlinable.
+ *
+ * This function could potentially use the same binary code as is used
+ * for encryption. To compensate for the difference between ShiftRows
+ * and InvShiftRows, half of the input byte offsets would have to be
+ * modifiable at runtime (half by an offset of +4/-4, half by an
+ * offset of -4/+4 for ShiftRows/InvShiftRows). This can be
+ * accomplished in x86 assembly within the number of available
+ * registers, but GCC's register allocator struggles to do so,
+ * resulting in a significant performance decrease due to registers
+ * being spilled to the stack. We therefore use two separate but very
+ * similar binary functions based on the same C source.
+ */
+static __attribute__ (( noinline )) void
+aes_decrypt_rounds ( union aes_matrix *in, union aes_matrix *out,
+ const union aes_matrix *key, unsigned int rounds ) {
+ union aes_matrix *tmp;
+
+ /* Perform intermediate rounds */
+ do {
+ /* Perform one intermediate round */
+ aes_round ( &aes_invmixcolumns, AES_STRIDE_INVSHIFTROWS,
+ in, out, key++ );
+
+ /* Swap input and output states for next round */
+ tmp = in;
+ in = out;
+ out = tmp;
+
+ } while ( --rounds );
+}
+
+/**
+ * Perform standalone AddRoundKey
+ *
+ * @v state AES state
+ * @v key AES round key
+ */
+static inline __attribute__ (( always_inline )) void
+aes_addroundkey ( union aes_matrix *state, const union aes_matrix *key ) {
+
+ state->column[0] ^= key->column[0];
+ state->column[1] ^= key->column[1];
+ state->column[2] ^= key->column[2];
+ state->column[3] ^= key->column[3];
+}
+
+/**
+ * Perform final round
+ *
+ * @v table AES lookup table
+ * @v stride AES row shift stride
+ * @v in AES input state
+ * @v out AES output state
+ * @v key AES round key
+ */
+static void aes_final ( const struct aes_table *table, size_t stride,
+ const union aes_matrix *in, union aes_matrix *out,
+ const union aes_matrix *key ) {
+ const union aes_table_entry *entry;
+ unsigned int byte;
+ size_t out_offset;
+ size_t in_offset;
+
+ /* Perform [Inv]ShiftRows and [Inv]SubBytes */
+ for ( out_offset = 0, in_offset = 0 ; out_offset < 16 ;
+ out_offset++, in_offset = ( ( in_offset + stride ) & 0xf ) ) {
+
+ /* Extract input byte (i.e. perform [Inv]ShiftRows) */
+ byte = in->byte[in_offset];
+
+ /* Locate lookup table entry for this input byte
+ * (i.e. perform [Inv]SubBytes).
+ */
+ entry = &table->entry[byte];
+
+ /* Store output byte */
+ out->byte[out_offset] = entry->byte[0];
+ }
+
+ /* Perform AddRoundKey */
+ aes_addroundkey ( out, key );
+}
+
+/**
+ * Encrypt data
+ *
+ * @v ctx Context
+ * @v src Data to encrypt
+ * @v dst Buffer for encrypted data
+ * @v len Length of data
+ */
+static void aes_encrypt ( void *ctx, const void *src, void *dst, size_t len ) {
+ struct aes_context *aes = ctx;
+ union aes_matrix buffer[2];
+ union aes_matrix *in = &buffer[0];
+ union aes_matrix *out = &buffer[1];
+ unsigned int rounds = aes->rounds;
+
+ /* Sanity check */
+ assert ( len == sizeof ( *in ) );
+
+ /* Initialise input state */
+ memcpy ( in, src, sizeof ( *in ) );
+
+ /* Perform initial round (AddRoundKey) */
+ aes_addroundkey ( in, &aes->encrypt.key[0] );
+
+ /* Perform intermediate rounds (ShiftRows, SubBytes,
+ * MixColumns, AddRoundKey).
+ */
+ aes_encrypt_rounds ( in, out, &aes->encrypt.key[1], ( rounds - 2 ) );
+ in = out;
+
+ /* Perform final round (ShiftRows, SubBytes, AddRoundKey) */
+ out = dst;
+ aes_final ( &aes_mixcolumns, AES_STRIDE_SHIFTROWS, in, out,
+ &aes->encrypt.key[ rounds - 1 ] );
+}
+
+/**
+ * Decrypt data
+ *
+ * @v ctx Context
+ * @v src Data to decrypt
+ * @v dst Buffer for decrypted data
+ * @v len Length of data
+ */
+static void aes_decrypt ( void *ctx, const void *src, void *dst, size_t len ) {
+ struct aes_context *aes = ctx;
+ union aes_matrix buffer[2];
+ union aes_matrix *in = &buffer[0];
+ union aes_matrix *out = &buffer[1];
+ unsigned int rounds = aes->rounds;
+
+ /* Sanity check */
+ assert ( len == sizeof ( *in ) );
+
+ /* Initialise input state */
+ memcpy ( in, src, sizeof ( *in ) );
+
+ /* Perform initial round (AddRoundKey) */
+ aes_addroundkey ( in, &aes->decrypt.key[0] );
+
+ /* Perform intermediate rounds (InvShiftRows, InvSubBytes,
+ * InvMixColumns, AddRoundKey).
+ */
+ aes_decrypt_rounds ( in, out, &aes->decrypt.key[1], ( rounds - 2 ) );
+ in = out;
+
+ /* Perform final round (InvShiftRows, InvSubBytes, AddRoundKey) */
+ out = dst;
+ aes_final ( &aes_invmixcolumns, AES_STRIDE_INVSHIFTROWS, in, out,
+ &aes->decrypt.key[ rounds - 1 ] );
+}
+
+/**
+ * Multiply a polynomial by (x) modulo (x^8 + x^4 + x^3 + x^2 + 1) in GF(2^8)
+ *
+ * @v poly Polynomial to be multiplied
+ * @ret result Result
+ */
+static __attribute__ (( const )) unsigned int aes_double ( unsigned int poly ) {
+
+ /* Multiply polynomial by (x), placing the resulting x^8
+ * coefficient in the LSB (i.e. rotate byte left by one).
+ */
+ poly = rol8 ( poly, 1 );
+
+ /* If coefficient of x^8 (in LSB) is non-zero, then reduce by
+ * subtracting (x^8 + x^4 + x^3 + x^2 + 1) in GF(2^8).
+ */
+ if ( poly & 0x01 ) {
+ poly ^= 0x01; /* Subtract x^8 (currently in LSB) */
+ poly ^= 0x1b; /* Subtract (x^4 + x^3 + x^2 + 1) */
+ }
+
+ return poly;
+}
+
+/**
+ * Fill in MixColumns lookup table entry
+ *
+ * @v entry AES lookup table entry for scalar multiplicand
+ *
+ * The MixColumns lookup table vector multiplier is {1,1,1,3,2,1,1,3}.
+ */
+static void aes_mixcolumns_entry ( union aes_table_entry *entry ) {
+ unsigned int scalar_x_1;
+ unsigned int scalar_x;
+ unsigned int scalar;
+
+ /* Retrieve scalar multiplicand */
+ scalar = entry->byte[0];
+ entry->byte[1] = scalar;
+ entry->byte[2] = scalar;
+ entry->byte[5] = scalar;
+ entry->byte[6] = scalar;
+
+ /* Calculate scalar multiplied by (x) */
+ scalar_x = aes_double ( scalar );
+ entry->byte[4] = scalar_x;
+
+ /* Calculate scalar multiplied by (x + 1) */
+ scalar_x_1 = ( scalar_x ^ scalar );
+ entry->byte[3] = scalar_x_1;
+ entry->byte[7] = scalar_x_1;
+}
+
+/**
+ * Fill in InvMixColumns lookup table entry
+ *
+ * @v entry AES lookup table entry for scalar multiplicand
+ *
+ * The InvMixColumns lookup table vector multiplier is {1,9,13,11,14,9,13,11}.
+ */
+static void aes_invmixcolumns_entry ( union aes_table_entry *entry ) {
+ unsigned int scalar_x3_x2_x;
+ unsigned int scalar_x3_x2_1;
+ unsigned int scalar_x3_x2;
+ unsigned int scalar_x3_x_1;
+ unsigned int scalar_x3_1;
+ unsigned int scalar_x3;
+ unsigned int scalar_x2;
+ unsigned int scalar_x;
+ unsigned int scalar;
+
+ /* Retrieve scalar multiplicand */
+ scalar = entry->byte[0];
+
+ /* Calculate scalar multiplied by (x) */
+ scalar_x = aes_double ( scalar );
+
+ /* Calculate scalar multiplied by (x^2) */
+ scalar_x2 = aes_double ( scalar_x );
+
+ /* Calculate scalar multiplied by (x^3) */
+ scalar_x3 = aes_double ( scalar_x2 );
+
+ /* Calculate scalar multiplied by (x^3 + 1) */
+ scalar_x3_1 = ( scalar_x3 ^ scalar );
+ entry->byte[1] = scalar_x3_1;
+ entry->byte[5] = scalar_x3_1;
+
+ /* Calculate scalar multiplied by (x^3 + x + 1) */
+ scalar_x3_x_1 = ( scalar_x3_1 ^ scalar_x );
+ entry->byte[3] = scalar_x3_x_1;
+ entry->byte[7] = scalar_x3_x_1;
+
+ /* Calculate scalar multiplied by (x^3 + x^2) */
+ scalar_x3_x2 = ( scalar_x3 ^ scalar_x2 );
+
+ /* Calculate scalar multiplied by (x^3 + x^2 + 1) */
+ scalar_x3_x2_1 = ( scalar_x3_x2 ^ scalar );
+ entry->byte[2] = scalar_x3_x2_1;
+ entry->byte[6] = scalar_x3_x2_1;
+
+ /* Calculate scalar multiplied by (x^3 + x^2 + x) */
+ scalar_x3_x2_x = ( scalar_x3_x2 ^ scalar_x );
+ entry->byte[4] = scalar_x3_x2_x;
+}
+
+/**
+ * Generate AES lookup tables
+ *
+ */
+static void aes_generate ( void ) {
+ union aes_table_entry *entry;
+ union aes_table_entry *inventry;
+ unsigned int poly = 0x01;
+ unsigned int invpoly = 0x01;
+ unsigned int transformed;
+ unsigned int i;
+
+ /* Iterate over non-zero values of GF(2^8) using generator (x + 1) */
+ do {
+
+ /* Multiply polynomial by (x + 1) */
+ poly ^= aes_double ( poly );
+
+ /* Divide inverse polynomial by (x + 1). This code
+ * fragment is taken directly from the Wikipedia page
+ * on the Rijndael S-box. An explanation of why it
+ * works would be greatly appreciated.
+ */
+ invpoly ^= ( invpoly << 1 );
+ invpoly ^= ( invpoly << 2 );
+ invpoly ^= ( invpoly << 4 );
+ if ( invpoly & 0x80 )
+ invpoly ^= 0x09;
+ invpoly &= 0xff;
+
+ /* Apply affine transformation */
+ transformed = ( 0x63 ^ invpoly ^ rol8 ( invpoly, 1 ) ^
+ rol8 ( invpoly, 2 ) ^ rol8 ( invpoly, 3 ) ^
+ rol8 ( invpoly, 4 ) );
+
+ /* Populate S-box (within MixColumns lookup table) */
+ aes_mixcolumns.entry[poly].byte[0] = transformed;
+
+ } while ( poly != 0x01 );
+
+ /* Populate zeroth S-box entry (which has no inverse) */
+ aes_mixcolumns.entry[0].byte[0] = 0x63;
+
+ /* Fill in MixColumns and InvMixColumns lookup tables */
+ for ( i = 0 ; i < 256 ; i++ ) {
+
+ /* Fill in MixColumns lookup table entry */
+ entry = &aes_mixcolumns.entry[i];
+ aes_mixcolumns_entry ( entry );
+
+ /* Populate inverse S-box (within InvMixColumns lookup table) */
+ inventry = &aes_invmixcolumns.entry[ entry->byte[0] ];
+ inventry->byte[0] = i;
+
+ /* Fill in InvMixColumns lookup table entry */
+ aes_invmixcolumns_entry ( inventry );
+ }
+}
+
+/**
+ * Rotate key column
+ *
+ * @v column Key column
+ * @ret column Updated key column
+ */
+static inline __attribute__ (( always_inline )) uint32_t
+aes_key_rotate ( uint32_t column ) {
+
+ return ( ( __BYTE_ORDER == __LITTLE_ENDIAN ) ?
+ ror32 ( column, 8 ) : rol32 ( column, 8 ) );
+}
+
+/**
+ * Apply S-box to key column
+ *
+ * @v column Key column
+ * @ret column Updated key column
+ */
+static uint32_t aes_key_sbox ( uint32_t column ) {
+ unsigned int i;
+ uint8_t byte;
+
+ for ( i = 0 ; i < 4 ; i++ ) {
+ byte = ( column & 0xff );
+ byte = aes_mixcolumns.entry[byte].byte[0];
+ column = ( ( column & ~0xff ) | byte );
+ column = rol32 ( column, 8 );
+ }
+ return column;
+}
+
+/**
+ * Apply schedule round constant to key column
+ *
+ * @v column Key column
+ * @v rcon Round constant
+ * @ret column Updated key column
+ */
+static inline __attribute__ (( always_inline )) uint32_t
+aes_key_rcon ( uint32_t column, unsigned int rcon ) {
+
+ return ( ( __BYTE_ORDER == __LITTLE_ENDIAN ) ?
+ ( column ^ rcon ) : ( column ^ ( rcon << 24 ) ) );
+}
+
+/**
+ * Set key
+ *
+ * @v ctx Context
+ * @v key Key
+ * @v keylen Key length
+ * @ret rc Return status code
+ */
+static int aes_setkey ( void *ctx, const void *key, size_t keylen ) {
+ struct aes_context *aes = ctx;
+ union aes_matrix *enc;
+ union aes_matrix *dec;
+ union aes_matrix temp;
+ union aes_matrix zero;
+ unsigned int rcon = 0x01;
+ unsigned int rounds;
+ size_t offset = 0;
+ uint32_t *prev;
+ uint32_t *next;
+ uint32_t *end;
+ uint32_t tmp;
+
+ /* Generate lookup tables, if not already done */
+ if ( ! aes_mixcolumns.entry[0].byte[0] )
+ aes_generate();
+
+ /* Validate key length and calculate number of intermediate rounds */
+ switch ( keylen ) {
+ case ( 128 / 8 ) :
+ rounds = 11;
+ break;
+ case ( 192 / 8 ) :
+ rounds = 13;
+ break;
+ case ( 256 / 8 ) :
+ rounds = 15;
+ break;
+ default:
+ DBGC ( aes, "AES %p unsupported key length (%zd bits)\n",
+ aes, ( keylen * 8 ) );
+ return -EINVAL;
+ }
+ aes->rounds = rounds;
+ enc = aes->encrypt.key;
+ end = enc[rounds].column;
+
+ /* Copy raw key */
+ memcpy ( enc, key, keylen );
+ prev = enc->column;
+ next = ( ( ( void * ) prev ) + keylen );
+ tmp = next[-1];
+
+ /* Construct expanded key */
+ while ( next < end ) {
+
+ /* If this is the first column of an expanded key
+ * block, or the middle column of an AES-256 key
+ * block, then apply the S-box.
+ */
+ if ( ( offset == 0 ) || ( ( offset | keylen ) == 48 ) )
+ tmp = aes_key_sbox ( tmp );
+
+ /* If this is the first column of an expanded key
+ * block then rotate and apply the round constant.
+ */
+ if ( offset == 0 ) {
+ tmp = aes_key_rotate ( tmp );
+ tmp = aes_key_rcon ( tmp, rcon );
+ rcon = aes_double ( rcon );
+ }
+
+ /* XOR with previous key column */
+ tmp ^= *prev;
+
+ /* Store column */
+ *next = tmp;
+
+ /* Move to next column */
+ offset += sizeof ( *next );
+ if ( offset == keylen )
+ offset = 0;
+ next++;
+ prev++;
+ }
+ DBGC2 ( aes, "AES %p expanded %zd-bit key:\n", aes, ( keylen * 8 ) );
+ DBGC2_HDA ( aes, 0, &aes->encrypt, ( rounds * sizeof ( *enc ) ) );
+
+ /* Convert to decryption key */
+ memset ( &zero, 0, sizeof ( zero ) );
+ dec = &aes->decrypt.key[ rounds - 1 ];
+ memcpy ( dec--, enc++, sizeof ( *dec ) );
+ while ( dec > aes->decrypt.key ) {
+ /* Perform InvMixColumns (by reusing the encryption
+ * final-round code to perform ShiftRows+SubBytes and
+ * reusing the decryption intermediate-round code to
+ * perform InvShiftRows+InvSubBytes+InvMixColumns, all
+ * with a zero encryption key).
+ */
+ aes_final ( &aes_mixcolumns, AES_STRIDE_SHIFTROWS,
+ enc++, &temp, &zero );
+ aes_decrypt_rounds ( &temp, dec--, &zero, 1 );
+ }
+ memcpy ( dec--, enc++, sizeof ( *dec ) );
+ DBGC2 ( aes, "AES %p inverted %zd-bit key:\n", aes, ( keylen * 8 ) );
+ DBGC2_HDA ( aes, 0, &aes->decrypt, ( rounds * sizeof ( *dec ) ) );
+
+ return 0;
+}
+
+/**
+ * Set initialisation vector
+ *
+ * @v ctx Context
+ * @v iv Initialisation vector
+ */
+static void aes_setiv ( void *ctx __unused, const void *iv __unused ) {
+ /* Nothing to do */
+}
+
+/** Basic AES algorithm */
+struct cipher_algorithm aes_algorithm = {
+ .name = "aes",
+ .ctxsize = sizeof ( struct aes_context ),
+ .blocksize = AES_BLOCKSIZE,
+ .setkey = aes_setkey,
+ .setiv = aes_setiv,
+ .encrypt = aes_encrypt,
+ .decrypt = aes_decrypt,
+};
+
+/* AES in Electronic Codebook mode */
+ECB_CIPHER ( aes_ecb, aes_ecb_algorithm,
+ aes_algorithm, struct aes_context, AES_BLOCKSIZE );
+
+/* AES in Cipher Block Chaining mode */
+CBC_CIPHER ( aes_cbc, aes_cbc_algorithm,
+ aes_algorithm, struct aes_context, AES_BLOCKSIZE );
diff --git a/roms/ipxe/src/crypto/asn1.c b/roms/ipxe/src/crypto/asn1.c
index 6d880704f..aca12bf30 100644
--- a/roms/ipxe/src/crypto/asn1.c
+++ b/roms/ipxe/src/crypto/asn1.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stddef.h>
diff --git a/roms/ipxe/src/crypto/axtls/aes.c b/roms/ipxe/src/crypto/axtls/aes.c
deleted file mode 100644
index bd99a7097..000000000
--- a/roms/ipxe/src/crypto/axtls/aes.c
+++ /dev/null
@@ -1,457 +0,0 @@
-/*
- * Copyright (c) 2007, Cameron Rich
- *
- * 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 axTLS project 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.
- */
-
-/**
- * AES implementation - this is a small code version. There are much faster
- * versions around but they are much larger in size (i.e. they use large
- * submix tables).
- */
-
-#include <string.h>
-#include "os_port.h"
-#include "crypto.h"
-
-/* all commented out in skeleton mode */
-#ifndef CONFIG_SSL_SKELETON_MODE
-
-#define rot1(x) (((x) << 24) | ((x) >> 8))
-#define rot2(x) (((x) << 16) | ((x) >> 16))
-#define rot3(x) (((x) << 8) | ((x) >> 24))
-
-/*
- * This cute trick does 4 'mul by two' at once. Stolen from
- * Dr B. R. Gladman <brg@gladman.uk.net> but I'm sure the u-(u>>7) is
- * a standard graphics trick
- * The key to this is that we need to xor with 0x1b if the top bit is set.
- * a 1xxx xxxx 0xxx 0xxx First we mask the 7bit,
- * b 1000 0000 0000 0000 then we shift right by 7 putting the 7bit in 0bit,
- * c 0000 0001 0000 0000 we then subtract (c) from (b)
- * d 0111 1111 0000 0000 and now we and with our mask
- * e 0001 1011 0000 0000
- */
-#define mt 0x80808080
-#define ml 0x7f7f7f7f
-#define mh 0xfefefefe
-#define mm 0x1b1b1b1b
-#define mul2(x,t) ((t)=((x)&mt), \
- ((((x)+(x))&mh)^(((t)-((t)>>7))&mm)))
-
-#define inv_mix_col(x,f2,f4,f8,f9) (\
- (f2)=mul2(x,f2), \
- (f4)=mul2(f2,f4), \
- (f8)=mul2(f4,f8), \
- (f9)=(x)^(f8), \
- (f8)=((f2)^(f4)^(f8)), \
- (f2)^=(f9), \
- (f4)^=(f9), \
- (f8)^=rot3(f2), \
- (f8)^=rot2(f4), \
- (f8)^rot1(f9))
-
-/*
- * AES S-box
- */
-static const uint8_t aes_sbox[256] =
-{
- 0x63,0x7C,0x77,0x7B,0xF2,0x6B,0x6F,0xC5,
- 0x30,0x01,0x67,0x2B,0xFE,0xD7,0xAB,0x76,
- 0xCA,0x82,0xC9,0x7D,0xFA,0x59,0x47,0xF0,
- 0xAD,0xD4,0xA2,0xAF,0x9C,0xA4,0x72,0xC0,
- 0xB7,0xFD,0x93,0x26,0x36,0x3F,0xF7,0xCC,
- 0x34,0xA5,0xE5,0xF1,0x71,0xD8,0x31,0x15,
- 0x04,0xC7,0x23,0xC3,0x18,0x96,0x05,0x9A,
- 0x07,0x12,0x80,0xE2,0xEB,0x27,0xB2,0x75,
- 0x09,0x83,0x2C,0x1A,0x1B,0x6E,0x5A,0xA0,
- 0x52,0x3B,0xD6,0xB3,0x29,0xE3,0x2F,0x84,
- 0x53,0xD1,0x00,0xED,0x20,0xFC,0xB1,0x5B,
- 0x6A,0xCB,0xBE,0x39,0x4A,0x4C,0x58,0xCF,
- 0xD0,0xEF,0xAA,0xFB,0x43,0x4D,0x33,0x85,
- 0x45,0xF9,0x02,0x7F,0x50,0x3C,0x9F,0xA8,
- 0x51,0xA3,0x40,0x8F,0x92,0x9D,0x38,0xF5,
- 0xBC,0xB6,0xDA,0x21,0x10,0xFF,0xF3,0xD2,
- 0xCD,0x0C,0x13,0xEC,0x5F,0x97,0x44,0x17,
- 0xC4,0xA7,0x7E,0x3D,0x64,0x5D,0x19,0x73,
- 0x60,0x81,0x4F,0xDC,0x22,0x2A,0x90,0x88,
- 0x46,0xEE,0xB8,0x14,0xDE,0x5E,0x0B,0xDB,
- 0xE0,0x32,0x3A,0x0A,0x49,0x06,0x24,0x5C,
- 0xC2,0xD3,0xAC,0x62,0x91,0x95,0xE4,0x79,
- 0xE7,0xC8,0x37,0x6D,0x8D,0xD5,0x4E,0xA9,
- 0x6C,0x56,0xF4,0xEA,0x65,0x7A,0xAE,0x08,
- 0xBA,0x78,0x25,0x2E,0x1C,0xA6,0xB4,0xC6,
- 0xE8,0xDD,0x74,0x1F,0x4B,0xBD,0x8B,0x8A,
- 0x70,0x3E,0xB5,0x66,0x48,0x03,0xF6,0x0E,
- 0x61,0x35,0x57,0xB9,0x86,0xC1,0x1D,0x9E,
- 0xE1,0xF8,0x98,0x11,0x69,0xD9,0x8E,0x94,
- 0x9B,0x1E,0x87,0xE9,0xCE,0x55,0x28,0xDF,
- 0x8C,0xA1,0x89,0x0D,0xBF,0xE6,0x42,0x68,
- 0x41,0x99,0x2D,0x0F,0xB0,0x54,0xBB,0x16,
-};
-
-/*
- * AES is-box
- */
-static const uint8_t aes_isbox[256] =
-{
- 0x52,0x09,0x6a,0xd5,0x30,0x36,0xa5,0x38,
- 0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb,
- 0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87,
- 0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb,
- 0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d,
- 0xee,0x4c,0x95,0x0b,0x42,0xfa,0xc3,0x4e,
- 0x08,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2,
- 0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25,
- 0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16,
- 0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92,
- 0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda,
- 0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84,
- 0x90,0xd8,0xab,0x00,0x8c,0xbc,0xd3,0x0a,
- 0xf7,0xe4,0x58,0x05,0xb8,0xb3,0x45,0x06,
- 0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0x0f,0x02,
- 0xc1,0xaf,0xbd,0x03,0x01,0x13,0x8a,0x6b,
- 0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea,
- 0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73,
- 0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85,
- 0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e,
- 0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89,
- 0x6f,0xb7,0x62,0x0e,0xaa,0x18,0xbe,0x1b,
- 0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20,
- 0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4,
- 0x1f,0xdd,0xa8,0x33,0x88,0x07,0xc7,0x31,
- 0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f,
- 0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0x0d,
- 0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef,
- 0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0,
- 0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61,
- 0x17,0x2b,0x04,0x7e,0xba,0x77,0xd6,0x26,
- 0xe1,0x69,0x14,0x63,0x55,0x21,0x0c,0x7d
-};
-
-static const unsigned char Rcon[30]=
-{
- 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,
- 0x1b,0x36,0x6c,0xd8,0xab,0x4d,0x9a,0x2f,
- 0x5e,0xbc,0x63,0xc6,0x97,0x35,0x6a,0xd4,
- 0xb3,0x7d,0xfa,0xef,0xc5,0x91,
-};
-
-/* ----- static functions ----- */
-static void AES_encrypt(const AES_CTX *ctx, uint32_t *data);
-static void AES_decrypt(const AES_CTX *ctx, uint32_t *data);
-
-/* Perform doubling in Galois Field GF(2^8) using the irreducible polynomial
- x^8+x^4+x^3+x+1 */
-static unsigned char AES_xtime(uint32_t x)
-{
- return (x&0x80) ? (x<<1)^0x1b : x<<1;
-}
-
-/**
- * Set up AES with the key/iv and cipher size.
- */
-void AES_set_key(AES_CTX *ctx, const uint8_t *key,
- const uint8_t *iv, AES_MODE mode)
-{
- int i, ii;
- uint32_t *W, tmp, tmp2;
- const unsigned char *ip;
- int words;
-
- switch (mode)
- {
- case AES_MODE_128:
- i = 10;
- words = 4;
- break;
-
- case AES_MODE_256:
- i = 14;
- words = 8;
- break;
-
- default: /* fail silently */
- return;
- }
-
- ctx->rounds = i;
- ctx->key_size = words;
- W = ctx->ks;
- for (i = 0; i < words; i+=2)
- {
- W[i+0]= ((uint32_t)key[ 0]<<24)|
- ((uint32_t)key[ 1]<<16)|
- ((uint32_t)key[ 2]<< 8)|
- ((uint32_t)key[ 3] );
- W[i+1]= ((uint32_t)key[ 4]<<24)|
- ((uint32_t)key[ 5]<<16)|
- ((uint32_t)key[ 6]<< 8)|
- ((uint32_t)key[ 7] );
- key += 8;
- }
-
- ip = Rcon;
- ii = 4 * (ctx->rounds+1);
- for (i = words; i<ii; i++)
- {
- tmp = W[i-1];
-
- if ((i % words) == 0)
- {
- tmp2 =(uint32_t)aes_sbox[(tmp )&0xff]<< 8;
- tmp2|=(uint32_t)aes_sbox[(tmp>> 8)&0xff]<<16;
- tmp2|=(uint32_t)aes_sbox[(tmp>>16)&0xff]<<24;
- tmp2|=(uint32_t)aes_sbox[(tmp>>24) ];
- tmp=tmp2^(((unsigned int)*ip)<<24);
- ip++;
- }
-
- if ((words == 8) && ((i % words) == 4))
- {
- tmp2 =(uint32_t)aes_sbox[(tmp )&0xff] ;
- tmp2|=(uint32_t)aes_sbox[(tmp>> 8)&0xff]<< 8;
- tmp2|=(uint32_t)aes_sbox[(tmp>>16)&0xff]<<16;
- tmp2|=(uint32_t)aes_sbox[(tmp>>24) ]<<24;
- tmp=tmp2;
- }
-
- W[i]=W[i-words]^tmp;
- }
-
- /* copy the iv across */
- memcpy(ctx->iv, iv, 16);
-}
-
-/**
- * Change a key for decryption.
- */
-void AES_convert_key(AES_CTX *ctx)
-{
- int i;
- uint32_t *k,w,t1,t2,t3,t4;
-
- k = ctx->ks;
- k += 4;
-
- for (i= ctx->rounds*4; i > 4; i--)
- {
- w= *k;
- w = inv_mix_col(w,t1,t2,t3,t4);
- *k++ =w;
- }
-}
-
-/**
- * Encrypt a byte sequence (with a block size 16) using the AES cipher.
- */
-void AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length)
-{
- int i;
- uint32_t tin[4], tout[4], iv[4];
-
- memcpy(iv, ctx->iv, AES_IV_SIZE);
- for (i = 0; i < 4; i++)
- tout[i] = ntohl(iv[i]);
-
- for (length -= AES_BLOCKSIZE; length >= 0; length -= AES_BLOCKSIZE)
- {
- uint32_t msg_32[4];
- uint32_t out_32[4];
- memcpy(msg_32, msg, AES_BLOCKSIZE);
- msg += AES_BLOCKSIZE;
-
- for (i = 0; i < 4; i++)
- tin[i] = ntohl(msg_32[i])^tout[i];
-
- AES_encrypt(ctx, tin);
-
- for (i = 0; i < 4; i++)
- {
- tout[i] = tin[i];
- out_32[i] = htonl(tout[i]);
- }
-
- memcpy(out, out_32, AES_BLOCKSIZE);
- out += AES_BLOCKSIZE;
- }
-
- for (i = 0; i < 4; i++)
- iv[i] = htonl(tout[i]);
- memcpy(ctx->iv, iv, AES_IV_SIZE);
-}
-
-/**
- * Decrypt a byte sequence (with a block size 16) using the AES cipher.
- */
-void AES_cbc_decrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length)
-{
- int i;
- uint32_t tin[4], xor[4], tout[4], data[4], iv[4];
-
- memcpy(iv, ctx->iv, AES_IV_SIZE);
- for (i = 0; i < 4; i++)
- xor[i] = ntohl(iv[i]);
-
- for (length -= 16; length >= 0; length -= 16)
- {
- uint32_t msg_32[4];
- uint32_t out_32[4];
- memcpy(msg_32, msg, AES_BLOCKSIZE);
- msg += AES_BLOCKSIZE;
-
- for (i = 0; i < 4; i++)
- {
- tin[i] = ntohl(msg_32[i]);
- data[i] = tin[i];
- }
-
- AES_decrypt(ctx, data);
-
- for (i = 0; i < 4; i++)
- {
- tout[i] = data[i]^xor[i];
- xor[i] = tin[i];
- out_32[i] = htonl(tout[i]);
- }
-
- memcpy(out, out_32, AES_BLOCKSIZE);
- out += AES_BLOCKSIZE;
- }
-
- for (i = 0; i < 4; i++)
- iv[i] = htonl(xor[i]);
- memcpy(ctx->iv, iv, AES_IV_SIZE);
-}
-
-/**
- * Encrypt a single block (16 bytes) of data
- */
-static void AES_encrypt(const AES_CTX *ctx, uint32_t *data)
-{
- /* To make this code smaller, generate the sbox entries on the fly.
- * This will have a really heavy effect upon performance.
- */
- uint32_t tmp[4];
- uint32_t tmp1, old_a0, a0, a1, a2, a3, row;
- int curr_rnd;
- int rounds = ctx->rounds;
- const uint32_t *k = ctx->ks;
-
- /* Pre-round key addition */
- for (row = 0; row < 4; row++)
- data[row] ^= *(k++);
-
- /* Encrypt one block. */
- for (curr_rnd = 0; curr_rnd < rounds; curr_rnd++)
- {
- /* Perform ByteSub and ShiftRow operations together */
- for (row = 0; row < 4; row++)
- {
- a0 = (uint32_t)aes_sbox[(data[row%4]>>24)&0xFF];
- a1 = (uint32_t)aes_sbox[(data[(row+1)%4]>>16)&0xFF];
- a2 = (uint32_t)aes_sbox[(data[(row+2)%4]>>8)&0xFF];
- a3 = (uint32_t)aes_sbox[(data[(row+3)%4])&0xFF];
-
- /* Perform MixColumn iff not last round */
- if (curr_rnd < (rounds - 1))
- {
- tmp1 = a0 ^ a1 ^ a2 ^ a3;
- old_a0 = a0;
- a0 ^= tmp1 ^ AES_xtime(a0 ^ a1);
- a1 ^= tmp1 ^ AES_xtime(a1 ^ a2);
- a2 ^= tmp1 ^ AES_xtime(a2 ^ a3);
- a3 ^= tmp1 ^ AES_xtime(a3 ^ old_a0);
- }
-
- tmp[row] = ((a0 << 24) | (a1 << 16) | (a2 << 8) | a3);
- }
-
- /* KeyAddition - note that it is vital that this loop is separate from
- the MixColumn operation, which must be atomic...*/
- for (row = 0; row < 4; row++)
- data[row] = tmp[row] ^ *(k++);
- }
-}
-
-/**
- * Decrypt a single block (16 bytes) of data
- */
-static void AES_decrypt(const AES_CTX *ctx, uint32_t *data)
-{
- uint32_t tmp[4];
- uint32_t xt0,xt1,xt2,xt3,xt4,xt5,xt6;
- uint32_t a0, a1, a2, a3, row;
- int curr_rnd;
- int rounds = ctx->rounds;
- const uint32_t *k = ctx->ks + ((rounds+1)*4);
-
- /* pre-round key addition */
- for (row=4; row > 0;row--)
- data[row-1] ^= *(--k);
-
- /* Decrypt one block */
- for (curr_rnd = 0; curr_rnd < rounds; curr_rnd++)
- {
- /* Perform ByteSub and ShiftRow operations together */
- for (row = 4; row > 0; row--)
- {
- a0 = aes_isbox[(data[(row+3)%4]>>24)&0xFF];
- a1 = aes_isbox[(data[(row+2)%4]>>16)&0xFF];
- a2 = aes_isbox[(data[(row+1)%4]>>8)&0xFF];
- a3 = aes_isbox[(data[row%4])&0xFF];
-
- /* Perform MixColumn iff not last round */
- if (curr_rnd<(rounds-1))
- {
- /* The MDS cofefficients (0x09, 0x0B, 0x0D, 0x0E)
- are quite large compared to encryption; this
- operation slows decryption down noticeably. */
- xt0 = AES_xtime(a0^a1);
- xt1 = AES_xtime(a1^a2);
- xt2 = AES_xtime(a2^a3);
- xt3 = AES_xtime(a3^a0);
- xt4 = AES_xtime(xt0^xt1);
- xt5 = AES_xtime(xt1^xt2);
- xt6 = AES_xtime(xt4^xt5);
-
- xt0 ^= a1^a2^a3^xt4^xt6;
- xt1 ^= a0^a2^a3^xt5^xt6;
- xt2 ^= a0^a1^a3^xt4^xt6;
- xt3 ^= a0^a1^a2^xt5^xt6;
- tmp[row-1] = ((xt0<<24)|(xt1<<16)|(xt2<<8)|xt3);
- }
- else
- tmp[row-1] = ((a0<<24)|(a1<<16)|(a2<<8)|a3);
- }
-
- for (row = 4; row > 0; row--)
- data[row-1] = tmp[row-1] ^ *(--k);
- }
-}
-
-#endif
diff --git a/roms/ipxe/src/crypto/axtls/bigint.h b/roms/ipxe/src/crypto/axtls/bigint.h
deleted file mode 100644
index 1f38c53d6..000000000
--- a/roms/ipxe/src/crypto/axtls/bigint.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (c) 2007, Cameron Rich
- *
- * 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 axTLS project 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.
- */
-
-#ifndef BIGINT_HEADER
-#define BIGINT_HEADER
-
-#include "crypto.h"
-
-BI_CTX *bi_initialize(void);
-void bi_terminate(BI_CTX *ctx);
-void bi_permanent(bigint *bi);
-void bi_depermanent(bigint *bi);
-void bi_clear_cache(BI_CTX *ctx);
-void bi_free(BI_CTX *ctx, bigint *bi);
-bigint *bi_copy(bigint *bi);
-bigint *bi_clone(BI_CTX *ctx, const bigint *bi);
-void bi_export(BI_CTX *ctx, bigint *bi, uint8_t *data, int size);
-bigint *bi_import(BI_CTX *ctx, const uint8_t *data, int len);
-bigint *int_to_bi(BI_CTX *ctx, comp i);
-
-/* the functions that actually do something interesting */
-bigint *bi_add(BI_CTX *ctx, bigint *bia, bigint *bib);
-bigint *bi_subtract(BI_CTX *ctx, bigint *bia,
- bigint *bib, int *is_negative);
-bigint *bi_divide(BI_CTX *ctx, bigint *bia, bigint *bim, int is_mod);
-bigint *bi_multiply(BI_CTX *ctx, bigint *bia, bigint *bib);
-bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp);
-bigint *bi_mod_power2(BI_CTX *ctx, bigint *bi, bigint *bim, bigint *biexp);
-int bi_compare(bigint *bia, bigint *bib);
-void bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset);
-void bi_free_mod(BI_CTX *ctx, int mod_offset);
-
-#ifdef CONFIG_SSL_FULL_MODE
-void bi_print(const char *label, bigint *bi);
-bigint *bi_str_import(BI_CTX *ctx, const char *data);
-#endif
-
-/**
- * @def bi_mod
- * Find the residue of B. bi_set_mod() must be called before hand.
- */
-#define bi_mod(A, B) bi_divide(A, B, ctx->bi_mod[ctx->mod_offset], 1)
-
-/**
- * bi_residue() is technically the same as bi_mod(), but it uses the
- * appropriate reduction technique (which is bi_mod() when doing classical
- * reduction).
- */
-#if defined(CONFIG_BIGINT_MONTGOMERY)
-#define bi_residue(A, B) bi_mont(A, B)
-bigint *bi_mont(BI_CTX *ctx, bigint *bixy);
-#elif defined(CONFIG_BIGINT_BARRETT)
-#define bi_residue(A, B) bi_barrett(A, B)
-bigint *bi_barrett(BI_CTX *ctx, bigint *bi);
-#else /* if defined(CONFIG_BIGINT_CLASSICAL) */
-#define bi_residue(A, B) bi_mod(A, B)
-#endif
-
-#ifdef CONFIG_BIGINT_SQUARE
-bigint *bi_square(BI_CTX *ctx, bigint *bi);
-#else
-#define bi_square(A, B) bi_multiply(A, bi_copy(B), B)
-#endif
-
-#ifdef CONFIG_BIGINT_CRT
-bigint *bi_crt(BI_CTX *ctx, bigint *bi,
- bigint *dP, bigint *dQ,
- bigint *p, bigint *q,
- bigint *qInv);
-#endif
-
-#endif
diff --git a/roms/ipxe/src/crypto/axtls/bigint_impl.h b/roms/ipxe/src/crypto/axtls/bigint_impl.h
deleted file mode 100644
index 09d8550ea..000000000
--- a/roms/ipxe/src/crypto/axtls/bigint_impl.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (c) 2007, Cameron Rich
- *
- * 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 axTLS project 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.
- */
-
-#ifndef BIGINT_IMPL_HEADER
-#define BIGINT_IMPL_HEADER
-
-/* Maintain a number of precomputed variables when doing reduction */
-#define BIGINT_M_OFFSET 0 /**< Normal modulo offset. */
-#ifdef CONFIG_BIGINT_CRT
-#define BIGINT_P_OFFSET 1 /**< p modulo offset. */
-#define BIGINT_Q_OFFSET 2 /**< q module offset. */
-#define BIGINT_NUM_MODS 3 /**< The number of modulus constants used. */
-#else
-#define BIGINT_NUM_MODS 1
-#endif
-
-/* Architecture specific functions for big ints */
-#if defined(CONFIG_INTEGER_8BIT)
-#define COMP_RADIX 256U /**< Max component + 1 */
-#define COMP_MAX 0xFFFFU/**< (Max dbl comp -1) */
-#define COMP_BIT_SIZE 8 /**< Number of bits in a component. */
-#define COMP_BYTE_SIZE 1 /**< Number of bytes in a component. */
-#define COMP_NUM_NIBBLES 2 /**< Used For diagnostics only. */
-typedef uint8_t comp; /**< A single precision component. */
-typedef uint16_t long_comp; /**< A double precision component. */
-typedef int16_t slong_comp; /**< A signed double precision component. */
-#elif defined(CONFIG_INTEGER_16BIT)
-#define COMP_RADIX 65536U /**< Max component + 1 */
-#define COMP_MAX 0xFFFFFFFFU/**< (Max dbl comp -1) */
-#define COMP_BIT_SIZE 16 /**< Number of bits in a component. */
-#define COMP_BYTE_SIZE 2 /**< Number of bytes in a component. */
-#define COMP_NUM_NIBBLES 4 /**< Used For diagnostics only. */
-typedef uint16_t comp; /**< A single precision component. */
-typedef uint32_t long_comp; /**< A double precision component. */
-typedef int32_t slong_comp; /**< A signed double precision component. */
-#else /* regular 32 bit */
-#ifdef WIN32
-#define COMP_RADIX 4294967296i64
-#define COMP_MAX 0xFFFFFFFFFFFFFFFFui64
-#else
-#define COMP_RADIX 4294967296ULL /**< Max component + 1 */
-#define COMP_MAX 0xFFFFFFFFFFFFFFFFULL/**< (Max dbl comp -1) */
-#endif
-#define COMP_BIT_SIZE 32 /**< Number of bits in a component. */
-#define COMP_BYTE_SIZE 4 /**< Number of bytes in a component. */
-#define COMP_NUM_NIBBLES 8 /**< Used For diagnostics only. */
-typedef uint32_t comp; /**< A single precision component. */
-typedef uint64_t long_comp; /**< A double precision component. */
-typedef int64_t slong_comp; /**< A signed double precision component. */
-#endif
-
-/**
- * @struct _bigint
- * @brief A big integer basic object
- */
-struct _bigint
-{
- struct _bigint* next; /**< The next bigint in the cache. */
- short size; /**< The number of components in this bigint. */
- short max_comps; /**< The heapsize allocated for this bigint */
- int refs; /**< An internal reference count. */
- comp* comps; /**< A ptr to the actual component data */
-};
-
-typedef struct _bigint bigint; /**< An alias for _bigint */
-
-/**
- * Maintains the state of the cache, and a number of variables used in
- * reduction.
- */
-typedef struct /**< A big integer "session" context. */
-{
- bigint *active_list; /**< Bigints currently used. */
- bigint *free_list; /**< Bigints not used. */
- bigint *bi_radix; /**< The radix used. */
- bigint *bi_mod[BIGINT_NUM_MODS]; /**< modulus */
-
-#if defined(CONFIG_BIGINT_MONTGOMERY)
- bigint *bi_RR_mod_m[BIGINT_NUM_MODS]; /**< R^2 mod m */
- bigint *bi_R_mod_m[BIGINT_NUM_MODS]; /**< R mod m */
- comp N0_dash[BIGINT_NUM_MODS];
-#elif defined(CONFIG_BIGINT_BARRETT)
- bigint *bi_mu[BIGINT_NUM_MODS]; /**< Storage for mu */
-#endif
- bigint *bi_normalised_mod[BIGINT_NUM_MODS]; /**< Normalised mod storage. */
- bigint **g; /**< Used by sliding-window. */
- int window; /**< The size of the sliding window */
- int active_count; /**< Number of active bigints. */
- int free_count; /**< Number of free bigints. */
-
-#ifdef CONFIG_BIGINT_MONTGOMERY
- uint8_t use_classical; /**< Use classical reduction. */
-#endif
- uint8_t mod_offset; /**< The mod offset we are using */
-} BI_CTX;
-
-#ifndef WIN32
-#define max(a,b) ((a)>(b)?(a):(b)) /**< Find the maximum of 2 numbers. */
-#define min(a,b) ((a)<(b)?(a):(b)) /**< Find the minimum of 2 numbers. */
-#endif
-
-#define PERMANENT 0x7FFF55AA /**< A magic number for permanents. */
-
-#endif
diff --git a/roms/ipxe/src/crypto/axtls/config.h b/roms/ipxe/src/crypto/axtls/config.h
deleted file mode 100644
index 32fa3bf03..000000000
--- a/roms/ipxe/src/crypto/axtls/config.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef AXTLS_CONFIG_H
-#define AXTLS_CONFIG_H
-
-/**
- * @file config.h
- *
- * Trick the axtls code into building within our build environment.
- */
-
-#define CONFIG_SSL_ENABLE_CLIENT 1
-#define CONFIG_BIGINT_CLASSICAL 1
-
-#endif
diff --git a/roms/ipxe/src/crypto/axtls/crypto.h b/roms/ipxe/src/crypto/axtls/crypto.h
deleted file mode 100644
index 2c4cda4de..000000000
--- a/roms/ipxe/src/crypto/axtls/crypto.h
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Copyright (c) 2007, Cameron Rich
- *
- * 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 axTLS project 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.
- */
-
-/**
- * @file crypto.h
- */
-
-#ifndef HEADER_CRYPTO_H
-#define HEADER_CRYPTO_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "config.h"
-#include "bigint_impl.h"
-#include "bigint.h"
-
-#ifndef STDCALL
-#define STDCALL
-#endif
-#ifndef EXP_FUNC
-#define EXP_FUNC
-#endif
-
-
-/* enable features based on a 'super-set' capbaility. */
-#if defined(CONFIG_SSL_FULL_MODE)
-#define CONFIG_SSL_ENABLE_CLIENT
-#define CONFIG_SSL_CERT_VERIFICATION
-#elif defined(CONFIG_SSL_ENABLE_CLIENT)
-#define CONFIG_SSL_CERT_VERIFICATION
-#endif
-
-/**************************************************************************
- * AES declarations
- **************************************************************************/
-
-#define AES_MAXROUNDS 14
-#define AES_BLOCKSIZE 16
-#define AES_IV_SIZE 16
-
-typedef struct aes_key_st
-{
- uint16_t rounds;
- uint16_t key_size;
- uint32_t ks[(AES_MAXROUNDS+1)*8];
- uint8_t iv[AES_IV_SIZE];
-} AES_CTX;
-
-typedef enum
-{
- AES_MODE_128,
- AES_MODE_256
-} AES_MODE;
-
-void AES_set_key(AES_CTX *ctx, const uint8_t *key,
- const uint8_t *iv, AES_MODE mode);
-void AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg,
- uint8_t *out, int length);
-void AES_cbc_decrypt(AES_CTX *ks, const uint8_t *in, uint8_t *out, int length);
-void AES_convert_key(AES_CTX *ctx);
-
-/**************************************************************************
- * RC4 declarations
- **************************************************************************/
-
-typedef struct
-{
- uint8_t x, y, m[256];
-} RC4_CTX;
-
-void RC4_setup(RC4_CTX *s, const uint8_t *key, int length);
-void RC4_crypt(RC4_CTX *s, const uint8_t *msg, uint8_t *data, int length);
-
-/**************************************************************************
- * SHA1 declarations
- **************************************************************************/
-
-#define SHA1_SIZE 20
-
-/*
- * This structure will hold context information for the SHA-1
- * hashing operation
- */
-typedef struct
-{
- uint32_t Intermediate_Hash[SHA1_SIZE/4]; /* Message Digest */
- uint32_t Length_Low; /* Message length in bits */
- uint32_t Length_High; /* Message length in bits */
- uint16_t Message_Block_Index; /* Index into message block array */
- uint8_t Message_Block[64]; /* 512-bit message blocks */
-} SHA1_CTX;
-
-void SHA1_Init(SHA1_CTX *);
-void SHA1_Update(SHA1_CTX *, const uint8_t * msg, int len);
-void SHA1_Final(uint8_t *digest, SHA1_CTX *);
-
-/**************************************************************************
- * MD2 declarations
- **************************************************************************/
-
-#define MD2_SIZE 16
-
-typedef struct
-{
- unsigned char cksum[16]; /* checksum of the data block */
- unsigned char state[48]; /* intermediate digest state */
- unsigned char buffer[16]; /* data block being processed */
- int left; /* amount of data in buffer */
-} MD2_CTX;
-
-EXP_FUNC void STDCALL MD2_Init(MD2_CTX *ctx);
-EXP_FUNC void STDCALL MD2_Update(MD2_CTX *ctx, const uint8_t *input, int ilen);
-EXP_FUNC void STDCALL MD2_Final(uint8_t *digest, MD2_CTX *ctx);
-
-/**************************************************************************
- * MD5 declarations
- **************************************************************************/
-
-#define MD5_SIZE 16
-
-typedef struct
-{
- uint32_t state[4]; /* state (ABCD) */
- uint32_t count[2]; /* number of bits, modulo 2^64 (lsb first) */
- uint8_t buffer[64]; /* input buffer */
-} MD5_CTX;
-
-EXP_FUNC void STDCALL MD5_Init(MD5_CTX *);
-EXP_FUNC void STDCALL MD5_Update(MD5_CTX *, const uint8_t *msg, int len);
-EXP_FUNC void STDCALL MD5_Final(uint8_t *digest, MD5_CTX *);
-
-/**************************************************************************
- * HMAC declarations
- **************************************************************************/
-void hmac_md5(const uint8_t *msg, int length, const uint8_t *key,
- int key_len, uint8_t *digest);
-void hmac_sha1(const uint8_t *msg, int length, const uint8_t *key,
- int key_len, uint8_t *digest);
-
-/**************************************************************************
- * RSA declarations
- **************************************************************************/
-
-typedef struct
-{
- bigint *m; /* modulus */
- bigint *e; /* public exponent */
- bigint *d; /* private exponent */
-#ifdef CONFIG_BIGINT_CRT
- bigint *p; /* p as in m = pq */
- bigint *q; /* q as in m = pq */
- bigint *dP; /* d mod (p-1) */
- bigint *dQ; /* d mod (q-1) */
- bigint *qInv; /* q^-1 mod p */
-#endif
- int num_octets;
- BI_CTX *bi_ctx;
-} RSA_CTX;
-
-void RSA_priv_key_new(RSA_CTX **rsa_ctx,
- const uint8_t *modulus, int mod_len,
- const uint8_t *pub_exp, int pub_len,
- const uint8_t *priv_exp, int priv_len
-#ifdef CONFIG_BIGINT_CRT
- , const uint8_t *p, int p_len,
- const uint8_t *q, int q_len,
- const uint8_t *dP, int dP_len,
- const uint8_t *dQ, int dQ_len,
- const uint8_t *qInv, int qInv_len
-#endif
- );
-void RSA_pub_key_new(RSA_CTX **rsa_ctx,
- const uint8_t *modulus, int mod_len,
- const uint8_t *pub_exp, int pub_len);
-void RSA_free(RSA_CTX *ctx);
-int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint8_t *out_data,
- int is_decryption);
-bigint *RSA_private(const RSA_CTX *c, bigint *bi_msg);
-#if defined(CONFIG_SSL_CERT_VERIFICATION) || defined(CONFIG_SSL_GENERATE_X509_CERT)
-bigint *RSA_sign_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len,
- bigint *modulus, bigint *pub_exp);
-bigint *RSA_public(const RSA_CTX * c, bigint *bi_msg);
-int RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len,
- uint8_t *out_data, int is_signing);
-void RSA_print(const RSA_CTX *ctx);
-#endif
-
-/**************************************************************************
- * RNG declarations
- **************************************************************************/
-EXP_FUNC void STDCALL RNG_initialize(const uint8_t *seed_buf, int size);
-EXP_FUNC void STDCALL RNG_terminate(void);
-EXP_FUNC void STDCALL get_random(int num_rand_bytes, uint8_t *rand_data);
-void get_random_NZ(int num_rand_bytes, uint8_t *rand_data);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/roms/ipxe/src/crypto/axtls/os_port.h b/roms/ipxe/src/crypto/axtls/os_port.h
deleted file mode 100644
index 76313e204..000000000
--- a/roms/ipxe/src/crypto/axtls/os_port.h
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef AXTLS_OS_PORT_H
-#define AXTLS_OS_PORT_H
-
-/**
- * @file os_port.h
- *
- * Trick the axtls code into building within our build environment.
- */
-
-#include <stdint.h>
-#include <byteswap.h>
-
-/** All imported axTLS files are licensed using the three-clause BSD licence */
-FILE_LICENCE ( BSD3 );
-
-/** We can't actually abort, since we are effectively a kernel... */
-#define abort() assert ( 0 )
-
-/** rsa.c uses alloca() */
-#define alloca( size ) __builtin_alloca ( size )
-
-#include <ipxe/random_nz.h>
-static inline void get_random_NZ ( int num_rand_bytes, uint8_t *rand_data ) {
- /* AXTLS does not check for failures when generating random
- * data. Rely on the fact that get_random_nz() does not
- * request prediction resistance (and so cannot introduce new
- * failures) and therefore any potential failure must already
- * have been encountered by e.g. tls_generate_random(), which
- * does check for failures.
- */
- get_random_nz ( rand_data, num_rand_bytes );
-}
-
-/* Expose AES_encrypt() and AES_decrypt() in aes.o */
-#define aes 1
-#if OBJECT
-
-struct aes_key_st;
-
-static void AES_encrypt ( const struct aes_key_st *ctx, uint32_t *data );
-static void AES_decrypt ( const struct aes_key_st *ctx, uint32_t *data );
-
-void axtls_aes_encrypt ( void *ctx, uint32_t *data ) {
- AES_encrypt ( ctx, data );
-}
-
-void axtls_aes_decrypt ( void *ctx, uint32_t *data ) {
- AES_decrypt ( ctx, data );
-}
-
-#endif
-#undef aes
-
-#endif
diff --git a/roms/ipxe/src/crypto/axtls_aes.c b/roms/ipxe/src/crypto/axtls_aes.c
deleted file mode 100644
index 7f93c0ed7..000000000
--- a/roms/ipxe/src/crypto/axtls_aes.c
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#include <string.h>
-#include <errno.h>
-#include <assert.h>
-#include <byteswap.h>
-#include <ipxe/crypto.h>
-#include <ipxe/cbc.h>
-#include <ipxe/aes.h>
-#include "crypto/axtls/crypto.h"
-
-/** @file
- *
- * AES algorithm
- *
- */
-
-/**
- * Set key
- *
- * @v ctx Context
- * @v key Key
- * @v keylen Key length
- * @ret rc Return status code
- */
-static int aes_setkey ( void *ctx, const void *key, size_t keylen ) {
- struct aes_context *aes_ctx = ctx;
- AES_MODE mode;
- void *iv;
-
- switch ( keylen ) {
- case ( 128 / 8 ):
- mode = AES_MODE_128;
- break;
- case ( 256 / 8 ):
- mode = AES_MODE_256;
- break;
- default:
- return -EINVAL;
- }
-
- /* IV is not a relevant concept at this stage; use a dummy
- * value that will have no side-effects.
- */
- iv = &aes_ctx->axtls_ctx.iv;
-
- AES_set_key ( &aes_ctx->axtls_ctx, key, iv, mode );
-
- aes_ctx->decrypting = 0;
-
- return 0;
-}
-
-/**
- * Set initialisation vector
- *
- * @v ctx Context
- * @v iv Initialisation vector
- */
-static void aes_setiv ( void *ctx __unused, const void *iv __unused ) {
- /* Nothing to do */
-}
-
-/**
- * Call AXTLS' AES_encrypt() or AES_decrypt() functions
- *
- * @v axtls_ctx AXTLS AES context
- * @v src Data to process
- * @v dst Buffer for output
- * @v func AXTLS AES function to call
- */
-static void aes_call_axtls ( AES_CTX *axtls_ctx, const void *src, void *dst,
- void ( * func ) ( const AES_CTX *axtls_ctx,
- uint32_t *data ) ){
- const uint32_t *srcl = src;
- uint32_t *dstl = dst;
- unsigned int i;
-
- /* AXTLS' AES_encrypt() and AES_decrypt() functions both
- * expect to deal with an array of four dwords in host-endian
- * order.
- */
- for ( i = 0 ; i < 4 ; i++ )
- dstl[i] = ntohl ( srcl[i] );
- func ( axtls_ctx, dstl );
- for ( i = 0 ; i < 4 ; i++ )
- dstl[i] = htonl ( dstl[i] );
-}
-
-/**
- * Encrypt data
- *
- * @v ctx Context
- * @v src Data to encrypt
- * @v dst Buffer for encrypted data
- * @v len Length of data
- */
-static void aes_encrypt ( void *ctx, const void *src, void *dst,
- size_t len ) {
- struct aes_context *aes_ctx = ctx;
-
- assert ( len == AES_BLOCKSIZE );
- if ( aes_ctx->decrypting )
- assert ( 0 );
- aes_call_axtls ( &aes_ctx->axtls_ctx, src, dst, axtls_aes_encrypt );
-}
-
-/**
- * Decrypt data
- *
- * @v ctx Context
- * @v src Data to decrypt
- * @v dst Buffer for decrypted data
- * @v len Length of data
- */
-static void aes_decrypt ( void *ctx, const void *src, void *dst,
- size_t len ) {
- struct aes_context *aes_ctx = ctx;
-
- assert ( len == AES_BLOCKSIZE );
- if ( ! aes_ctx->decrypting ) {
- AES_convert_key ( &aes_ctx->axtls_ctx );
- aes_ctx->decrypting = 1;
- }
- aes_call_axtls ( &aes_ctx->axtls_ctx, src, dst, axtls_aes_decrypt );
-}
-
-/** Basic AES algorithm */
-struct cipher_algorithm aes_algorithm = {
- .name = "aes",
- .ctxsize = sizeof ( struct aes_context ),
- .blocksize = AES_BLOCKSIZE,
- .setkey = aes_setkey,
- .setiv = aes_setiv,
- .encrypt = aes_encrypt,
- .decrypt = aes_decrypt,
-};
-
-/* AES with cipher-block chaining */
-CBC_CIPHER ( aes_cbc, aes_cbc_algorithm,
- aes_algorithm, struct aes_context, AES_BLOCKSIZE );
diff --git a/roms/ipxe/src/crypto/bigint.c b/roms/ipxe/src/crypto/bigint.c
index 340128e2f..50f320302 100644
--- a/roms/ipxe/src/crypto/bigint.c
+++ b/roms/ipxe/src/crypto/bigint.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <string.h>
diff --git a/roms/ipxe/src/crypto/cbc.c b/roms/ipxe/src/crypto/cbc.c
index 9bf0e8b49..0ba17ee48 100644
--- a/roms/ipxe/src/crypto/cbc.c
+++ b/roms/ipxe/src/crypto/cbc.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <assert.h>
diff --git a/roms/ipxe/src/crypto/certstore.c b/roms/ipxe/src/crypto/certstore.c
index 77cf6ebb6..503ce499e 100644
--- a/roms/ipxe/src/crypto/certstore.c
+++ b/roms/ipxe/src/crypto/certstore.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/crypto/chap.c b/roms/ipxe/src/crypto/chap.c
index db64371c7..c90c16def 100644
--- a/roms/ipxe/src/crypto/chap.c
+++ b/roms/ipxe/src/crypto/chap.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/crypto/cms.c b/roms/ipxe/src/crypto/cms.c
index b4a41de6c..bc2148e8a 100644
--- a/roms/ipxe/src/crypto/cms.c
+++ b/roms/ipxe/src/crypto/cms.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/crypto/crypto_null.c b/roms/ipxe/src/crypto/crypto_null.c
index ba05f7269..15a1c538b 100644
--- a/roms/ipxe/src/crypto/crypto_null.c
+++ b/roms/ipxe/src/crypto/crypto_null.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @file
diff --git a/roms/ipxe/src/crypto/deflate.c b/roms/ipxe/src/crypto/deflate.c
index 91a489961..e1c87d5fe 100644
--- a/roms/ipxe/src/crypto/deflate.c
+++ b/roms/ipxe/src/crypto/deflate.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <strings.h>
diff --git a/roms/ipxe/src/crypto/drbg.c b/roms/ipxe/src/crypto/drbg.c
index 9e0175d25..5c8b5e612 100644
--- a/roms/ipxe/src/crypto/drbg.c
+++ b/roms/ipxe/src/crypto/drbg.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/crypto/ecb.c b/roms/ipxe/src/crypto/ecb.c
new file mode 100644
index 000000000..3c9cf340c
--- /dev/null
+++ b/roms/ipxe/src/crypto/ecb.c
@@ -0,0 +1,80 @@
+/*
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <assert.h>
+#include <ipxe/crypto.h>
+#include <ipxe/ecb.h>
+
+/** @file
+ *
+ * Electronic codebook (ECB)
+ *
+ */
+
+/**
+ * Encrypt data
+ *
+ * @v ctx Context
+ * @v src Data to encrypt
+ * @v dst Buffer for encrypted data
+ * @v len Length of data
+ * @v raw_cipher Underlying cipher algorithm
+ */
+void ecb_encrypt ( void *ctx, const void *src, void *dst, size_t len,
+ struct cipher_algorithm *raw_cipher ) {
+ size_t blocksize = raw_cipher->blocksize;
+
+ assert ( ( len % blocksize ) == 0 );
+
+ while ( len ) {
+ cipher_encrypt ( raw_cipher, ctx, src, dst, blocksize );
+ dst += blocksize;
+ src += blocksize;
+ len -= blocksize;
+ }
+}
+
+/**
+ * Decrypt data
+ *
+ * @v ctx Context
+ * @v src Data to decrypt
+ * @v dst Buffer for decrypted data
+ * @v len Length of data
+ * @v raw_cipher Underlying cipher algorithm
+ */
+void ecb_decrypt ( void *ctx, const void *src, void *dst, size_t len,
+ struct cipher_algorithm *raw_cipher ) {
+ size_t blocksize = raw_cipher->blocksize;
+
+ assert ( ( len % blocksize ) == 0 );
+
+ while ( len ) {
+ cipher_decrypt ( raw_cipher, ctx, src, dst, blocksize );
+ dst += blocksize;
+ src += blocksize;
+ len -= blocksize;
+ }
+}
diff --git a/roms/ipxe/src/crypto/entropy.c b/roms/ipxe/src/crypto/entropy.c
index c7045840e..5acbc0258 100644
--- a/roms/ipxe/src/crypto/entropy.c
+++ b/roms/ipxe/src/crypto/entropy.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/crypto/hash_df.c b/roms/ipxe/src/crypto/hash_df.c
index adf1d87e4..c1417e683 100644
--- a/roms/ipxe/src/crypto/hash_df.c
+++ b/roms/ipxe/src/crypto/hash_df.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/crypto/hmac.c b/roms/ipxe/src/crypto/hmac.c
index e9459198c..95a46195c 100644
--- a/roms/ipxe/src/crypto/hmac.c
+++ b/roms/ipxe/src/crypto/hmac.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @file
diff --git a/roms/ipxe/src/crypto/hmac_drbg.c b/roms/ipxe/src/crypto/hmac_drbg.c
index 1e5f732e2..6c1d5deb2 100644
--- a/roms/ipxe/src/crypto/hmac_drbg.c
+++ b/roms/ipxe/src/crypto/hmac_drbg.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/crypto/md5.c b/roms/ipxe/src/crypto/md5.c
index 122c7d59e..f9738b0ac 100644
--- a/roms/ipxe/src/crypto/md5.c
+++ b/roms/ipxe/src/crypto/md5.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/crypto/mishmash/rsa_aes_cbc_sha1.c b/roms/ipxe/src/crypto/mishmash/rsa_aes_cbc_sha1.c
new file mode 100644
index 000000000..06722c0e1
--- /dev/null
+++ b/roms/ipxe/src/crypto/mishmash/rsa_aes_cbc_sha1.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2015 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <byteswap.h>
+#include <ipxe/rsa.h>
+#include <ipxe/aes.h>
+#include <ipxe/sha1.h>
+#include <ipxe/tls.h>
+
+/** TLS_RSA_WITH_AES_128_CBC_SHA cipher suite */
+struct tls_cipher_suite tls_rsa_with_aes_128_cbc_sha __tls_cipher_suite (03) = {
+ .code = htons ( TLS_RSA_WITH_AES_128_CBC_SHA ),
+ .key_len = ( 128 / 8 ),
+ .pubkey = &rsa_algorithm,
+ .cipher = &aes_cbc_algorithm,
+ .digest = &sha1_algorithm,
+};
+
+/** TLS_RSA_WITH_AES_256_CBC_SHA cipher suite */
+struct tls_cipher_suite tls_rsa_with_aes_256_cbc_sha __tls_cipher_suite (04) = {
+ .code = htons ( TLS_RSA_WITH_AES_256_CBC_SHA ),
+ .key_len = ( 256 / 8 ),
+ .pubkey = &rsa_algorithm,
+ .cipher = &aes_cbc_algorithm,
+ .digest = &sha1_algorithm,
+};
diff --git a/roms/ipxe/src/crypto/mishmash/rsa_aes_cbc_sha256.c b/roms/ipxe/src/crypto/mishmash/rsa_aes_cbc_sha256.c
new file mode 100644
index 000000000..c609eacea
--- /dev/null
+++ b/roms/ipxe/src/crypto/mishmash/rsa_aes_cbc_sha256.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2015 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <byteswap.h>
+#include <ipxe/rsa.h>
+#include <ipxe/aes.h>
+#include <ipxe/sha256.h>
+#include <ipxe/tls.h>
+
+/** TLS_RSA_WITH_AES_128_CBC_SHA256 cipher suite */
+struct tls_cipher_suite tls_rsa_with_aes_128_cbc_sha256 __tls_cipher_suite(01)={
+ .code = htons ( TLS_RSA_WITH_AES_128_CBC_SHA256 ),
+ .key_len = ( 128 / 8 ),
+ .pubkey = &rsa_algorithm,
+ .cipher = &aes_cbc_algorithm,
+ .digest = &sha256_algorithm,
+};
+
+/** TLS_RSA_WITH_AES_256_CBC_SHA256 cipher suite */
+struct tls_cipher_suite tls_rsa_with_aes_256_cbc_sha256 __tls_cipher_suite(02)={
+ .code = htons ( TLS_RSA_WITH_AES_256_CBC_SHA256 ),
+ .key_len = ( 256 / 8 ),
+ .pubkey = &rsa_algorithm,
+ .cipher = &aes_cbc_algorithm,
+ .digest = &sha256_algorithm,
+};
diff --git a/roms/ipxe/src/crypto/mishmash/rsa_md5.c b/roms/ipxe/src/crypto/mishmash/rsa_md5.c
new file mode 100644
index 000000000..ac828ac11
--- /dev/null
+++ b/roms/ipxe/src/crypto/mishmash/rsa_md5.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2015 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <ipxe/rsa.h>
+#include <ipxe/md5.h>
+#include <ipxe/asn1.h>
+
+/** "md5WithRSAEncryption" object identifier */
+static uint8_t oid_md5_with_rsa_encryption[] =
+ { ASN1_OID_MD5WITHRSAENCRYPTION };
+
+/** "md5WithRSAEncryption" OID-identified algorithm */
+struct asn1_algorithm md5_with_rsa_encryption_algorithm __asn1_algorithm = {
+ .name = "md5WithRSAEncryption",
+ .pubkey = &rsa_algorithm,
+ .digest = &md5_algorithm,
+ .oid = ASN1_OID_CURSOR ( oid_md5_with_rsa_encryption ),
+};
+
+/** MD5 digestInfo prefix */
+static const uint8_t rsa_md5_prefix_data[] =
+ { RSA_DIGESTINFO_PREFIX ( MD5_DIGEST_SIZE, ASN1_OID_MD5 ) };
+
+/** MD5 digestInfo prefix */
+struct rsa_digestinfo_prefix rsa_md5_prefix __rsa_digestinfo_prefix = {
+ .digest = &md5_algorithm,
+ .data = rsa_md5_prefix_data,
+ .len = sizeof ( rsa_md5_prefix_data ),
+};
diff --git a/roms/ipxe/src/crypto/mishmash/rsa_sha1.c b/roms/ipxe/src/crypto/mishmash/rsa_sha1.c
new file mode 100644
index 000000000..39424bf2d
--- /dev/null
+++ b/roms/ipxe/src/crypto/mishmash/rsa_sha1.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2015 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <ipxe/rsa.h>
+#include <ipxe/sha1.h>
+#include <ipxe/asn1.h>
+#include <ipxe/tls.h>
+
+/** "sha1WithRSAEncryption" object identifier */
+static uint8_t oid_sha1_with_rsa_encryption[] =
+ { ASN1_OID_SHA1WITHRSAENCRYPTION };
+
+/** "sha1WithRSAEncryption" OID-identified algorithm */
+struct asn1_algorithm sha1_with_rsa_encryption_algorithm __asn1_algorithm = {
+ .name = "sha1WithRSAEncryption",
+ .pubkey = &rsa_algorithm,
+ .digest = &sha1_algorithm,
+ .oid = ASN1_OID_CURSOR ( oid_sha1_with_rsa_encryption ),
+};
+
+/** SHA-1 digestInfo prefix */
+static const uint8_t rsa_sha1_prefix_data[] =
+ { RSA_DIGESTINFO_PREFIX ( SHA1_DIGEST_SIZE, ASN1_OID_SHA1 ) };
+
+/** SHA-1 digestInfo prefix */
+struct rsa_digestinfo_prefix rsa_sha1_prefix __rsa_digestinfo_prefix = {
+ .digest = &sha1_algorithm,
+ .data = rsa_sha1_prefix_data,
+ .len = sizeof ( rsa_sha1_prefix_data ),
+};
+
+/** RSA with SHA-1 signature hash algorithm */
+struct tls_signature_hash_algorithm tls_rsa_sha1 __tls_sig_hash_algorithm = {
+ .code = {
+ .signature = TLS_RSA_ALGORITHM,
+ .hash = TLS_SHA1_ALGORITHM,
+ },
+ .pubkey = &rsa_algorithm,
+ .digest = &sha1_algorithm,
+};
diff --git a/roms/ipxe/src/crypto/mishmash/rsa_sha224.c b/roms/ipxe/src/crypto/mishmash/rsa_sha224.c
new file mode 100644
index 000000000..5e8755aab
--- /dev/null
+++ b/roms/ipxe/src/crypto/mishmash/rsa_sha224.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2015 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <ipxe/rsa.h>
+#include <ipxe/sha256.h>
+#include <ipxe/asn1.h>
+#include <ipxe/tls.h>
+
+/** "sha224WithRSAEncryption" object identifier */
+static uint8_t oid_sha224_with_rsa_encryption[] =
+ { ASN1_OID_SHA224WITHRSAENCRYPTION };
+
+/** "sha224WithRSAEncryption" OID-identified algorithm */
+struct asn1_algorithm sha224_with_rsa_encryption_algorithm __asn1_algorithm = {
+ .name = "sha224WithRSAEncryption",
+ .pubkey = &rsa_algorithm,
+ .digest = &sha224_algorithm,
+ .oid = ASN1_OID_CURSOR ( oid_sha224_with_rsa_encryption ),
+};
+
+/** SHA-224 digestInfo prefix */
+static const uint8_t rsa_sha224_prefix_data[] =
+ { RSA_DIGESTINFO_PREFIX ( SHA224_DIGEST_SIZE, ASN1_OID_SHA224 ) };
+
+/** SHA-224 digestInfo prefix */
+struct rsa_digestinfo_prefix rsa_sha224_prefix __rsa_digestinfo_prefix = {
+ .digest = &sha224_algorithm,
+ .data = rsa_sha224_prefix_data,
+ .len = sizeof ( rsa_sha224_prefix_data ),
+};
+
+/** RSA with SHA-224 signature hash algorithm */
+struct tls_signature_hash_algorithm tls_rsa_sha224 __tls_sig_hash_algorithm = {
+ .code = {
+ .signature = TLS_RSA_ALGORITHM,
+ .hash = TLS_SHA224_ALGORITHM,
+ },
+ .pubkey = &rsa_algorithm,
+ .digest = &sha224_algorithm,
+};
diff --git a/roms/ipxe/src/crypto/mishmash/rsa_sha256.c b/roms/ipxe/src/crypto/mishmash/rsa_sha256.c
new file mode 100644
index 000000000..b44af5f19
--- /dev/null
+++ b/roms/ipxe/src/crypto/mishmash/rsa_sha256.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2015 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <ipxe/rsa.h>
+#include <ipxe/sha256.h>
+#include <ipxe/asn1.h>
+#include <ipxe/tls.h>
+
+/** "sha256WithRSAEncryption" object identifier */
+static uint8_t oid_sha256_with_rsa_encryption[] =
+ { ASN1_OID_SHA256WITHRSAENCRYPTION };
+
+/** "sha256WithRSAEncryption" OID-identified algorithm */
+struct asn1_algorithm sha256_with_rsa_encryption_algorithm __asn1_algorithm = {
+ .name = "sha256WithRSAEncryption",
+ .pubkey = &rsa_algorithm,
+ .digest = &sha256_algorithm,
+ .oid = ASN1_OID_CURSOR ( oid_sha256_with_rsa_encryption ),
+};
+
+/** SHA-256 digestInfo prefix */
+static const uint8_t rsa_sha256_prefix_data[] =
+ { RSA_DIGESTINFO_PREFIX ( SHA256_DIGEST_SIZE, ASN1_OID_SHA256 ) };
+
+/** SHA-256 digestInfo prefix */
+struct rsa_digestinfo_prefix rsa_sha256_prefix __rsa_digestinfo_prefix = {
+ .digest = &sha256_algorithm,
+ .data = rsa_sha256_prefix_data,
+ .len = sizeof ( rsa_sha256_prefix_data ),
+};
+
+/** RSA with SHA-256 signature hash algorithm */
+struct tls_signature_hash_algorithm tls_rsa_sha256 __tls_sig_hash_algorithm = {
+ .code = {
+ .signature = TLS_RSA_ALGORITHM,
+ .hash = TLS_SHA256_ALGORITHM,
+ },
+ .pubkey = &rsa_algorithm,
+ .digest = &sha256_algorithm,
+};
diff --git a/roms/ipxe/src/crypto/mishmash/rsa_sha384.c b/roms/ipxe/src/crypto/mishmash/rsa_sha384.c
new file mode 100644
index 000000000..af22a2bf0
--- /dev/null
+++ b/roms/ipxe/src/crypto/mishmash/rsa_sha384.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2015 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <ipxe/rsa.h>
+#include <ipxe/sha512.h>
+#include <ipxe/asn1.h>
+#include <ipxe/tls.h>
+
+/** "sha384WithRSAEncryption" object identifier */
+static uint8_t oid_sha384_with_rsa_encryption[] =
+ { ASN1_OID_SHA384WITHRSAENCRYPTION };
+
+/** "sha384WithRSAEncryption" OID-identified algorithm */
+struct asn1_algorithm sha384_with_rsa_encryption_algorithm __asn1_algorithm = {
+ .name = "sha384WithRSAEncryption",
+ .pubkey = &rsa_algorithm,
+ .digest = &sha384_algorithm,
+ .oid = ASN1_OID_CURSOR ( oid_sha384_with_rsa_encryption ),
+};
+
+/** SHA-384 digestInfo prefix */
+static const uint8_t rsa_sha384_prefix_data[] =
+ { RSA_DIGESTINFO_PREFIX ( SHA384_DIGEST_SIZE, ASN1_OID_SHA384 ) };
+
+/** SHA-384 digestInfo prefix */
+struct rsa_digestinfo_prefix rsa_sha384_prefix __rsa_digestinfo_prefix = {
+ .digest = &sha384_algorithm,
+ .data = rsa_sha384_prefix_data,
+ .len = sizeof ( rsa_sha384_prefix_data ),
+};
+
+/** RSA with SHA-384 signature hash algorithm */
+struct tls_signature_hash_algorithm tls_rsa_sha384 __tls_sig_hash_algorithm = {
+ .code = {
+ .signature = TLS_RSA_ALGORITHM,
+ .hash = TLS_SHA384_ALGORITHM,
+ },
+ .pubkey = &rsa_algorithm,
+ .digest = &sha384_algorithm,
+};
diff --git a/roms/ipxe/src/crypto/mishmash/rsa_sha512.c b/roms/ipxe/src/crypto/mishmash/rsa_sha512.c
new file mode 100644
index 000000000..29ee15493
--- /dev/null
+++ b/roms/ipxe/src/crypto/mishmash/rsa_sha512.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2015 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <ipxe/rsa.h>
+#include <ipxe/sha512.h>
+#include <ipxe/asn1.h>
+#include <ipxe/tls.h>
+
+/** "sha512WithRSAEncryption" object identifier */
+static uint8_t oid_sha512_with_rsa_encryption[] =
+ { ASN1_OID_SHA512WITHRSAENCRYPTION };
+
+/** "sha512WithRSAEncryption" OID-identified algorithm */
+struct asn1_algorithm sha512_with_rsa_encryption_algorithm __asn1_algorithm = {
+ .name = "sha512WithRSAEncryption",
+ .pubkey = &rsa_algorithm,
+ .digest = &sha512_algorithm,
+ .oid = ASN1_OID_CURSOR ( oid_sha512_with_rsa_encryption ),
+};
+
+/** SHA-512 digestInfo prefix */
+static const uint8_t rsa_sha512_prefix_data[] =
+ { RSA_DIGESTINFO_PREFIX ( SHA512_DIGEST_SIZE, ASN1_OID_SHA512 ) };
+
+/** SHA-512 digestInfo prefix */
+struct rsa_digestinfo_prefix rsa_sha512_prefix __rsa_digestinfo_prefix = {
+ .digest = &sha512_algorithm,
+ .data = rsa_sha512_prefix_data,
+ .len = sizeof ( rsa_sha512_prefix_data ),
+};
+
+/** RSA with SHA-512 signature hash algorithm */
+struct tls_signature_hash_algorithm tls_rsa_sha512 __tls_sig_hash_algorithm = {
+ .code = {
+ .signature = TLS_RSA_ALGORITHM,
+ .hash = TLS_SHA512_ALGORITHM,
+ },
+ .pubkey = &rsa_algorithm,
+ .digest = &sha512_algorithm,
+};
diff --git a/roms/ipxe/src/crypto/null_entropy.c b/roms/ipxe/src/crypto/null_entropy.c
index c56d5e76f..d1e1a6f73 100644
--- a/roms/ipxe/src/crypto/null_entropy.c
+++ b/roms/ipxe/src/crypto/null_entropy.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/crypto/ocsp.c b/roms/ipxe/src/crypto/ocsp.c
index 66e47c57e..5df55bc96 100644
--- a/roms/ipxe/src/crypto/ocsp.c
+++ b/roms/ipxe/src/crypto/ocsp.c
@@ -233,7 +233,7 @@ static int ocsp_uri_string ( struct ocsp_check *ocsp ) {
goto err_path_base64;
}
base64_encode ( ocsp->request.builder.data, ocsp->request.builder.len,
- path_base64_string );
+ path_base64_string, path_len );
/* URI-encode the Base64-encoded request */
memset ( &path_uri, 0, sizeof ( path_uri ) );
diff --git a/roms/ipxe/src/crypto/privkey.c b/roms/ipxe/src/crypto/privkey.c
index e010649c0..a6043bd1e 100644
--- a/roms/ipxe/src/crypto/privkey.c
+++ b/roms/ipxe/src/crypto/privkey.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/crypto/random_nz.c b/roms/ipxe/src/crypto/random_nz.c
index f1d2e187d..5fe576e05 100644
--- a/roms/ipxe/src/crypto/random_nz.c
+++ b/roms/ipxe/src/crypto/random_nz.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/crypto/rbg.c b/roms/ipxe/src/crypto/rbg.c
index e2d06978c..943b288c3 100644
--- a/roms/ipxe/src/crypto/rbg.c
+++ b/roms/ipxe/src/crypto/rbg.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/crypto/rootcert.c b/roms/ipxe/src/crypto/rootcert.c
index ae28905ac..00ea1647e 100644
--- a/roms/ipxe/src/crypto/rootcert.c
+++ b/roms/ipxe/src/crypto/rootcert.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdlib.h>
#include <ipxe/crypto.h>
diff --git a/roms/ipxe/src/crypto/rsa.c b/roms/ipxe/src/crypto/rsa.c
index 0ab7b2ad3..36109280d 100644
--- a/roms/ipxe/src/crypto/rsa.c
+++ b/roms/ipxe/src/crypto/rsa.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
@@ -28,9 +32,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/crypto.h>
#include <ipxe/bigint.h>
#include <ipxe/random_nz.h>
-#include <ipxe/md5.h>
-#include <ipxe/sha1.h>
-#include <ipxe/sha256.h>
#include <ipxe/rsa.h>
/** @file
@@ -49,18 +50,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
/** "rsaEncryption" object identifier */
static uint8_t oid_rsa_encryption[] = { ASN1_OID_RSAENCRYPTION };
-/** "md5WithRSAEncryption" object identifier */
-static uint8_t oid_md5_with_rsa_encryption[] =
- { ASN1_OID_MD5WITHRSAENCRYPTION };
-
-/** "sha1WithRSAEncryption" object identifier */
-static uint8_t oid_sha1_with_rsa_encryption[] =
- { ASN1_OID_SHA1WITHRSAENCRYPTION };
-
-/** "sha256WithRSAEncryption" object identifier */
-static uint8_t oid_sha256_with_rsa_encryption[] =
- { ASN1_OID_SHA256WITHRSAENCRYPTION };
-
/** "rsaEncryption" OID-identified algorithm */
struct asn1_algorithm rsa_encryption_algorithm __asn1_algorithm = {
.name = "rsaEncryption",
@@ -69,63 +58,6 @@ struct asn1_algorithm rsa_encryption_algorithm __asn1_algorithm = {
.oid = ASN1_OID_CURSOR ( oid_rsa_encryption ),
};
-/** "md5WithRSAEncryption" OID-identified algorithm */
-struct asn1_algorithm md5_with_rsa_encryption_algorithm __asn1_algorithm = {
- .name = "md5WithRSAEncryption",
- .pubkey = &rsa_algorithm,
- .digest = &md5_algorithm,
- .oid = ASN1_OID_CURSOR ( oid_md5_with_rsa_encryption ),
-};
-
-/** "sha1WithRSAEncryption" OID-identified algorithm */
-struct asn1_algorithm sha1_with_rsa_encryption_algorithm __asn1_algorithm = {
- .name = "sha1WithRSAEncryption",
- .pubkey = &rsa_algorithm,
- .digest = &sha1_algorithm,
- .oid = ASN1_OID_CURSOR ( oid_sha1_with_rsa_encryption ),
-};
-
-/** "sha256WithRSAEncryption" OID-identified algorithm */
-struct asn1_algorithm sha256_with_rsa_encryption_algorithm __asn1_algorithm = {
- .name = "sha256WithRSAEncryption",
- .pubkey = &rsa_algorithm,
- .digest = &sha256_algorithm,
- .oid = ASN1_OID_CURSOR ( oid_sha256_with_rsa_encryption ),
-};
-
-/** MD5 digestInfo prefix */
-static const uint8_t rsa_md5_prefix_data[] =
- { RSA_DIGESTINFO_PREFIX ( MD5_DIGEST_SIZE, ASN1_OID_MD5 ) };
-
-/** SHA-1 digestInfo prefix */
-static const uint8_t rsa_sha1_prefix_data[] =
- { RSA_DIGESTINFO_PREFIX ( SHA1_DIGEST_SIZE, ASN1_OID_SHA1 ) };
-
-/** SHA-256 digestInfo prefix */
-static const uint8_t rsa_sha256_prefix_data[] =
- { RSA_DIGESTINFO_PREFIX ( SHA256_DIGEST_SIZE, ASN1_OID_SHA256 ) };
-
-/** MD5 digestInfo prefix */
-struct rsa_digestinfo_prefix rsa_md5_prefix __rsa_digestinfo_prefix = {
- .digest = &md5_algorithm,
- .data = rsa_md5_prefix_data,
- .len = sizeof ( rsa_md5_prefix_data ),
-};
-
-/** SHA-1 digestInfo prefix */
-struct rsa_digestinfo_prefix rsa_sha1_prefix __rsa_digestinfo_prefix = {
- .digest = &sha1_algorithm,
- .data = rsa_sha1_prefix_data,
- .len = sizeof ( rsa_sha1_prefix_data ),
-};
-
-/** SHA-256 digestInfo prefix */
-struct rsa_digestinfo_prefix rsa_sha256_prefix __rsa_digestinfo_prefix = {
- .digest = &sha256_algorithm,
- .data = rsa_sha256_prefix_data,
- .len = sizeof ( rsa_sha256_prefix_data ),
-};
-
/**
* Identify RSA prefix
*
diff --git a/roms/ipxe/src/crypto/sha1.c b/roms/ipxe/src/crypto/sha1.c
index e1bef669e..51866f4b7 100644
--- a/roms/ipxe/src/crypto/sha1.c
+++ b/roms/ipxe/src/crypto/sha1.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/crypto/sha224.c b/roms/ipxe/src/crypto/sha224.c
new file mode 100644
index 000000000..be25f24e9
--- /dev/null
+++ b/roms/ipxe/src/crypto/sha224.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/** @file
+ *
+ * SHA-224 algorithm
+ *
+ */
+
+#include <stdint.h>
+#include <byteswap.h>
+#include <ipxe/crypto.h>
+#include <ipxe/asn1.h>
+#include <ipxe/sha256.h>
+
+/** SHA-224 initial digest values */
+static const struct sha256_digest sha224_init_digest = {
+ .h = {
+ cpu_to_be32 ( 0xc1059ed8 ),
+ cpu_to_be32 ( 0x367cd507 ),
+ cpu_to_be32 ( 0x3070dd17 ),
+ cpu_to_be32 ( 0xf70e5939 ),
+ cpu_to_be32 ( 0xffc00b31 ),
+ cpu_to_be32 ( 0x68581511 ),
+ cpu_to_be32 ( 0x64f98fa7 ),
+ cpu_to_be32 ( 0xbefa4fa4 ),
+ },
+};
+
+/**
+ * Initialise SHA-224 algorithm
+ *
+ * @v ctx SHA-224 context
+ */
+static void sha224_init ( void *ctx ) {
+ struct sha256_context *context = ctx;
+
+ sha256_family_init ( context, &sha224_init_digest, SHA224_DIGEST_SIZE );
+}
+
+/** SHA-224 algorithm */
+struct digest_algorithm sha224_algorithm = {
+ .name = "sha224",
+ .ctxsize = sizeof ( struct sha256_context ),
+ .blocksize = sizeof ( union sha256_block ),
+ .digestsize = SHA224_DIGEST_SIZE,
+ .init = sha224_init,
+ .update = sha256_update,
+ .final = sha256_final,
+};
+
+/** "sha224" object identifier */
+static uint8_t oid_sha224[] = { ASN1_OID_SHA224 };
+
+/** "sha224" OID-identified algorithm */
+struct asn1_algorithm oid_sha224_algorithm __asn1_algorithm = {
+ .name = "sha224",
+ .digest = &sha224_algorithm,
+ .oid = ASN1_OID_CURSOR ( oid_sha224 ),
+};
diff --git a/roms/ipxe/src/crypto/sha256.c b/roms/ipxe/src/crypto/sha256.c
index 36e02b3c2..0360d8d16 100644
--- a/roms/ipxe/src/crypto/sha256.c
+++ b/roms/ipxe/src/crypto/sha256.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
@@ -47,11 +51,11 @@ struct sha256_variables {
uint32_t f;
uint32_t g;
uint32_t h;
- uint32_t w[64];
+ uint32_t w[SHA256_ROUNDS];
} __attribute__ (( packed ));
/** SHA-256 constants */
-static const uint32_t k[64] = {
+static const uint32_t k[SHA256_ROUNDS] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
@@ -65,6 +69,37 @@ static const uint32_t k[64] = {
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};
+/** SHA-256 initial digest values */
+static const struct sha256_digest sha256_init_digest = {
+ .h = {
+ cpu_to_be32 ( 0x6a09e667 ),
+ cpu_to_be32 ( 0xbb67ae85 ),
+ cpu_to_be32 ( 0x3c6ef372 ),
+ cpu_to_be32 ( 0xa54ff53a ),
+ cpu_to_be32 ( 0x510e527f ),
+ cpu_to_be32 ( 0x9b05688c ),
+ cpu_to_be32 ( 0x1f83d9ab ),
+ cpu_to_be32 ( 0x5be0cd19 ),
+ },
+};
+
+/**
+ * Initialise SHA-256 family algorithm
+ *
+ * @v context SHA-256 context
+ * @v init Initial digest values
+ * @v digestsize Digest size
+ */
+void sha256_family_init ( struct sha256_context *context,
+ const struct sha256_digest *init,
+ size_t digestsize ) {
+
+ context->len = 0;
+ context->digestsize = digestsize;
+ memcpy ( &context->ddd.dd.digest, init,
+ sizeof ( context->ddd.dd.digest ) );
+}
+
/**
* Initialise SHA-256 algorithm
*
@@ -73,15 +108,8 @@ static const uint32_t k[64] = {
static void sha256_init ( void *ctx ) {
struct sha256_context *context = ctx;
- context->ddd.dd.digest.h[0] = cpu_to_be32 ( 0x6a09e667 );
- context->ddd.dd.digest.h[1] = cpu_to_be32 ( 0xbb67ae85 );
- context->ddd.dd.digest.h[2] = cpu_to_be32 ( 0x3c6ef372 );
- context->ddd.dd.digest.h[3] = cpu_to_be32 ( 0xa54ff53a );
- context->ddd.dd.digest.h[4] = cpu_to_be32 ( 0x510e527f );
- context->ddd.dd.digest.h[5] = cpu_to_be32 ( 0x9b05688c );
- context->ddd.dd.digest.h[6] = cpu_to_be32 ( 0x1f83d9ab );
- context->ddd.dd.digest.h[7] = cpu_to_be32 ( 0x5be0cd19 );
- context->len = 0;
+ sha256_family_init ( context, &sha256_init_digest,
+ sizeof ( struct sha256_digest ) );
}
/**
@@ -139,7 +167,7 @@ static void sha256_digest ( struct sha256_context *context ) {
}
/* Initialise w[16..63] */
- for ( i = 16 ; i < 64 ; i++ ) {
+ for ( i = 16 ; i < SHA256_ROUNDS ; i++ ) {
s0 = ( ror32 ( w[i-15], 7 ) ^ ror32 ( w[i-15], 18 ) ^
( w[i-15] >> 3 ) );
s1 = ( ror32 ( w[i-2], 17 ) ^ ror32 ( w[i-2], 19 ) ^
@@ -148,7 +176,7 @@ static void sha256_digest ( struct sha256_context *context ) {
}
/* Main loop */
- for ( i = 0 ; i < 64 ; i++ ) {
+ for ( i = 0 ; i < SHA256_ROUNDS ; i++ ) {
s0 = ( ror32 ( *a, 2 ) ^ ror32 ( *a, 13 ) ^ ror32 ( *a, 22 ) );
maj = ( ( *a & *b ) ^ ( *a & *c ) ^ ( *b & *c ) );
t2 = ( s0 + maj );
@@ -186,7 +214,7 @@ static void sha256_digest ( struct sha256_context *context ) {
* @v data Data
* @v len Length of data
*/
-static void sha256_update ( void *ctx, const void *data, size_t len ) {
+void sha256_update ( void *ctx, const void *data, size_t len ) {
struct sha256_context *context = ctx;
const uint8_t *byte = data;
size_t offset;
@@ -209,7 +237,7 @@ static void sha256_update ( void *ctx, const void *data, size_t len ) {
* @v ctx SHA-256 context
* @v out Output buffer
*/
-static void sha256_final ( void *ctx, void *out ) {
+void sha256_final ( void *ctx, void *out ) {
struct sha256_context *context = ctx;
uint64_t len_bits;
uint8_t pad;
@@ -230,8 +258,7 @@ static void sha256_final ( void *ctx, void *out ) {
assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 );
/* Copy out final digest */
- memcpy ( out, &context->ddd.dd.digest,
- sizeof ( context->ddd.dd.digest ) );
+ memcpy ( out, &context->ddd.dd.digest, context->digestsize );
}
/** SHA-256 algorithm */
diff --git a/roms/ipxe/src/crypto/sha384.c b/roms/ipxe/src/crypto/sha384.c
new file mode 100644
index 000000000..017751826
--- /dev/null
+++ b/roms/ipxe/src/crypto/sha384.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/** @file
+ *
+ * SHA-384 algorithm
+ *
+ */
+
+#include <stdint.h>
+#include <byteswap.h>
+#include <ipxe/crypto.h>
+#include <ipxe/asn1.h>
+#include <ipxe/sha512.h>
+
+/** SHA-384 initial digest values */
+static const struct sha512_digest sha384_init_digest = {
+ .h = {
+ cpu_to_be64 ( 0xcbbb9d5dc1059ed8ULL ),
+ cpu_to_be64 ( 0x629a292a367cd507ULL ),
+ cpu_to_be64 ( 0x9159015a3070dd17ULL ),
+ cpu_to_be64 ( 0x152fecd8f70e5939ULL ),
+ cpu_to_be64 ( 0x67332667ffc00b31ULL ),
+ cpu_to_be64 ( 0x8eb44a8768581511ULL ),
+ cpu_to_be64 ( 0xdb0c2e0d64f98fa7ULL ),
+ cpu_to_be64 ( 0x47b5481dbefa4fa4ULL ),
+ },
+};
+
+/**
+ * Initialise SHA-384 algorithm
+ *
+ * @v ctx SHA-384 context
+ */
+static void sha384_init ( void *ctx ) {
+ struct sha512_context *context = ctx;
+
+ sha512_family_init ( context, &sha384_init_digest, SHA384_DIGEST_SIZE );
+}
+
+/** SHA-384 algorithm */
+struct digest_algorithm sha384_algorithm = {
+ .name = "sha384",
+ .ctxsize = sizeof ( struct sha512_context ),
+ .blocksize = sizeof ( union sha512_block ),
+ .digestsize = SHA384_DIGEST_SIZE,
+ .init = sha384_init,
+ .update = sha512_update,
+ .final = sha512_final,
+};
+
+/** "sha384" object identifier */
+static uint8_t oid_sha384[] = { ASN1_OID_SHA384 };
+
+/** "sha384" OID-identified algorithm */
+struct asn1_algorithm oid_sha384_algorithm __asn1_algorithm = {
+ .name = "sha384",
+ .digest = &sha384_algorithm,
+ .oid = ASN1_OID_CURSOR ( oid_sha384 ),
+};
diff --git a/roms/ipxe/src/crypto/sha512.c b/roms/ipxe/src/crypto/sha512.c
new file mode 100644
index 000000000..814f44563
--- /dev/null
+++ b/roms/ipxe/src/crypto/sha512.c
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/** @file
+ *
+ * SHA-512 algorithm
+ *
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <byteswap.h>
+#include <assert.h>
+#include <ipxe/rotate.h>
+#include <ipxe/crypto.h>
+#include <ipxe/asn1.h>
+#include <ipxe/sha512.h>
+
+/** SHA-512 variables */
+struct sha512_variables {
+ /* This layout matches that of struct sha512_digest_data,
+ * allowing for efficient endianness-conversion,
+ */
+ uint64_t a;
+ uint64_t b;
+ uint64_t c;
+ uint64_t d;
+ uint64_t e;
+ uint64_t f;
+ uint64_t g;
+ uint64_t h;
+ uint64_t w[SHA512_ROUNDS];
+} __attribute__ (( packed ));
+
+/** SHA-512 constants */
+static const uint64_t k[SHA512_ROUNDS] = {
+ 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL,
+ 0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
+ 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL,
+ 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
+ 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL,
+ 0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
+ 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL,
+ 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
+ 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL,
+ 0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
+ 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL,
+ 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
+ 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL,
+ 0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
+ 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL,
+ 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
+ 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL,
+ 0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
+ 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL,
+ 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
+ 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL,
+ 0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
+ 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL,
+ 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
+ 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL,
+ 0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
+ 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
+};
+
+/** SHA-512 initial digest values */
+static const struct sha512_digest sha512_init_digest = {
+ .h = {
+ cpu_to_be64 ( 0x6a09e667f3bcc908ULL ),
+ cpu_to_be64 ( 0xbb67ae8584caa73bULL ),
+ cpu_to_be64 ( 0x3c6ef372fe94f82bULL ),
+ cpu_to_be64 ( 0xa54ff53a5f1d36f1ULL ),
+ cpu_to_be64 ( 0x510e527fade682d1ULL ),
+ cpu_to_be64 ( 0x9b05688c2b3e6c1fULL ),
+ cpu_to_be64 ( 0x1f83d9abfb41bd6bULL ),
+ cpu_to_be64 ( 0x5be0cd19137e2179ULL ),
+ },
+};
+
+/**
+ * Initialise SHA-512 family algorithm
+ *
+ * @v context SHA-512 context
+ * @v init Initial digest values
+ * @v digestsize Digest size
+ */
+void sha512_family_init ( struct sha512_context *context,
+ const struct sha512_digest *init,
+ size_t digestsize ) {
+
+ context->len = 0;
+ context->digestsize = digestsize;
+ memcpy ( &context->ddq.dd.digest, init,
+ sizeof ( context->ddq.dd.digest ) );
+}
+
+/**
+ * Initialise SHA-512 algorithm
+ *
+ * @v ctx SHA-512 context
+ */
+static void sha512_init ( void *ctx ) {
+ struct sha512_context *context = ctx;
+
+ sha512_family_init ( context, &sha512_init_digest,
+ sizeof ( struct sha512_digest ) );
+}
+
+/**
+ * Calculate SHA-512 digest of accumulated data
+ *
+ * @v context SHA-512 context
+ */
+static void sha512_digest ( struct sha512_context *context ) {
+ union {
+ union sha512_digest_data_qwords ddq;
+ struct sha512_variables v;
+ } u;
+ uint64_t *a = &u.v.a;
+ uint64_t *b = &u.v.b;
+ uint64_t *c = &u.v.c;
+ uint64_t *d = &u.v.d;
+ uint64_t *e = &u.v.e;
+ uint64_t *f = &u.v.f;
+ uint64_t *g = &u.v.g;
+ uint64_t *h = &u.v.h;
+ uint64_t *w = u.v.w;
+ uint64_t s0;
+ uint64_t s1;
+ uint64_t maj;
+ uint64_t t1;
+ uint64_t t2;
+ uint64_t ch;
+ unsigned int i;
+
+ /* Sanity checks */
+ assert ( ( context->len % sizeof ( context->ddq.dd.data ) ) == 0 );
+ linker_assert ( &u.ddq.dd.digest.h[0] == a, sha512_bad_layout );
+ linker_assert ( &u.ddq.dd.digest.h[1] == b, sha512_bad_layout );
+ linker_assert ( &u.ddq.dd.digest.h[2] == c, sha512_bad_layout );
+ linker_assert ( &u.ddq.dd.digest.h[3] == d, sha512_bad_layout );
+ linker_assert ( &u.ddq.dd.digest.h[4] == e, sha512_bad_layout );
+ linker_assert ( &u.ddq.dd.digest.h[5] == f, sha512_bad_layout );
+ linker_assert ( &u.ddq.dd.digest.h[6] == g, sha512_bad_layout );
+ linker_assert ( &u.ddq.dd.digest.h[7] == h, sha512_bad_layout );
+ linker_assert ( &u.ddq.dd.data.qword[0] == w, sha512_bad_layout );
+
+ DBGC ( context, "SHA512 digesting:\n" );
+ DBGC_HDA ( context, 0, &context->ddq.dd.digest,
+ sizeof ( context->ddq.dd.digest ) );
+ DBGC_HDA ( context, context->len, &context->ddq.dd.data,
+ sizeof ( context->ddq.dd.data ) );
+
+ /* Convert h[0..7] to host-endian, and initialise a, b, c, d,
+ * e, f, g, h, and w[0..15]
+ */
+ for ( i = 0 ; i < ( sizeof ( u.ddq.qword ) /
+ sizeof ( u.ddq.qword[0] ) ) ; i++ ) {
+ be64_to_cpus ( &context->ddq.qword[i] );
+ u.ddq.qword[i] = context->ddq.qword[i];
+ }
+
+ /* Initialise w[16..79] */
+ for ( i = 16 ; i < SHA512_ROUNDS ; i++ ) {
+ s0 = ( ror64 ( w[i-15], 1 ) ^ ror64 ( w[i-15], 8 ) ^
+ ( w[i-15] >> 7 ) );
+ s1 = ( ror64 ( w[i-2], 19 ) ^ ror64 ( w[i-2], 61 ) ^
+ ( w[i-2] >> 6 ) );
+ w[i] = ( w[i-16] + s0 + w[i-7] + s1 );
+ }
+
+ /* Main loop */
+ for ( i = 0 ; i < SHA512_ROUNDS ; i++ ) {
+ s0 = ( ror64 ( *a, 28 ) ^ ror64 ( *a, 34 ) ^ ror64 ( *a, 39 ) );
+ maj = ( ( *a & *b ) ^ ( *a & *c ) ^ ( *b & *c ) );
+ t2 = ( s0 + maj );
+ s1 = ( ror64 ( *e, 14 ) ^ ror64 ( *e, 18 ) ^ ror64 ( *e, 41 ) );
+ ch = ( ( *e & *f ) ^ ( (~*e) & *g ) );
+ t1 = ( *h + s1 + ch + k[i] + w[i] );
+ *h = *g;
+ *g = *f;
+ *f = *e;
+ *e = ( *d + t1 );
+ *d = *c;
+ *c = *b;
+ *b = *a;
+ *a = ( t1 + t2 );
+ DBGC2 ( context, "%2d : %016llx %016llx %016llx %016llx "
+ "%016llx %016llx %016llx %016llx\n",
+ i, *a, *b, *c, *d, *e, *f, *g, *h );
+ }
+
+ /* Add chunk to hash and convert back to big-endian */
+ for ( i = 0 ; i < 8 ; i++ ) {
+ context->ddq.dd.digest.h[i] =
+ cpu_to_be64 ( context->ddq.dd.digest.h[i] +
+ u.ddq.dd.digest.h[i] );
+ }
+
+ DBGC ( context, "SHA512 digested:\n" );
+ DBGC_HDA ( context, 0, &context->ddq.dd.digest,
+ sizeof ( context->ddq.dd.digest ) );
+}
+
+/**
+ * Accumulate data with SHA-512 algorithm
+ *
+ * @v ctx SHA-512 context
+ * @v data Data
+ * @v len Length of data
+ */
+void sha512_update ( void *ctx, const void *data, size_t len ) {
+ struct sha512_context *context = ctx;
+ const uint8_t *byte = data;
+ size_t offset;
+
+ /* Accumulate data a byte at a time, performing the digest
+ * whenever we fill the data buffer
+ */
+ while ( len-- ) {
+ offset = ( context->len % sizeof ( context->ddq.dd.data ) );
+ context->ddq.dd.data.byte[offset] = *(byte++);
+ context->len++;
+ if ( ( context->len % sizeof ( context->ddq.dd.data ) ) == 0 )
+ sha512_digest ( context );
+ }
+}
+
+/**
+ * Generate SHA-512 digest
+ *
+ * @v ctx SHA-512 context
+ * @v out Output buffer
+ */
+void sha512_final ( void *ctx, void *out ) {
+ struct sha512_context *context = ctx;
+ uint64_t len_bits_hi;
+ uint64_t len_bits_lo;
+ uint8_t pad;
+
+ /* Record length before pre-processing */
+ len_bits_hi = 0;
+ len_bits_lo = cpu_to_be64 ( ( ( uint64_t ) context->len ) * 8 );
+
+ /* Pad with a single "1" bit followed by as many "0" bits as required */
+ pad = 0x80;
+ do {
+ sha512_update ( ctx, &pad, sizeof ( pad ) );
+ pad = 0x00;
+ } while ( ( context->len % sizeof ( context->ddq.dd.data ) ) !=
+ offsetof ( typeof ( context->ddq.dd.data ), final.len_hi ) );
+
+ /* Append length (in bits) */
+ sha512_update ( ctx, &len_bits_hi, sizeof ( len_bits_hi ) );
+ sha512_update ( ctx, &len_bits_lo, sizeof ( len_bits_lo ) );
+ assert ( ( context->len % sizeof ( context->ddq.dd.data ) ) == 0 );
+
+ /* Copy out final digest */
+ memcpy ( out, &context->ddq.dd.digest, context->digestsize );
+}
+
+/** SHA-512 algorithm */
+struct digest_algorithm sha512_algorithm = {
+ .name = "sha512",
+ .ctxsize = sizeof ( struct sha512_context ),
+ .blocksize = sizeof ( union sha512_block ),
+ .digestsize = sizeof ( struct sha512_digest ),
+ .init = sha512_init,
+ .update = sha512_update,
+ .final = sha512_final,
+};
+
+/** "sha512" object identifier */
+static uint8_t oid_sha512[] = { ASN1_OID_SHA512 };
+
+/** "sha512" OID-identified algorithm */
+struct asn1_algorithm oid_sha512_algorithm __asn1_algorithm = {
+ .name = "sha512",
+ .digest = &sha512_algorithm,
+ .oid = ASN1_OID_CURSOR ( oid_sha512 ),
+};
diff --git a/roms/ipxe/src/crypto/sha512_224.c b/roms/ipxe/src/crypto/sha512_224.c
new file mode 100644
index 000000000..8c37b566b
--- /dev/null
+++ b/roms/ipxe/src/crypto/sha512_224.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/** @file
+ *
+ * SHA-512/224 algorithm
+ *
+ */
+
+#include <stdint.h>
+#include <byteswap.h>
+#include <ipxe/crypto.h>
+#include <ipxe/asn1.h>
+#include <ipxe/sha512.h>
+
+/** SHA-512/224 initial digest values */
+static const struct sha512_digest sha512_224_init_digest = {
+ .h = {
+ cpu_to_be64 ( 0x8c3d37c819544da2ULL ),
+ cpu_to_be64 ( 0x73e1996689dcd4d6ULL ),
+ cpu_to_be64 ( 0x1dfab7ae32ff9c82ULL ),
+ cpu_to_be64 ( 0x679dd514582f9fcfULL ),
+ cpu_to_be64 ( 0x0f6d2b697bd44da8ULL ),
+ cpu_to_be64 ( 0x77e36f7304c48942ULL ),
+ cpu_to_be64 ( 0x3f9d85a86a1d36c8ULL ),
+ cpu_to_be64 ( 0x1112e6ad91d692a1ULL ),
+ },
+};
+
+/**
+ * Initialise SHA-512/224 algorithm
+ *
+ * @v ctx SHA-512/224 context
+ */
+static void sha512_224_init ( void *ctx ) {
+ struct sha512_context *context = ctx;
+
+ sha512_family_init ( context, &sha512_224_init_digest,
+ SHA512_224_DIGEST_SIZE );
+}
+
+/** SHA-512/224 algorithm */
+struct digest_algorithm sha512_224_algorithm = {
+ .name = "sha512/224",
+ .ctxsize = sizeof ( struct sha512_context ),
+ .blocksize = sizeof ( union sha512_block ),
+ .digestsize = SHA512_224_DIGEST_SIZE,
+ .init = sha512_224_init,
+ .update = sha512_update,
+ .final = sha512_final,
+};
+
+/** "sha512_224" object identifier */
+static uint8_t oid_sha512_224[] = { ASN1_OID_SHA512_224 };
+
+/** "sha512_224" OID-identified algorithm */
+struct asn1_algorithm oid_sha512_224_algorithm __asn1_algorithm = {
+ .name = "sha512/224",
+ .digest = &sha512_224_algorithm,
+ .oid = ASN1_OID_CURSOR ( oid_sha512_224 ),
+};
diff --git a/roms/ipxe/src/crypto/sha512_256.c b/roms/ipxe/src/crypto/sha512_256.c
new file mode 100644
index 000000000..f8afaf3e3
--- /dev/null
+++ b/roms/ipxe/src/crypto/sha512_256.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/** @file
+ *
+ * SHA-512/256 algorithm
+ *
+ */
+
+#include <stdint.h>
+#include <byteswap.h>
+#include <ipxe/crypto.h>
+#include <ipxe/asn1.h>
+#include <ipxe/sha512.h>
+
+/** SHA-512/256 initial digest values */
+static const struct sha512_digest sha512_256_init_digest = {
+ .h = {
+ cpu_to_be64 ( 0x22312194fc2bf72cULL ),
+ cpu_to_be64 ( 0x9f555fa3c84c64c2ULL ),
+ cpu_to_be64 ( 0x2393b86b6f53b151ULL ),
+ cpu_to_be64 ( 0x963877195940eabdULL ),
+ cpu_to_be64 ( 0x96283ee2a88effe3ULL ),
+ cpu_to_be64 ( 0xbe5e1e2553863992ULL ),
+ cpu_to_be64 ( 0x2b0199fc2c85b8aaULL ),
+ cpu_to_be64 ( 0x0eb72ddc81c52ca2ULL ),
+ },
+};
+
+/**
+ * Initialise SHA-512/256 algorithm
+ *
+ * @v ctx SHA-512/256 context
+ */
+static void sha512_256_init ( void *ctx ) {
+ struct sha512_context *context = ctx;
+
+ sha512_family_init ( context, &sha512_256_init_digest,
+ SHA512_256_DIGEST_SIZE );
+}
+
+/** SHA-512/256 algorithm */
+struct digest_algorithm sha512_256_algorithm = {
+ .name = "sha512/256",
+ .ctxsize = sizeof ( struct sha512_context ),
+ .blocksize = sizeof ( union sha512_block ),
+ .digestsize = SHA512_256_DIGEST_SIZE,
+ .init = sha512_256_init,
+ .update = sha512_update,
+ .final = sha512_final,
+};
+
+/** "sha512_256" object identifier */
+static uint8_t oid_sha512_256[] = { ASN1_OID_SHA512_256 };
+
+/** "sha512_256" OID-identified algorithm */
+struct asn1_algorithm oid_sha512_256_algorithm __asn1_algorithm = {
+ .name = "sha512/256",
+ .digest = &sha512_256_algorithm,
+ .oid = ASN1_OID_CURSOR ( oid_sha512_256 ),
+};
diff --git a/roms/ipxe/src/crypto/x509.c b/roms/ipxe/src/crypto/x509.c
index 4a02dad14..43a4ca17a 100644
--- a/roms/ipxe/src/crypto/x509.c
+++ b/roms/ipxe/src/crypto/x509.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdlib.h>
#include <string.h>
@@ -139,7 +143,8 @@ const char * x509_name ( struct x509_certificate *cert ) {
} else {
/* Certificate has no commonName: use SHA-1 fingerprint */
x509_fingerprint ( cert, digest, fingerprint );
- base16_encode ( fingerprint, sizeof ( fingerprint ), buf );
+ base16_encode ( fingerprint, sizeof ( fingerprint ),
+ buf, sizeof ( buf ) );
}
return buf;
}
@@ -1761,5 +1766,11 @@ int x509_validate_chain ( struct x509_chain *chain, time_t time,
return -EACCES_USELESS;
}
+/* Drag in objects via x509_validate() */
+REQUIRING_SYMBOL ( x509_validate );
+
/* Drag in certificate store */
REQUIRE_OBJECT ( certstore );
+
+/* Drag in crypto configuration */
+REQUIRE_OBJECT ( config_crypto );
diff --git a/roms/ipxe/src/drivers/bitbash/bitbash.c b/roms/ipxe/src/drivers/bitbash/bitbash.c
index 23ca30356..9b24f716c 100644
--- a/roms/ipxe/src/drivers/bitbash/bitbash.c
+++ b/roms/ipxe/src/drivers/bitbash/bitbash.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/bitbash.h>
diff --git a/roms/ipxe/src/drivers/bitbash/i2c_bit.c b/roms/ipxe/src/drivers/bitbash/i2c_bit.c
index decc8d80e..707d9447d 100644
--- a/roms/ipxe/src/drivers/bitbash/i2c_bit.c
+++ b/roms/ipxe/src/drivers/bitbash/i2c_bit.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <stdint.h>
diff --git a/roms/ipxe/src/drivers/bitbash/spi_bit.c b/roms/ipxe/src/drivers/bitbash/spi_bit.c
index 1b39d72fa..04fddc20b 100644
--- a/roms/ipxe/src/drivers/bitbash/spi_bit.c
+++ b/roms/ipxe/src/drivers/bitbash/spi_bit.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <stdint.h>
diff --git a/roms/ipxe/src/drivers/block/ata.c b/roms/ipxe/src/drivers/block/ata.c
index c9b87c20c..b1c6855a0 100644
--- a/roms/ipxe/src/drivers/block/ata.c
+++ b/roms/ipxe/src/drivers/block/ata.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/drivers/block/scsi.c b/roms/ipxe/src/drivers/block/scsi.c
index 64d692986..fd5f82b9f 100644
--- a/roms/ipxe/src/drivers/block/scsi.c
+++ b/roms/ipxe/src/drivers/block/scsi.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/drivers/bus/cdc.c b/roms/ipxe/src/drivers/bus/cdc.c
new file mode 100644
index 000000000..373a03072
--- /dev/null
+++ b/roms/ipxe/src/drivers/bus/cdc.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2015 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stddef.h>
+#include <ipxe/usb.h>
+#include <ipxe/cdc.h>
+
+/** @file
+ *
+ * USB Communications Device Class (CDC)
+ *
+ */
+
+/**
+ * Locate CDC union functional descriptor
+ *
+ * @v config Configuration descriptor
+ * @v interface Interface descriptor
+ * @ret desc Union functional descriptor, or NULL if not found
+ */
+struct cdc_union_descriptor *
+cdc_union_descriptor ( struct usb_configuration_descriptor *config,
+ struct usb_interface_descriptor *interface ) {
+ struct cdc_union_descriptor *desc;
+
+ for_each_interface_descriptor ( desc, config, interface ) {
+ if ( ( desc->header.type == USB_CS_INTERFACE_DESCRIPTOR ) &&
+ ( desc->subtype == CDC_SUBTYPE_UNION ) )
+ return desc;
+ }
+ return NULL;
+}
diff --git a/roms/ipxe/src/drivers/bus/pci.c b/roms/ipxe/src/drivers/bus/pci.c
index 4a8d00b54..6fbedd940 100644
--- a/roms/ipxe/src/drivers/bus/pci.c
+++ b/roms/ipxe/src/drivers/bus/pci.c
@@ -18,9 +18,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
@@ -58,8 +62,8 @@ static unsigned long pci_bar ( struct pci_device *pci, unsigned int reg ) {
uint32_t high;
pci_read_config_dword ( pci, reg, &low );
- if ( ( low & (PCI_BASE_ADDRESS_SPACE|PCI_BASE_ADDRESS_MEM_TYPE_MASK) )
- == (PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64) ){
+ if ( ( low & (PCI_BASE_ADDRESS_SPACE_IO|PCI_BASE_ADDRESS_MEM_TYPE_MASK))
+ == PCI_BASE_ADDRESS_MEM_TYPE_64 ) {
pci_read_config_dword ( pci, reg + 4, &high );
if ( high ) {
if ( sizeof ( unsigned long ) > sizeof ( uint32_t ) ) {
@@ -93,10 +97,10 @@ unsigned long pci_bar_start ( struct pci_device *pci, unsigned int reg ) {
unsigned long bar;
bar = pci_bar ( pci, reg );
- if ( (bar & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY ){
- return ( bar & PCI_BASE_ADDRESS_MEM_MASK );
+ if ( bar & PCI_BASE_ADDRESS_SPACE_IO ) {
+ return ( bar & ~PCI_BASE_ADDRESS_IO_MASK );
} else {
- return ( bar & PCI_BASE_ADDRESS_IO_MASK );
+ return ( bar & ~PCI_BASE_ADDRESS_MEM_MASK );
}
}
@@ -122,11 +126,11 @@ static void pci_read_bases ( struct pci_device *pci ) {
if ( bar & PCI_BASE_ADDRESS_SPACE_IO ) {
if ( ! pci->ioaddr )
pci->ioaddr =
- ( bar & PCI_BASE_ADDRESS_IO_MASK );
+ ( bar & ~PCI_BASE_ADDRESS_IO_MASK );
} else {
if ( ! pci->membase )
pci->membase =
- ( bar & PCI_BASE_ADDRESS_MEM_MASK );
+ ( bar & ~PCI_BASE_ADDRESS_MEM_MASK );
/* Skip next BAR if 64-bit */
if ( bar & PCI_BASE_ADDRESS_MEM_TYPE_64 )
reg += 4;
@@ -181,7 +185,7 @@ int pci_read_config ( struct pci_device *pci ) {
pci->busdevfn = PCI_FIRST_FUNC ( pci->busdevfn );
pci_read_config_byte ( pci, PCI_HEADER_TYPE, &hdrtype );
pci->busdevfn = busdevfn;
- if ( ! ( hdrtype & 0x80 ) )
+ if ( ! ( hdrtype & PCI_HEADER_TYPE_MULTI ) )
return -ENODEV;
}
@@ -253,6 +257,8 @@ int pci_find_driver ( struct pci_device *pci ) {
unsigned int i;
for_each_table_entry ( driver, PCI_DRIVERS ) {
+ if ( ( driver->class.class ^ pci->class ) & driver->class.mask )
+ continue;
for ( i = 0 ; i < driver->id_count ; i++ ) {
id = &driver->ids[i];
if ( ( id->vendor != PCI_ANY_ID ) &&
@@ -334,14 +340,15 @@ static int pcibus_probe ( struct root_device *rootdev ) {
/* Look for a driver */
if ( ( rc = pci_find_driver ( pci ) ) != 0 ) {
- DBGC ( pci, PCI_FMT " (%04x:%04x) has no driver\n",
- PCI_ARGS ( pci ), pci->vendor, pci->device );
+ DBGC ( pci, PCI_FMT " (%04x:%04x class %06x) has no "
+ "driver\n", PCI_ARGS ( pci ), pci->vendor,
+ pci->device, pci->class );
continue;
}
/* Add to device hierarchy */
pci->dev.parent = &rootdev->dev;
- list_add ( &pci->dev.siblings, &rootdev->dev.children);
+ list_add ( &pci->dev.siblings, &rootdev->dev.children );
/* Look for a driver */
if ( ( rc = pci_probe ( pci ) ) == 0 ) {
diff --git a/roms/ipxe/src/drivers/bus/pci_settings.c b/roms/ipxe/src/drivers/bus/pci_settings.c
index db20452e0..1cb9fa5a3 100644
--- a/roms/ipxe/src/drivers/bus/pci_settings.c
+++ b/roms/ipxe/src/drivers/bus/pci_settings.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdio.h>
#include <errno.h>
diff --git a/roms/ipxe/src/drivers/bus/pcibackup.c b/roms/ipxe/src/drivers/bus/pcibackup.c
index 6b592e893..fecad8192 100644
--- a/roms/ipxe/src/drivers/bus/pcibackup.c
+++ b/roms/ipxe/src/drivers/bus/pcibackup.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/pci.h>
diff --git a/roms/ipxe/src/drivers/bus/pciextra.c b/roms/ipxe/src/drivers/bus/pciextra.c
index c4417e0cb..82287fb86 100644
--- a/roms/ipxe/src/drivers/bus/pciextra.c
+++ b/roms/ipxe/src/drivers/bus/pciextra.c
@@ -1,4 +1,4 @@
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/pci.h>
@@ -26,7 +26,7 @@ int pci_find_capability ( struct pci_device *pci, int cap ) {
return 0;
pci_read_config_byte ( pci, PCI_HEADER_TYPE, &hdr_type );
- switch ( hdr_type & 0x7F ) {
+ switch ( hdr_type & PCI_HEADER_TYPE_MASK ) {
case PCI_HEADER_TYPE_NORMAL:
case PCI_HEADER_TYPE_BRIDGE:
default:
@@ -38,13 +38,13 @@ int pci_find_capability ( struct pci_device *pci, int cap ) {
}
while ( ttl-- && pos >= 0x40 ) {
pos &= ~3;
- pci_read_config_byte ( pci, pos + PCI_CAP_LIST_ID, &id );
+ pci_read_config_byte ( pci, pos + PCI_CAP_ID, &id );
DBG ( "PCI Capability: %d\n", id );
if ( id == 0xff )
break;
if ( id == cap )
return pos;
- pci_read_config_byte ( pci, pos + PCI_CAP_LIST_NEXT, &pos );
+ pci_read_config_byte ( pci, pos + PCI_CAP_NEXT, &pos );
}
return 0;
}
@@ -76,9 +76,9 @@ unsigned long pci_bar_size ( struct pci_device *pci, unsigned int reg ) {
/* Restore the original command register. This reenables decoding. */
pci_write_config_word ( pci, PCI_COMMAND, cmd );
if ( start & PCI_BASE_ADDRESS_SPACE_IO ) {
- size &= PCI_BASE_ADDRESS_IO_MASK;
+ size &= ~PCI_BASE_ADDRESS_IO_MASK;
} else {
- size &= PCI_BASE_ADDRESS_MEM_MASK;
+ size &= ~PCI_BASE_ADDRESS_MEM_MASK;
}
/* Find the lowest bit set */
size = size & ~( size - 1 );
diff --git a/roms/ipxe/src/drivers/bus/pcivpd.c b/roms/ipxe/src/drivers/bus/pcivpd.c
index 0b7a879fe..243b1f779 100644
--- a/roms/ipxe/src/drivers/bus/pcivpd.c
+++ b/roms/ipxe/src/drivers/bus/pcivpd.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/drivers/bus/usb.c b/roms/ipxe/src/drivers/bus/usb.c
new file mode 100644
index 000000000..2019e3341
--- /dev/null
+++ b/roms/ipxe/src/drivers/bus/usb.c
@@ -0,0 +1,2128 @@
+/*
+ * Copyright (C) 2014 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <ipxe/usb.h>
+#include <ipxe/cdc.h>
+
+/** @file
+ *
+ * Universal Serial Bus (USB)
+ *
+ */
+
+/** List of USB buses */
+struct list_head usb_buses = LIST_HEAD_INIT ( usb_buses );
+
+/** List of changed ports */
+static struct list_head usb_changed = LIST_HEAD_INIT ( usb_changed );
+
+/** List of halted endpoints */
+static struct list_head usb_halted = LIST_HEAD_INIT ( usb_halted );
+
+/******************************************************************************
+ *
+ * Utility functions
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Get USB speed name (for debugging)
+ *
+ * @v speed Speed
+ * @ret name Speed name
+ */
+static inline const char * usb_speed_name ( unsigned int speed ) {
+ static const char *exponents[4] = { "", "k", "M", "G" };
+ static char buf[ 10 /* "xxxxxXbps" + NUL */ ];
+ unsigned int mantissa;
+ unsigned int exponent;
+
+ /* Extract mantissa and exponent */
+ mantissa = USB_SPEED_MANTISSA ( speed );
+ exponent = USB_SPEED_EXPONENT ( speed );
+
+ /* Name speed */
+ switch ( speed ) {
+ case USB_SPEED_NONE: return "DETACHED";
+ case USB_SPEED_LOW: return "low";
+ case USB_SPEED_FULL: return "full";
+ case USB_SPEED_HIGH: return "high";
+ case USB_SPEED_SUPER: return "super";
+ default:
+ snprintf ( buf, sizeof ( buf ), "%d%sbps",
+ mantissa, exponents[exponent] );
+ return buf;
+ }
+}
+
+/**
+ * Transcribe USB BCD-coded value (for debugging)
+ *
+ * @v bcd BCD-coded value
+ * @ret string Transcribed value
+ */
+static inline const char * usb_bcd ( uint16_t bcd ) {
+ static char buf[ 6 /* "xx.xx" + NUL */ ];
+ uint8_t high = ( bcd >> 8 );
+ uint8_t low = ( bcd >> 0 );
+
+ snprintf ( buf, sizeof ( buf ), "%x.%02x", high, low );
+ return buf;
+}
+
+/******************************************************************************
+ *
+ * USB descriptors
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Locate USB interface association descriptor
+ *
+ * @v config Configuraton descriptor
+ * @v first First interface number
+ * @ret desc Interface association descriptor, or NULL if not found
+ */
+static struct usb_interface_association_descriptor *
+usb_interface_association_descriptor ( struct usb_configuration_descriptor
+ *config,
+ unsigned int first ) {
+ struct usb_interface_association_descriptor *desc;
+
+ /* Find a matching interface association descriptor */
+ for_each_config_descriptor ( desc, config ) {
+ if ( ( desc->header.type ==
+ USB_INTERFACE_ASSOCIATION_DESCRIPTOR ) &&
+ ( desc->first == first ) )
+ return desc;
+ }
+ return NULL;
+}
+
+/**
+ * Locate USB interface descriptor
+ *
+ * @v config Configuraton descriptor
+ * @v interface Interface number
+ * @v alternate Alternate setting
+ * @ret desc Interface descriptor, or NULL if not found
+ */
+struct usb_interface_descriptor *
+usb_interface_descriptor ( struct usb_configuration_descriptor *config,
+ unsigned int interface, unsigned int alternate ) {
+ struct usb_interface_descriptor *desc;
+
+ /* Find a matching interface descriptor */
+ for_each_config_descriptor ( desc, config ) {
+ if ( ( desc->header.type == USB_INTERFACE_DESCRIPTOR ) &&
+ ( desc->interface == interface ) &&
+ ( desc->alternate == alternate ) )
+ return desc;
+ }
+ return NULL;
+}
+
+/**
+ * Locate USB endpoint descriptor
+ *
+ * @v config Configuration descriptor
+ * @v interface Interface descriptor
+ * @v type Endpoint (internal) type
+ * @v index Endpoint index
+ * @ret desc Descriptor, or NULL if not found
+ */
+struct usb_endpoint_descriptor *
+usb_endpoint_descriptor ( struct usb_configuration_descriptor *config,
+ struct usb_interface_descriptor *interface,
+ unsigned int type, unsigned int index ) {
+ struct usb_endpoint_descriptor *desc;
+ unsigned int attributes = ( type & USB_ENDPOINT_ATTR_TYPE_MASK );
+ unsigned int direction = ( type & USB_DIR_IN );
+
+ /* Find a matching endpoint descriptor */
+ for_each_interface_descriptor ( desc, config, interface ) {
+ if ( ( desc->header.type == USB_ENDPOINT_DESCRIPTOR ) &&
+ ( ( desc->attributes &
+ USB_ENDPOINT_ATTR_TYPE_MASK ) == attributes ) &&
+ ( ( desc->endpoint & USB_DIR_IN ) == direction ) &&
+ ( index-- == 0 ) )
+ return desc;
+ }
+ return NULL;
+}
+
+/**
+ * Locate USB endpoint companion descriptor
+ *
+ * @v config Configuration descriptor
+ * @v desc Endpoint descriptor
+ * @ret descx Companion descriptor, or NULL if not found
+ */
+struct usb_endpoint_companion_descriptor *
+usb_endpoint_companion_descriptor ( struct usb_configuration_descriptor *config,
+ struct usb_endpoint_descriptor *desc ) {
+ struct usb_endpoint_companion_descriptor *descx;
+
+ /* Get companion descriptor, if present */
+ descx = container_of ( usb_next_descriptor ( &desc->header ),
+ struct usb_endpoint_companion_descriptor,
+ header );
+ return ( ( usb_is_within_config ( config, &descx->header ) &&
+ descx->header.type == USB_ENDPOINT_COMPANION_DESCRIPTOR )
+ ? descx : NULL );
+}
+
+/******************************************************************************
+ *
+ * USB endpoint
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Get USB endpoint name (for debugging)
+ *
+ * @v ep USB endpoint
+ * @ret name Endpoint name
+ */
+const char * usb_endpoint_name ( struct usb_endpoint *ep ) {
+ static char buf[ 9 /* "EPxx OUT" + NUL */ ];
+ unsigned int address = ep->address;
+
+ snprintf ( buf, sizeof ( buf ), "EP%d%s",
+ ( address & USB_ENDPOINT_MAX ),
+ ( address ?
+ ( ( address & USB_ENDPOINT_IN ) ? " IN" : " OUT" ) : "" ));
+ return buf;
+}
+
+/**
+ * Describe USB endpoint from device configuration
+ *
+ * @v ep USB endpoint
+ * @v config Configuration descriptor
+ * @v interface Interface descriptor
+ * @v type Endpoint (internal) type
+ * @v index Endpoint index
+ * @ret rc Return status code
+ */
+int usb_endpoint_described ( struct usb_endpoint *ep,
+ struct usb_configuration_descriptor *config,
+ struct usb_interface_descriptor *interface,
+ unsigned int type, unsigned int index ) {
+ struct usb_device *usb = ep->usb;
+ struct usb_port *port = usb->port;
+ struct usb_endpoint_descriptor *desc;
+ struct usb_endpoint_companion_descriptor *descx;
+ unsigned int sizes;
+ unsigned int burst;
+ unsigned int interval;
+ size_t mtu;
+
+ /* Locate endpoint descriptor */
+ desc = usb_endpoint_descriptor ( config, interface, type, index );
+ if ( ! desc )
+ return -ENOENT;
+
+ /* Locate companion descriptor, if any */
+ descx = usb_endpoint_companion_descriptor ( config, desc );
+
+ /* Calculate MTU and burst size */
+ sizes = le16_to_cpu ( desc->sizes );
+ mtu = USB_ENDPOINT_MTU ( sizes );
+ burst = ( descx ? descx->burst : USB_ENDPOINT_BURST ( sizes ) );
+
+ /* Calculate interval */
+ if ( ( type & USB_ENDPOINT_ATTR_TYPE_MASK ) ==
+ USB_ENDPOINT_ATTR_INTERRUPT ) {
+ if ( port->speed >= USB_SPEED_HIGH ) {
+ /* 2^(desc->interval-1) is a microframe count */
+ interval = ( 1 << ( desc->interval - 1 ) );
+ } else {
+ /* desc->interval is a (whole) frame count */
+ interval = ( desc->interval << 3 );
+ }
+ } else {
+ /* desc->interval is a microframe count */
+ interval = desc->interval;
+ }
+
+ /* Describe endpoint */
+ usb_endpoint_describe ( ep, desc->endpoint, desc->attributes,
+ mtu, burst, interval );
+ return 0;
+}
+
+/**
+ * Open USB endpoint
+ *
+ * @v ep USB endpoint
+ * @ret rc Return status code
+ */
+int usb_endpoint_open ( struct usb_endpoint *ep ) {
+ struct usb_device *usb = ep->usb;
+ unsigned int idx = USB_ENDPOINT_IDX ( ep->address );
+ int rc;
+
+ /* Populate host controller operations */
+ ep->host = &usb->port->hub->bus->op->endpoint;
+
+ /* Add to endpoint list */
+ if ( usb->ep[idx] != NULL ) {
+ DBGC ( usb, "USB %s %s is already open\n",
+ usb->name, usb_endpoint_name ( ep ) );
+ rc = -EALREADY;
+ goto err_already;
+ }
+ usb->ep[idx] = ep;
+ INIT_LIST_HEAD ( &ep->halted );
+
+ /* Open endpoint */
+ if ( ( rc = ep->host->open ( ep ) ) != 0 ) {
+ DBGC ( usb, "USB %s %s could not open: %s\n", usb->name,
+ usb_endpoint_name ( ep ), strerror ( rc ) );
+ goto err_open;
+ }
+ ep->open = 1;
+
+ DBGC2 ( usb, "USB %s %s opened with MTU %zd, burst %d, interval %d\n",
+ usb->name, usb_endpoint_name ( ep ), ep->mtu, ep->burst,
+ ep->interval );
+ return 0;
+
+ ep->open = 0;
+ ep->host->close ( ep );
+ err_open:
+ usb->ep[idx] = NULL;
+ err_already:
+ if ( ep->max )
+ usb_flush ( ep );
+ return rc;
+}
+
+/**
+ * Clear transaction translator (if applicable)
+ *
+ * @v ep USB endpoint
+ * @ret rc Return status code
+ */
+static int usb_endpoint_clear_tt ( struct usb_endpoint *ep ) {
+ struct usb_device *usb = ep->usb;
+ struct usb_port *tt;
+ int rc;
+
+ /* Do nothing if this is a periodic endpoint */
+ if ( ep->attributes & USB_ENDPOINT_ATTR_PERIODIC )
+ return 0;
+
+ /* Do nothing if this endpoint is not behind a transaction translator */
+ tt = usb_transaction_translator ( usb );
+ if ( ! tt )
+ return 0;
+
+ /* Clear transaction translator buffer */
+ if ( ( rc = tt->hub->driver->clear_tt ( tt->hub, tt, ep ) ) != 0 ) {
+ DBGC ( usb, "USB %s %s could not clear transaction translator: "
+ "%s\n", usb->name, usb_endpoint_name ( ep ),
+ strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Close USB endpoint
+ *
+ * @v ep USB endpoint
+ */
+void usb_endpoint_close ( struct usb_endpoint *ep ) {
+ struct usb_device *usb = ep->usb;
+ unsigned int idx = USB_ENDPOINT_IDX ( ep->address );
+
+ /* Sanity checks */
+ assert ( usb->ep[idx] == ep );
+
+ /* Close endpoint */
+ ep->open = 0;
+ ep->host->close ( ep );
+ assert ( ep->fill == 0 );
+
+ /* Remove from endpoint list */
+ usb->ep[idx] = NULL;
+ list_del ( &ep->halted );
+
+ /* Discard any recycled buffers, if applicable */
+ if ( ep->max )
+ usb_flush ( ep );
+
+ /* Clear transaction translator, if applicable */
+ usb_endpoint_clear_tt ( ep );
+}
+
+/**
+ * Reset USB endpoint
+ *
+ * @v ep USB endpoint
+ * @ret rc Return status code
+ */
+static int usb_endpoint_reset ( struct usb_endpoint *ep ) {
+ struct usb_device *usb = ep->usb;
+ unsigned int type;
+ int rc;
+
+ /* Sanity check */
+ assert ( ! list_empty ( &ep->halted ) );
+
+ /* Reset endpoint */
+ if ( ( rc = ep->host->reset ( ep ) ) != 0 ) {
+ DBGC ( usb, "USB %s %s could not reset: %s\n",
+ usb->name, usb_endpoint_name ( ep ), strerror ( rc ) );
+ return rc;
+ }
+
+ /* Clear transaction translator, if applicable */
+ if ( ( rc = usb_endpoint_clear_tt ( ep ) ) != 0 )
+ return rc;
+
+ /* Clear endpoint halt, if applicable */
+ type = ( ep->attributes & USB_ENDPOINT_ATTR_TYPE_MASK );
+ if ( ( type != USB_ENDPOINT_ATTR_CONTROL ) &&
+ ( ( rc = usb_clear_feature ( usb, USB_RECIP_ENDPOINT,
+ USB_ENDPOINT_HALT,
+ ep->address ) ) != 0 ) ) {
+ DBGC ( usb, "USB %s %s could not clear endpoint halt: %s\n",
+ usb->name, usb_endpoint_name ( ep ), strerror ( rc ) );
+ return rc;
+ }
+
+ /* Remove from list of halted endpoints */
+ list_del ( &ep->halted );
+ INIT_LIST_HEAD ( &ep->halted );
+
+ DBGC ( usb, "USB %s %s reset\n",
+ usb->name, usb_endpoint_name ( ep ) );
+ return 0;
+}
+
+/**
+ * Update endpoint MTU
+ *
+ * @v ep USB endpoint
+ * @v mtu New MTU
+ * @ret rc Return status code
+ */
+static int usb_endpoint_mtu ( struct usb_endpoint *ep, size_t mtu ) {
+ struct usb_device *usb = ep->usb;
+ int rc;
+
+ /* Update MTU */
+ ep->mtu = mtu;
+ if ( ( rc = ep->host->mtu ( ep ) ) != 0 ) {
+ DBGC ( usb, "USB %s %s could not update MTU: %s\n",
+ usb->name, usb_endpoint_name ( ep ), strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Enqueue USB message transfer
+ *
+ * @v ep USB endpoint
+ * @v request Request
+ * @v value Value parameter
+ * @v index Index parameter
+ * @v iobuf I/O buffer
+ * @ret rc Return status code
+ *
+ * The I/O buffer must have sufficient headroom to contain a setup
+ * packet.
+ */
+int usb_message ( struct usb_endpoint *ep, unsigned int request,
+ unsigned int value, unsigned int index,
+ struct io_buffer *iobuf ) {
+ struct usb_device *usb = ep->usb;
+ struct usb_port *port = usb->port;
+ struct usb_setup_packet *packet;
+ size_t len = iob_len ( iobuf );
+ int rc;
+
+ /* Sanity check */
+ assert ( iob_headroom ( iobuf ) >= sizeof ( *packet ) );
+
+ /* Fail immediately if device has been unplugged */
+ if ( port->speed == USB_SPEED_NONE )
+ return -ENODEV;
+
+ /* Reset endpoint if required */
+ if ( ( ! list_empty ( &ep->halted ) ) &&
+ ( ( rc = usb_endpoint_reset ( ep ) ) != 0 ) )
+ return rc;
+
+ /* Zero input data buffer (if applicable) */
+ if ( request & USB_DIR_IN )
+ memset ( iobuf->data, 0, len );
+
+ /* Construct setup packet */
+ packet = iob_push ( iobuf, sizeof ( *packet ) );
+ packet->request = cpu_to_le16 ( request );
+ packet->value = cpu_to_le16 ( value );
+ packet->index = cpu_to_le16 ( index );
+ packet->len = cpu_to_le16 ( len );
+
+ /* Enqueue message transfer */
+ if ( ( rc = ep->host->message ( ep, iobuf ) ) != 0 ) {
+ DBGC ( usb, "USB %s %s could not enqueue message transfer: "
+ "%s\n", usb->name, usb_endpoint_name ( ep ),
+ strerror ( rc ) );
+ return rc;
+ }
+
+ /* Increment fill level */
+ ep->fill++;
+
+ return 0;
+}
+
+/**
+ * Enqueue USB stream transfer
+ *
+ * @v ep USB endpoint
+ * @v iobuf I/O buffer
+ * @v terminate Terminate using a short packet
+ * @ret rc Return status code
+ */
+int usb_stream ( struct usb_endpoint *ep, struct io_buffer *iobuf,
+ int terminate ) {
+ struct usb_device *usb = ep->usb;
+ struct usb_port *port = usb->port;
+ int rc;
+
+ /* Fail immediately if device has been unplugged */
+ if ( port->speed == USB_SPEED_NONE )
+ return -ENODEV;
+
+ /* Reset endpoint if required */
+ if ( ( ! list_empty ( &ep->halted ) ) &&
+ ( ( rc = usb_endpoint_reset ( ep ) ) != 0 ) )
+ return rc;
+
+ /* Enqueue stream transfer */
+ if ( ( rc = ep->host->stream ( ep, iobuf, terminate ) ) != 0 ) {
+ DBGC ( usb, "USB %s %s could not enqueue stream transfer: %s\n",
+ usb->name, usb_endpoint_name ( ep ), strerror ( rc ) );
+ return rc;
+ }
+
+ /* Increment fill level */
+ ep->fill++;
+
+ return 0;
+}
+
+/**
+ * Complete transfer (possibly with error)
+ *
+ * @v ep USB endpoint
+ * @v iobuf I/O buffer
+ * @v rc Completion status code
+ */
+void usb_complete_err ( struct usb_endpoint *ep, struct io_buffer *iobuf,
+ int rc ) {
+ struct usb_device *usb = ep->usb;
+
+ /* Decrement fill level */
+ assert ( ep->fill > 0 );
+ ep->fill--;
+
+ /* Schedule reset, if applicable */
+ if ( ( rc != 0 ) && ep->open ) {
+ DBGC ( usb, "USB %s %s completion failed: %s\n",
+ usb->name, usb_endpoint_name ( ep ), strerror ( rc ) );
+ list_del ( &ep->halted );
+ list_add_tail ( &ep->halted, &usb_halted );
+ }
+
+ /* Report completion */
+ ep->driver->complete ( ep, iobuf, rc );
+}
+
+/******************************************************************************
+ *
+ * Endpoint refilling
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Prefill endpoint recycled buffer list
+ *
+ * @v ep USB endpoint
+ * @ret rc Return status code
+ */
+int usb_prefill ( struct usb_endpoint *ep ) {
+ struct io_buffer *iobuf;
+ size_t len = ( ep->len ? ep->len : ep->mtu );
+ unsigned int fill;
+ int rc;
+
+ /* Sanity checks */
+ assert ( ep->fill == 0 );
+ assert ( ep->max > 0 );
+ assert ( list_empty ( &ep->recycled ) );
+
+ /* Fill recycled buffer list */
+ for ( fill = 0 ; fill < ep->max ; fill++ ) {
+
+ /* Allocate I/O buffer */
+ iobuf = alloc_iob ( len );
+ if ( ! iobuf ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+
+ /* Add to recycled buffer list */
+ list_add_tail ( &iobuf->list, &ep->recycled );
+ }
+
+ return 0;
+
+ err_alloc:
+ usb_flush ( ep );
+ return rc;
+}
+
+/**
+ * Refill endpoint
+ *
+ * @v ep USB endpoint
+ * @ret rc Return status code
+ */
+int usb_refill ( struct usb_endpoint *ep ) {
+ struct io_buffer *iobuf;
+ size_t len = ( ep->len ? ep->len : ep->mtu );
+ int rc;
+
+ /* Sanity checks */
+ assert ( ep->open );
+ assert ( ep->max > 0 );
+
+ /* Refill endpoint */
+ while ( ep->fill < ep->max ) {
+
+ /* Get or allocate buffer */
+ if ( list_empty ( &ep->recycled ) ) {
+ /* Recycled buffer list is empty; allocate new buffer */
+ iobuf = alloc_iob ( len );
+ if ( ! iobuf )
+ return -ENOMEM;
+ } else {
+ /* Get buffer from recycled buffer list */
+ iobuf = list_first_entry ( &ep->recycled,
+ struct io_buffer, list );
+ assert ( iobuf != NULL );
+ list_del ( &iobuf->list );
+ }
+
+ /* Reset buffer to maximum size */
+ assert ( iob_len ( iobuf ) <= len );
+ iob_put ( iobuf, ( len - iob_len ( iobuf ) ) );
+
+ /* Enqueue buffer */
+ if ( ( rc = usb_stream ( ep, iobuf, 0 ) ) != 0 ) {
+ list_add ( &iobuf->list, &ep->recycled );
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Discard endpoint recycled buffer list
+ *
+ * @v ep USB endpoint
+ */
+void usb_flush ( struct usb_endpoint *ep ) {
+ struct io_buffer *iobuf;
+ struct io_buffer *tmp;
+
+ /* Sanity checks */
+ assert ( ! ep->open );
+ assert ( ep->max > 0 );
+
+ /* Free all I/O buffers */
+ list_for_each_entry_safe ( iobuf, tmp, &ep->recycled, list ) {
+ list_del ( &iobuf->list );
+ free_iob ( iobuf );
+ }
+}
+
+/******************************************************************************
+ *
+ * Control endpoint
+ *
+ ******************************************************************************
+ */
+
+/** USB control transfer pseudo-header */
+struct usb_control_pseudo_header {
+ /** Completion status */
+ int rc;
+};
+
+/**
+ * Complete USB control transfer
+ *
+ * @v ep USB endpoint
+ * @v iobuf I/O buffer
+ * @v rc Completion status code
+ */
+static void usb_control_complete ( struct usb_endpoint *ep,
+ struct io_buffer *iobuf, int rc ) {
+ struct usb_device *usb = ep->usb;
+ struct usb_control_pseudo_header *pshdr;
+
+ /* Record completion status in buffer */
+ pshdr = iob_push ( iobuf, sizeof ( *pshdr ) );
+ pshdr->rc = rc;
+
+ /* Add to list of completed I/O buffers */
+ list_add_tail ( &iobuf->list, &usb->complete );
+}
+
+/** USB control endpoint driver operations */
+static struct usb_endpoint_driver_operations usb_control_operations = {
+ .complete = usb_control_complete,
+};
+
+/**
+ * Issue USB control transaction
+ *
+ * @v usb USB device
+ * @v request Request
+ * @v value Value parameter
+ * @v index Index parameter
+ * @v data Data buffer (if any)
+ * @v len Length of data
+ * @ret rc Return status code
+ */
+int usb_control ( struct usb_device *usb, unsigned int request,
+ unsigned int value, unsigned int index, void *data,
+ size_t len ) {
+ struct usb_bus *bus = usb->port->hub->bus;
+ struct usb_endpoint *ep = &usb->control;
+ struct io_buffer *iobuf;
+ struct io_buffer *cmplt;
+ union {
+ struct usb_setup_packet setup;
+ struct usb_control_pseudo_header pshdr;
+ } *headroom;
+ struct usb_control_pseudo_header *pshdr;
+ unsigned int i;
+ int rc;
+
+ /* Allocate I/O buffer */
+ iobuf = alloc_iob ( sizeof ( *headroom ) + len );
+ if ( ! iobuf ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ iob_reserve ( iobuf, sizeof ( *headroom ) );
+ iob_put ( iobuf, len );
+ if ( request & USB_DIR_IN ) {
+ memset ( data, 0, len );
+ } else {
+ memcpy ( iobuf->data, data, len );
+ }
+
+ /* Enqueue message */
+ if ( ( rc = usb_message ( ep, request, value, index, iobuf ) ) != 0 )
+ goto err_message;
+
+ /* Wait for completion */
+ for ( i = 0 ; i < USB_CONTROL_MAX_WAIT_MS ; i++ ) {
+
+ /* Poll bus */
+ usb_poll ( bus );
+
+ /* Check for completion */
+ while ( ( cmplt = list_first_entry ( &usb->complete,
+ struct io_buffer,
+ list ) ) ) {
+
+ /* Remove from completion list */
+ list_del ( &cmplt->list );
+
+ /* Extract and strip completion status */
+ pshdr = cmplt->data;
+ iob_pull ( cmplt, sizeof ( *pshdr ) );
+ rc = pshdr->rc;
+
+ /* Discard stale completions */
+ if ( cmplt != iobuf ) {
+ DBGC ( usb, "USB %s stale control completion: "
+ "%s\n", usb->name, strerror ( rc ) );
+ DBGC_HDA ( usb, 0, cmplt->data,
+ iob_len ( cmplt ) );
+ free_iob ( cmplt );
+ continue;
+ }
+
+ /* Fail immediately if completion was in error */
+ if ( rc != 0 ) {
+ DBGC ( usb, "USB %s control %04x:%04x:%04x "
+ "failed: %s\n", usb->name, request,
+ value, index, strerror ( rc ) );
+ free_iob ( cmplt );
+ return rc;
+ }
+
+ /* Copy completion to data buffer, if applicable */
+ assert ( iob_len ( cmplt ) <= len );
+ if ( request & USB_DIR_IN )
+ memcpy ( data, cmplt->data, iob_len ( cmplt ) );
+ free_iob ( cmplt );
+ return 0;
+ }
+
+ /* Delay */
+ mdelay ( 1 );
+ }
+
+ DBGC ( usb, "USB %s timed out waiting for control %04x:%04x:%04x\n",
+ usb->name, request, value, index );
+ return -ETIMEDOUT;
+
+ err_message:
+ free_iob ( iobuf );
+ err_alloc:
+ return rc;
+}
+
+/**
+ * Get USB string descriptor
+ *
+ * @v usb USB device
+ * @v index String index
+ * @v language Language ID
+ * @v buf Data buffer
+ * @v len Length of buffer
+ * @ret len String length (excluding NUL), or negative error
+ */
+int usb_get_string_descriptor ( struct usb_device *usb, unsigned int index,
+ unsigned int language, char *buf, size_t len ) {
+ size_t max = ( len ? ( len - 1 /* NUL */ ) : 0 );
+ struct {
+ struct usb_descriptor_header header;
+ uint16_t character[max];
+ } __attribute__ (( packed )) *desc;
+ unsigned int actual;
+ unsigned int i;
+ int rc;
+
+ /* Allocate buffer for string */
+ desc = malloc ( sizeof ( *desc ) );
+ if ( ! desc ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+
+ /* Get descriptor */
+ if ( ( rc = usb_get_descriptor ( usb, 0, USB_STRING_DESCRIPTOR, index,
+ language, &desc->header,
+ sizeof ( *desc ) ) ) != 0 )
+ goto err_get_descriptor;
+
+ /* Copy to buffer */
+ actual = ( ( desc->header.len - sizeof ( desc->header ) ) /
+ sizeof ( desc->character[0] ) );
+ for ( i = 0 ; ( ( i < actual ) && ( i < max ) ) ; i++ )
+ buf[i] = le16_to_cpu ( desc->character[i] );
+ if ( len )
+ buf[i] = '\0';
+
+ /* Free buffer */
+ free ( desc );
+
+ return actual;
+
+ err_get_descriptor:
+ free ( desc );
+ err_alloc:
+ return rc;
+}
+
+/******************************************************************************
+ *
+ * USB device driver
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Describe USB function
+ *
+ * @v func USB function
+ * @v config Configuration descriptor
+ * @v first First interface number
+ * @ret rc Return status code
+ */
+static int usb_function ( struct usb_function *func,
+ struct usb_configuration_descriptor *config,
+ unsigned int first ) {
+ struct usb_device *usb = func->usb;
+ struct usb_interface_association_descriptor *association;
+ struct usb_interface_descriptor *interface;
+ struct cdc_union_descriptor *cdc_union;
+ unsigned int i;
+
+ /* First, look for an interface association descriptor */
+ association = usb_interface_association_descriptor ( config, first );
+ if ( association ) {
+
+ /* Sanity check */
+ if ( association->count > config->interfaces ) {
+ DBGC ( usb, "USB %s has invalid association [%d-%d)\n",
+ func->name, association->first,
+ ( association->first + association->count ) );
+ return -ERANGE;
+ }
+
+ /* Describe function */
+ memcpy ( &func->class, &association->class,
+ sizeof ( func->class ) );
+ func->count = association->count;
+ for ( i = 0 ; i < association->count ; i++ )
+ func->interface[i] = ( association->first + i );
+ return 0;
+ }
+
+ /* Next, look for an interface descriptor */
+ interface = usb_interface_descriptor ( config, first, 0 );
+ if ( ! interface ) {
+ DBGC ( usb, "USB %s has no interface descriptor\n",
+ func->name );
+ return -ENOENT;
+ }
+
+ /* Describe function */
+ memcpy ( &func->class, &interface->class, sizeof ( func->class ) );
+ func->count = 1;
+ func->interface[0] = first;
+
+ /* Look for a CDC union descriptor, if applicable */
+ if ( ( func->class.class == USB_CLASS_CDC ) &&
+ ( cdc_union = cdc_union_descriptor ( config, interface ) ) ) {
+
+ /* Determine interface count */
+ func->count = ( ( cdc_union->header.len -
+ offsetof ( typeof ( *cdc_union ),
+ interface[0] ) ) /
+ sizeof ( cdc_union->interface[0] ) );
+ if ( func->count > config->interfaces ) {
+ DBGC ( usb, "USB %s has invalid union functional "
+ "descriptor with %d interfaces\n",
+ func->name, func->count );
+ return -ERANGE;
+ }
+
+ /* Describe function */
+ for ( i = 0 ; i < func->count ; i++ )
+ func->interface[i] = cdc_union->interface[i];
+
+ return 0;
+ }
+
+ return 0;
+}
+
+/**
+ * Check for a USB device ID match
+ *
+ * @v func USB function
+ * @v id Device ID
+ * @ret matches Device ID matches
+ */
+static int
+usb_device_id_matches ( struct usb_function *func, struct usb_device_id *id ) {
+
+ return ( ( ( id->vendor == func->dev.desc.vendor ) ||
+ ( id->vendor == USB_ANY_ID ) ) &&
+ ( ( id->product == func->dev.desc.device ) ||
+ ( id->product == USB_ANY_ID ) ) &&
+ ( id->class.class == func->class.class ) &&
+ ( id->class.subclass == func->class.subclass ) &&
+ ( id->class.protocol == func->class.protocol ) );
+}
+
+/**
+ * Probe USB device driver
+ *
+ * @v func USB function
+ * @v config Configuration descriptor
+ * @ret rc Return status code
+ */
+static int usb_probe ( struct usb_function *func,
+ struct usb_configuration_descriptor *config ) {
+ struct usb_device *usb = func->usb;
+ struct usb_driver *driver;
+ struct usb_device_id *id;
+ unsigned int i;
+ int rc;
+
+ /* Look for a matching driver */
+ for_each_table_entry ( driver, USB_DRIVERS ) {
+ for ( i = 0 ; i < driver->id_count ; i++ ) {
+
+ /* Check for a matching ID */
+ id = &driver->ids[i];
+ if ( ! usb_device_id_matches ( func, id ) )
+ continue;
+
+ /* Probe driver */
+ if ( ( rc = driver->probe ( func, config ) ) != 0 ) {
+ DBGC ( usb, "USB %s failed to probe driver %s: "
+ "%s\n", func->name, id->name,
+ strerror ( rc ) );
+ /* Continue trying other drivers */
+ continue;
+ }
+
+ /* Record driver */
+ func->driver = driver;
+ func->dev.driver_name = id->name;
+ return 0;
+ }
+ }
+
+ /* No driver found */
+ DBGC ( usb, "USB %s %04x:%04x class %d:%d:%d has no driver\n",
+ func->name, func->dev.desc.vendor, func->dev.desc.device,
+ func->class.class, func->class.subclass, func->class.protocol );
+ return -ENOENT;
+}
+
+/**
+ * Remove USB device driver
+ *
+ * @v func USB function
+ */
+static void usb_remove ( struct usb_function *func ) {
+
+ /* Remove driver */
+ func->driver->remove ( func );
+}
+
+/**
+ * Probe all USB device drivers
+ *
+ * @v usb USB device
+ * @v config Configuration descriptor
+ */
+static void
+usb_probe_all ( struct usb_device *usb,
+ struct usb_configuration_descriptor *config ) {
+ struct usb_bus *bus = usb->port->hub->bus;
+ struct usb_function *func;
+ uint8_t used[config->interfaces];
+ unsigned int first;
+ unsigned int i;
+ int rc;
+
+ /* Identify each function in turn */
+ memset ( used, 0, sizeof ( used ) );
+ for ( first = 0 ; first < config->interfaces ; first++ ) {
+
+ /* Skip interfaces already used */
+ if ( used[first] )
+ continue;
+
+ /* Allocate and initialise structure */
+ func = zalloc ( sizeof ( *func ) +
+ ( config->interfaces *
+ sizeof ( func->interface[0] ) ) );
+ if ( ! func )
+ goto err_alloc;
+ func->name = func->dev.name;
+ func->usb = usb;
+ func->dev.desc.bus_type = BUS_TYPE_USB;
+ func->dev.desc.location = usb->address;
+ func->dev.desc.vendor = le16_to_cpu ( usb->device.vendor );
+ func->dev.desc.device = le16_to_cpu ( usb->device.product );
+ snprintf ( func->dev.name, sizeof ( func->dev.name ),
+ "%s-%d.%d", usb->name, config->config, first );
+ INIT_LIST_HEAD ( &func->dev.children );
+ func->dev.parent = bus->dev;
+
+ /* Identify function */
+ if ( ( rc = usb_function ( func, config, first ) ) != 0 )
+ goto err_function;
+ assert ( func->count <= config->interfaces );
+
+ /* Mark interfaces as used */
+ for ( i = 0 ; i < func->count ; i++ ) {
+ if ( func->interface[i] >= config->interfaces ) {
+ DBGC ( usb, "USB %s has invalid interface %d\n",
+ func->name, func->interface[i] );
+ goto err_interface;
+ }
+ used[ func->interface[i] ] = 1;
+ }
+
+ /* Probe device driver */
+ if ( ( rc = usb_probe ( func, config ) ) != 0 )
+ goto err_probe;
+ DBGC ( usb, "USB %s %04x:%04x class %d:%d:%d interfaces ",
+ func->name, func->dev.desc.vendor, func->dev.desc.device,
+ func->class.class, func->class.subclass,
+ func->class.protocol );
+ for ( i = 0 ; i < func->count ; i++ )
+ DBGC ( usb, "%s%d", ( i ? "," : "" ),
+ func->interface[i] );
+ DBGC ( usb, " using driver %s\n", func->dev.driver_name );
+
+ /* Add to list of functions */
+ list_add ( &func->list, &usb->functions );
+
+ /* Add to device hierarchy */
+ list_add_tail ( &func->dev.siblings, &bus->dev->children );
+
+ continue;
+
+ list_del ( &func->dev.siblings );
+ list_del ( &func->list );
+ usb_remove ( func );
+ err_probe:
+ free ( func );
+ err_alloc:
+ err_interface:
+ err_function:
+ /* Continue registering other functions */
+ continue;
+ }
+}
+
+/**
+ * Remove all device drivers
+ *
+ * @v usb USB device
+ */
+static void usb_remove_all ( struct usb_device *usb ) {
+ struct usb_function *func;
+ struct usb_function *tmp;
+
+ /* Remove all functions */
+ list_for_each_entry_safe ( func, tmp, &usb->functions, list ) {
+
+ /* Remove device driver */
+ usb_remove ( func );
+
+ /* Remove from device hierarchy */
+ assert ( list_empty ( &func->dev.children ) );
+ list_del ( &func->dev.siblings );
+
+ /* Remove from list of functions */
+ list_del ( &func->list );
+
+ /* Free function */
+ free ( func );
+ }
+}
+
+/**
+ * Select USB device configuration
+ *
+ * @v usb USB device
+ * @v index Configuration index
+ * @ret rc Return status code
+ */
+static int usb_configure ( struct usb_device *usb, unsigned int index ) {
+ struct usb_configuration_descriptor partial;
+ struct usb_configuration_descriptor *config;
+ size_t len;
+ int rc;
+
+ /* Read first part of configuration descriptor to get size */
+ if ( ( rc = usb_get_config_descriptor ( usb, index, &partial,
+ sizeof ( partial ) ) ) != 0 ) {
+ DBGC ( usb, "USB %s could not get configuration descriptor %d: "
+ "%s\n", usb->name, index, strerror ( rc ) );
+ goto err_get_partial;
+ }
+ len = le16_to_cpu ( partial.len );
+ if ( len < sizeof ( partial ) ) {
+ DBGC ( usb, "USB %s underlength configuraton descriptor %d\n",
+ usb->name, index );
+ rc = -EINVAL;
+ goto err_partial_len;
+ }
+
+ /* Allocate buffer for whole configuration descriptor */
+ config = malloc ( len );
+ if ( ! config ) {
+ rc = -ENOMEM;
+ goto err_alloc_config;
+ }
+
+ /* Read whole configuration descriptor */
+ if ( ( rc = usb_get_config_descriptor ( usb, index, config,
+ len ) ) != 0 ) {
+ DBGC ( usb, "USB %s could not get configuration descriptor %d: "
+ "%s\n", usb->name, index, strerror ( rc ) );
+ goto err_get_config_descriptor;
+ }
+ if ( config->len != partial.len ) {
+ DBGC ( usb, "USB %s bad configuration descriptor %d length\n",
+ usb->name, index );
+ rc = -EINVAL;
+ goto err_config_len;
+ }
+
+ /* Set configuration */
+ if ( ( rc = usb_set_configuration ( usb, config->config ) ) != 0){
+ DBGC ( usb, "USB %s could not set configuration %d: %s\n",
+ usb->name, config->config, strerror ( rc ) );
+ goto err_set_configuration;
+ }
+
+ /* Probe USB device drivers */
+ usb_probe_all ( usb, config );
+
+ /* Free configuration descriptor */
+ free ( config );
+
+ return 0;
+
+ usb_remove_all ( usb );
+ usb_set_configuration ( usb, 0 );
+ err_set_configuration:
+ err_config_len:
+ err_get_config_descriptor:
+ free ( config );
+ err_alloc_config:
+ err_partial_len:
+ err_get_partial:
+ return rc;
+}
+
+/**
+ * Clear USB device configuration
+ *
+ * @v usb USB device
+ */
+static void usb_deconfigure ( struct usb_device *usb ) {
+ unsigned int i;
+
+ /* Remove device drivers */
+ usb_remove_all ( usb );
+
+ /* Sanity checks */
+ for ( i = 0 ; i < ( sizeof ( usb->ep ) / sizeof ( usb->ep[0] ) ) ; i++){
+ if ( i != USB_ENDPOINT_IDX ( USB_EP0_ADDRESS ) )
+ assert ( usb->ep[i] == NULL );
+ }
+
+ /* Clear device configuration */
+ usb_set_configuration ( usb, 0 );
+}
+
+/**
+ * Find and select a supported USB device configuration
+ *
+ * @v usb USB device
+ * @ret rc Return status code
+ */
+static int usb_configure_any ( struct usb_device *usb ) {
+ unsigned int index;
+ int rc = -ENOENT;
+
+ /* Attempt all configuration indexes */
+ for ( index = 0 ; index < usb->device.configurations ; index++ ) {
+
+ /* Attempt this configuration index */
+ if ( ( rc = usb_configure ( usb, index ) ) != 0 )
+ continue;
+
+ /* If we have no drivers, then try the next configuration */
+ if ( list_empty ( &usb->functions ) ) {
+ rc = -ENOTSUP;
+ usb_deconfigure ( usb );
+ continue;
+ }
+
+ return 0;
+ }
+
+ return rc;
+}
+
+/******************************************************************************
+ *
+ * USB device
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Allocate USB device
+ *
+ * @v port USB port
+ * @ret usb USB device, or NULL on allocation failure
+ */
+static struct usb_device * alloc_usb ( struct usb_port *port ) {
+ struct usb_hub *hub = port->hub;
+ struct usb_bus *bus = hub->bus;
+ struct usb_device *usb;
+
+ /* Allocate and initialise structure */
+ usb = zalloc ( sizeof ( *usb ) );
+ if ( ! usb )
+ return NULL;
+ snprintf ( usb->name, sizeof ( usb->name ), "%s%c%d", hub->name,
+ ( hub->usb ? '.' : '-' ), port->address );
+ usb->port = port;
+ INIT_LIST_HEAD ( &usb->functions );
+ usb->host = &bus->op->device;
+ usb_endpoint_init ( &usb->control, usb, &usb_control_operations );
+ INIT_LIST_HEAD ( &usb->complete );
+
+ return usb;
+}
+
+/**
+ * Register USB device
+ *
+ * @v usb USB device
+ * @ret rc Return status code
+ */
+static int register_usb ( struct usb_device *usb ) {
+ struct usb_port *port = usb->port;
+ struct usb_hub *hub = port->hub;
+ struct usb_bus *bus = hub->bus;
+ unsigned int protocol;
+ size_t mtu;
+ int rc;
+
+ /* Add to port */
+ if ( port->usb != NULL ) {
+ DBGC ( hub, "USB hub %s port %d is already registered to %s\n",
+ hub->name, port->address, port->usb->name );
+ rc = -EALREADY;
+ goto err_already;
+ }
+ port->usb = usb;
+
+ /* Add to bus device list */
+ list_add_tail ( &usb->list, &bus->devices );
+
+ /* Enable device */
+ if ( ( rc = hub->driver->enable ( hub, port ) ) != 0 ) {
+ DBGC ( hub, "USB hub %s port %d could not enable: %s\n",
+ hub->name, port->address, strerror ( rc ) );
+ goto err_enable;
+ }
+
+ /* Allow recovery interval since port may have been reset */
+ mdelay ( USB_RESET_RECOVER_DELAY_MS );
+
+ /* Get device speed */
+ if ( ( rc = hub->driver->speed ( hub, port ) ) != 0 ) {
+ DBGC ( hub, "USB hub %s port %d could not get speed: %s\n",
+ hub->name, port->address, strerror ( rc ) );
+ goto err_speed;
+ }
+ DBGC2 ( usb, "USB %s attached as %s-speed device\n",
+ usb->name, usb_speed_name ( port->speed ) );
+
+ /* Open device */
+ if ( ( rc = usb->host->open ( usb ) ) != 0 ) {
+ DBGC ( usb, "USB %s could not open: %s\n",
+ usb->name, strerror ( rc ) );
+ goto err_open;
+ }
+
+ /* Describe control endpoint */
+ mtu = USB_EP0_DEFAULT_MTU ( port->speed );
+ usb_endpoint_describe ( &usb->control, USB_EP0_ADDRESS,
+ USB_EP0_ATTRIBUTES, mtu, USB_EP0_BURST,
+ USB_EP0_INTERVAL );
+
+ /* Open control endpoint */
+ if ( ( rc = usb_endpoint_open ( &usb->control ) ) != 0 )
+ goto err_open_control;
+ assert ( usb_endpoint ( usb, USB_EP0_ADDRESS ) == &usb->control );
+
+ /* Assign device address */
+ if ( ( rc = usb->host->address ( usb ) ) != 0 ) {
+ DBGC ( usb, "USB %s could not set address: %s\n",
+ usb->name, strerror ( rc ) );
+ goto err_address;
+ }
+ DBGC2 ( usb, "USB %s assigned address %d\n", usb->name, usb->address );
+
+ /* Allow recovery interval after Set Address command */
+ mdelay ( USB_SET_ADDRESS_RECOVER_DELAY_MS );
+
+ /* Read first part of device descriptor to get EP0 MTU */
+ if ( ( rc = usb_get_mtu ( usb, &usb->device ) ) != 0 ) {
+ DBGC ( usb, "USB %s could not get MTU: %s\n",
+ usb->name, strerror ( rc ) );
+ goto err_get_mtu;
+ }
+
+ /* Calculate EP0 MTU */
+ protocol = le16_to_cpu ( usb->device.protocol );
+ mtu = ( ( protocol < USB_PROTO_3_0 ) ?
+ usb->device.mtu : ( 1 << usb->device.mtu ) );
+ DBGC2 ( usb, "USB %s has control MTU %zd (guessed %zd)\n",
+ usb->name, mtu, usb->control.mtu );
+
+ /* Update MTU */
+ if ( ( rc = usb_endpoint_mtu ( &usb->control, mtu ) ) != 0 )
+ goto err_mtu;
+
+ /* Read whole device descriptor */
+ if ( ( rc = usb_get_device_descriptor ( usb, &usb->device ) ) != 0 ) {
+ DBGC ( usb, "USB %s could not get device descriptor: %s\n",
+ usb->name, strerror ( rc ) );
+ goto err_get_device_descriptor;
+ }
+ DBGC ( usb, "USB %s addr %d %04x:%04x class %d:%d:%d (v%s, %s-speed, "
+ "MTU %zd)\n", usb->name, usb->address,
+ le16_to_cpu ( usb->device.vendor ),
+ le16_to_cpu ( usb->device.product ), usb->device.class.class,
+ usb->device.class.subclass, usb->device.class.protocol,
+ usb_bcd ( le16_to_cpu ( usb->device.protocol ) ),
+ usb_speed_name ( port->speed ), usb->control.mtu );
+
+ /* Configure device */
+ if ( ( rc = usb_configure_any ( usb ) ) != 0 )
+ goto err_configure_any;
+
+ return 0;
+
+ usb_deconfigure ( usb );
+ err_configure_any:
+ err_get_device_descriptor:
+ err_mtu:
+ err_get_mtu:
+ err_address:
+ usb_endpoint_close ( &usb->control );
+ err_open_control:
+ usb->host->close ( usb );
+ err_open:
+ err_speed:
+ hub->driver->disable ( hub, port );
+ err_enable:
+ list_del ( &usb->list );
+ port->usb = NULL;
+ err_already:
+ return rc;
+}
+
+/**
+ * Unregister USB device
+ *
+ * @v usb USB device
+ */
+static void unregister_usb ( struct usb_device *usb ) {
+ struct usb_port *port = usb->port;
+ struct usb_hub *hub = port->hub;
+ struct io_buffer *iobuf;
+ struct io_buffer *tmp;
+
+ /* Sanity checks */
+ assert ( port->usb == usb );
+
+ /* Clear device configuration */
+ usb_deconfigure ( usb );
+
+ /* Close control endpoint */
+ usb_endpoint_close ( &usb->control );
+
+ /* Discard any stale control completions */
+ list_for_each_entry_safe ( iobuf, tmp, &usb->complete, list ) {
+ list_del ( &iobuf->list );
+ free_iob ( iobuf );
+ }
+
+ /* Close device */
+ usb->host->close ( usb );
+
+ /* Disable port */
+ hub->driver->disable ( hub, port );
+
+ /* Remove from bus device list */
+ list_del ( &usb->list );
+
+ /* Remove from port */
+ port->usb = NULL;
+}
+
+/**
+ * Free USB device
+ *
+ * @v usb USB device
+ */
+static void free_usb ( struct usb_device *usb ) {
+ unsigned int i;
+
+ /* Sanity checks */
+ for ( i = 0 ; i < ( sizeof ( usb->ep ) / sizeof ( usb->ep[0] ) ) ; i++ )
+ assert ( usb->ep[i] == NULL );
+ assert ( list_empty ( &usb->functions ) );
+ assert ( list_empty ( &usb->complete ) );
+
+ /* Free device */
+ free ( usb );
+}
+
+/******************************************************************************
+ *
+ * USB device hotplug event handling
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Handle newly attached USB device
+ *
+ * @v port USB port
+ * @ret rc Return status code
+ */
+static int usb_attached ( struct usb_port *port ) {
+ struct usb_device *usb;
+ int rc;
+
+ /* Mark port as attached */
+ port->attached = 1;
+
+ /* Sanity checks */
+ assert ( port->usb == NULL );
+
+ /* Allocate USB device */
+ usb = alloc_usb ( port );
+ if ( ! usb ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+
+ /* Register USB device */
+ if ( ( rc = register_usb ( usb ) ) != 0 )
+ goto err_register;
+
+ return 0;
+
+ unregister_usb ( usb );
+ err_register:
+ free_usb ( usb );
+ err_alloc:
+ return rc;
+}
+
+/**
+ * Handle newly detached USB device
+ *
+ * @v port USB port
+ */
+static void usb_detached ( struct usb_port *port ) {
+ struct usb_device *usb = port->usb;
+
+ /* Mark port as detached */
+ port->attached = 0;
+
+ /* Do nothing if we have no USB device */
+ if ( ! usb )
+ return;
+
+ /* Unregister USB device */
+ unregister_usb ( usb );
+
+ /* Free USB device */
+ free_usb ( usb );
+}
+
+/**
+ * Handle newly attached or detached USB device
+ *
+ * @v port USB port
+ * @ret rc Return status code
+ */
+static int usb_hotplugged ( struct usb_port *port ) {
+ struct usb_hub *hub = port->hub;
+ int rc;
+
+ /* Get current port speed */
+ if ( ( rc = hub->driver->speed ( hub, port ) ) != 0 ) {
+ DBGC ( hub, "USB hub %s port %d could not get speed: %s\n",
+ hub->name, port->address, strerror ( rc ) );
+ goto err_speed;
+ }
+
+ /* Detach device, if applicable */
+ if ( port->attached && ( port->disconnected || ! port->speed ) )
+ usb_detached ( port );
+
+ /* Attach device, if applicable */
+ if ( port->speed && ( ! port->attached ) &&
+ ( ( rc = usb_attached ( port ) ) != 0 ) )
+ goto err_attached;
+
+ err_attached:
+ err_speed:
+ /* Clear any recorded disconnections */
+ port->disconnected = 0;
+ return rc;
+}
+
+/******************************************************************************
+ *
+ * USB process
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Report port status change
+ *
+ * @v port USB port
+ */
+void usb_port_changed ( struct usb_port *port ) {
+
+ /* Record hub port status change */
+ list_del ( &port->changed );
+ list_add_tail ( &port->changed, &usb_changed );
+}
+
+/**
+ * Handle newly attached or detached USB device
+ *
+ */
+static void usb_hotplug ( void ) {
+ struct usb_port *port;
+
+ /* Handle any changed ports, allowing for the fact that the
+ * port list may change as we perform hotplug actions.
+ */
+ while ( ! list_empty ( &usb_changed ) ) {
+
+ /* Get first changed port */
+ port = list_first_entry ( &usb_changed, struct usb_port,
+ changed );
+ assert ( port != NULL );
+
+ /* Remove from list of changed ports */
+ list_del ( &port->changed );
+ INIT_LIST_HEAD ( &port->changed );
+
+ /* Perform appropriate hotplug action */
+ usb_hotplugged ( port );
+ }
+}
+
+/**
+ * USB process
+ *
+ * @v process USB process
+ */
+static void usb_step ( struct process *process __unused ) {
+ struct usb_bus *bus;
+ struct usb_endpoint *ep;
+
+ /* Poll all buses */
+ for_each_usb_bus ( bus )
+ usb_poll ( bus );
+
+ /* Attempt to reset first halted endpoint in list, if any. We
+ * do not attempt to process the complete list, since this
+ * would require extra code to allow for the facts that the
+ * halted endpoint list may change as we do so, and that
+ * resetting an endpoint may fail.
+ */
+ if ( ( ep = list_first_entry ( &usb_halted, struct usb_endpoint,
+ halted ) ) != NULL )
+ usb_endpoint_reset ( ep );
+
+ /* Handle any changed ports */
+ usb_hotplug();
+}
+
+/** USB process */
+PERMANENT_PROCESS ( usb_process, usb_step );
+
+/******************************************************************************
+ *
+ * USB hub
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Allocate USB hub
+ *
+ * @v bus USB bus
+ * @v usb Underlying USB device, if any
+ * @v ports Number of ports
+ * @v driver Hub driver operations
+ * @ret hub USB hub, or NULL on allocation failure
+ */
+struct usb_hub * alloc_usb_hub ( struct usb_bus *bus, struct usb_device *usb,
+ unsigned int ports,
+ struct usb_hub_driver_operations *driver ) {
+ struct usb_hub *hub;
+ struct usb_port *port;
+ unsigned int i;
+
+ /* Allocate and initialise structure */
+ hub = zalloc ( sizeof ( *hub ) + ( ports * sizeof ( hub->port[0] ) ) );
+ if ( ! hub )
+ return NULL;
+ hub->name = ( usb ? usb->name : bus->name );
+ hub->bus = bus;
+ hub->usb = usb;
+ if ( usb )
+ hub->protocol = usb->port->protocol;
+ hub->ports = ports;
+ hub->driver = driver;
+ hub->host = &bus->op->hub;
+
+ /* Initialise port list */
+ for ( i = 1 ; i <= hub->ports ; i++ ) {
+ port = usb_port ( hub, i );
+ port->hub = hub;
+ port->address = i;
+ if ( usb )
+ port->protocol = usb->port->protocol;
+ INIT_LIST_HEAD ( &port->changed );
+ }
+
+ return hub;
+}
+
+/**
+ * Register USB hub
+ *
+ * @v hub USB hub
+ * @ret rc Return status code
+ */
+int register_usb_hub ( struct usb_hub *hub ) {
+ struct usb_bus *bus = hub->bus;
+ struct usb_port *port;
+ unsigned int i;
+ int rc;
+
+ /* Add to hub list */
+ list_add_tail ( &hub->list, &bus->hubs );
+
+ /* Open hub (host controller) */
+ if ( ( rc = hub->host->open ( hub ) ) != 0 ) {
+ DBGC ( hub, "USB hub %s could not open: %s\n",
+ hub->name, strerror ( rc ) );
+ goto err_host_open;
+ }
+
+ /* Open hub (driver) */
+ if ( ( rc = hub->driver->open ( hub ) ) != 0 ) {
+ DBGC ( hub, "USB hub %s could not open: %s\n",
+ hub->name, strerror ( rc ) );
+ goto err_driver_open;
+ }
+
+ /* Delay to allow ports to stabilise */
+ mdelay ( USB_PORT_DELAY_MS );
+
+ /* Mark all ports as changed */
+ for ( i = 1 ; i <= hub->ports ; i++ ) {
+ port = usb_port ( hub, i );
+ usb_port_changed ( port );
+ }
+
+ /* Some hubs seem to defer reporting device connections until
+ * their interrupt endpoint is polled for the first time.
+ * Poll the bus once now in order to pick up any such
+ * connections.
+ */
+ usb_poll ( bus );
+
+ return 0;
+
+ hub->driver->close ( hub );
+ err_driver_open:
+ hub->host->close ( hub );
+ err_host_open:
+ list_del ( &hub->list );
+ return rc;
+}
+
+/**
+ * Unregister USB hub
+ *
+ * @v hub USB hub
+ */
+void unregister_usb_hub ( struct usb_hub *hub ) {
+ struct usb_port *port;
+ unsigned int i;
+
+ /* Detach all devices */
+ for ( i = 1 ; i <= hub->ports ; i++ ) {
+ port = usb_port ( hub, i );
+ if ( port->attached )
+ usb_detached ( port );
+ }
+
+ /* Close hub (driver) */
+ hub->driver->close ( hub );
+
+ /* Close hub (host controller) */
+ hub->host->close ( hub );
+
+ /* Cancel any pending port status changes */
+ for ( i = 1 ; i <= hub->ports ; i++ ) {
+ port = usb_port ( hub, i );
+ list_del ( &port->changed );
+ INIT_LIST_HEAD ( &port->changed );
+ }
+
+ /* Remove from hub list */
+ list_del ( &hub->list );
+}
+
+/**
+ * Free USB hub
+ *
+ * @v hub USB hub
+ */
+void free_usb_hub ( struct usb_hub *hub ) {
+ struct usb_port *port;
+ unsigned int i;
+
+ /* Sanity checks */
+ for ( i = 1 ; i <= hub->ports ; i++ ) {
+ port = usb_port ( hub, i );
+ assert ( ! port->attached );
+ assert ( port->usb == NULL );
+ assert ( list_empty ( &port->changed ) );
+ }
+
+ /* Free hub */
+ free ( hub );
+}
+
+/******************************************************************************
+ *
+ * USB bus
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Allocate USB bus
+ *
+ * @v dev Underlying hardware device
+ * @v ports Number of root hub ports
+ * @v mtu Largest transfer allowed on the bus
+ * @v op Host controller operations
+ * @ret bus USB bus, or NULL on allocation failure
+ */
+struct usb_bus * alloc_usb_bus ( struct device *dev, unsigned int ports,
+ size_t mtu, struct usb_host_operations *op ) {
+ struct usb_bus *bus;
+
+ /* Allocate and initialise structure */
+ bus = zalloc ( sizeof ( *bus ) );
+ if ( ! bus )
+ goto err_alloc_bus;
+ bus->name = dev->name;
+ bus->dev = dev;
+ bus->mtu = mtu;
+ bus->op = op;
+ INIT_LIST_HEAD ( &bus->devices );
+ INIT_LIST_HEAD ( &bus->hubs );
+ bus->host = &bus->op->bus;
+
+ /* Allocate root hub */
+ bus->hub = alloc_usb_hub ( bus, NULL, ports, &op->root );
+ if ( ! bus->hub )
+ goto err_alloc_hub;
+
+ return bus;
+
+ free_usb_hub ( bus->hub );
+ err_alloc_hub:
+ free ( bus );
+ err_alloc_bus:
+ return NULL;
+}
+
+/**
+ * Register USB bus
+ *
+ * @v bus USB bus
+ * @ret rc Return status code
+ */
+int register_usb_bus ( struct usb_bus *bus ) {
+ int rc;
+
+ /* Sanity checks */
+ assert ( bus->hub != NULL );
+
+ /* Open bus */
+ if ( ( rc = bus->host->open ( bus ) ) != 0 )
+ goto err_open;
+
+ /* Add to list of USB buses */
+ list_add_tail ( &bus->list, &usb_buses );
+
+ /* Register root hub */
+ if ( ( rc = register_usb_hub ( bus->hub ) ) != 0 )
+ goto err_register_hub;
+
+ /* Attach any devices already present */
+ usb_hotplug();
+
+ return 0;
+
+ unregister_usb_hub ( bus->hub );
+ err_register_hub:
+ list_del ( &bus->list );
+ bus->host->close ( bus );
+ err_open:
+ return rc;
+}
+
+/**
+ * Unregister USB bus
+ *
+ * @v bus USB bus
+ */
+void unregister_usb_bus ( struct usb_bus *bus ) {
+
+ /* Sanity checks */
+ assert ( bus->hub != NULL );
+
+ /* Unregister root hub */
+ unregister_usb_hub ( bus->hub );
+
+ /* Remove from list of USB buses */
+ list_del ( &bus->list );
+
+ /* Close bus */
+ bus->host->close ( bus );
+
+ /* Sanity checks */
+ assert ( list_empty ( &bus->devices ) );
+ assert ( list_empty ( &bus->hubs ) );
+}
+
+/**
+ * Free USB bus
+ *
+ * @v bus USB bus
+ */
+void free_usb_bus ( struct usb_bus *bus ) {
+ struct usb_endpoint *ep;
+ struct usb_port *port;
+
+ /* Sanity checks */
+ assert ( list_empty ( &bus->devices ) );
+ assert ( list_empty ( &bus->hubs ) );
+ list_for_each_entry ( ep, &usb_halted, halted )
+ assert ( ep->usb->port->hub->bus != bus );
+ list_for_each_entry ( port, &usb_changed, changed )
+ assert ( port->hub->bus != bus );
+
+ /* Free root hub */
+ free_usb_hub ( bus->hub );
+
+ /* Free bus */
+ free ( bus );
+}
+
+/**
+ * Find USB bus by device location
+ *
+ * @v bus_type Bus type
+ * @v location Bus location
+ * @ret bus USB bus, or NULL
+ */
+struct usb_bus * find_usb_bus_by_location ( unsigned int bus_type,
+ unsigned int location ) {
+ struct usb_bus *bus;
+
+ for_each_usb_bus ( bus ) {
+ if ( ( bus->dev->desc.bus_type == bus_type ) &&
+ ( bus->dev->desc.location == location ) )
+ return bus;
+ }
+
+ return NULL;
+}
+
+/******************************************************************************
+ *
+ * USB address assignment
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Allocate device address
+ *
+ * @v bus USB bus
+ * @ret address Device address, or negative error
+ */
+int usb_alloc_address ( struct usb_bus *bus ) {
+ unsigned int address;
+
+ /* Find first free device address */
+ address = ffsll ( ~bus->addresses );
+ if ( ! address )
+ return -ENOENT;
+
+ /* Mark address as used */
+ bus->addresses |= ( 1ULL << ( address - 1 ) );
+
+ return address;
+}
+
+/**
+ * Free device address
+ *
+ * @v bus USB bus
+ * @v address Device address
+ */
+void usb_free_address ( struct usb_bus *bus, unsigned int address ) {
+
+ /* Sanity check */
+ assert ( address > 0 );
+ assert ( bus->addresses & ( 1ULL << ( address - 1 ) ) );
+
+ /* Mark address as free */
+ bus->addresses &= ~( 1ULL << ( address - 1 ) );
+}
+
+/******************************************************************************
+ *
+ * USB bus topology
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Get USB route string
+ *
+ * @v usb USB device
+ * @ret route USB route string
+ */
+unsigned int usb_route_string ( struct usb_device *usb ) {
+ struct usb_device *parent;
+ unsigned int route;
+
+ /* Navigate up to root hub, constructing route string as we go */
+ for ( route = 0 ; ( parent = usb->port->hub->usb ) ; usb = parent ) {
+ route <<= 4;
+ route |= ( ( usb->port->address > 0xf ) ?
+ 0xf : usb->port->address );
+ }
+
+ return route;
+}
+
+/**
+ * Get USB depth
+ *
+ * @v usb USB device
+ * @ret depth Hub depth
+ */
+unsigned int usb_depth ( struct usb_device *usb ) {
+ struct usb_device *parent;
+ unsigned int depth;
+
+ /* Navigate up to root hub, constructing depth as we go */
+ for ( depth = 0 ; ( parent = usb->port->hub->usb ) ; usb = parent )
+ depth++;
+
+ return depth;
+}
+
+/**
+ * Get USB root hub port
+ *
+ * @v usb USB device
+ * @ret port Root hub port
+ */
+struct usb_port * usb_root_hub_port ( struct usb_device *usb ) {
+ struct usb_device *parent;
+
+ /* Navigate up to root hub */
+ while ( ( parent = usb->port->hub->usb ) )
+ usb = parent;
+
+ return usb->port;
+}
+
+/**
+ * Get USB transaction translator
+ *
+ * @v usb USB device
+ * @ret port Transaction translator port, or NULL
+ */
+struct usb_port * usb_transaction_translator ( struct usb_device *usb ) {
+ struct usb_device *parent;
+
+ /* Navigate up to root hub. If we find a low-speed or
+ * full-speed port with a higher-speed parent device, then
+ * that port is the transaction translator.
+ */
+ for ( ; ( parent = usb->port->hub->usb ) ; usb = parent ) {
+ if ( ( usb->port->speed <= USB_SPEED_FULL ) &&
+ ( parent->port->speed > USB_SPEED_FULL ) )
+ return usb->port;
+ }
+
+ return NULL;
+}
+
+/* Drag in objects via register_usb_bus() */
+REQUIRING_SYMBOL ( register_usb_bus );
+
+/* Drag in USB configuration */
+REQUIRE_OBJECT ( config_usb );
+
+/* Drag in hub driver */
+REQUIRE_OBJECT ( usbhub );
diff --git a/roms/ipxe/src/drivers/infiniband/arbel.c b/roms/ipxe/src/drivers/infiniband/arbel.c
index 1a56ff9af..2a6c32dec 100644
--- a/roms/ipxe/src/drivers/infiniband/arbel.c
+++ b/roms/ipxe/src/drivers/infiniband/arbel.c
@@ -18,9 +18,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/drivers/infiniband/arbel.h b/roms/ipxe/src/drivers/infiniband/arbel.h
index c0303f1bc..73394cd9a 100644
--- a/roms/ipxe/src/drivers/infiniband/arbel.h
+++ b/roms/ipxe/src/drivers/infiniband/arbel.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/uaccess.h>
diff --git a/roms/ipxe/src/drivers/infiniband/linda.c b/roms/ipxe/src/drivers/infiniband/linda.c
index 4afda1208..a6ae9f529 100644
--- a/roms/ipxe/src/drivers/infiniband/linda.c
+++ b/roms/ipxe/src/drivers/infiniband/linda.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/drivers/infiniband/linda.h b/roms/ipxe/src/drivers/infiniband/linda.h
index 72ce70868..46a920a17 100644
--- a/roms/ipxe/src/drivers/infiniband/linda.h
+++ b/roms/ipxe/src/drivers/infiniband/linda.h
@@ -18,9 +18,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @file
diff --git a/roms/ipxe/src/drivers/infiniband/qib7322.c b/roms/ipxe/src/drivers/infiniband/qib7322.c
index 9979b346e..e22f2349a 100644
--- a/roms/ipxe/src/drivers/infiniband/qib7322.c
+++ b/roms/ipxe/src/drivers/infiniband/qib7322.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/drivers/infiniband/qib7322.h b/roms/ipxe/src/drivers/infiniband/qib7322.h
index 63abe221b..72797b240 100644
--- a/roms/ipxe/src/drivers/infiniband/qib7322.h
+++ b/roms/ipxe/src/drivers/infiniband/qib7322.h
@@ -18,9 +18,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @file
diff --git a/roms/ipxe/src/drivers/net/amd8111e.h b/roms/ipxe/src/drivers/net/amd8111e.h
index 2000df158..8ecd159af 100644
--- a/roms/ipxe/src/drivers/net/amd8111e.h
+++ b/roms/ipxe/src/drivers/net/amd8111e.h
@@ -16,6 +16,10 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
* USA
Module Name:
@@ -36,7 +40,7 @@ Revision History:
3.0.1
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifndef _AMD811E_H
#define _AMD811E_H
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ani.h b/roms/ipxe/src/drivers/net/ath/ath9k/ani.h
index dbd4d4d5b..ba87ba0fd 100644
--- a/roms/ipxe/src/drivers/net/ath/ath9k/ani.h
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ani.h
@@ -125,7 +125,7 @@ struct ar5416AniState {
u8 mrcCCKOff;
u8 spurImmunityLevel;
u8 firstepLevel;
- u8 ofdmWeakSigDetectOff;
+ u8 ofdmWeakSigDetect;
u8 cckWeakSigThreshold;
u32 listenTime;
int32_t rssiThrLow;
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ani.c b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ani.c
index ff7df497f..76ca79cba 100644
--- a/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ani.c
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ani.c
@@ -177,7 +177,7 @@ static void ath9k_hw_ani_ofdm_err_trigger_old(struct ath_hw *ah)
rssi = BEACON_RSSI(ah);
if (rssi > aniState->rssiThrHigh) {
- if (!aniState->ofdmWeakSigDetectOff) {
+ if (aniState->ofdmWeakSigDetect) {
if (ath9k_hw_ani_control(ah,
ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
0)) {
@@ -192,7 +192,7 @@ static void ath9k_hw_ani_ofdm_err_trigger_old(struct ath_hw *ah)
return;
}
} else if (rssi > aniState->rssiThrLow) {
- if (aniState->ofdmWeakSigDetectOff)
+ if (!aniState->ofdmWeakSigDetect)
ath9k_hw_ani_control(ah,
ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
1);
@@ -202,7 +202,7 @@ static void ath9k_hw_ani_ofdm_err_trigger_old(struct ath_hw *ah)
return;
} else {
if ((ah->dev->channels + ah->dev->channel)->band == NET80211_BAND_2GHZ) {
- if (!aniState->ofdmWeakSigDetectOff)
+ if (aniState->ofdmWeakSigDetect)
ath9k_hw_ani_control(ah,
ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
0);
@@ -360,7 +360,7 @@ static void ath9k_hw_ani_lower_immunity_old(struct ath_hw *ah)
if (rssi > aniState->rssiThrHigh) {
/* XXX: Handle me */
} else if (rssi > aniState->rssiThrLow) {
- if (aniState->ofdmWeakSigDetectOff) {
+ if (!aniState->ofdmWeakSigDetect) {
if (ath9k_hw_ani_control(ah,
ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
1) == 1)
@@ -436,9 +436,9 @@ static void ath9k_ani_reset_old(struct ath_hw *ah)
if (aniState->spurImmunityLevel != 0)
ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
aniState->spurImmunityLevel);
- if (aniState->ofdmWeakSigDetectOff)
+ if (!aniState->ofdmWeakSigDetect)
ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
- !aniState->ofdmWeakSigDetectOff);
+ aniState->ofdmWeakSigDetect);
if (aniState->cckWeakSigThreshold)
ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
aniState->cckWeakSigThreshold);
@@ -709,8 +709,8 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
ani->rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
ani->rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
- ani->ofdmWeakSigDetectOff =
- !ATH9K_ANI_USE_OFDM_WEAK_SIG;
+ ani->ofdmWeakSigDetect =
+ ATH9K_ANI_USE_OFDM_WEAK_SIG;
ani->cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL;
}
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar5008_phy.c b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar5008_phy.c
index 60e87e9e2..2b6c133cb 100644
--- a/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar5008_phy.c
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar5008_phy.c
@@ -1141,12 +1141,12 @@ static int ar5008_hw_ani_control_old(struct ath_hw *ah,
REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
- if (!on != aniState->ofdmWeakSigDetectOff) {
+ if (on != aniState->ofdmWeakSigDetect) {
if (on)
ah->stats.ast_ani_ofdmon++;
else
ah->stats.ast_ani_ofdmoff++;
- aniState->ofdmWeakSigDetectOff = !on;
+ aniState->ofdmWeakSigDetect = on;
}
break;
}
@@ -1215,10 +1215,10 @@ static int ar5008_hw_ani_control_old(struct ath_hw *ah,
DBG2("ath9k: ANI parameters:\n");
DBG2(
- "noiseImmunityLevel=%d, spurImmunityLevel=%d, ofdmWeakSigDetectOff=%d\n",
+ "noiseImmunityLevel=%d, spurImmunityLevel=%d, ofdmWeakSigDetect=%d\n",
aniState->noiseImmunityLevel,
aniState->spurImmunityLevel,
- !aniState->ofdmWeakSigDetectOff);
+ aniState->ofdmWeakSigDetect);
DBG2(
"cckWeakSigThreshold=%d, firstepLevel=%d, listenTime=%d\n",
aniState->cckWeakSigThreshold,
@@ -1307,18 +1307,18 @@ static int ar5008_hw_ani_control_new(struct ath_hw *ah,
REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
- if (!on != aniState->ofdmWeakSigDetectOff) {
+ if (on != aniState->ofdmWeakSigDetect) {
DBG2("ath9k: "
"** ch %d: ofdm weak signal: %s=>%s\n",
chan->channel,
- !aniState->ofdmWeakSigDetectOff ?
+ aniState->ofdmWeakSigDetect ?
"on" : "off",
on ? "on" : "off");
if (on)
ah->stats.ast_ani_ofdmon++;
else
ah->stats.ast_ani_ofdmoff++;
- aniState->ofdmWeakSigDetectOff = !on;
+ aniState->ofdmWeakSigDetect = on;
}
break;
}
@@ -1467,7 +1467,7 @@ static int ar5008_hw_ani_control_new(struct ath_hw *ah,
DBG2("ath9k: "
"ANI parameters: SI=%d, ofdmWS=%s FS=%d MRCcck=%s listenTime=%d ofdmErrs=%d cckErrs=%d\n",
aniState->spurImmunityLevel,
- !aniState->ofdmWeakSigDetectOff ? "on" : "off",
+ aniState->ofdmWeakSigDetect ? "on" : "off",
aniState->firstepLevel,
!aniState->mrcCCKOff ? "on" : "off",
aniState->listenTime,
@@ -1554,7 +1554,7 @@ static void ar5008_hw_ani_cache_ini_regs(struct ath_hw *ah)
/* these levels just got reset to defaults by the INI */
aniState->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL_NEW;
aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW;
- aniState->ofdmWeakSigDetectOff = !ATH9K_ANI_USE_OFDM_WEAK_SIG;
+ aniState->ofdmWeakSigDetect = ATH9K_ANI_USE_OFDM_WEAK_SIG;
aniState->mrcCCKOff = 1; /* not available on pre AR9003 */
}
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9003_phy.c b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9003_phy.c
index 6103040ab..2244b775a 100644
--- a/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9003_phy.c
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9003_phy.c
@@ -859,18 +859,18 @@ static int ar9003_hw_ani_control(struct ath_hw *ah,
REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
- if (!on != aniState->ofdmWeakSigDetectOff) {
+ if (on != aniState->ofdmWeakSigDetect) {
DBG2("ath9k: "
"** ch %d: ofdm weak signal: %s=>%s\n",
chan->channel,
- !aniState->ofdmWeakSigDetectOff ?
+ aniState->ofdmWeakSigDetect ?
"on" : "off",
on ? "on" : "off");
if (on)
ah->stats.ast_ani_ofdmon++;
else
ah->stats.ast_ani_ofdmoff++;
- aniState->ofdmWeakSigDetectOff = !on;
+ aniState->ofdmWeakSigDetect = on;
}
break;
}
@@ -1013,7 +1013,7 @@ static int ar9003_hw_ani_control(struct ath_hw *ah,
AR_PHY_MRC_CCK_ENABLE, is_on);
REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL,
AR_PHY_MRC_CCK_MUX_REG, is_on);
- if (!is_on != aniState->mrcCCKOff) {
+ if (!(is_on != aniState->mrcCCKOff)) {
DBG2("ath9k: "
"** ch %d: MRC CCK: %s=>%s\n",
chan->channel,
@@ -1037,7 +1037,7 @@ static int ar9003_hw_ani_control(struct ath_hw *ah,
DBG2("ath9k: "
"ANI parameters: SI=%d, ofdmWS=%s FS=%d MRCcck=%s listenTime=%d ofdmErrs=%d cckErrs=%d\n",
aniState->spurImmunityLevel,
- !aniState->ofdmWeakSigDetectOff ? "on" : "off",
+ aniState->ofdmWeakSigDetect ? "on" : "off",
aniState->firstepLevel,
!aniState->mrcCCKOff ? "on" : "off",
aniState->listenTime,
@@ -1137,7 +1137,7 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah)
/* these levels just got reset to defaults by the INI */
aniState->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL_NEW;
aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW;
- aniState->ofdmWeakSigDetectOff = !ATH9K_ANI_USE_OFDM_WEAK_SIG;
+ aniState->ofdmWeakSigDetect = ATH9K_ANI_USE_OFDM_WEAK_SIG;
aniState->mrcCCKOff = !ATH9K_ANI_ENABLE_MRC_CCK;
}
diff --git a/roms/ipxe/src/drivers/net/atl1e.c b/roms/ipxe/src/drivers/net/atl1e.c
index 1ff0f0d10..d010d8c4a 100644
--- a/roms/ipxe/src/drivers/net/atl1e.c
+++ b/roms/ipxe/src/drivers/net/atl1e.c
@@ -224,7 +224,7 @@ static int atl1e_sw_init(struct atl1e_adapter *adapter)
adapter->link_duplex = FULL_DUPLEX;
/* PCI config space info */
- pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
+ pci_read_config_byte(pdev, PCI_REVISION, &rev_id);
phy_status_data = AT_READ_REG(hw, REG_PHY_STATUS);
/* nic type */
diff --git a/roms/ipxe/src/drivers/net/davicom.c b/roms/ipxe/src/drivers/net/davicom.c
index a4870a729..9d3d8b915 100644
--- a/roms/ipxe/src/drivers/net/davicom.c
+++ b/roms/ipxe/src/drivers/net/davicom.c
@@ -340,6 +340,7 @@ static void davicom_media_chk(struct nic * nic __unused)
csr6 = 0x00200000; /* SF */
outl(csr6, ioaddr + CSR6);
+#define PCI_VENDOR_ID_DAVICOM 0x1282
#define PCI_DEVICE_ID_DM9009 0x9009
if (vendor == PCI_VENDOR_ID_DAVICOM && dev_id == PCI_DEVICE_ID_DM9009) {
/* Set to 10BaseT mode for DM9009 */
diff --git a/roms/ipxe/src/drivers/net/dm96xx.c b/roms/ipxe/src/drivers/net/dm96xx.c
new file mode 100644
index 000000000..58d8dd964
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/dm96xx.c
@@ -0,0 +1,671 @@
+/*
+ * Copyright (C) 2015 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/usb.h>
+#include <ipxe/usbnet.h>
+#include "dm96xx.h"
+
+/** @file
+ *
+ * Davicom DM96xx USB Ethernet driver
+ *
+ */
+
+/******************************************************************************
+ *
+ * Register operations
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Reset device
+ *
+ * @v dm96xx DM96xx device
+ * @ret rc Return status code
+ */
+static int dm96xx_reset ( struct dm96xx_device *dm96xx ) {
+ int ncr;
+ int rc;
+
+ /* Reset device */
+ if ( ( rc = dm96xx_write_register ( dm96xx, DM96XX_NCR,
+ DM96XX_NCR_RST ) ) != 0 ) {
+ DBGC ( dm96xx, "DM96XX %p could not reset: %s\n",
+ dm96xx, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Wait for reset to complete */
+ udelay ( DM96XX_RESET_DELAY_US );
+
+ /* Check that reset has completed */
+ ncr = dm96xx_read_register ( dm96xx, DM96XX_NCR );
+ if ( ncr < 0 ) {
+ rc = ncr;
+ DBGC ( dm96xx, "DM96XX %p failed to reset: %s\n",
+ dm96xx, strerror ( rc ) );
+ return rc;
+ }
+ if ( ncr & DM96XX_NCR_RST ) {
+ DBGC ( dm96xx, "DM96XX %p failed to reset (NCR=%#02x)\n",
+ dm96xx, ncr );
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/**
+ * Read MAC address
+ *
+ * @v dm96xx DM96xx device
+ * @v mac MAC address to fill in
+ * @ret rc Return status code
+ */
+static int dm96xx_read_mac ( struct dm96xx_device *dm96xx, uint8_t *mac ) {
+ int rc;
+
+ /* Read MAC address */
+ if ( ( rc = dm96xx_read_registers ( dm96xx, DM96XX_PAR, mac,
+ ETH_ALEN ) ) != 0 ) {
+ DBGC ( dm96xx, "DM96XX %p could not read MAC address: %s\n",
+ dm96xx, strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Write MAC address
+ *
+ * @v dm96xx DM96xx device
+ * @v mac MAC address
+ * @ret rc Return status code
+ */
+static int dm96xx_write_mac ( struct dm96xx_device *dm96xx, uint8_t *mac ) {
+ int rc;
+
+ /* Write MAC address */
+ if ( ( rc = dm96xx_write_registers ( dm96xx, DM96XX_PAR, mac,
+ ETH_ALEN ) ) != 0 ) {
+ DBGC ( dm96xx, "DM96XX %p could not write MAC address: %s\n",
+ dm96xx, strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Update link status based on network status register
+ *
+ * @v dm96xx DM96xx device
+ * @v nsr Network status register
+ */
+static void dm96xx_link_nsr ( struct dm96xx_device *dm96xx, unsigned int nsr ) {
+ struct net_device *netdev = dm96xx->netdev;
+
+ if ( nsr & DM96XX_NSR_LINKST ) {
+ if ( ! netdev_link_ok ( netdev ) )
+ netdev_link_up ( netdev );
+ } else {
+ if ( netdev_link_ok ( netdev ) )
+ netdev_link_down ( netdev );
+ }
+}
+
+/**
+ * Get link status
+ *
+ * @v dm96xx DM96xx device
+ * @ret rc Return status code
+ */
+static int dm96xx_check_link ( struct dm96xx_device *dm96xx ) {
+ int nsr;
+ int rc;
+
+ /* Read network status register */
+ nsr = dm96xx_read_register ( dm96xx, DM96XX_NSR );
+ if ( nsr < 0 ) {
+ rc = nsr;
+ DBGC ( dm96xx, "DM96XX %p could not read network status: %s\n",
+ dm96xx, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Update link status */
+ dm96xx_link_nsr ( dm96xx, nsr );
+
+ return 0;
+}
+
+/**
+ * Set DM9601-compatible RX header mode
+ *
+ * @v dm96xx DM96xx device
+ * @ret rc Return status code
+ */
+static int dm96xx_rx_mode ( struct dm96xx_device *dm96xx ) {
+ int chipr;
+ int mode_ctl;
+ int rc;
+
+ /* Get chip revision */
+ chipr = dm96xx_read_register ( dm96xx, DM96XX_CHIPR );
+ if ( chipr < 0 ) {
+ rc = chipr;
+ DBGC ( dm96xx, "DM96XX %p could not read chip revision: %s\n",
+ dm96xx, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Do nothing if device is a DM9601 anyway */
+ if ( chipr == DM96XX_CHIPR_9601 )
+ return 0;
+
+ /* Read current mode control */
+ mode_ctl = dm96xx_read_register ( dm96xx, DM96XX_MODE_CTL );
+ if ( mode_ctl < 0 ) {
+ rc = mode_ctl;
+ DBGC ( dm96xx, "DM96XX %p could not read mode control: %s\n",
+ dm96xx, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Write mode control */
+ mode_ctl &= ~DM96XX_MODE_CTL_MODE;
+ if ( ( rc = dm96xx_write_register ( dm96xx, DM96XX_MODE_CTL,
+ mode_ctl ) ) != 0 ) {
+ DBGC ( dm96xx, "DM96XX %p could not write mode control: %s\n",
+ dm96xx, strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * Endpoint operations
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Complete interrupt transfer
+ *
+ * @v ep USB endpoint
+ * @v iobuf I/O buffer
+ * @v rc Completion status code
+ */
+static void dm96xx_intr_complete ( struct usb_endpoint *ep,
+ struct io_buffer *iobuf, int rc ) {
+ struct dm96xx_device *dm96xx = container_of ( ep, struct dm96xx_device,
+ usbnet.intr );
+ struct net_device *netdev = dm96xx->netdev;
+ struct dm96xx_interrupt *intr;
+ size_t len = iob_len ( iobuf );
+
+ /* Ignore packets cancelled when the endpoint closes */
+ if ( ! ep->open )
+ goto done;
+
+ /* Record USB errors against the network device */
+ if ( rc != 0 ) {
+ DBGC ( dm96xx, "DM96XX %p interrupt failed: %s\n",
+ dm96xx, strerror ( rc ) );
+ DBGC_HDA ( dm96xx, 0, iobuf->data, iob_len ( iobuf ) );
+ netdev_rx_err ( netdev, NULL, rc );
+ goto done;
+ }
+
+ /* Extract message header */
+ if ( len < sizeof ( *intr ) ) {
+ DBGC ( dm96xx, "DM96XX %p underlength interrupt:\n", dm96xx );
+ DBGC_HDA ( dm96xx, 0, iobuf->data, iob_len ( iobuf ) );
+ netdev_rx_err ( netdev, NULL, -EINVAL );
+ goto done;
+ }
+ intr = iobuf->data;
+
+ /* Update link status */
+ dm96xx_link_nsr ( dm96xx, intr->nsr );
+
+ done:
+ /* Free I/O buffer */
+ free_iob ( iobuf );
+}
+
+/** Interrupt endpoint operations */
+static struct usb_endpoint_driver_operations dm96xx_intr_operations = {
+ .complete = dm96xx_intr_complete,
+};
+
+/**
+ * Complete bulk IN transfer
+ *
+ * @v ep USB endpoint
+ * @v iobuf I/O buffer
+ * @v rc Completion status code
+ */
+static void dm96xx_in_complete ( struct usb_endpoint *ep,
+ struct io_buffer *iobuf, int rc ) {
+ struct dm96xx_device *dm96xx = container_of ( ep, struct dm96xx_device,
+ usbnet.in );
+ struct net_device *netdev = dm96xx->netdev;
+ struct dm96xx_rx_header *header;
+
+ /* Ignore packets cancelled when the endpoint closes */
+ if ( ! ep->open ) {
+ free_iob ( iobuf );
+ return;
+ }
+
+ /* Record USB errors against the network device */
+ if ( rc != 0 ) {
+ DBGC ( dm96xx, "DM96XX %p bulk IN failed: %s\n",
+ dm96xx, strerror ( rc ) );
+ goto err;
+ }
+
+ /* Sanity check */
+ if ( iob_len ( iobuf ) < ( sizeof ( *header ) + 4 /* CRC */ ) ) {
+ DBGC ( dm96xx, "DM96XX %p underlength bulk IN\n", dm96xx );
+ DBGC_HDA ( dm96xx, 0, iobuf->data, iob_len ( iobuf ) );
+ rc = -EINVAL;
+ goto err;
+ }
+
+ /* Strip header and CRC */
+ header = iobuf->data;
+ iob_pull ( iobuf, sizeof ( *header ) );
+ iob_unput ( iobuf, 4 /* CRC */ );
+
+ /* Check status */
+ if ( header->rsr & ~DM96XX_RSR_MF ) {
+ DBGC ( dm96xx, "DM96XX %p receive error %02x:\n",
+ dm96xx, header->rsr );
+ DBGC_HDA ( dm96xx, 0, iobuf->data, iob_len ( iobuf ) );
+ rc = -EIO;
+ goto err;
+ }
+
+ /* Hand off to network stack */
+ netdev_rx ( netdev, iob_disown ( iobuf ) );
+ return;
+
+ err:
+ /* Hand off to network stack */
+ netdev_rx_err ( netdev, iob_disown ( iobuf ), rc );
+}
+
+/** Bulk IN endpoint operations */
+static struct usb_endpoint_driver_operations dm96xx_in_operations = {
+ .complete = dm96xx_in_complete,
+};
+
+/**
+ * Transmit packet
+ *
+ * @v dm96xx DM96xx device
+ * @v iobuf I/O buffer
+ * @ret rc Return status code
+ */
+static int dm96xx_out_transmit ( struct dm96xx_device *dm96xx,
+ struct io_buffer *iobuf ) {
+ struct dm96xx_tx_header *header;
+ size_t len = iob_len ( iobuf );
+ int rc;
+
+ /* Prepend header */
+ if ( ( rc = iob_ensure_headroom ( iobuf, sizeof ( *header ) ) ) != 0 )
+ return rc;
+ header = iob_push ( iobuf, sizeof ( *header ) );
+ header->len = cpu_to_le16 ( len );
+
+ /* Enqueue I/O buffer */
+ if ( ( rc = usb_stream ( &dm96xx->usbnet.out, iobuf, 0 ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/**
+ * Complete bulk OUT transfer
+ *
+ * @v ep USB endpoint
+ * @v iobuf I/O buffer
+ * @v rc Completion status code
+ */
+static void dm96xx_out_complete ( struct usb_endpoint *ep,
+ struct io_buffer *iobuf, int rc ) {
+ struct dm96xx_device *dm96xx = container_of ( ep, struct dm96xx_device,
+ usbnet.out );
+ struct net_device *netdev = dm96xx->netdev;
+
+ /* Report TX completion */
+ netdev_tx_complete_err ( netdev, iobuf, rc );
+}
+
+/** Bulk OUT endpoint operations */
+static struct usb_endpoint_driver_operations dm96xx_out_operations = {
+ .complete = dm96xx_out_complete,
+};
+
+/******************************************************************************
+ *
+ * Network device interface
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Open network device
+ *
+ * @v netdev Network device
+ * @ret rc Return status code
+ */
+static int dm96xx_open ( struct net_device *netdev ) {
+ struct dm96xx_device *dm96xx = netdev->priv;
+ unsigned int rcr;
+ int rc;
+
+ /* Set DM9601-compatible RX header mode */
+ if ( ( rc = dm96xx_rx_mode ( dm96xx ) ) != 0 )
+ goto err_rx_mode;
+
+ /* Write MAC address */
+ if ( ( rc = dm96xx_write_mac ( dm96xx, netdev->ll_addr ) ) != 0 )
+ goto err_write_mac;
+
+ /* Open USB network device */
+ if ( ( rc = usbnet_open ( &dm96xx->usbnet ) ) != 0 ) {
+ DBGC ( dm96xx, "DM96XX %p could not open: %s\n",
+ dm96xx, strerror ( rc ) );
+ goto err_open;
+ }
+
+ /* Set receive filters */
+ rcr = ( DM96XX_RCR_ALL | DM96XX_RCR_RUNT | DM96XX_RCR_PRMSC |
+ DM96XX_RCR_RXEN );
+ if ( ( rc = dm96xx_write_register ( dm96xx, DM96XX_RCR, rcr ) ) != 0 ) {
+ DBGC ( dm96xx, "DM96XX %p could not write receive filters: "
+ "%s\n", dm96xx, strerror ( rc ) );
+ goto err_write_rcr;
+ }
+
+ /* Update link status */
+ if ( ( rc = dm96xx_check_link ( dm96xx ) ) != 0 )
+ goto err_check_link;
+
+ return 0;
+
+ err_check_link:
+ err_write_rcr:
+ usbnet_close ( &dm96xx->usbnet );
+ err_open:
+ err_write_mac:
+ err_rx_mode:
+ return rc;
+}
+
+/**
+ * Close network device
+ *
+ * @v netdev Network device
+ */
+static void dm96xx_close ( struct net_device *netdev ) {
+ struct dm96xx_device *dm96xx = netdev->priv;
+
+ /* Close USB network device */
+ usbnet_close ( &dm96xx->usbnet );
+
+ /* Reset device */
+ dm96xx_reset ( dm96xx );
+}
+
+/**
+ * Transmit packet
+ *
+ * @v netdev Network device
+ * @v iobuf I/O buffer
+ * @ret rc Return status code
+ */
+static int dm96xx_transmit ( struct net_device *netdev,
+ struct io_buffer *iobuf ) {
+ struct dm96xx_device *dm96xx = netdev->priv;
+ int rc;
+
+ /* Transmit packet */
+ if ( ( rc = dm96xx_out_transmit ( dm96xx, iobuf ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/**
+ * Poll for completed and received packets
+ *
+ * @v netdev Network device
+ */
+static void dm96xx_poll ( struct net_device *netdev ) {
+ struct dm96xx_device *dm96xx = netdev->priv;
+ int rc;
+
+ /* Poll USB bus */
+ usb_poll ( dm96xx->bus );
+
+ /* Refill endpoints */
+ if ( ( rc = usbnet_refill ( &dm96xx->usbnet ) ) != 0 )
+ netdev_rx_err ( netdev, NULL, rc );
+}
+
+/** DM96xx network device operations */
+static struct net_device_operations dm96xx_operations = {
+ .open = dm96xx_open,
+ .close = dm96xx_close,
+ .transmit = dm96xx_transmit,
+ .poll = dm96xx_poll,
+};
+
+/******************************************************************************
+ *
+ * USB interface
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Probe device
+ *
+ * @v func USB function
+ * @v config Configuration descriptor
+ * @ret rc Return status code
+ */
+static int dm96xx_probe ( struct usb_function *func,
+ struct usb_configuration_descriptor *config ) {
+ struct usb_device *usb = func->usb;
+ struct net_device *netdev;
+ struct dm96xx_device *dm96xx;
+ int rc;
+
+ /* Allocate and initialise structure */
+ netdev = alloc_etherdev ( sizeof ( *dm96xx ) );
+ if ( ! netdev ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ netdev_init ( netdev, &dm96xx_operations );
+ netdev->dev = &func->dev;
+ dm96xx = netdev->priv;
+ memset ( dm96xx, 0, sizeof ( *dm96xx ) );
+ dm96xx->usb = usb;
+ dm96xx->bus = usb->port->hub->bus;
+ dm96xx->netdev = netdev;
+ usbnet_init ( &dm96xx->usbnet, func, &dm96xx_intr_operations,
+ &dm96xx_in_operations, &dm96xx_out_operations );
+ usb_refill_init ( &dm96xx->usbnet.intr, 0, DM96XX_INTR_MAX_FILL );
+ usb_refill_init ( &dm96xx->usbnet.in, DM96XX_IN_MTU,
+ DM96XX_IN_MAX_FILL );
+ DBGC ( dm96xx, "DM96XX %p on %s\n", dm96xx, func->name );
+
+ /* Describe USB network device */
+ if ( ( rc = usbnet_describe ( &dm96xx->usbnet, config ) ) != 0 ) {
+ DBGC ( dm96xx, "DM96XX %p could not describe: %s\n",
+ dm96xx, strerror ( rc ) );
+ goto err_describe;
+ }
+
+ /* Reset device */
+ if ( ( rc = dm96xx_reset ( dm96xx ) ) != 0 )
+ goto err_reset;
+
+ /* Read MAC address */
+ if ( ( rc = dm96xx_read_mac ( dm96xx, netdev->hw_addr ) ) != 0 )
+ goto err_read_mac;
+
+ /* Get initial link status */
+ if ( ( rc = dm96xx_check_link ( dm96xx ) ) != 0 )
+ goto err_check_link;
+
+ /* Register network device */
+ if ( ( rc = register_netdev ( netdev ) ) != 0 )
+ goto err_register;
+
+ usb_func_set_drvdata ( func, netdev );
+ return 0;
+
+ unregister_netdev ( netdev );
+ err_register:
+ err_check_link:
+ err_read_mac:
+ err_reset:
+ err_describe:
+ netdev_nullify ( netdev );
+ netdev_put ( netdev );
+ err_alloc:
+ return rc;
+}
+
+/**
+ * Remove device
+ *
+ * @v func USB function
+ */
+static void dm96xx_remove ( struct usb_function *func ) {
+ struct net_device *netdev = usb_func_get_drvdata ( func );
+
+ unregister_netdev ( netdev );
+ netdev_nullify ( netdev );
+ netdev_put ( netdev );
+}
+
+/** DM96xx device IDs */
+static struct usb_device_id dm96xx_ids[] = {
+ {
+ .name = "dm9601-corega",
+ .vendor = 0x07aa,
+ .product = 0x9601,
+ },
+ {
+ .name = "dm9601",
+ .vendor = 0x0a46,
+ .product = 0x9601,
+ },
+ {
+ .name = "zt6688",
+ .vendor = 0x0a46,
+ .product = 0x6688,
+ },
+ {
+ .name = "st268",
+ .vendor = 0x0a46,
+ .product = 0x0268,
+ },
+ {
+ .name = "adm8515",
+ .vendor = 0x0a46,
+ .product = 0x8515,
+ },
+ {
+ .name = "dm9601-hirose",
+ .vendor = 0x0a47,
+ .product = 0x9601,
+ },
+ {
+ .name = "dm9601-8101",
+ .vendor = 0x0fe6,
+ .product = 0x8101,
+ },
+ {
+ .name = "dm9601-9700",
+ .vendor = 0x0fe6,
+ .product = 0x9700,
+ },
+ {
+ .name = "dm9000e",
+ .vendor = 0x0a46,
+ .product = 0x9000,
+ },
+ {
+ .name = "dm9620",
+ .vendor = 0x0a46,
+ .product = 0x9620,
+ },
+ {
+ .name = "dm9621A",
+ .vendor = 0x0a46,
+ .product = 0x9621,
+ },
+ {
+ .name = "dm9622",
+ .vendor = 0x0a46,
+ .product = 0x9622,
+ },
+ {
+ .name = "dm962Oa",
+ .vendor = 0x0a46,
+ .product = 0x0269,
+ },
+ {
+ .name = "dm9621a",
+ .vendor = 0x0a46,
+ .product = 0x1269,
+ },
+};
+
+/** Davicom DM96xx driver */
+struct usb_driver dm96xx_driver __usb_driver = {
+ .ids = dm96xx_ids,
+ .id_count = ( sizeof ( dm96xx_ids ) / sizeof ( dm96xx_ids[0] ) ),
+ .probe = dm96xx_probe,
+ .remove = dm96xx_remove,
+};
diff --git a/roms/ipxe/src/drivers/net/dm96xx.h b/roms/ipxe/src/drivers/net/dm96xx.h
new file mode 100644
index 000000000..43a1a4e30
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/dm96xx.h
@@ -0,0 +1,194 @@
+#ifndef _DM96XX_H
+#define _DM96XX_H
+
+/** @file
+ *
+ * Davicom DM96xx USB Ethernet driver
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <ipxe/usb.h>
+#include <ipxe/usbnet.h>
+#include <ipxe/if_ether.h>
+
+/** Read register(s) */
+#define DM96XX_READ_REGISTER \
+ ( USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE | \
+ USB_REQUEST_TYPE ( 0x00 ) )
+
+/** Write register(s) */
+#define DM96XX_WRITE_REGISTER \
+ ( USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE | \
+ USB_REQUEST_TYPE ( 0x01 ) )
+
+/** Write single register */
+#define DM96XX_WRITE1_REGISTER \
+ ( USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE | \
+ USB_REQUEST_TYPE ( 0x03 ) )
+
+/** Network control register */
+#define DM96XX_NCR 0x00
+#define DM96XX_NCR_RST 0x01 /**< Software reset */
+
+/** Network status register */
+#define DM96XX_NSR 0x01
+#define DM96XX_NSR_LINKST 0x40 /**< Link status */
+
+/** Receive control register */
+#define DM96XX_RCR 0x05
+#define DM96XX_RCR_ALL 0x08 /**< Pass all multicast */
+#define DM96XX_RCR_RUNT 0x04 /**< Pass runt packet */
+#define DM96XX_RCR_PRMSC 0x02 /**< Promiscuous mode */
+#define DM96XX_RCR_RXEN 0x01 /**< RX enable */
+
+/** Receive status register */
+#define DM96XX_RSR 0x06
+#define DM96XX_RSR_MF 0x40 /**< Multicast frame */
+
+/** PHY address registers */
+#define DM96XX_PAR 0x10
+
+/** Chip revision register */
+#define DM96XX_CHIPR 0x2c
+#define DM96XX_CHIPR_9601 0x00 /**< DM9601 */
+#define DM96XX_CHIPR_9620 0x01 /**< DM9620 */
+
+/** RX header control/status register (DM9620+ only) */
+#define DM96XX_MODE_CTL 0x91
+#define DM96XX_MODE_CTL_MODE 0x80 /**< 4-byte header mode */
+
+/** DM96xx interrupt data */
+struct dm96xx_interrupt {
+ /** Network status register */
+ uint8_t nsr;
+ /** Transmit status registers */
+ uint8_t tsr[2];
+ /** Receive status register */
+ uint8_t rsr;
+ /** Receive overflow counter register */
+ uint8_t rocr;
+ /** Receive packet counter */
+ uint8_t rxc;
+ /** Transmit packet counter */
+ uint8_t txc;
+ /** General purpose register */
+ uint8_t gpr;
+} __attribute__ (( packed ));
+
+/** DM96xx receive header */
+struct dm96xx_rx_header {
+ /** Packet status */
+ uint8_t rsr;
+ /** Packet length (excluding this header, including CRC) */
+ uint16_t len;
+} __attribute__ (( packed ));
+
+/** DM96xx transmit header */
+struct dm96xx_tx_header {
+ /** Packet length (excluding this header) */
+ uint16_t len;
+} __attribute__ (( packed ));
+
+/** A DM96xx network device */
+struct dm96xx_device {
+ /** USB device */
+ struct usb_device *usb;
+ /** USB bus */
+ struct usb_bus *bus;
+ /** Network device */
+ struct net_device *netdev;
+ /** USB network device */
+ struct usbnet_device usbnet;
+};
+
+/**
+ * Read registers
+ *
+ * @v dm96xx DM96xx device
+ * @v offset Register offset
+ * @v data Data buffer
+ * @v len Length of data
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+dm96xx_read_registers ( struct dm96xx_device *dm96xx, unsigned int offset,
+ void *data, size_t len ) {
+
+ return usb_control ( dm96xx->usb, DM96XX_READ_REGISTER, 0, offset,
+ data, len );
+}
+
+/**
+ * Read register
+ *
+ * @v dm96xx DM96xx device
+ * @v offset Register offset
+ * @ret value Register value, or negative error
+ */
+static inline __attribute__ (( always_inline )) int
+dm96xx_read_register ( struct dm96xx_device *dm96xx, unsigned int offset ) {
+ uint8_t value;
+ int rc;
+
+ if ( ( rc = dm96xx_read_registers ( dm96xx, offset, &value,
+ sizeof ( value ) ) ) != 0 )
+ return rc;
+ return value;
+}
+
+/**
+ * Write registers
+ *
+ * @v dm96xx DM96xx device
+ * @v offset Register offset
+ * @v data Data buffer
+ * @v len Length of data
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+dm96xx_write_registers ( struct dm96xx_device *dm96xx, unsigned int offset,
+ void *data, size_t len ) {
+
+ return usb_control ( dm96xx->usb, DM96XX_WRITE_REGISTER, 0, offset,
+ data, len );
+}
+
+/**
+ * Write register
+ *
+ * @v dm96xx DM96xx device
+ * @v offset Register offset
+ * @v value Register value
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+dm96xx_write_register ( struct dm96xx_device *dm96xx, unsigned int offset,
+ uint8_t value ) {
+
+ return usb_control ( dm96xx->usb, DM96XX_WRITE1_REGISTER, value,
+ offset, NULL, 0 );
+}
+
+/** Reset delay (in microseconds) */
+#define DM96XX_RESET_DELAY_US 10
+
+/** Interrupt maximum fill level
+ *
+ * This is a policy decision.
+ */
+#define DM96XX_INTR_MAX_FILL 2
+
+/** Bulk IN maximum fill level
+ *
+ * This is a policy decision.
+ */
+#define DM96XX_IN_MAX_FILL 8
+
+/** Bulk IN buffer size */
+#define DM96XX_IN_MTU \
+ ( 4 /* DM96xx header */ + ETH_FRAME_LEN + \
+ 4 /* possible VLAN header */ + 4 /* CRC */ )
+
+#endif /* _DM96XX_H */
diff --git a/roms/ipxe/src/drivers/net/dmfe.c b/roms/ipxe/src/drivers/net/dmfe.c
index aae40fce7..2ea0d2b2b 100644
--- a/roms/ipxe/src/drivers/net/dmfe.c
+++ b/roms/ipxe/src/drivers/net/dmfe.c
@@ -462,7 +462,7 @@ static int dmfe_probe ( struct nic *nic, struct pci_device *pci ) {
pci->id->name, pci->vendor, pci->device);
/* Read Chip revision */
- pci_read_config_dword(pci, PCI_REVISION_ID, &dev_rev);
+ pci_read_config_dword(pci, PCI_REVISION, &dev_rev);
dprintf(("Revision %lX\n", dev_rev));
/* point to private storage */
diff --git a/roms/ipxe/src/drivers/net/ecm.c b/roms/ipxe/src/drivers/net/ecm.c
new file mode 100644
index 000000000..8c84ea9e9
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ecm.c
@@ -0,0 +1,520 @@
+/*
+ * Copyright (C) 2014 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
+#include <errno.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/base16.h>
+#include <ipxe/profile.h>
+#include <ipxe/usb.h>
+#include "ecm.h"
+
+/** @file
+ *
+ * CDC-ECM USB Ethernet driver
+ *
+ */
+
+/** Interrupt completion profiler */
+static struct profiler ecm_intr_profiler __profiler =
+ { .name = "ecm.intr" };
+
+/** Bulk IN completion profiler */
+static struct profiler ecm_in_profiler __profiler =
+ { .name = "ecm.in" };
+
+/** Bulk OUT profiler */
+static struct profiler ecm_out_profiler __profiler =
+ { .name = "ecm.out" };
+
+/******************************************************************************
+ *
+ * Ethernet functional descriptor
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Locate Ethernet functional descriptor
+ *
+ * @v config Configuration descriptor
+ * @v interface Interface descriptor
+ * @ret desc Descriptor, or NULL if not found
+ */
+struct ecm_ethernet_descriptor *
+ecm_ethernet_descriptor ( struct usb_configuration_descriptor *config,
+ struct usb_interface_descriptor *interface ) {
+ struct ecm_ethernet_descriptor *desc;
+
+ for_each_interface_descriptor ( desc, config, interface ) {
+ if ( ( desc->header.type == USB_CS_INTERFACE_DESCRIPTOR ) &&
+ ( desc->subtype == CDC_SUBTYPE_ETHERNET ) )
+ return desc;
+ }
+ return NULL;
+}
+
+/**
+ * Get hardware MAC address
+ *
+ * @v usb USB device
+ * @v desc Ethernet functional descriptor
+ * @v hw_addr Hardware address to fill in
+ * @ret rc Return status code
+ */
+int ecm_fetch_mac ( struct usb_device *usb,
+ struct ecm_ethernet_descriptor *desc, uint8_t *hw_addr ) {
+ char buf[ base16_encoded_len ( ETH_ALEN ) + 1 /* NUL */ ];
+ int len;
+ int rc;
+
+ /* Fetch MAC address string */
+ len = usb_get_string_descriptor ( usb, desc->mac, 0, buf,
+ sizeof ( buf ) );
+ if ( len < 0 ) {
+ rc = len;
+ return rc;
+ }
+
+ /* Sanity check */
+ if ( len != ( ( int ) ( sizeof ( buf ) - 1 /* NUL */ ) ) )
+ return -EINVAL;
+
+ /* Decode MAC address */
+ len = base16_decode ( buf, hw_addr, ETH_ALEN );
+ if ( len < 0 ) {
+ rc = len;
+ return rc;
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * CDC-ECM communications interface
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Complete interrupt transfer
+ *
+ * @v ep USB endpoint
+ * @v iobuf I/O buffer
+ * @v rc Completion status code
+ */
+static void ecm_intr_complete ( struct usb_endpoint *ep,
+ struct io_buffer *iobuf, int rc ) {
+ struct ecm_device *ecm = container_of ( ep, struct ecm_device,
+ usbnet.intr );
+ struct net_device *netdev = ecm->netdev;
+ struct usb_setup_packet *message;
+ size_t len = iob_len ( iobuf );
+
+ /* Profile completions */
+ profile_start ( &ecm_intr_profiler );
+
+ /* Ignore packets cancelled when the endpoint closes */
+ if ( ! ep->open )
+ goto ignore;
+
+ /* Drop packets with errors */
+ if ( rc != 0 ) {
+ DBGC ( ecm, "ECM %p interrupt failed: %s\n",
+ ecm, strerror ( rc ) );
+ DBGC_HDA ( ecm, 0, iobuf->data, iob_len ( iobuf ) );
+ goto error;
+ }
+
+ /* Extract message header */
+ if ( len < sizeof ( *message ) ) {
+ DBGC ( ecm, "ECM %p underlength interrupt:\n", ecm );
+ DBGC_HDA ( ecm, 0, iobuf->data, iob_len ( iobuf ) );
+ rc = -EINVAL;
+ goto error;
+ }
+ message = iobuf->data;
+
+ /* Parse message header */
+ switch ( message->request ) {
+
+ case cpu_to_le16 ( CDC_NETWORK_CONNECTION ) :
+ if ( message->value && ! netdev_link_ok ( netdev ) ) {
+ DBGC ( ecm, "ECM %p link up\n", ecm );
+ netdev_link_up ( netdev );
+ } else if ( netdev_link_ok ( netdev ) && ! message->value ) {
+ DBGC ( ecm, "ECM %p link down\n", ecm );
+ netdev_link_down ( netdev );
+ }
+ break;
+
+ case cpu_to_le16 ( CDC_CONNECTION_SPEED_CHANGE ) :
+ /* Ignore */
+ break;
+
+ default:
+ DBGC ( ecm, "ECM %p unrecognised interrupt:\n", ecm );
+ DBGC_HDA ( ecm, 0, iobuf->data, iob_len ( iobuf ) );
+ rc = -ENOTSUP;
+ goto error;
+ }
+
+ /* Free I/O buffer */
+ free_iob ( iobuf );
+ profile_stop ( &ecm_intr_profiler );
+
+ return;
+
+ error:
+ netdev_rx_err ( netdev, iob_disown ( iobuf ), rc );
+ ignore:
+ free_iob ( iobuf );
+ return;
+}
+
+/** Interrupt endpoint operations */
+static struct usb_endpoint_driver_operations ecm_intr_operations = {
+ .complete = ecm_intr_complete,
+};
+
+/******************************************************************************
+ *
+ * CDC-ECM data interface
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Complete bulk IN transfer
+ *
+ * @v ep USB endpoint
+ * @v iobuf I/O buffer
+ * @v rc Completion status code
+ */
+static void ecm_in_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf,
+ int rc ) {
+ struct ecm_device *ecm = container_of ( ep, struct ecm_device,
+ usbnet.in );
+ struct net_device *netdev = ecm->netdev;
+
+ /* Profile receive completions */
+ profile_start ( &ecm_in_profiler );
+
+ /* Ignore packets cancelled when the endpoint closes */
+ if ( ! ep->open )
+ goto ignore;
+
+ /* Record USB errors against the network device */
+ if ( rc != 0 ) {
+ DBGC ( ecm, "ECM %p bulk IN failed: %s\n",
+ ecm, strerror ( rc ) );
+ goto error;
+ }
+
+ /* Hand off to network stack */
+ netdev_rx ( netdev, iob_disown ( iobuf ) );
+
+ profile_stop ( &ecm_in_profiler );
+ return;
+
+ error:
+ netdev_rx_err ( netdev, iob_disown ( iobuf ), rc );
+ ignore:
+ free_iob ( iobuf );
+}
+
+/** Bulk IN endpoint operations */
+static struct usb_endpoint_driver_operations ecm_in_operations = {
+ .complete = ecm_in_complete,
+};
+
+/**
+ * Transmit packet
+ *
+ * @v ecm CDC-ECM device
+ * @v iobuf I/O buffer
+ * @ret rc Return status code
+ */
+static int ecm_out_transmit ( struct ecm_device *ecm,
+ struct io_buffer *iobuf ) {
+ int rc;
+
+ /* Profile transmissions */
+ profile_start ( &ecm_out_profiler );
+
+ /* Enqueue I/O buffer */
+ if ( ( rc = usb_stream ( &ecm->usbnet.out, iobuf, 1 ) ) != 0 )
+ return rc;
+
+ profile_stop ( &ecm_out_profiler );
+ return 0;
+}
+
+/**
+ * Complete bulk OUT transfer
+ *
+ * @v ep USB endpoint
+ * @v iobuf I/O buffer
+ * @v rc Completion status code
+ */
+static void ecm_out_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf,
+ int rc ) {
+ struct ecm_device *ecm = container_of ( ep, struct ecm_device,
+ usbnet.out );
+ struct net_device *netdev = ecm->netdev;
+
+ /* Report TX completion */
+ netdev_tx_complete_err ( netdev, iobuf, rc );
+}
+
+/** Bulk OUT endpoint operations */
+static struct usb_endpoint_driver_operations ecm_out_operations = {
+ .complete = ecm_out_complete,
+};
+
+/******************************************************************************
+ *
+ * Network device interface
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Open network device
+ *
+ * @v netdev Network device
+ * @ret rc Return status code
+ */
+static int ecm_open ( struct net_device *netdev ) {
+ struct ecm_device *ecm = netdev->priv;
+ struct usb_device *usb = ecm->usb;
+ unsigned int filter;
+ int rc;
+
+ /* Open USB network device */
+ if ( ( rc = usbnet_open ( &ecm->usbnet ) ) != 0 ) {
+ DBGC ( ecm, "ECM %p could not open: %s\n",
+ ecm, strerror ( rc ) );
+ goto err_open;
+ }
+
+ /* Set packet filter */
+ filter = ( ECM_PACKET_TYPE_PROMISCUOUS |
+ ECM_PACKET_TYPE_ALL_MULTICAST |
+ ECM_PACKET_TYPE_DIRECTED |
+ ECM_PACKET_TYPE_BROADCAST );
+ if ( ( rc = usb_control ( usb, ECM_SET_ETHERNET_PACKET_FILTER,
+ filter, ecm->usbnet.comms, NULL, 0 ) ) != 0 ){
+ DBGC ( ecm, "ECM %p could not set packet filter: %s\n",
+ ecm, strerror ( rc ) );
+ goto err_set_filter;
+ }
+
+ return 0;
+
+ err_set_filter:
+ usbnet_close ( &ecm->usbnet );
+ err_open:
+ return rc;
+}
+
+/**
+ * Close network device
+ *
+ * @v netdev Network device
+ */
+static void ecm_close ( struct net_device *netdev ) {
+ struct ecm_device *ecm = netdev->priv;
+
+ /* Close USB network device */
+ usbnet_close ( &ecm->usbnet );
+}
+
+/**
+ * Transmit packet
+ *
+ * @v netdev Network device
+ * @v iobuf I/O buffer
+ * @ret rc Return status code
+ */
+static int ecm_transmit ( struct net_device *netdev,
+ struct io_buffer *iobuf ) {
+ struct ecm_device *ecm = netdev->priv;
+ int rc;
+
+ /* Transmit packet */
+ if ( ( rc = ecm_out_transmit ( ecm, iobuf ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/**
+ * Poll for completed and received packets
+ *
+ * @v netdev Network device
+ */
+static void ecm_poll ( struct net_device *netdev ) {
+ struct ecm_device *ecm = netdev->priv;
+ int rc;
+
+ /* Poll USB bus */
+ usb_poll ( ecm->bus );
+
+ /* Refill endpoints */
+ if ( ( rc = usbnet_refill ( &ecm->usbnet ) ) != 0 )
+ netdev_rx_err ( netdev, NULL, rc );
+}
+
+/** CDC-ECM network device operations */
+static struct net_device_operations ecm_operations = {
+ .open = ecm_open,
+ .close = ecm_close,
+ .transmit = ecm_transmit,
+ .poll = ecm_poll,
+};
+
+/******************************************************************************
+ *
+ * USB interface
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Probe device
+ *
+ * @v func USB function
+ * @v config Configuration descriptor
+ * @ret rc Return status code
+ */
+static int ecm_probe ( struct usb_function *func,
+ struct usb_configuration_descriptor *config ) {
+ struct usb_device *usb = func->usb;
+ struct net_device *netdev;
+ struct ecm_device *ecm;
+ struct usb_interface_descriptor *comms;
+ struct ecm_ethernet_descriptor *ethernet;
+ int rc;
+
+ /* Allocate and initialise structure */
+ netdev = alloc_etherdev ( sizeof ( *ecm ) );
+ if ( ! netdev ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ netdev_init ( netdev, &ecm_operations );
+ netdev->dev = &func->dev;
+ ecm = netdev->priv;
+ memset ( ecm, 0, sizeof ( *ecm ) );
+ ecm->usb = usb;
+ ecm->bus = usb->port->hub->bus;
+ ecm->netdev = netdev;
+ usbnet_init ( &ecm->usbnet, func, &ecm_intr_operations,
+ &ecm_in_operations, &ecm_out_operations );
+ usb_refill_init ( &ecm->usbnet.intr, 0, ECM_INTR_MAX_FILL );
+ usb_refill_init ( &ecm->usbnet.in, ECM_IN_MTU, ECM_IN_MAX_FILL );
+ DBGC ( ecm, "ECM %p on %s\n", ecm, func->name );
+
+ /* Describe USB network device */
+ if ( ( rc = usbnet_describe ( &ecm->usbnet, config ) ) != 0 ) {
+ DBGC ( ecm, "ECM %p could not describe: %s\n",
+ ecm, strerror ( rc ) );
+ goto err_describe;
+ }
+
+ /* Locate Ethernet descriptor */
+ comms = usb_interface_descriptor ( config, ecm->usbnet.comms, 0 );
+ assert ( comms != NULL );
+ ethernet = ecm_ethernet_descriptor ( config, comms );
+ if ( ! ethernet ) {
+ DBGC ( ecm, "ECM %p has no Ethernet descriptor\n", ecm );
+ rc = -EINVAL;
+ goto err_ethernet;
+ }
+
+ /* Fetch MAC address */
+ if ( ( rc = ecm_fetch_mac ( usb, ethernet, netdev->hw_addr ) ) != 0 ) {
+ DBGC ( ecm, "ECM %p could not fetch MAC address: %s\n",
+ ecm, strerror ( rc ) );
+ goto err_fetch_mac;
+ }
+
+ /* Register network device */
+ if ( ( rc = register_netdev ( netdev ) ) != 0 )
+ goto err_register;
+
+ usb_func_set_drvdata ( func, ecm );
+ return 0;
+
+ unregister_netdev ( netdev );
+ err_register:
+ err_fetch_mac:
+ err_ethernet:
+ err_describe:
+ netdev_nullify ( netdev );
+ netdev_put ( netdev );
+ err_alloc:
+ return rc;
+}
+
+/**
+ * Remove device
+ *
+ * @v func USB function
+ */
+static void ecm_remove ( struct usb_function *func ) {
+ struct ecm_device *ecm = usb_func_get_drvdata ( func );
+ struct net_device *netdev = ecm->netdev;
+
+ unregister_netdev ( netdev );
+ netdev_nullify ( netdev );
+ netdev_put ( netdev );
+}
+
+/** CDC-ECM device IDs */
+static struct usb_device_id ecm_ids[] = {
+ {
+ .name = "cdc-ecm",
+ .vendor = USB_ANY_ID,
+ .product = USB_ANY_ID,
+ .class = {
+ .class = USB_CLASS_CDC,
+ .subclass = USB_SUBCLASS_CDC_ECM,
+ .protocol = 0,
+ },
+ },
+};
+
+/** CDC-ECM driver */
+struct usb_driver ecm_driver __usb_driver = {
+ .ids = ecm_ids,
+ .id_count = ( sizeof ( ecm_ids ) / sizeof ( ecm_ids[0] ) ),
+ .probe = ecm_probe,
+ .remove = ecm_remove,
+};
diff --git a/roms/ipxe/src/drivers/net/ecm.h b/roms/ipxe/src/drivers/net/ecm.h
new file mode 100644
index 000000000..83d324bdc
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ecm.h
@@ -0,0 +1,93 @@
+#ifndef _ECM_H
+#define _ECM_H
+
+/** @file
+ *
+ * CDC-ECM USB Ethernet driver
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <ipxe/usb.h>
+#include <ipxe/usbnet.h>
+#include <ipxe/cdc.h>
+
+/** CDC-ECM subclass */
+#define USB_SUBCLASS_CDC_ECM 0x06
+
+/** Set Ethernet packet filter */
+#define ECM_SET_ETHERNET_PACKET_FILTER \
+ ( USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE | \
+ USB_REQUEST_TYPE ( 0x43 ) )
+
+/** Ethernet packet types */
+enum ecm_ethernet_packet_filter {
+ /** Promiscuous mode */
+ ECM_PACKET_TYPE_PROMISCUOUS = 0x0001,
+ /** All multicast packets */
+ ECM_PACKET_TYPE_ALL_MULTICAST = 0x0002,
+ /** Unicast packets */
+ ECM_PACKET_TYPE_DIRECTED = 0x0004,
+ /** Broadcast packets */
+ ECM_PACKET_TYPE_BROADCAST = 0x0008,
+ /** Specified multicast packets */
+ ECM_PACKET_TYPE_MULTICAST = 0x0010,
+};
+
+/** An Ethernet Functional Descriptor */
+struct ecm_ethernet_descriptor {
+ /** Descriptor header */
+ struct usb_descriptor_header header;
+ /** Descriptor subtype */
+ uint8_t subtype;
+ /** MAC address string */
+ uint8_t mac;
+ /** Ethernet statistics bitmap */
+ uint32_t statistics;
+ /** Maximum segment size */
+ uint16_t mtu;
+ /** Multicast filter configuration */
+ uint16_t mcast;
+ /** Number of wake-on-LAN filters */
+ uint8_t wol;
+} __attribute__ (( packed ));
+
+/** A CDC-ECM network device */
+struct ecm_device {
+ /** USB device */
+ struct usb_device *usb;
+ /** USB bus */
+ struct usb_bus *bus;
+ /** Network device */
+ struct net_device *netdev;
+ /** USB network device */
+ struct usbnet_device usbnet;
+};
+
+/** Interrupt maximum fill level
+ *
+ * This is a policy decision.
+ */
+#define ECM_INTR_MAX_FILL 2
+
+/** Bulk IN maximum fill level
+ *
+ * This is a policy decision.
+ */
+#define ECM_IN_MAX_FILL 8
+
+/** Bulk IN buffer size
+ *
+ * This is a policy decision.
+ */
+#define ECM_IN_MTU ( ETH_FRAME_LEN + 4 /* possible VLAN header */ )
+
+extern struct ecm_ethernet_descriptor *
+ecm_ethernet_descriptor ( struct usb_configuration_descriptor *config,
+ struct usb_interface_descriptor *interface );
+extern int ecm_fetch_mac ( struct usb_device *usb,
+ struct ecm_ethernet_descriptor *desc,
+ uint8_t *hw_addr );
+
+#endif /* _ECM_H */
diff --git a/roms/ipxe/src/drivers/net/eepro.c b/roms/ipxe/src/drivers/net/eepro.c
index 909482bcc..97b4c4061 100644
--- a/roms/ipxe/src/drivers/net/eepro.c
+++ b/roms/ipxe/src/drivers/net/eepro.c
@@ -27,8 +27,18 @@ has 34 pins, the top row of 2 are not used.
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2, or (at
- * your option) any later version.
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
@@ -591,9 +601,9 @@ static int eepro_probe ( struct nic *nic, struct isa_device *isa ) {
l_eepro = 0;
name = "Intel 82595-based LAN card";
}
- station_addr.saddr[0] = swap16(station_addr.saddr[0]);
- station_addr.saddr[1] = swap16(station_addr.saddr[1]);
- station_addr.saddr[2] = swap16(station_addr.saddr[2]);
+ station_addr.saddr[0] = bswap_16(station_addr.saddr[0]);
+ station_addr.saddr[1] = bswap_16(station_addr.saddr[1]);
+ station_addr.saddr[2] = bswap_16(station_addr.saddr[2]);
for (i = 0; i < ETH_ALEN; i++) {
nic->node_addr[i] = station_addr.caddr[i];
}
diff --git a/roms/ipxe/src/drivers/net/eepro100.c b/roms/ipxe/src/drivers/net/eepro100.c
index ede0a1a4b..1046cda39 100644
--- a/roms/ipxe/src/drivers/net/eepro100.c
+++ b/roms/ipxe/src/drivers/net/eepro100.c
@@ -1136,7 +1136,6 @@ PCI_ROM(0x8086, 0x2449, "82562em", "Intel EtherExpressPro100 82562EM", 0),
PCI_ROM(0x8086, 0x2459, "82562-1", "Intel 82562 based Fast Ethernet Connection", 0),
PCI_ROM(0x8086, 0x245d, "82562-2", "Intel 82562 based Fast Ethernet Connection", 0),
PCI_ROM(0x8086, 0x1050, "82562ez", "Intel 82562EZ Network Connection", 0),
-PCI_ROM(0x8086, 0x1051, "eepro100-1051", "Intel 82801EB/ER (ICH5/ICH5R) Chipset Ethernet Controller", 0),
PCI_ROM(0x8086, 0x1065, "82562-3", "Intel 82562 based Fast Ethernet Connection", 0),
PCI_ROM(0x8086, 0x5200, "eepro100-5200", "Intel EtherExpress PRO/100 Intelligent Server", 0),
PCI_ROM(0x8086, 0x5201, "eepro100-5201", "Intel EtherExpress PRO/100 Intelligent Server", 0),
diff --git a/roms/ipxe/src/drivers/net/efi/nii.c b/roms/ipxe/src/drivers/net/efi/nii.c
index d0d7da95a..b91848f5c 100644
--- a/roms/ipxe/src/drivers/net/efi/nii.c
+++ b/roms/ipxe/src/drivers/net/efi/nii.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <strings.h>
@@ -168,6 +172,9 @@ struct nii_nic {
/** Saved task priority level */
EFI_TPL saved_tpl;
+ /** Media status is supported */
+ int media;
+
/** Current transmit buffer */
struct io_buffer *txbuf;
/** Current receive buffer */
@@ -408,6 +415,13 @@ static int nii_issue_cpb_db ( struct nii_nic *nii, unsigned int op, void *cpb,
cdb.IFnum = nii->nii->IfNum;
/* Issue command */
+ DBGC2 ( nii, "NII %s issuing %02x:%04x ifnum %d%s%s\n",
+ nii->dev.name, cdb.OpCode, cdb.OpFlags, cdb.IFnum,
+ ( cpb ? " cpb" : "" ), ( db ? " db" : "" ) );
+ if ( cpb )
+ DBGC2_HD ( nii, cpb, cpb_len );
+ if ( db )
+ DBGC2_HD ( nii, db, db_len );
nii->issue ( ( intptr_t ) &cdb );
/* Check completion status */
@@ -552,6 +566,7 @@ static int nii_get_init_info ( struct nii_nic *nii,
nii->buffer_len = db.MemoryRequired;
nii->mtu = ( db.FrameDataLen + db.MediaHeaderLen );
netdev->max_pkt_len = nii->mtu;
+ nii->media = ( stat & PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED );
return 0;
}
@@ -560,10 +575,12 @@ static int nii_get_init_info ( struct nii_nic *nii,
* Initialise UNDI
*
* @v nii NII NIC
+ * @v flags Flags
* @ret rc Return status code
*/
-static int nii_initialise ( struct nii_nic *nii ) {
+static int nii_initialise_flags ( struct nii_nic *nii, unsigned int flags ) {
PXE_CPB_INITIALIZE cpb;
+ PXE_DB_INITIALIZE db;
unsigned int op;
int stat;
int rc;
@@ -580,10 +597,13 @@ static int nii_initialise ( struct nii_nic *nii ) {
cpb.MemoryAddr = ( ( intptr_t ) nii->buffer );
cpb.MemoryLength = nii->buffer_len;
+ /* Construct data block */
+ memset ( &db, 0, sizeof ( db ) );
+
/* Issue command */
- op = NII_OP ( PXE_OPCODE_INITIALIZE,
- PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE );
- if ( ( stat = nii_issue_cpb ( nii, op, &cpb, sizeof ( cpb ) ) ) < 0 ) {
+ op = NII_OP ( PXE_OPCODE_INITIALIZE, flags );
+ if ( ( stat = nii_issue_cpb_db ( nii, op, &cpb, sizeof ( cpb ),
+ &db, sizeof ( db ) ) ) < 0 ) {
rc = -EIO_STAT ( stat );
DBGC ( nii, "NII %s could not initialise: %s\n",
nii->dev.name, strerror ( rc ) );
@@ -599,6 +619,36 @@ static int nii_initialise ( struct nii_nic *nii ) {
}
/**
+ * Initialise UNDI
+ *
+ * @v nii NII NIC
+ * @ret rc Return status code
+ */
+static int nii_initialise ( struct nii_nic *nii ) {
+ unsigned int flags;
+
+ /* Initialise UNDI */
+ flags = PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE;
+ return nii_initialise_flags ( nii, flags );
+}
+
+/**
+ * Initialise UNDI and detect cable
+ *
+ * @v nii NII NIC
+ * @ret rc Return status code
+ */
+static int nii_initialise_and_detect ( struct nii_nic *nii ) {
+ unsigned int flags;
+
+ /* Initialise UNDI and detect cable. This is required to work
+ * around bugs in some Emulex NII drivers.
+ */
+ flags = PXE_OPFLAGS_INITIALIZE_DETECT_CABLE;
+ return nii_initialise_flags ( nii, flags );
+}
+
+/**
* Shut down UNDI
*
* @v nii NII NIC
@@ -630,6 +680,7 @@ static void nii_shutdown ( struct nii_nic *nii ) {
static int nii_get_station_address ( struct nii_nic *nii,
struct net_device *netdev ) {
PXE_DB_STATION_ADDRESS db;
+ unsigned int op;
int stat;
int rc;
@@ -638,8 +689,9 @@ static int nii_get_station_address ( struct nii_nic *nii,
goto err_initialise;
/* Issue command */
- if ( ( stat = nii_issue_db ( nii, PXE_OPCODE_STATION_ADDRESS, &db,
- sizeof ( db ) ) ) < 0 ) {
+ op = NII_OP ( PXE_OPCODE_STATION_ADDRESS,
+ PXE_OPFLAGS_STATION_ADDRESS_READ );
+ if ( ( stat = nii_issue_db ( nii, op, &db, sizeof ( db ) ) ) < 0 ) {
rc = -EIO_STAT ( stat );
DBGC ( nii, "NII %s could not get station address: %s\n",
nii->dev.name, strerror ( rc ) );
@@ -669,18 +721,25 @@ static int nii_get_station_address ( struct nii_nic *nii,
*/
static int nii_set_station_address ( struct nii_nic *nii,
struct net_device *netdev ) {
+ uint32_t implementation = nii->undi->Implementation;
PXE_CPB_STATION_ADDRESS cpb;
+ unsigned int op;
int stat;
int rc;
+ /* Fail if setting station address is unsupported */
+ if ( ! ( implementation & PXE_ROMID_IMP_STATION_ADDR_SETTABLE ) )
+ return -ENOTSUP;
+
/* Construct parameter block */
memset ( &cpb, 0, sizeof ( cpb ) );
memcpy ( cpb.StationAddr, netdev->ll_addr,
netdev->ll_protocol->ll_addr_len );
/* Issue command */
- if ( ( stat = nii_issue_cpb ( nii, PXE_OPCODE_STATION_ADDRESS,
- &cpb, sizeof ( cpb ) ) ) < 0 ) {
+ op = NII_OP ( PXE_OPCODE_STATION_ADDRESS,
+ PXE_OPFLAGS_STATION_ADDRESS_WRITE );
+ if ( ( stat = nii_issue_cpb ( nii, op, &cpb, sizeof ( cpb ) ) ) < 0 ) {
rc = -EIO_STAT ( stat );
DBGC ( nii, "NII %s could not set station address: %s\n",
nii->dev.name, strerror ( rc ) );
@@ -697,21 +756,28 @@ static int nii_set_station_address ( struct nii_nic *nii,
* @ret rc Return status code
*/
static int nii_set_rx_filters ( struct nii_nic *nii ) {
+ uint32_t implementation = nii->undi->Implementation;
+ unsigned int flags;
unsigned int op;
int stat;
int rc;
+ /* Construct receive filter set */
+ flags = ( PXE_OPFLAGS_RECEIVE_FILTER_ENABLE |
+ PXE_OPFLAGS_RECEIVE_FILTER_UNICAST );
+ if ( implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED )
+ flags |= PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
+ if ( implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED )
+ flags |= PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS;
+ if ( implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED )
+ flags |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
+
/* Issue command */
- op = NII_OP ( PXE_OPCODE_RECEIVE_FILTERS,
- ( PXE_OPFLAGS_RECEIVE_FILTER_ENABLE |
- PXE_OPFLAGS_RECEIVE_FILTER_UNICAST |
- PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST |
- PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS |
- PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST ) );
+ op = NII_OP ( PXE_OPCODE_RECEIVE_FILTERS, flags );
if ( ( stat = nii_issue ( nii, op ) ) < 0 ) {
rc = -EIO_STAT ( stat );
- DBGC ( nii, "NII %s could not set receive filters: %s\n",
- nii->dev.name, strerror ( rc ) );
+ DBGC ( nii, "NII %s could not set receive filters %#04x: %s\n",
+ nii->dev.name, flags, strerror ( rc ) );
return rc;
}
@@ -729,6 +795,7 @@ static int nii_transmit ( struct net_device *netdev,
struct io_buffer *iobuf ) {
struct nii_nic *nii = netdev->priv;
PXE_CPB_TRANSMIT cpb;
+ unsigned int op;
int stat;
int rc;
@@ -745,8 +812,10 @@ static int nii_transmit ( struct net_device *netdev,
cpb.MediaheaderLen = netdev->ll_protocol->ll_header_len;
/* Transmit packet */
- if ( ( stat = nii_issue_cpb ( nii, PXE_OPCODE_TRANSMIT, &cpb,
- sizeof ( cpb ) ) ) < 0 ) {
+ op = NII_OP ( PXE_OPCODE_TRANSMIT,
+ ( PXE_OPFLAGS_TRANSMIT_WHOLE |
+ PXE_OPFLAGS_TRANSMIT_DONT_BLOCK ) );
+ if ( ( stat = nii_issue_cpb ( nii, op, &cpb, sizeof ( cpb ) ) ) < 0 ) {
rc = -EIO_STAT ( stat );
DBGC ( nii, "NII %s could not transmit: %s\n",
nii->dev.name, strerror ( rc ) );
@@ -772,12 +841,7 @@ static void nii_poll_tx ( struct net_device *netdev, unsigned int stat ) {
return;
/* Sanity check */
- if ( ! nii->txbuf ) {
- DBGC ( nii, "NII %s reported spurious TX completion\n",
- nii->dev.name );
- netdev_tx_err ( netdev, NULL, -EPIPE );
- return;
- }
+ assert ( nii->txbuf != NULL );
/* Complete transmission */
iobuf = nii->txbuf;
@@ -869,11 +933,14 @@ static void nii_poll ( struct net_device *netdev ) {
int stat;
int rc;
+ /* Construct data block */
+ memset ( &db, 0, sizeof ( db ) );
+
/* Get status */
op = NII_OP ( PXE_OPCODE_GET_STATUS,
( PXE_OPFLAGS_GET_INTERRUPT_STATUS |
- PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS |
- PXE_OPFLAGS_GET_MEDIA_STATUS ) );
+ ( nii->txbuf ? PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS : 0)|
+ ( nii->media ? PXE_OPFLAGS_GET_MEDIA_STATUS : 0 ) ) );
if ( ( stat = nii_issue_db ( nii, op, &db, sizeof ( db ) ) ) < 0 ) {
rc = -EIO_STAT ( stat );
DBGC ( nii, "NII %s could not get status: %s\n",
@@ -882,13 +949,15 @@ static void nii_poll ( struct net_device *netdev ) {
}
/* Process any TX completions */
- nii_poll_tx ( netdev, stat );
+ if ( nii->txbuf )
+ nii_poll_tx ( netdev, stat );
/* Process any RX completions */
nii_poll_rx ( netdev );
/* Check for link state changes */
- nii_poll_link ( netdev, stat );
+ if ( nii->media )
+ nii_poll_link ( netdev, stat );
}
/**
@@ -901,8 +970,18 @@ static int nii_open ( struct net_device *netdev ) {
struct nii_nic *nii = netdev->priv;
int rc;
- /* Initialise NIC */
- if ( ( rc = nii_initialise ( nii ) ) != 0 )
+ /* Initialise NIC
+ *
+ * Some Emulex NII drivers have a bug which prevents packets
+ * from being sent or received unless we specifically ask it
+ * to detect cable presence during initialisation. Work
+ * around these buggy drivers by requesting cable detection at
+ * this point, even though we don't care about link state here
+ * (and would prefer to have the NIC initialise even if no
+ * cable is present, to match the behaviour of all other iPXE
+ * drivers).
+ */
+ if ( ( rc = nii_initialise_and_detect ( nii ) ) != 0 )
goto err_initialise;
/* Attempt to set station address */
@@ -1023,8 +1102,9 @@ int nii_start ( struct efi_device *efidev ) {
nii->issue = ( ( ( void * ) nii->undi ) +
nii->undi->EntryPoint );
}
- DBGC ( nii, "NII %s using UNDI v%x.%x at %p entry %p\n", nii->dev.name,
- nii->nii->MajorVer, nii->nii->MinorVer, nii->undi, nii->issue );
+ DBGC ( nii, "NII %s using UNDI v%x.%x at %p entry %p impl %#08x\n",
+ nii->dev.name, nii->nii->MajorVer, nii->nii->MinorVer,
+ nii->undi, nii->issue, nii->undi->Implementation );
/* Open PCI I/O protocols and locate BARs */
if ( ( rc = nii_pci_open ( nii ) ) != 0 )
@@ -1048,6 +1128,10 @@ int nii_start ( struct efi_device *efidev ) {
DBGC ( nii, "NII %s registered as %s for %p %s\n", nii->dev.name,
netdev->name, device, efi_handle_name ( device ) );
+ /* Set initial link state (if media detection is not supported) */
+ if ( ! nii->media )
+ netdev_link_up ( netdev );
+
return 0;
unregister_netdev ( netdev );
diff --git a/roms/ipxe/src/drivers/net/efi/nii.h b/roms/ipxe/src/drivers/net/efi/nii.h
index de0ac687b..c10be9db5 100644
--- a/roms/ipxe/src/drivers/net/efi/nii.h
+++ b/roms/ipxe/src/drivers/net/efi/nii.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
struct efi_device;
diff --git a/roms/ipxe/src/drivers/net/efi/snp.c b/roms/ipxe/src/drivers/net/efi/snp.c
index 2b5fc8618..acfcfba9f 100644
--- a/roms/ipxe/src/drivers/net/efi/snp.c
+++ b/roms/ipxe/src/drivers/net/efi/snp.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <errno.h>
#include <ipxe/efi/efi.h>
diff --git a/roms/ipxe/src/drivers/net/efi/snponly.c b/roms/ipxe/src/drivers/net/efi/snponly.c
index 99f264bca..73abfdbf4 100644
--- a/roms/ipxe/src/drivers/net/efi/snponly.c
+++ b/roms/ipxe/src/drivers/net/efi/snponly.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <errno.h>
diff --git a/roms/ipxe/src/drivers/net/etherfabric.c b/roms/ipxe/src/drivers/net/etherfabric.c
index 5e0efb1e1..29d117443 100644
--- a/roms/ipxe/src/drivers/net/etherfabric.c
+++ b/roms/ipxe/src/drivers/net/etherfabric.c
@@ -3176,7 +3176,7 @@ falcon_probe_nic_variant ( struct efab_nic *efab, struct pci_device *pci )
uint8_t revision;
/* PCI revision */
- pci_read_config_byte ( pci, PCI_CLASS_REVISION, &revision );
+ pci_read_config_byte ( pci, PCI_REVISION, &revision );
efab->pci_revision = revision;
/* Asic vs FPGA */
diff --git a/roms/ipxe/src/drivers/net/forcedeth.c b/roms/ipxe/src/drivers/net/forcedeth.c
index d8ece9a7a..79938cbbb 100644
--- a/roms/ipxe/src/drivers/net/forcedeth.c
+++ b/roms/ipxe/src/drivers/net/forcedeth.c
@@ -1749,10 +1749,8 @@ forcedeth_map_regs ( struct forcedeth_private *priv )
for ( reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4 ) {
pci_read_config_dword ( priv->pci_dev, reg, &bar );
- if ( ( ( bar & PCI_BASE_ADDRESS_SPACE ) ==
- PCI_BASE_ADDRESS_SPACE_MEMORY ) &&
- ( pci_bar_size ( priv->pci_dev, reg ) >=
- register_size ) ) {
+ if ( ( ! ( bar & PCI_BASE_ADDRESS_SPACE_IO ) ) &&
+ ( pci_bar_size ( priv->pci_dev, reg ) >= register_size ) ){
addr = pci_bar_start ( priv->pci_dev, reg );
break;
}
diff --git a/roms/ipxe/src/drivers/net/igbvf/igbvf_main.c b/roms/ipxe/src/drivers/net/igbvf/igbvf_main.c
index aace5ad56..fc7021c38 100644
--- a/roms/ipxe/src/drivers/net/igbvf/igbvf_main.c
+++ b/roms/ipxe/src/drivers/net/igbvf/igbvf_main.c
@@ -461,7 +461,7 @@ static int __devinit igbvf_sw_init ( struct igbvf_adapter *adapter )
hw->vendor_id = pdev->vendor;
hw->device_id = pdev->device;
- pci_read_config_byte ( pdev, PCI_REVISION_ID, &hw->revision_id );
+ pci_read_config_byte ( pdev, PCI_REVISION, &hw->revision_id );
pci_read_config_word ( pdev, PCI_COMMAND, &hw->bus.pci_cmd_word );
diff --git a/roms/ipxe/src/drivers/net/intel.c b/roms/ipxe/src/drivers/net/intel.c
index a89f947b2..6309e9aa5 100644
--- a/roms/ipxe/src/drivers/net/intel.c
+++ b/roms/ipxe/src/drivers/net/intel.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <string.h>
@@ -248,32 +252,6 @@ static int intel_fetch_mac ( struct intel_nic *intel, uint8_t *hw_addr ) {
/******************************************************************************
*
- * Diagnostics
- *
- ******************************************************************************
- */
-
-/**
- * Dump diagnostic information
- *
- * @v intel Intel device
- */
-static void __attribute__ (( unused )) intel_diag ( struct intel_nic *intel ) {
-
- DBGC ( intel, "INTEL %p TX %04x(%02x)/%04x(%02x) "
- "RX %04x(%02x)/%04x(%02x)\n", intel,
- ( intel->tx.cons & 0xffff ),
- readl ( intel->regs + intel->tx.reg + INTEL_xDH ),
- ( intel->tx.prod & 0xffff ),
- readl ( intel->regs + intel->tx.reg + INTEL_xDT ),
- ( intel->rx.cons & 0xffff ),
- readl ( intel->regs + intel->rx.reg + INTEL_xDH ),
- ( intel->rx.prod & 0xffff ),
- readl ( intel->regs + intel->rx.reg + INTEL_xDT ) );
-}
-
-/******************************************************************************
- *
* Device reset
*
******************************************************************************
@@ -371,6 +349,67 @@ static void intel_check_link ( struct net_device *netdev ) {
/******************************************************************************
*
+ * Descriptors
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Populate transmit descriptor
+ *
+ * @v tx Transmit descriptor
+ * @v addr Data buffer address
+ * @v len Length of data
+ */
+void intel_describe_tx ( struct intel_descriptor *tx, physaddr_t addr,
+ size_t len ) {
+
+ /* Populate transmit descriptor */
+ tx->address = cpu_to_le64 ( addr );
+ tx->length = cpu_to_le16 ( len );
+ tx->flags = 0;
+ tx->command = ( INTEL_DESC_CMD_RS | INTEL_DESC_CMD_IFCS |
+ INTEL_DESC_CMD_EOP );
+ tx->status = 0;
+}
+
+/**
+ * Populate advanced transmit descriptor
+ *
+ * @v tx Transmit descriptor
+ * @v addr Data buffer address
+ * @v len Length of data
+ */
+void intel_describe_tx_adv ( struct intel_descriptor *tx, physaddr_t addr,
+ size_t len ) {
+
+ /* Populate advanced transmit descriptor */
+ tx->address = cpu_to_le64 ( addr );
+ tx->length = cpu_to_le16 ( len );
+ tx->flags = INTEL_DESC_FL_DTYP_DATA;
+ tx->command = ( INTEL_DESC_CMD_DEXT | INTEL_DESC_CMD_RS |
+ INTEL_DESC_CMD_IFCS | INTEL_DESC_CMD_EOP );
+ tx->status = cpu_to_le32 ( INTEL_DESC_STATUS_PAYLEN ( len ) );
+}
+
+/**
+ * Populate receive descriptor
+ *
+ * @v rx Receive descriptor
+ * @v addr Data buffer address
+ * @v len Length of data
+ */
+void intel_describe_rx ( struct intel_descriptor *rx, physaddr_t addr,
+ size_t len __unused ) {
+
+ /* Populate transmit descriptor */
+ rx->address = cpu_to_le64 ( addr );
+ rx->length = 0;
+ rx->status = 0;
+}
+
+/******************************************************************************
+ *
* Network device interface
*
******************************************************************************
@@ -479,10 +518,7 @@ void intel_refill_rx ( struct intel_nic *intel ) {
/* Populate receive descriptor */
address = virt_to_bus ( iobuf->data );
- rx->address = cpu_to_le64 ( address );
- rx->length = 0;
- rx->status = 0;
- rx->errors = 0;
+ intel->rx.describe ( rx, address, 0 );
/* Record I/O buffer */
assert ( intel->rx_iobuf[rx_idx] == NULL );
@@ -568,6 +604,13 @@ static int intel_open ( struct net_device *netdev ) {
/* Update link state */
intel_check_link ( netdev );
+ /* Apply required errata */
+ if ( intel->flags & INTEL_VMWARE ) {
+ DBGC ( intel, "INTEL %p applying VMware errata workaround\n",
+ intel );
+ intel->force_icr = INTEL_IRQ_RXT0;
+ }
+
return 0;
intel_destroy_ring ( intel, &intel->rx );
@@ -617,6 +660,7 @@ int intel_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) {
unsigned int tx_idx;
unsigned int tx_tail;
physaddr_t address;
+ size_t len;
/* Get next transmit descriptor */
if ( ( intel->tx.prod - intel->tx.cons ) >= INTEL_TX_FILL ) {
@@ -629,11 +673,8 @@ int intel_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) {
/* Populate transmit descriptor */
address = virt_to_bus ( iobuf->data );
- tx->address = cpu_to_le64 ( address );
- tx->length = cpu_to_le16 ( iob_len ( iobuf ) );
- tx->command = ( INTEL_DESC_CMD_RS | INTEL_DESC_CMD_IFCS |
- INTEL_DESC_CMD_EOP );
- tx->status = 0;
+ len = iob_len ( iobuf );
+ intel->tx.describe ( tx, address, len );
wmb();
/* Notify card that there are packets ready to transmit */
@@ -644,7 +685,7 @@ int intel_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) {
DBGC2 ( intel, "INTEL %p TX %d is [%llx,%llx)\n", intel, tx_idx,
( ( unsigned long long ) address ),
- ( ( unsigned long long ) address + iob_len ( iobuf ) ) );
+ ( ( unsigned long long ) address + len ) );
return 0;
}
@@ -667,7 +708,7 @@ void intel_poll_tx ( struct net_device *netdev ) {
tx = &intel->tx.desc[tx_idx];
/* Stop if descriptor is still in use */
- if ( ! ( tx->status & INTEL_DESC_STATUS_DD ) )
+ if ( ! ( tx->status & cpu_to_le32 ( INTEL_DESC_STATUS_DD ) ) )
return;
DBGC2 ( intel, "INTEL %p TX %d complete\n", intel, tx_idx );
@@ -698,7 +739,7 @@ void intel_poll_rx ( struct net_device *netdev ) {
rx = &intel->rx.desc[rx_idx];
/* Stop if descriptor is still in use */
- if ( ! ( rx->status & INTEL_DESC_STATUS_DD ) )
+ if ( ! ( rx->status & cpu_to_le32 ( INTEL_DESC_STATUS_DD ) ) )
return;
/* Populate I/O buffer */
@@ -708,10 +749,10 @@ void intel_poll_rx ( struct net_device *netdev ) {
iob_put ( iobuf, len );
/* Hand off to network stack */
- if ( rx->errors ) {
+ if ( rx->status & cpu_to_le32 ( INTEL_DESC_STATUS_RXE ) ) {
DBGC ( intel, "INTEL %p RX %d error (length %zd, "
- "errors %02x)\n",
- intel, rx_idx, len, rx->errors );
+ "status %08x)\n", intel, rx_idx, len,
+ le32_to_cpu ( rx->status ) );
netdev_rx_err ( netdev, iobuf, -EIO );
} else {
DBGC2 ( intel, "INTEL %p RX %d complete (length %zd)\n",
@@ -736,6 +777,7 @@ static void intel_poll ( struct net_device *netdev ) {
icr = readl ( intel->regs + INTEL_ICR );
profile_stop ( &intel_vm_poll_profiler );
profile_exclude ( &intel_vm_poll_profiler );
+ icr |= intel->force_icr;
if ( ! icr )
return;
@@ -755,6 +797,14 @@ static void intel_poll ( struct net_device *netdev ) {
if ( icr & INTEL_IRQ_LSC )
intel_check_link ( netdev );
+ /* Check for unexpected interrupts */
+ if ( icr & ~( INTEL_IRQ_TXDW | INTEL_IRQ_TXQE | INTEL_IRQ_LSC |
+ INTEL_IRQ_RXDMT0 | INTEL_IRQ_RXT0 | INTEL_IRQ_RXO ) ) {
+ DBGC ( intel, "INTEL %p unexpected ICR %08x\n", intel, icr );
+ /* Report as a TX error */
+ netdev_tx_err ( netdev, NULL, -ENOTSUP );
+ }
+
/* Refill RX ring */
intel_refill_rx ( intel );
}
@@ -817,8 +867,10 @@ static int intel_probe ( struct pci_device *pci ) {
memset ( intel, 0, sizeof ( *intel ) );
intel->port = PCI_FUNC ( pci->busdevfn );
intel->flags = pci->id->driver_data;
- intel_init_ring ( &intel->tx, INTEL_NUM_TX_DESC, INTEL_TD );
- intel_init_ring ( &intel->rx, INTEL_NUM_RX_DESC, INTEL_RD );
+ intel_init_ring ( &intel->tx, INTEL_NUM_TX_DESC, INTEL_TD,
+ intel_describe_tx );
+ intel_init_ring ( &intel->rx, INTEL_NUM_RX_DESC, INTEL_RD,
+ intel_describe_rx );
/* Fix up PCI device */
adjust_pci_device ( pci );
@@ -895,7 +947,7 @@ static struct pci_device_id intel_nics[] = {
PCI_ROM ( 0x8086, 0x100c, "82544gc", "82544GC (Copper)", 0 ),
PCI_ROM ( 0x8086, 0x100d, "82544gc-l", "82544GC (LOM)", 0 ),
PCI_ROM ( 0x8086, 0x100e, "82540em", "82540EM", 0 ),
- PCI_ROM ( 0x8086, 0x100f, "82545em", "82545EM (Copper)", 0 ),
+ PCI_ROM ( 0x8086, 0x100f, "82545em", "82545EM (Copper)", INTEL_VMWARE ),
PCI_ROM ( 0x8086, 0x1010, "82546eb", "82546EB (Copper)", 0 ),
PCI_ROM ( 0x8086, 0x1011, "82545em-f", "82545EM (Fiber)", 0 ),
PCI_ROM ( 0x8086, 0x1012, "82546eb-f", "82546EB (Fiber)", 0 ),
@@ -998,6 +1050,12 @@ static struct pci_device_id intel_nics[] = {
PCI_ROM ( 0x8086, 0x1533, "i210", "I210", 0 ),
PCI_ROM ( 0x8086, 0x153a, "i217lm", "I217-LM", 0 ),
PCI_ROM ( 0x8086, 0x153b, "i217v", "I217-V", 0 ),
+ PCI_ROM ( 0x8086, 0x1559, "i218v", "I218-V", 0),
+ PCI_ROM ( 0x8086, 0x155a, "i218lm", "I218-LM", 0),
+ PCI_ROM ( 0x8086, 0x15a0, "i218lm-2", "I218-LM", 0 ),
+ PCI_ROM ( 0x8086, 0x15a1, "i218v-2", "I218-V", 0 ),
+ PCI_ROM ( 0x8086, 0x15a2, "i218lm-3", "I218-LM", 0 ),
+ PCI_ROM ( 0x8086, 0x15a3, "i218v-3", "I218-V", 0 ),
PCI_ROM ( 0x8086, 0x294c, "82566dc-2", "82566DC-2", 0 ),
PCI_ROM ( 0x8086, 0x2e6e, "cemedia", "CE Media Processor", 0 ),
};
diff --git a/roms/ipxe/src/drivers/net/intel.h b/roms/ipxe/src/drivers/net/intel.h
index 8c4479bb4..ce9e3f467 100644
--- a/roms/ipxe/src/drivers/net/intel.h
+++ b/roms/ipxe/src/drivers/net/intel.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/if_ether.h>
@@ -22,33 +22,38 @@ struct intel_descriptor {
uint64_t address;
/** Length */
uint16_t length;
- /** Reserved */
- uint8_t reserved_a;
+ /** Flags */
+ uint8_t flags;
/** Command */
uint8_t command;
/** Status */
- uint8_t status;
- /** Errors */
- uint8_t errors;
- /** Reserved */
- uint16_t reserved_b;
+ uint32_t status;
} __attribute__ (( packed ));
-/** Packet descriptor command bits */
-enum intel_descriptor_command {
- /** Report status */
- INTEL_DESC_CMD_RS = 0x08,
- /** Insert frame checksum (CRC) */
- INTEL_DESC_CMD_IFCS = 0x02,
- /** End of packet */
- INTEL_DESC_CMD_EOP = 0x01,
-};
+/** Descriptor type */
+#define INTEL_DESC_FL_DTYP( dtyp ) ( (dtyp) << 4 )
+#define INTEL_DESC_FL_DTYP_DATA INTEL_DESC_FL_DTYP ( 0x03 )
-/** Packet descriptor status bits */
-enum intel_descriptor_status {
- /** Descriptor done */
- INTEL_DESC_STATUS_DD = 0x01,
-};
+/** Descriptor extension */
+#define INTEL_DESC_CMD_DEXT 0x20
+
+/** Report status */
+#define INTEL_DESC_CMD_RS 0x08
+
+/** Insert frame checksum (CRC) */
+#define INTEL_DESC_CMD_IFCS 0x02
+
+/** End of packet */
+#define INTEL_DESC_CMD_EOP 0x01
+
+/** Descriptor done */
+#define INTEL_DESC_STATUS_DD 0x00000001UL
+
+/** Receive error */
+#define INTEL_DESC_STATUS_RXE 0x00000100UL
+
+/** Payload length */
+#define INTEL_DESC_STATUS_PAYLEN( len ) ( (len) << 14 )
/** Device Control Register */
#define INTEL_CTRL 0x00000UL
@@ -91,7 +96,9 @@ enum intel_descriptor_status {
/** Interrupt Cause Read Register */
#define INTEL_ICR 0x000c0UL
#define INTEL_IRQ_TXDW 0x00000001UL /**< Transmit descriptor done */
+#define INTEL_IRQ_TXQE 0x00000002UL /**< Transmit queue empty */
#define INTEL_IRQ_LSC 0x00000004UL /**< Link status change */
+#define INTEL_IRQ_RXDMT0 0x00000010UL /**< Receive queue low */
#define INTEL_IRQ_RXT0 0x00000080UL /**< Receive timer */
#define INTEL_IRQ_RXO 0x00000400UL /**< Receive overrun */
@@ -207,6 +214,15 @@ struct intel_ring {
unsigned int reg;
/** Length (in bytes) */
size_t len;
+
+ /** Populate descriptor
+ *
+ * @v desc Descriptor
+ * @v addr Data buffer address
+ * @v len Length of data
+ */
+ void ( * describe ) ( struct intel_descriptor *desc, physaddr_t addr,
+ size_t len );
};
/**
@@ -215,12 +231,39 @@ struct intel_ring {
* @v ring Descriptor ring
* @v count Number of descriptors
* @v reg Descriptor register block
+ * @v describe Method to populate descriptor
*/
static inline __attribute__ (( always_inline)) void
-intel_init_ring ( struct intel_ring *ring, unsigned int count,
- unsigned int reg ) {
+intel_init_ring ( struct intel_ring *ring, unsigned int count, unsigned int reg,
+ void ( * describe ) ( struct intel_descriptor *desc,
+ physaddr_t addr, size_t len ) ) {
+
ring->len = ( count * sizeof ( ring->desc[0] ) );
ring->reg = reg;
+ ring->describe = describe;
+}
+
+/** An Intel virtual function mailbox */
+struct intel_mailbox {
+ /** Mailbox control register */
+ unsigned int ctrl;
+ /** Mailbox memory base */
+ unsigned int mem;
+};
+
+/**
+ * Initialise mailbox
+ *
+ * @v mbox Mailbox
+ * @v ctrl Mailbox control register
+ * @v mem Mailbox memory register base
+ */
+static inline __attribute__ (( always_inline )) void
+intel_init_mbox ( struct intel_mailbox *mbox, unsigned int ctrl,
+ unsigned int mem ) {
+
+ mbox->ctrl = ctrl;
+ mbox->mem = mem;
}
/** An Intel network card */
@@ -231,6 +274,8 @@ struct intel_nic {
unsigned int port;
/** Flags */
unsigned int flags;
+ /** Forced interrupts */
+ unsigned int force_icr;
/** EEPROM */
struct nvs_device eeprom;
@@ -239,6 +284,9 @@ struct intel_nic {
/** EEPROM address shift */
unsigned int eerd_addr_shift;
+ /** Mailbox */
+ struct intel_mailbox mbox;
+
/** Transmit descriptor ring */
struct intel_ring tx;
/** Receive descriptor ring */
@@ -251,8 +299,35 @@ struct intel_nic {
enum intel_flags {
/** PBS/PBA errata workaround required */
INTEL_PBS_ERRATA = 0x0001,
+ /** VMware missing interrupt workaround required */
+ INTEL_VMWARE = 0x0002,
};
+/**
+ * Dump diagnostic information
+ *
+ * @v intel Intel device
+ */
+static inline void intel_diag ( struct intel_nic *intel ) {
+
+ DBGC ( intel, "INTEL %p TX %04x(%02x)/%04x(%02x) "
+ "RX %04x(%02x)/%04x(%02x)\n", intel,
+ ( intel->tx.cons & 0xffff ),
+ readl ( intel->regs + intel->tx.reg + INTEL_xDH ),
+ ( intel->tx.prod & 0xffff ),
+ readl ( intel->regs + intel->tx.reg + INTEL_xDT ),
+ ( intel->rx.cons & 0xffff ),
+ readl ( intel->regs + intel->rx.reg + INTEL_xDH ),
+ ( intel->rx.prod & 0xffff ),
+ readl ( intel->regs + intel->rx.reg + INTEL_xDT ) );
+}
+
+extern void intel_describe_tx ( struct intel_descriptor *tx,
+ physaddr_t addr, size_t len );
+extern void intel_describe_tx_adv ( struct intel_descriptor *tx,
+ physaddr_t addr, size_t len );
+extern void intel_describe_rx ( struct intel_descriptor *rx,
+ physaddr_t addr, size_t len );
extern int intel_create_ring ( struct intel_nic *intel,
struct intel_ring *ring );
extern void intel_destroy_ring ( struct intel_nic *intel,
diff --git a/roms/ipxe/src/drivers/net/intelvf.c b/roms/ipxe/src/drivers/net/intelvf.c
new file mode 100644
index 000000000..ac6fea745
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/intelvf.c
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2015 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <ipxe/io.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/ethernet.h>
+#include "intelvf.h"
+
+/** @file
+ *
+ * Intel 10/100/1000 virtual function network card driver
+ *
+ */
+
+/******************************************************************************
+ *
+ * Mailbox messages
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Write message to mailbox
+ *
+ * @v intel Intel device
+ * @v msg Message
+ */
+static void intelvf_mbox_write ( struct intel_nic *intel,
+ const union intelvf_msg *msg ) {
+ unsigned int i;
+
+ /* Write message */
+ DBGC2 ( intel, "INTEL %p sending message", intel );
+ for ( i = 0 ; i < ( sizeof ( *msg ) / sizeof ( msg->dword[0] ) ) ; i++){
+ DBGC2 ( intel, "%c%08x", ( i ? ':' : ' ' ), msg->dword[i] );
+ writel ( msg->dword[i], ( intel->regs + intel->mbox.mem +
+ ( i * sizeof ( msg->dword[0] ) ) ) );
+ }
+ DBGC2 ( intel, "\n" );
+}
+
+/**
+ * Read message from mailbox
+ *
+ * @v intel Intel device
+ * @v msg Message
+ */
+static void intelvf_mbox_read ( struct intel_nic *intel,
+ union intelvf_msg *msg ) {
+ unsigned int i;
+
+ /* Read message */
+ DBGC2 ( intel, "INTEL %p received message", intel );
+ for ( i = 0 ; i < ( sizeof ( *msg ) / sizeof ( msg->dword[0] ) ) ; i++){
+ msg->dword[i] = readl ( intel->regs + intel->mbox.mem +
+ ( i * sizeof ( msg->dword[0] ) ) );
+ DBGC2 ( intel, "%c%08x", ( i ? ':' : ' ' ), msg->dword[i] );
+ }
+ DBGC2 ( intel, "\n" );
+}
+
+/**
+ * Poll mailbox
+ *
+ * @v intel Intel device
+ * @ret rc Return status code
+ *
+ * Note that polling the mailbox may fail if the underlying PF is
+ * reset.
+ */
+int intelvf_mbox_poll ( struct intel_nic *intel ) {
+ struct intel_mailbox *mbox = &intel->mbox;
+ union intelvf_msg msg;
+ uint32_t ctrl;
+
+ /* Get mailbox status */
+ ctrl = readl ( intel->regs + mbox->ctrl );
+
+ /* Fail if a reset is in progress */
+ if ( ctrl & INTELVF_MBCTRL_RSTI )
+ return -EPIPE;
+
+ /* Acknowledge (and ignore) any received messages */
+ if ( ctrl & INTELVF_MBCTRL_PFSTS ) {
+ intelvf_mbox_read ( intel, &msg );
+ writel ( INTELVF_MBCTRL_ACK, intel->regs + mbox->ctrl );
+ }
+
+ return 0;
+}
+
+/**
+ * Wait for PF reset to complete
+ *
+ * @v intel Intel device
+ * @ret rc Return status code
+ */
+int intelvf_mbox_wait ( struct intel_nic *intel ) {
+ unsigned int i;
+ int rc;
+
+ /* Wait until a poll completes successfully */
+ for ( i = 0 ; i < INTELVF_MBOX_MAX_WAIT_MS ; i++ ) {
+
+ /* Check for successful poll */
+ if ( ( rc = intelvf_mbox_poll ( intel ) ) == 0 )
+ return 0;
+
+ /* Delay */
+ mdelay ( 1 );
+ }
+
+ DBGC ( intel, "INTEL %p timed out waiting for reset\n", intel );
+ return -ETIMEDOUT;
+}
+
+/**
+ * Send/receive mailbox message
+ *
+ * @v intel Intel device
+ * @v msg Message buffer
+ * @ret rc Return status code
+ */
+int intelvf_mbox_msg ( struct intel_nic *intel, union intelvf_msg *msg ) {
+ struct intel_mailbox *mbox = &intel->mbox;
+ uint32_t ctrl;
+ uint32_t seen = 0;
+ unsigned int i;
+
+ /* Sanity check */
+ assert ( ! ( msg->hdr & INTELVF_MSG_RESPONSE ) );
+
+ /* Handle mailbox */
+ for ( i = 0 ; i < INTELVF_MBOX_MAX_WAIT_MS ; i++ ) {
+
+ /* Attempt to claim mailbox, if we have not yet sent
+ * our message.
+ */
+ if ( ! ( seen & INTELVF_MBCTRL_VFU ) )
+ writel ( INTELVF_MBCTRL_VFU, intel->regs + mbox->ctrl );
+
+ /* Get mailbox status and record observed flags */
+ ctrl = readl ( intel->regs + mbox->ctrl );
+ seen |= ctrl;
+
+ /* If a reset is in progress, clear VFU and abort */
+ if ( ctrl & INTELVF_MBCTRL_RSTI ) {
+ writel ( 0, intel->regs + mbox->ctrl );
+ return -EPIPE;
+ }
+
+ /* Write message to mailbox, if applicable. This
+ * potentially overwrites a message sent by the PF (if
+ * the PF has simultaneously released PFU (thus
+ * allowing our VFU) and asserted PFSTS), but that
+ * doesn't really matter since there are no
+ * unsolicited PF->VF messages that require the actual
+ * message content to be observed.
+ */
+ if ( ctrl & INTELVF_MBCTRL_VFU )
+ intelvf_mbox_write ( intel, msg );
+
+ /* Read message from mailbox, if applicable. */
+ if ( ( seen & INTELVF_MBCTRL_VFU ) &&
+ ( seen & INTELVF_MBCTRL_PFACK ) &&
+ ( ctrl & INTELVF_MBCTRL_PFSTS ) )
+ intelvf_mbox_read ( intel, msg );
+
+ /* Acknowledge received message (if applicable),
+ * release VFU lock, and send message (if applicable).
+ */
+ ctrl = ( ( ( ctrl & INTELVF_MBCTRL_PFSTS ) ?
+ INTELVF_MBCTRL_ACK : 0 ) |
+ ( ( ctrl & INTELVF_MBCTRL_VFU ) ?
+ INTELVF_MBCTRL_REQ : 0 ) );
+ writel ( ctrl, intel->regs + mbox->ctrl );
+
+ /* Exit successfully if we have received a response */
+ if ( msg->hdr & INTELVF_MSG_RESPONSE ) {
+
+ /* Sanity check */
+ assert ( seen & INTELVF_MBCTRL_VFU );
+ assert ( seen & INTELVF_MBCTRL_PFACK );
+ assert ( seen & INTELVF_MBCTRL_PFSTS );
+
+ return 0;
+ }
+
+ /* Delay */
+ mdelay ( 1 );
+ }
+
+ DBGC ( intel, "INTEL %p timed out waiting for mailbox (seen %08x)\n",
+ intel, seen );
+ return -ETIMEDOUT;
+}
+
+/**
+ * Send reset message and get initial MAC address
+ *
+ * @v intel Intel device
+ * @v hw_addr Hardware address to fill in, or NULL
+ * @ret rc Return status code
+ */
+int intelvf_mbox_reset ( struct intel_nic *intel, uint8_t *hw_addr ) {
+ union intelvf_msg msg;
+ int rc;
+
+ /* Send reset message */
+ memset ( &msg, 0, sizeof ( msg ) );
+ msg.hdr = INTELVF_MSG_TYPE_RESET;
+ if ( ( rc = intelvf_mbox_msg ( intel, &msg ) ) != 0 ) {
+ DBGC ( intel, "INTEL %p reset failed: %s\n",
+ intel, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Check response */
+ if ( ( msg.hdr & INTELVF_MSG_TYPE_MASK ) != INTELVF_MSG_TYPE_RESET ) {
+ DBGC ( intel, "INTEL %p reset unexpected response:\n", intel );
+ DBGC_HDA ( intel, 0, &msg, sizeof ( msg ) );
+ return -EPROTO;
+ }
+
+ /* Fill in MAC address, if applicable */
+ if ( hw_addr ) {
+ if ( msg.hdr & INTELVF_MSG_ACK ) {
+ memcpy ( hw_addr, msg.mac.mac, sizeof ( msg.mac.mac ) );
+ DBGC ( intel, "INTEL %p reset assigned MAC address "
+ "%s\n", intel, eth_ntoa ( hw_addr ) );
+ } else {
+ eth_random_addr ( hw_addr );
+ DBGC ( intel, "INTEL %p reset generated MAC address "
+ "%s\n", intel, eth_ntoa ( hw_addr ) );
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Send set MAC address message
+ *
+ * @v intel Intel device
+ * @v ll_addr Link-layer address
+ * @ret rc Return status code
+ */
+int intelvf_mbox_set_mac ( struct intel_nic *intel, const uint8_t *ll_addr ) {
+ union intelvf_msg msg;
+ int rc;
+
+ /* Send set MAC address message */
+ memset ( &msg, 0, sizeof ( msg ) );
+ msg.hdr = INTELVF_MSG_TYPE_SET_MAC;
+ memcpy ( msg.mac.mac, ll_addr, sizeof ( msg.mac.mac ) );
+ if ( ( rc = intelvf_mbox_msg ( intel, &msg ) ) != 0 ) {
+ DBGC ( intel, "INTEL %p set MAC address failed: %s\n",
+ intel, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Check response */
+ if ( ( msg.hdr & INTELVF_MSG_TYPE_MASK ) != INTELVF_MSG_TYPE_SET_MAC ) {
+ DBGC ( intel, "INTEL %p set MAC address unexpected response:\n",
+ intel );
+ DBGC_HDA ( intel, 0, &msg, sizeof ( msg ) );
+ return -EPROTO;
+ }
+
+ /* Check that we were allowed to set the MAC address */
+ if ( ! ( msg.hdr & INTELVF_MSG_ACK ) ) {
+ DBGC ( intel, "INTEL %p set MAC address refused\n", intel );
+ return -EPERM;
+ }
+
+ return 0;
+}
+
+/**
+ * Send set MTU message
+ *
+ * @v intel Intel device
+ * @v mtu Maximum packet size
+ * @ret rc Return status code
+ */
+int intelvf_mbox_set_mtu ( struct intel_nic *intel, size_t mtu ) {
+ union intelvf_msg msg;
+ int rc;
+
+ /* Send set MTU message */
+ memset ( &msg, 0, sizeof ( msg ) );
+ msg.hdr = INTELVF_MSG_TYPE_SET_MTU;
+ msg.mtu.mtu = mtu;
+ if ( ( rc = intelvf_mbox_msg ( intel, &msg ) ) != 0 ) {
+ DBGC ( intel, "INTEL %p set MTU failed: %s\n",
+ intel, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Check response */
+ if ( ( msg.hdr & INTELVF_MSG_TYPE_MASK ) != INTELVF_MSG_TYPE_SET_MTU ) {
+ DBGC ( intel, "INTEL %p set MTU unexpected response:\n",
+ intel );
+ DBGC_HDA ( intel, 0, &msg, sizeof ( msg ) );
+ return -EPROTO;
+ }
+
+ /* Check that we were allowed to set the MTU */
+ if ( ! ( msg.hdr & INTELVF_MSG_ACK ) ) {
+ DBGC ( intel, "INTEL %p set MTU refused\n", intel );
+ return -EPERM;
+ }
+
+ return 0;
+}
diff --git a/roms/ipxe/src/drivers/net/intelvf.h b/roms/ipxe/src/drivers/net/intelvf.h
new file mode 100644
index 000000000..d2f98d874
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/intelvf.h
@@ -0,0 +1,109 @@
+#ifndef _INTELVF_H
+#define _INTELVF_H
+
+/** @file
+ *
+ * Intel 10/100/1000 virtual function network card driver
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include "intel.h"
+
+/** Intel VF BAR size */
+#define INTELVF_BAR_SIZE ( 16 * 1024 )
+
+/** Mailbox Control Register */
+#define INTELVF_MBCTRL 0x0c40UL
+#define INTELVF_MBCTRL_REQ 0x00000001UL /**< Request for PF ready */
+#define INTELVF_MBCTRL_ACK 0x00000002UL /**< PF message received */
+#define INTELVF_MBCTRL_VFU 0x00000004UL /**< Buffer taken by VF */
+#define INTELVF_MBCTRL_PFU 0x00000008UL /**< Buffer taken to PF */
+#define INTELVF_MBCTRL_PFSTS 0x00000010UL /**< PF wrote a message */
+#define INTELVF_MBCTRL_PFACK 0x00000020UL /**< PF acknowledged message */
+#define INTELVF_MBCTRL_RSTI 0x00000040UL /**< PF reset in progress */
+#define INTELVF_MBCTRL_RSTD 0x00000080UL /**< PF reset complete */
+
+/** Mailbox Memory Register Base */
+#define INTELVF_MBMEM 0x0800UL
+
+/** Reset mailbox message */
+#define INTELVF_MSG_TYPE_RESET 0x00000001UL
+
+/** Set MAC address mailbox message */
+#define INTELVF_MSG_TYPE_SET_MAC 0x00000002UL
+
+/** Set MTU mailbox message */
+#define INTELVF_MSG_TYPE_SET_MTU 0x00000005UL
+
+/** Control ("ping") mailbox message */
+#define INTELVF_MSG_TYPE_CONTROL 0x00000100UL
+
+/** Message type mask */
+#define INTELVF_MSG_TYPE_MASK 0x0000ffffUL
+
+/** Message NACK flag */
+#define INTELVF_MSG_NACK 0x40000000UL
+
+/** Message ACK flag */
+#define INTELVF_MSG_ACK 0x80000000UL
+
+/** Message is a response */
+#define INTELVF_MSG_RESPONSE ( INTELVF_MSG_ACK | INTELVF_MSG_NACK )
+
+/** MAC address mailbox message */
+struct intelvf_msg_mac {
+ /** Message header */
+ uint32_t hdr;
+ /** MAC address */
+ uint8_t mac[ETH_ALEN];
+ /** Alignment padding */
+ uint8_t reserved[ (-ETH_ALEN) & 0x3 ];
+} __attribute__ (( packed ));
+
+/** Version number mailbox message */
+struct intelvf_msg_version {
+ /** Message header */
+ uint32_t hdr;
+ /** API version */
+ uint32_t version;
+} __attribute__ (( packed ));
+
+/** MTU mailbox message */
+struct intelvf_msg_mtu {
+ /** Message header */
+ uint32_t hdr;
+ /** Maximum packet size */
+ uint32_t mtu;
+} __attribute__ (( packed ));
+
+/** Mailbox message */
+union intelvf_msg {
+ /** Message header */
+ uint32_t hdr;
+ /** MAC address message */
+ struct intelvf_msg_mac mac;
+ /** Version number message */
+ struct intelvf_msg_version version;
+ /** MTU message */
+ struct intelvf_msg_mtu mtu;
+ /** Raw dwords */
+ uint32_t dword[0];
+};
+
+/** Maximum time to wait for mailbox message
+ *
+ * This is a policy decision.
+ */
+#define INTELVF_MBOX_MAX_WAIT_MS 500
+
+extern int intelvf_mbox_msg ( struct intel_nic *intel, union intelvf_msg *msg );
+extern int intelvf_mbox_poll ( struct intel_nic *intel );
+extern int intelvf_mbox_wait ( struct intel_nic *intel );
+extern int intelvf_mbox_reset ( struct intel_nic *intel, uint8_t *hw_addr );
+extern int intelvf_mbox_set_mac ( struct intel_nic *intel,
+ const uint8_t *ll_addr );
+extern int intelvf_mbox_set_mtu ( struct intel_nic *intel, size_t mtu );
+
+#endif /* _INTELVF_H */
diff --git a/roms/ipxe/src/drivers/net/intelx.c b/roms/ipxe/src/drivers/net/intelx.c
index d69900e41..982b74f12 100644
--- a/roms/ipxe/src/drivers/net/intelx.c
+++ b/roms/ipxe/src/drivers/net/intelx.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <string.h>
@@ -392,8 +396,10 @@ static int intelx_probe ( struct pci_device *pci ) {
netdev->dev = &pci->dev;
memset ( intel, 0, sizeof ( *intel ) );
intel->port = PCI_FUNC ( pci->busdevfn );
- intel_init_ring ( &intel->tx, INTEL_NUM_TX_DESC, INTELX_TD );
- intel_init_ring ( &intel->rx, INTEL_NUM_RX_DESC, INTELX_RD );
+ intel_init_ring ( &intel->tx, INTEL_NUM_TX_DESC, INTELX_TD,
+ intel_describe_tx );
+ intel_init_ring ( &intel->rx, INTEL_NUM_RX_DESC, INTELX_RD,
+ intel_describe_rx );
/* Fix up PCI device */
adjust_pci_device ( pci );
@@ -458,10 +464,15 @@ static void intelx_remove ( struct pci_device *pci ) {
/** PCI device IDs */
static struct pci_device_id intelx_nics[] = {
- PCI_ROM ( 0x8086, 0x10fb, "82599", "82599", 0 ),
- PCI_ROM ( 0x8086, 0x1528, "x540at2", "X540-AT2", 0 ),
- PCI_ROM ( 0x8086, 0x154d, "x520", "X520", 0 ),
- PCI_ROM ( 0x8086, 0x1557, "82599", "82599", 0 ),
+ PCI_ROM ( 0x8086, 0x10f7, "82599-kx4", "82599 (KX/KX4)", 0 ),
+ PCI_ROM ( 0x8086, 0x10f8, "82599-combo-backplane", "82599 (combined backplane; KR/KX4/KX)", 0 ),
+ PCI_ROM ( 0x8086, 0x10f9, "82599-cx4", "82599 (CX4)", 0 ),
+ PCI_ROM ( 0x8086, 0x10fb, "82599-sfp", "82599 (SFI/SFP+)", 0 ),
+ PCI_ROM ( 0x8086, 0x10fc, "82599-xaui", "82599 (XAUI/BX4)", 0 ),
+ PCI_ROM ( 0x8086, 0x1528, "x540t", "X540-AT2/X540-BT2", 0 ),
+ PCI_ROM ( 0x8086, 0x154d, "82599-sfp-sf2", "82599 (SFI/SFP+)", 0 ),
+ PCI_ROM ( 0x8086, 0x1557, "82599en-sfp", "82599 (Single Port SFI Only)", 0 ),
+ PCI_ROM ( 0x8086, 0x1560, "x540t1", "X540-AT2/X540-BT2 (with single port NVM)", 0 ),
};
/** PCI driver */
diff --git a/roms/ipxe/src/drivers/net/intelx.h b/roms/ipxe/src/drivers/net/intelx.h
index 60bb294d5..6383dfcad 100644
--- a/roms/ipxe/src/drivers/net/intelx.h
+++ b/roms/ipxe/src/drivers/net/intelx.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/if_ether.h>
diff --git a/roms/ipxe/src/drivers/net/intelxvf.c b/roms/ipxe/src/drivers/net/intelxvf.c
new file mode 100644
index 000000000..05e34c127
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/intelxvf.c
@@ -0,0 +1,466 @@
+/*
+ * Copyright (C) 2015 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <ipxe/io.h>
+#include <ipxe/pci.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/ethernet.h>
+#include "intelxvf.h"
+
+/** @file
+ *
+ * Intel 10 Gigabit Ethernet virtual function network card driver
+ *
+ */
+
+/******************************************************************************
+ *
+ * Diagnostics
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Dump statistics
+ *
+ * @v intel Intel device
+ */
+static __attribute__ (( unused )) void
+intelxvf_stats ( struct intel_nic *intel ) {
+
+ DBGC ( intel, "INTEL %p TX %d (%#x%08x) RX %d (%#x%08x) multi %d\n",
+ intel, readl ( intel->regs + INTELXVF_GPTC ),
+ readl ( intel->regs + INTELXVF_GOTCH ),
+ readl ( intel->regs + INTELXVF_GOTCL ),
+ readl ( intel->regs + INTELXVF_GPRC ),
+ readl ( intel->regs + INTELXVF_GORCH ),
+ readl ( intel->regs + INTELXVF_GORCL ),
+ readl ( intel->regs + INTELXVF_MPRC ) );
+}
+
+/******************************************************************************
+ *
+ * Device reset
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Reset hardware
+ *
+ * @v intel Intel device
+ */
+static void intelxvf_reset ( struct intel_nic *intel ) {
+
+ /* Perform a function-level reset */
+ writel ( INTELXVF_CTRL_RST, intel->regs + INTELXVF_CTRL );
+}
+
+/******************************************************************************
+ *
+ * Link state
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Check link state
+ *
+ * @v netdev Network device
+ */
+static void intelxvf_check_link ( struct net_device *netdev ) {
+ struct intel_nic *intel = netdev->priv;
+ uint32_t links;
+
+ /* Read link status */
+ links = readl ( intel->regs + INTELXVF_LINKS );
+ DBGC ( intel, "INTEL %p link status is %08x\n", intel, links );
+
+ /* Update network device */
+ if ( links & INTELXVF_LINKS_UP ) {
+ netdev_link_up ( netdev );
+ } else {
+ netdev_link_down ( netdev );
+ }
+}
+
+/******************************************************************************
+ *
+ * Mailbox messages
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Send negotiate API version message
+ *
+ * @v intel Intel device
+ * @v version Requested version
+ * @ret rc Return status code
+ */
+static int intelxvf_mbox_version ( struct intel_nic *intel,
+ unsigned int version ) {
+ union intelvf_msg msg;
+ int rc;
+
+ /* Send set MTU message */
+ memset ( &msg, 0, sizeof ( msg ) );
+ msg.hdr = INTELXVF_MSG_TYPE_VERSION;
+ msg.version.version = version;
+ if ( ( rc = intelvf_mbox_msg ( intel, &msg ) ) != 0 ) {
+ DBGC ( intel, "INTEL %p negotiate API version failed: %s\n",
+ intel, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Check response */
+ if ( ( msg.hdr & INTELVF_MSG_TYPE_MASK ) != INTELXVF_MSG_TYPE_VERSION ){
+ DBGC ( intel, "INTEL %p negotiate API version unexpected "
+ "response:\n", intel );
+ DBGC_HDA ( intel, 0, &msg, sizeof ( msg ) );
+ return -EPROTO;
+ }
+
+ /* Check that this version is supported */
+ if ( ! ( msg.hdr & INTELVF_MSG_ACK ) ) {
+ DBGC ( intel, "INTEL %p negotiate API version failed\n",
+ intel );
+ return -EPERM;
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * Network device interface
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Open network device
+ *
+ * @v netdev Network device
+ * @ret rc Return status code
+ */
+static int intelxvf_open ( struct net_device *netdev ) {
+ struct intel_nic *intel = netdev->priv;
+ uint32_t srrctl;
+ uint32_t dca_rxctrl;
+ int rc;
+
+ /* Reset the function */
+ intelxvf_reset ( intel );
+
+ /* Notify PF that reset is complete */
+ if ( ( rc = intelvf_mbox_reset ( intel, NULL ) ) != 0 ) {
+ DBGC ( intel, "INTEL %p could not reset: %s\n",
+ intel, strerror ( rc ) );
+ goto err_mbox_reset;
+ }
+
+ /* Negotiate API version 1.1. If we do not negotiate at least
+ * this version, then the RX datapath will remain disabled if
+ * the PF has jumbo frames enabled.
+ *
+ * Ignore failures, since the host may not actually support
+ * v1.1.
+ */
+ intelxvf_mbox_version ( intel, INTELXVF_MSG_VERSION_1_1 );
+
+ /* Set MAC address */
+ if ( ( rc = intelvf_mbox_set_mac ( intel, netdev->ll_addr ) ) != 0 ) {
+ DBGC ( intel, "INTEL %p could not set MAC address: %s\n",
+ intel, strerror ( rc ) );
+ goto err_mbox_set_mac;
+ }
+
+ /* Set MTU */
+ if ( ( rc = intelvf_mbox_set_mtu ( intel, netdev->max_pkt_len ) ) != 0){
+ DBGC ( intel, "INTEL %p could not set MTU %zd: %s\n",
+ intel, netdev->max_pkt_len, strerror ( rc ) );
+ goto err_mbox_set_mtu;
+ }
+
+ /* Create transmit descriptor ring */
+ if ( ( rc = intel_create_ring ( intel, &intel->tx ) ) != 0 )
+ goto err_create_tx;
+
+ /* Create receive descriptor ring */
+ if ( ( rc = intel_create_ring ( intel, &intel->rx ) ) != 0 )
+ goto err_create_rx;
+
+ /* Allocate interrupt vectors */
+ writel ( ( INTELXVF_IVAR_RX0_DEFAULT | INTELXVF_IVAR_RX0_VALID |
+ INTELXVF_IVAR_TX0_DEFAULT | INTELXVF_IVAR_TX0_VALID ),
+ intel->regs + INTELXVF_IVAR );
+ writel ( ( INTELXVF_IVARM_MBOX_DEFAULT | INTELXVF_IVARM_MBOX_VALID ),
+ intel->regs + INTELXVF_IVARM );
+
+ /* Configure receive buffer sizes and set receive descriptor type */
+ srrctl = readl ( intel->regs + INTELXVF_SRRCTL );
+ srrctl &= ~( INTELXVF_SRRCTL_BSIZE_MASK |
+ INTELXVF_SRRCTL_DESCTYPE_MASK );
+ srrctl |= ( INTELXVF_SRRCTL_BSIZE_DEFAULT |
+ INTELXVF_SRRCTL_DESCTYPE_DEFAULT );
+ writel ( srrctl, intel->regs + INTELXVF_SRRCTL );
+
+ /* Clear "must-be-zero" bit for direct cache access (DCA). We
+ * leave DCA disabled anyway, but if we do not clear this bit
+ * then the received packets contain garbage data.
+ */
+ dca_rxctrl = readl ( intel->regs + INTELXVF_DCA_RXCTRL );
+ dca_rxctrl &= ~INTELXVF_DCA_RXCTRL_MUST_BE_ZERO;
+ writel ( dca_rxctrl, intel->regs + INTELXVF_DCA_RXCTRL );
+
+ /* Fill receive ring */
+ intel_refill_rx ( intel );
+
+ /* Update link state */
+ intelxvf_check_link ( netdev );
+
+ return 0;
+
+ intel_destroy_ring ( intel, &intel->rx );
+ err_create_rx:
+ intel_destroy_ring ( intel, &intel->tx );
+ err_create_tx:
+ err_mbox_set_mtu:
+ err_mbox_set_mac:
+ err_mbox_reset:
+ intelxvf_reset ( intel );
+ return rc;
+}
+
+/**
+ * Close network device
+ *
+ * @v netdev Network device
+ */
+static void intelxvf_close ( struct net_device *netdev ) {
+ struct intel_nic *intel = netdev->priv;
+
+ /* Destroy receive descriptor ring */
+ intel_destroy_ring ( intel, &intel->rx );
+
+ /* Discard any unused receive buffers */
+ intel_empty_rx ( intel );
+
+ /* Destroy transmit descriptor ring */
+ intel_destroy_ring ( intel, &intel->tx );
+
+ /* Reset the function */
+ intelxvf_reset ( intel );
+}
+
+/**
+ * Poll for completed and received packets
+ *
+ * @v netdev Network device
+ */
+static void intelxvf_poll ( struct net_device *netdev ) {
+ struct intel_nic *intel = netdev->priv;
+ uint32_t eicr;
+ int rc;
+
+ /* Check for and acknowledge interrupts */
+ eicr = readl ( intel->regs + INTELXVF_EICR );
+ if ( ! eicr )
+ return;
+
+ /* Poll for TX completions, if applicable */
+ if ( eicr & INTELXVF_EIRQ_TX0 )
+ intel_poll_tx ( netdev );
+
+ /* Poll for RX completions, if applicable */
+ if ( eicr & INTELXVF_EIRQ_RX0 )
+ intel_poll_rx ( netdev );
+
+ /* Poll for mailbox messages, if applicable */
+ if ( eicr & INTELXVF_EIRQ_MBOX ) {
+
+ /* Poll mailbox */
+ if ( ( rc = intelvf_mbox_poll ( intel ) ) != 0 ) {
+ DBGC ( intel, "INTEL %p mailbox poll failed!\n",
+ intel );
+ netdev_rx_err ( netdev, NULL, rc );
+ }
+
+ /* Update link state */
+ intelxvf_check_link ( netdev );
+ }
+
+ /* Refill RX ring */
+ intel_refill_rx ( intel );
+}
+
+/**
+ * Enable or disable interrupts
+ *
+ * @v netdev Network device
+ * @v enable Interrupts should be enabled
+ */
+static void intelxvf_irq ( struct net_device *netdev, int enable ) {
+ struct intel_nic *intel = netdev->priv;
+ uint32_t mask;
+
+ mask = ( INTELXVF_EIRQ_MBOX | INTELXVF_EIRQ_TX0 | INTELXVF_EIRQ_RX0 );
+ if ( enable ) {
+ writel ( mask, intel->regs + INTELXVF_EIMS );
+ } else {
+ writel ( mask, intel->regs + INTELXVF_EIMC );
+ }
+}
+
+/** Network device operations */
+static struct net_device_operations intelxvf_operations = {
+ .open = intelxvf_open,
+ .close = intelxvf_close,
+ .transmit = intel_transmit,
+ .poll = intelxvf_poll,
+ .irq = intelxvf_irq,
+};
+
+/******************************************************************************
+ *
+ * PCI interface
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Probe PCI device
+ *
+ * @v pci PCI device
+ * @ret rc Return status code
+ */
+static int intelxvf_probe ( struct pci_device *pci ) {
+ struct net_device *netdev;
+ struct intel_nic *intel;
+ int rc;
+
+ /* Allocate and initialise net device */
+ netdev = alloc_etherdev ( sizeof ( *intel ) );
+ if ( ! netdev ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ netdev_init ( netdev, &intelxvf_operations );
+ intel = netdev->priv;
+ pci_set_drvdata ( pci, netdev );
+ netdev->dev = &pci->dev;
+ memset ( intel, 0, sizeof ( *intel ) );
+ intel_init_mbox ( &intel->mbox, INTELXVF_MBCTRL, INTELXVF_MBMEM );
+ intel_init_ring ( &intel->tx, INTEL_NUM_TX_DESC, INTELXVF_TD,
+ intel_describe_tx_adv );
+ intel_init_ring ( &intel->rx, INTEL_NUM_RX_DESC, INTELXVF_RD,
+ intel_describe_rx );
+
+ /* Fix up PCI device */
+ adjust_pci_device ( pci );
+
+ /* Map registers */
+ intel->regs = ioremap ( pci->membase, INTELVF_BAR_SIZE );
+ if ( ! intel->regs ) {
+ rc = -ENODEV;
+ goto err_ioremap;
+ }
+
+ /* Reset the function */
+ intelxvf_reset ( intel );
+
+ /* Send reset message and fetch MAC address */
+ if ( ( rc = intelvf_mbox_reset ( intel, netdev->hw_addr ) ) != 0 ) {
+ DBGC ( intel, "INTEL %p could not reset and fetch MAC: %s\n",
+ intel, strerror ( rc ) );
+ goto err_mbox_reset;
+ }
+
+ /* Reset the function (since we will not respond to Control
+ * ("ping") mailbox messages until the network device is opened.
+ */
+ intelxvf_reset ( intel );
+
+ /* Register network device */
+ if ( ( rc = register_netdev ( netdev ) ) != 0 )
+ goto err_register_netdev;
+
+ /* Set initial link state */
+ intelxvf_check_link ( netdev );
+
+ return 0;
+
+ unregister_netdev ( netdev );
+ err_register_netdev:
+ err_mbox_reset:
+ intelxvf_reset ( intel );
+ iounmap ( intel->regs );
+ err_ioremap:
+ netdev_nullify ( netdev );
+ netdev_put ( netdev );
+ err_alloc:
+ return rc;
+}
+
+/**
+ * Remove PCI device
+ *
+ * @v pci PCI device
+ */
+static void intelxvf_remove ( struct pci_device *pci ) {
+ struct net_device *netdev = pci_get_drvdata ( pci );
+ struct intel_nic *intel = netdev->priv;
+
+ /* Unregister network device */
+ unregister_netdev ( netdev );
+
+ /* Reset the NIC */
+ intelxvf_reset ( intel );
+
+ /* Free network device */
+ iounmap ( intel->regs );
+ netdev_nullify ( netdev );
+ netdev_put ( netdev );
+}
+
+/** PCI device IDs */
+static struct pci_device_id intelxvf_nics[] = {
+ PCI_ROM ( 0x8086, 0x10ed, "82599-vf", "82599 VF", 0 ),
+ PCI_ROM ( 0x8086, 0x1515, "x540-vf", "X540 VF", 0 ),
+ PCI_ROM ( 0x8086, 0x1565, "x550-vf", "X550 VF", 0 ),
+ PCI_ROM ( 0x8086, 0x15a8, "x552-vf", "X552 VF", 0 ),
+};
+
+/** PCI driver */
+struct pci_driver intelxvf_driver __pci_driver = {
+ .ids = intelxvf_nics,
+ .id_count = ( sizeof ( intelxvf_nics ) / sizeof ( intelxvf_nics[0] ) ),
+ .probe = intelxvf_probe,
+ .remove = intelxvf_remove,
+};
diff --git a/roms/ipxe/src/drivers/net/intelxvf.h b/roms/ipxe/src/drivers/net/intelxvf.h
new file mode 100644
index 000000000..ad046a65c
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/intelxvf.h
@@ -0,0 +1,104 @@
+#ifndef _INTELXVF_H
+#define _INTELXVF_H
+
+/** @file
+ *
+ * Intel 10 Gigabit Ethernet virtual function network card driver
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include "intelvf.h"
+
+/** Control Register */
+#define INTELXVF_CTRL 0x0000UL
+#define INTELXVF_CTRL_RST 0x04000000UL /**< Function-level reset */
+
+/** Link Status Register */
+#define INTELXVF_LINKS 0x0010UL
+#define INTELXVF_LINKS_UP 0x40000000UL /**< Link up */
+
+/** Extended Interrupt Cause Read Register */
+#define INTELXVF_EICR 0x0100UL
+#define INTELXVF_EIRQ_RX0 0x00000001UL /**< RX queue 0 (via IVAR) */
+#define INTELXVF_EIRQ_TX0 0x00000002UL /**< TX queue 0 (via IVAR) */
+#define INTELXVF_EIRQ_MBOX 0x00000004UL /**< Mailbox (via IVARM) */
+
+/** Extended Interrupt Mask Set/Read Register */
+#define INTELXVF_EIMS 0x0108UL
+
+/** Extended Interrupt Mask Clear Register */
+#define INTELXVF_EIMC 0x010cUL
+
+/** Interrupt Vector Allocation Register */
+#define INTELXVF_IVAR 0x0120UL
+#define INTELXVF_IVAR_RX0(bit) ( (bit) << 0 ) /**< RX queue 0 allocation */
+#define INTELXVF_IVAR_RX0_DEFAULT INTELXVF_IVAR_RX0 ( 0x00 )
+#define INTELXVF_IVAR_RX0_MASK INTELXVF_IVAR_RX0 ( 0x01 )
+#define INTELXVF_IVAR_RX0_VALID 0x00000080UL /**< RX queue 0 valid */
+#define INTELXVF_IVAR_TX0(bit) ( (bit) << 8 ) /**< TX queue 0 allocation */
+#define INTELXVF_IVAR_TX0_DEFAULT INTELXVF_IVAR_TX0 ( 0x01 )
+#define INTELXVF_IVAR_TX0_MASK INTELXVF_IVAR_TX0 ( 0x01 )
+#define INTELXVF_IVAR_TX0_VALID 0x00008000UL /**< TX queue 0 valid */
+
+/** Interrupt Vector Allocation Miscellaneous Register */
+#define INTELXVF_IVARM 0x0140UL
+#define INTELXVF_IVARM_MBOX(bit) ( (bit) << 0 ) /**< Mailbox allocation */
+#define INTELXVF_IVARM_MBOX_DEFAULT INTELXVF_IVARM_MBOX ( 0x02 )
+#define INTELXVF_IVARM_MBOX_MASK INTELXVF_IVARM_MBOX ( 0x03 )
+#define INTELXVF_IVARM_MBOX_VALID 0x00000080UL /**< Mailbox valid */
+
+/** Mailbox Memory Register Base */
+#define INTELXVF_MBMEM 0x0200UL
+
+/** Mailbox Control Register */
+#define INTELXVF_MBCTRL 0x02fcUL
+
+/** Receive Descriptor register block */
+#define INTELXVF_RD 0x1000UL
+
+/** RX DCA Control Register */
+#define INTELXVF_DCA_RXCTRL 0x100cUL
+#define INTELXVF_DCA_RXCTRL_MUST_BE_ZERO 0x00001000UL /**< Must be zero */
+
+/** Split Receive Control Register */
+#define INTELXVF_SRRCTL 0x1014UL
+#define INTELXVF_SRRCTL_BSIZE(kb) ( (kb) << 0 ) /**< Receive buffer size */
+#define INTELXVF_SRRCTL_BSIZE_DEFAULT INTELXVF_SRRCTL_BSIZE ( 0x02 )
+#define INTELXVF_SRRCTL_BSIZE_MASK INTELXVF_SRRCTL_BSIZE ( 0x1f )
+#define INTELXVF_SRRCTL_DESCTYPE(typ) ( (typ) << 25 ) /**< Descriptor type */
+#define INTELXVF_SRRCTL_DESCTYPE_DEFAULT INTELXVF_SRRCTL_DESCTYPE ( 0x00 )
+#define INTELXVF_SRRCTL_DESCTYPE_MASK INTELXVF_SRRCTL_DESCTYPE ( 0x07 )
+
+/** Good Packets Received Count */
+#define INTELXVF_GPRC 0x101c
+
+/** Good Packets Received Count Low */
+#define INTELXVF_GORCL 0x1020
+
+/** Good Packets Received Count High */
+#define INTELXVF_GORCH 0x1024
+
+/* Multicast Packets Received Count */
+#define INTELXVF_MPRC 0x1034
+
+/** Transmit Descriptor register block */
+#define INTELXVF_TD 0x2000UL
+
+/** Good Packets Transmitted Count */
+#define INTELXVF_GPTC 0x201c
+
+/** Good Packets Transmitted Count Low */
+#define INTELXVF_GOTCL 0x2020
+
+/** Good Packets Transmitted Count High */
+#define INTELXVF_GOTCH 0x2024
+
+/** Negotiate API version mailbox message */
+#define INTELXVF_MSG_TYPE_VERSION 0x00000008UL
+
+/** API version 1.1 */
+#define INTELXVF_MSG_VERSION_1_1 0x00000002UL
+
+#endif /* _INTELXVF_H */
diff --git a/roms/ipxe/src/drivers/net/ipoib.c b/roms/ipxe/src/drivers/net/ipoib.c
index 1b5391776..6552d764e 100644
--- a/roms/ipxe/src/drivers/net/ipoib.c
+++ b/roms/ipxe/src/drivers/net/ipoib.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
@@ -29,8 +33,10 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/errortab.h>
#include <ipxe/malloc.h>
#include <ipxe/if_arp.h>
+#include <ipxe/arp.h>
#include <ipxe/if_ether.h>
#include <ipxe/ethernet.h>
+#include <ipxe/ip.h>
#include <ipxe/iobuf.h>
#include <ipxe/netdevice.h>
#include <ipxe/infiniband.h>
@@ -44,6 +50,20 @@ FILE_LICENCE ( GPL2_OR_LATER );
* IP over Infiniband
*/
+/* Disambiguate the various error causes */
+#define ENXIO_ARP_REPLY __einfo_error ( EINFO_ENXIO_ARP_REPLY )
+#define EINFO_ENXIO_ARP_REPLY \
+ __einfo_uniqify ( EINFO_ENXIO, 0x01, \
+ "Missing REMAC for ARP reply target address" )
+#define ENXIO_NON_IPV4 __einfo_error ( EINFO_ENXIO_NON_IPV4 )
+#define EINFO_ENXIO_NON_IPV4 \
+ __einfo_uniqify ( EINFO_ENXIO, 0x02, \
+ "Missing REMAC for non-IPv4 packet" )
+#define ENXIO_ARP_SENT __einfo_error ( EINFO_ENXIO_ARP_SENT )
+#define EINFO_ENXIO_ARP_SENT \
+ __einfo_uniqify ( EINFO_ENXIO, 0x03, \
+ "Missing REMAC for IPv4 packet (ARP sent)" )
+
/** Number of IPoIB send work queue entries */
#define IPOIB_NUM_SEND_WQES 2
@@ -96,6 +116,8 @@ struct errortab ipoib_errors[] __errortab = {
__einfo_errortab ( EINFO_EINPROGRESS_JOINING ),
};
+static struct net_device_operations ipoib_operations;
+
/****************************************************************************
*
* IPoIB REMAC cache
@@ -124,8 +146,10 @@ static struct ipoib_mac * ipoib_find_remac ( struct ipoib_device *ipoib,
const struct ipoib_remac *remac ) {
struct ipoib_peer *peer;
- /* Check for broadcast REMAC */
- if ( is_broadcast_ether_addr ( remac ) )
+ /* Check for broadcast or multicast REMAC. We transmit
+ * multicasts as broadcasts for simplicity.
+ */
+ if ( is_multicast_ether_addr ( remac ) )
return &ipoib->broadcast;
/* Try to find via REMAC cache */
@@ -202,14 +226,20 @@ static void ipoib_flush_remac ( struct ipoib_device *ipoib ) {
* @ret discarded Number of cached items discarded
*/
static unsigned int ipoib_discard_remac ( void ) {
- struct ib_device *ibdev;
+ struct net_device *netdev;
struct ipoib_device *ipoib;
struct ipoib_peer *peer;
unsigned int discarded = 0;
/* Try to discard one cache entry for each IPoIB device */
- for_each_ibdev ( ibdev ) {
- ipoib = ib_get_ownerdata ( ibdev );
+ for_each_netdev ( netdev ) {
+
+ /* Skip non-IPoIB devices */
+ if ( netdev->op != &ipoib_operations )
+ continue;
+ ipoib = netdev->priv;
+
+ /* Discard least recently used cache entry (if any) */
list_for_each_entry_reverse ( peer, &ipoib->peers, list ) {
list_del ( &peer->list );
free ( peer );
@@ -222,7 +252,7 @@ static unsigned int ipoib_discard_remac ( void ) {
}
/** IPoIB cache discarder */
-struct cache_discarder ipoib_discarder __cache_discarder ( CACHE_NORMAL ) = {
+struct cache_discarder ipoib_discarder __cache_discarder ( CACHE_EXPENSIVE ) = {
.discard = ipoib_discard_remac,
};
@@ -324,8 +354,11 @@ static int ipoib_translate_tx_arp ( struct net_device *netdev,
/* Look up REMAC, if applicable */
if ( arphdr->ar_op == ARPOP_REPLY ) {
target_ha = ipoib_find_remac ( ipoib, arp_target_pa ( arphdr ));
- if ( ! target_ha )
- return -ENXIO;
+ if ( ! target_ha ) {
+ DBGC ( ipoib, "IPoIB %p no REMAC for %s ARP reply\n",
+ ipoib, eth_ntoa ( arp_target_pa ( arphdr ) ) );
+ return -ENXIO_ARP_REPLY;
+ }
}
/* Construct new packet */
@@ -461,6 +494,7 @@ static int ipoib_transmit ( struct net_device *netdev,
struct ipoib_device *ipoib = netdev->priv;
struct ib_device *ibdev = ipoib->ibdev;
struct ethhdr *ethhdr;
+ struct iphdr *iphdr;
struct ipoib_hdr *ipoib_hdr;
struct ipoib_mac *mac;
struct ib_address_vector dest;
@@ -485,9 +519,34 @@ static int ipoib_transmit ( struct net_device *netdev,
iob_pull ( iobuf, sizeof ( *ethhdr ) );
/* Identify destination address */
- mac = ipoib_find_remac ( ipoib, ( ( void *) ethhdr->h_dest ) );
- if ( ! mac )
- return -ENXIO;
+ mac = ipoib_find_remac ( ipoib, ( ( void * ) ethhdr->h_dest ) );
+ if ( ! mac ) {
+ /* Generate a new ARP request (if possible) to trigger
+ * population of the REMAC cache entry.
+ */
+ if ( ( net_proto != htons ( ETH_P_IP ) ) ||
+ ( iob_len ( iobuf ) < sizeof ( *iphdr ) ) ) {
+ DBGC ( ipoib, "IPoIB %p no REMAC for %s non-IPv4 "
+ "packet type %04x\n", ipoib,
+ eth_ntoa ( ethhdr->h_dest ),
+ ntohs ( net_proto ) );
+ return -ENXIO_NON_IPV4;
+ }
+ iphdr = iobuf->data;
+ if ( ( rc = arp_tx_request ( netdev, &ipv4_protocol,
+ &iphdr->dest, &iphdr->src ) ) !=0){
+ DBGC ( ipoib, "IPoIB %p could not ARP for %s/%s/",
+ ipoib, eth_ntoa ( ethhdr->h_dest ),
+ inet_ntoa ( iphdr->dest ) );
+ DBGC ( ipoib, "%s: %s\n", inet_ntoa ( iphdr->src ),
+ strerror ( rc ) );
+ return rc;
+ }
+ DBGC ( ipoib, "IPoIB %p no REMAC for %s/%s/", ipoib,
+ eth_ntoa ( ethhdr->h_dest ), inet_ntoa ( iphdr->dest ) );
+ DBGC ( ipoib, "%s\n", inet_ntoa ( iphdr->src ) );
+ return -ENXIO_ARP_SENT;
+ }
/* Translate packet if applicable */
if ( ( rc = ipoib_translate_tx ( netdev, iobuf, net_proto ) ) != 0 )
@@ -732,7 +791,8 @@ static void ipoib_link_state_changed ( struct ib_device *ibdev ) {
int rc;
/* Leave existing broadcast group */
- ipoib_leave_broadcast_group ( ipoib );
+ if ( ipoib->qp )
+ ipoib_leave_broadcast_group ( ipoib );
/* Update MAC address based on potentially-new GID prefix */
memcpy ( &ipoib->mac.gid.s.prefix, &ibdev->gid.s.prefix,
@@ -747,7 +807,7 @@ static void ipoib_link_state_changed ( struct ib_device *ibdev ) {
netdev_link_err ( netdev, ( rc ? rc : -EINPROGRESS_JOINING ) );
/* Join new broadcast group */
- if ( ib_is_open ( ibdev ) && ib_link_ok ( ibdev ) &&
+ if ( ib_is_open ( ibdev ) && ib_link_ok ( ibdev ) && ipoib->qp &&
( ( rc = ipoib_join_broadcast_group ( ipoib ) ) != 0 ) ) {
DBGC ( ipoib, "IPoIB %p could not rejoin broadcast group: "
"%s\n", ipoib, strerror ( rc ) );
@@ -835,7 +895,9 @@ static void ipoib_close ( struct net_device *netdev ) {
/* Tear down the queues */
ib_destroy_qp ( ibdev, ipoib->qp );
+ ipoib->qp = NULL;
ib_destroy_cq ( ibdev, ipoib->cq );
+ ipoib->cq = NULL;
/* Close IB device */
ib_close ( ibdev );
diff --git a/roms/ipxe/src/drivers/net/legacy.c b/roms/ipxe/src/drivers/net/legacy.c
index 4edbef162..73a80194f 100644
--- a/roms/ipxe/src/drivers/net/legacy.c
+++ b/roms/ipxe/src/drivers/net/legacy.c
@@ -17,7 +17,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
struct nic nic;
diff --git a/roms/ipxe/src/drivers/net/mii.c b/roms/ipxe/src/drivers/net/mii.c
index c4d32514d..9b297029a 100644
--- a/roms/ipxe/src/drivers/net/mii.c
+++ b/roms/ipxe/src/drivers/net/mii.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <unistd.h>
@@ -111,3 +115,35 @@ int mii_reset ( struct mii_interface *mii ) {
DBGC ( mii, "MII %p timed out waiting for reset\n", mii );
return -ETIMEDOUT;
}
+
+/**
+ * Update link status via MII
+ *
+ * @v mii MII interface
+ * @v netdev Network device
+ * @ret rc Return status code
+ */
+int mii_check_link ( struct mii_interface *mii, struct net_device *netdev ) {
+ int bmsr;
+ int link;
+ int rc;
+
+ /* Read BMSR */
+ bmsr = mii_read ( mii, MII_BMSR );
+ if ( bmsr < 0 ) {
+ rc = bmsr;
+ return rc;
+ }
+
+ /* Report link status */
+ link = ( bmsr & BMSR_LSTATUS );
+ DBGC ( mii, "MII %p link %s (BMSR %#04x)\n",
+ mii, ( link ? "up" : "down" ), bmsr );
+ if ( link ) {
+ netdev_link_up ( netdev );
+ } else {
+ netdev_link_down ( netdev );
+ }
+
+ return 0;
+}
diff --git a/roms/ipxe/src/drivers/net/myson.c b/roms/ipxe/src/drivers/net/myson.c
index 6abb55660..84a550596 100644
--- a/roms/ipxe/src/drivers/net/myson.c
+++ b/roms/ipxe/src/drivers/net/myson.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <string.h>
diff --git a/roms/ipxe/src/drivers/net/myson.h b/roms/ipxe/src/drivers/net/myson.h
index 8d7cc5855..05a6b8a58 100644
--- a/roms/ipxe/src/drivers/net/myson.h
+++ b/roms/ipxe/src/drivers/net/myson.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/if_ether.h>
diff --git a/roms/ipxe/src/drivers/net/ncm.c b/roms/ipxe/src/drivers/net/ncm.c
new file mode 100644
index 000000000..10728d2a1
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ncm.c
@@ -0,0 +1,672 @@
+/*
+ * Copyright (C) 2014 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <string.h>
+#include <errno.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/profile.h>
+#include <ipxe/usb.h>
+#include <ipxe/usbnet.h>
+#include "ecm.h"
+#include "ncm.h"
+
+/** @file
+ *
+ * CDC-NCM USB Ethernet driver
+ *
+ */
+
+/** Interrupt completion profiler */
+static struct profiler ncm_intr_profiler __profiler =
+ { .name = "ncm.intr" };
+
+/** Bulk IN completion profiler */
+static struct profiler ncm_in_profiler __profiler =
+ { .name = "ncm.in" };
+
+/** Bulk IN per-datagram profiler */
+static struct profiler ncm_in_datagram_profiler __profiler =
+ { .name = "ncm.in_dgram" };
+
+/** Bulk OUT profiler */
+static struct profiler ncm_out_profiler __profiler =
+ { .name = "ncm.out" };
+
+/******************************************************************************
+ *
+ * CDC-NCM communications interface
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Complete interrupt transfer
+ *
+ * @v ep USB endpoint
+ * @v iobuf I/O buffer
+ * @v rc Completion status code
+ */
+static void ncm_intr_complete ( struct usb_endpoint *ep,
+ struct io_buffer *iobuf, int rc ) {
+ struct ncm_device *ncm = container_of ( ep, struct ncm_device,
+ usbnet.intr );
+ struct net_device *netdev = ncm->netdev;
+ struct usb_setup_packet *message;
+ size_t len = iob_len ( iobuf );
+
+ /* Profile completions */
+ profile_start ( &ncm_intr_profiler );
+
+ /* Ignore packets cancelled when the endpoint closes */
+ if ( ! ep->open )
+ goto ignore;
+
+ /* Ignore packets with errors */
+ if ( rc != 0 ) {
+ DBGC ( ncm, "NCM %p interrupt failed: %s\n",
+ ncm, strerror ( rc ) );
+ DBGC_HDA ( ncm, 0, iobuf->data, iob_len ( iobuf ) );
+ goto error;
+ }
+
+ /* Extract message header */
+ if ( len < sizeof ( *message ) ) {
+ DBGC ( ncm, "NCM %p underlength interrupt:\n", ncm );
+ DBGC_HDA ( ncm, 0, iobuf->data, iob_len ( iobuf ) );
+ rc = -EINVAL;
+ goto error;
+ }
+ message = iobuf->data;
+
+ /* Parse message header */
+ switch ( message->request ) {
+
+ case cpu_to_le16 ( CDC_NETWORK_CONNECTION ) :
+ if ( message->value ) {
+ DBGC ( ncm, "NCM %p link up\n", ncm );
+ netdev_link_up ( netdev );
+ } else {
+ DBGC ( ncm, "NCM %p link down\n", ncm );
+ netdev_link_down ( netdev );
+ }
+ break;
+
+ case cpu_to_le16 ( CDC_CONNECTION_SPEED_CHANGE ) :
+ /* Ignore */
+ break;
+
+ default:
+ DBGC ( ncm, "NCM %p unrecognised interrupt:\n", ncm );
+ DBGC_HDA ( ncm, 0, iobuf->data, iob_len ( iobuf ) );
+ goto error;
+ }
+
+ /* Free I/O buffer */
+ free_iob ( iobuf );
+ profile_stop ( &ncm_intr_profiler );
+
+ return;
+
+ error:
+ netdev_rx_err ( netdev, iob_disown ( iobuf ), rc );
+ ignore:
+ free_iob ( iobuf );
+ return;
+}
+
+/** Interrupt endpoint operations */
+static struct usb_endpoint_driver_operations ncm_intr_operations = {
+ .complete = ncm_intr_complete,
+};
+
+/******************************************************************************
+ *
+ * CDC-NCM data interface
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Prefill bulk IN endpoint
+ *
+ * @v ncm CDC-NCM device
+ * @ret rc Return status code
+ */
+static int ncm_in_prefill ( struct ncm_device *ncm ) {
+ struct usb_bus *bus = ncm->bus;
+ size_t mtu;
+ unsigned int count;
+ int rc;
+
+ /* Some devices have a very small number of internal buffers,
+ * and rely on being able to pack multiple packets into each
+ * buffer. We therefore want to use large buffers if
+ * possible. However, large allocations have a reasonable
+ * chance of failure, especially if this is not the first or
+ * only device to be opened.
+ *
+ * We therefore attempt to find a usable buffer size, starting
+ * large and working downwards until allocation succeeds.
+ * Smaller buffers will still work, albeit with a higher
+ * chance of packet loss and so lower overall throughput.
+ */
+ for ( mtu = ncm->mtu ; mtu >= NCM_MIN_NTB_INPUT_SIZE ; mtu >>= 1 ) {
+
+ /* Attempt allocation at this MTU */
+ if ( mtu > NCM_MAX_NTB_INPUT_SIZE )
+ continue;
+ if ( mtu > bus->mtu )
+ continue;
+ count = ( NCM_IN_MIN_SIZE / mtu );
+ if ( count < NCM_IN_MIN_COUNT )
+ count = NCM_IN_MIN_COUNT;
+ if ( ( count * mtu ) > NCM_IN_MAX_SIZE )
+ continue;
+ usb_refill_init ( &ncm->usbnet.in, mtu, count );
+ if ( ( rc = usb_prefill ( &ncm->usbnet.in ) ) != 0 ) {
+ DBGC ( ncm, "NCM %p could not prefill %dx %zd-byte "
+ "buffers for bulk IN\n", ncm, count, mtu );
+ continue;
+ }
+
+ DBGC ( ncm, "NCM %p using %dx %zd-byte buffers for bulk IN\n",
+ ncm, count, mtu );
+ return 0;
+ }
+
+ DBGC ( ncm, "NCM %p could not prefill bulk IN endpoint\n", ncm );
+ return -ENOMEM;
+}
+
+/**
+ * Complete bulk IN transfer
+ *
+ * @v ep USB endpoint
+ * @v iobuf I/O buffer
+ * @v rc Completion status code
+ */
+static void ncm_in_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf,
+ int rc ) {
+ struct ncm_device *ncm = container_of ( ep, struct ncm_device,
+ usbnet.in );
+ struct net_device *netdev = ncm->netdev;
+ struct ncm_transfer_header *nth;
+ struct ncm_datagram_pointer *ndp;
+ struct ncm_datagram_descriptor *desc;
+ struct io_buffer *pkt;
+ unsigned int remaining;
+ size_t ndp_offset;
+ size_t ndp_len;
+ size_t pkt_offset;
+ size_t pkt_len;
+ size_t headroom;
+ size_t len;
+
+ /* Profile overall bulk IN completion */
+ profile_start ( &ncm_in_profiler );
+
+ /* Ignore packets cancelled when the endpoint closes */
+ if ( ! ep->open )
+ goto ignore;
+
+ /* Record USB errors against the network device */
+ if ( rc != 0 ) {
+ DBGC ( ncm, "NCM %p bulk IN failed: %s\n",
+ ncm, strerror ( rc ) );
+ goto error;
+ }
+
+ /* Locate transfer header */
+ len = iob_len ( iobuf );
+ if ( sizeof ( *nth ) > len ) {
+ DBGC ( ncm, "NCM %p packet too short for NTH:\n", ncm );
+ rc = -EINVAL;
+ goto error;
+ }
+ nth = iobuf->data;
+
+ /* Locate datagram pointer */
+ ndp_offset = le16_to_cpu ( nth->offset );
+ if ( ( ndp_offset + sizeof ( *ndp ) ) > len ) {
+ DBGC ( ncm, "NCM %p packet too short for NDP:\n", ncm );
+ rc = -EINVAL;
+ goto error;
+ }
+ ndp = ( iobuf->data + ndp_offset );
+ ndp_len = le16_to_cpu ( ndp->header_len );
+ if ( ndp_len < offsetof ( typeof ( *ndp ), desc ) ) {
+ DBGC ( ncm, "NCM %p NDP header length too short:\n", ncm );
+ rc = -EINVAL;
+ goto error;
+ }
+ if ( ( ndp_offset + ndp_len ) > len ) {
+ DBGC ( ncm, "NCM %p packet too short for NDP:\n", ncm );
+ rc = -EINVAL;
+ goto error;
+ }
+
+ /* Process datagrams */
+ remaining = ( ( ndp_len - offsetof ( typeof ( *ndp ), desc ) ) /
+ sizeof ( ndp->desc[0] ) );
+ for ( desc = ndp->desc ; remaining && desc->offset ; remaining-- ) {
+
+ /* Profile individual datagrams */
+ profile_start ( &ncm_in_datagram_profiler );
+
+ /* Locate datagram */
+ pkt_offset = le16_to_cpu ( desc->offset );
+ pkt_len = le16_to_cpu ( desc->len );
+ if ( pkt_len < ETH_HLEN ) {
+ DBGC ( ncm, "NCM %p underlength datagram:\n", ncm );
+ rc = -EINVAL;
+ goto error;
+ }
+ if ( ( pkt_offset + pkt_len ) > len ) {
+ DBGC ( ncm, "NCM %p datagram exceeds packet:\n", ncm );
+ rc = -EINVAL;
+ goto error;
+ }
+
+ /* Move to next descriptor */
+ desc++;
+
+ /* Copy data to a new I/O buffer. Our USB buffers may
+ * be very large and so we choose to recycle the
+ * buffers directly rather than attempt reallocation
+ * while the device is running. We therefore copy the
+ * data to a new I/O buffer even if this is the only
+ * (or last) packet within the buffer.
+ *
+ * We reserve enough space at the start of each buffer
+ * to allow for our own transmission header, to
+ * support protocols such as ARP which may modify the
+ * received packet and reuse the same I/O buffer for
+ * transmission.
+ */
+ headroom = ( sizeof ( struct ncm_ntb_header ) + ncm->padding );
+ pkt = alloc_iob ( headroom + pkt_len );
+ if ( ! pkt ) {
+ /* Record error and continue */
+ netdev_rx_err ( netdev, NULL, -ENOMEM );
+ continue;
+ }
+ iob_reserve ( pkt, headroom );
+ memcpy ( iob_put ( pkt, pkt_len ),
+ ( iobuf->data + pkt_offset ), pkt_len );
+
+ /* Strip CRC, if present */
+ if ( ndp->magic & cpu_to_le32 ( NCM_DATAGRAM_POINTER_MAGIC_CRC))
+ iob_unput ( pkt, 4 /* CRC32 */ );
+
+ /* Hand off to network stack */
+ netdev_rx ( netdev, pkt );
+ profile_stop ( &ncm_in_datagram_profiler );
+ }
+
+ /* Recycle I/O buffer */
+ usb_recycle ( &ncm->usbnet.in, iobuf );
+ profile_stop ( &ncm_in_profiler );
+
+ return;
+
+ error:
+ /* Record error against network device */
+ DBGC_HDA ( ncm, 0, iobuf->data, iob_len ( iobuf ) );
+ netdev_rx_err ( netdev, NULL, rc );
+ ignore:
+ usb_recycle ( &ncm->usbnet.in, iobuf );
+}
+
+/** Bulk IN endpoint operations */
+static struct usb_endpoint_driver_operations ncm_in_operations = {
+ .complete = ncm_in_complete,
+};
+
+/**
+ * Transmit packet
+ *
+ * @v ncm CDC-NCM device
+ * @v iobuf I/O buffer
+ * @ret rc Return status code
+ */
+static int ncm_out_transmit ( struct ncm_device *ncm,
+ struct io_buffer *iobuf ) {
+ struct ncm_ntb_header *header;
+ size_t len = iob_len ( iobuf );
+ size_t header_len = ( sizeof ( *header ) + ncm->padding );
+ int rc;
+
+ /* Profile transmissions */
+ profile_start ( &ncm_out_profiler );
+
+ /* Prepend header */
+ if ( ( rc = iob_ensure_headroom ( iobuf, header_len ) ) != 0 )
+ return rc;
+ header = iob_push ( iobuf, header_len );
+
+ /* Populate header */
+ header->nth.magic = cpu_to_le32 ( NCM_TRANSFER_HEADER_MAGIC );
+ header->nth.header_len = cpu_to_le16 ( sizeof ( header->nth ) );
+ header->nth.sequence = cpu_to_le16 ( ncm->sequence );
+ header->nth.len = cpu_to_le16 ( iob_len ( iobuf ) );
+ header->nth.offset =
+ cpu_to_le16 ( offsetof ( typeof ( *header ), ndp ) );
+ header->ndp.magic = cpu_to_le32 ( NCM_DATAGRAM_POINTER_MAGIC );
+ header->ndp.header_len = cpu_to_le16 ( sizeof ( header->ndp ) +
+ sizeof ( header->desc ) );
+ header->ndp.offset = cpu_to_le16 ( 0 );
+ header->desc[0].offset = cpu_to_le16 ( header_len );
+ header->desc[0].len = cpu_to_le16 ( len );
+ memset ( &header->desc[1], 0, sizeof ( header->desc[1] ) );
+
+ /* Enqueue I/O buffer */
+ if ( ( rc = usb_stream ( &ncm->usbnet.out, iobuf, 0 ) ) != 0 )
+ return rc;
+
+ /* Increment sequence number */
+ ncm->sequence++;
+
+ profile_stop ( &ncm_out_profiler );
+ return 0;
+}
+
+/**
+ * Complete bulk OUT transfer
+ *
+ * @v ep USB endpoint
+ * @v iobuf I/O buffer
+ * @v rc Completion status code
+ */
+static void ncm_out_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf,
+ int rc ) {
+ struct ncm_device *ncm = container_of ( ep, struct ncm_device,
+ usbnet.out );
+ struct net_device *netdev = ncm->netdev;
+
+ /* Report TX completion */
+ netdev_tx_complete_err ( netdev, iobuf, rc );
+}
+
+/** Bulk OUT endpoint operations */
+static struct usb_endpoint_driver_operations ncm_out_operations = {
+ .complete = ncm_out_complete,
+};
+
+/******************************************************************************
+ *
+ * Network device interface
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Open network device
+ *
+ * @v netdev Network device
+ * @ret rc Return status code
+ */
+static int ncm_open ( struct net_device *netdev ) {
+ struct ncm_device *ncm = netdev->priv;
+ struct usb_device *usb = ncm->usb;
+ struct ncm_set_ntb_input_size size;
+ int rc;
+
+ /* Reset sequence number */
+ ncm->sequence = 0;
+
+ /* Prefill I/O buffers */
+ if ( ( rc = ncm_in_prefill ( ncm ) ) != 0 )
+ goto err_prefill;
+
+ /* Set maximum input size */
+ memset ( &size, 0, sizeof ( size ) );
+ size.mtu = cpu_to_le32 ( ncm->usbnet.in.len );
+ if ( ( rc = usb_control ( usb, NCM_SET_NTB_INPUT_SIZE, 0,
+ ncm->usbnet.comms, &size,
+ sizeof ( size ) ) ) != 0 ) {
+ DBGC ( ncm, "NCM %p could not set input size to %zd: %s\n",
+ ncm, ncm->usbnet.in.len, strerror ( rc ) );
+ goto err_set_ntb_input_size;
+ }
+
+ /* Open USB network device */
+ if ( ( rc = usbnet_open ( &ncm->usbnet ) ) != 0 ) {
+ DBGC ( ncm, "NCM %p could not open: %s\n",
+ ncm, strerror ( rc ) );
+ goto err_open;
+ }
+
+ return 0;
+
+ usbnet_close ( &ncm->usbnet );
+ err_open:
+ err_set_ntb_input_size:
+ usb_flush ( &ncm->usbnet.in );
+ err_prefill:
+ return rc;
+}
+
+/**
+ * Close network device
+ *
+ * @v netdev Network device
+ */
+static void ncm_close ( struct net_device *netdev ) {
+ struct ncm_device *ncm = netdev->priv;
+
+ /* Close USB network device */
+ usbnet_close ( &ncm->usbnet );
+}
+
+/**
+ * Transmit packet
+ *
+ * @v netdev Network device
+ * @v iobuf I/O buffer
+ * @ret rc Return status code
+ */
+static int ncm_transmit ( struct net_device *netdev,
+ struct io_buffer *iobuf ) {
+ struct ncm_device *ncm = netdev->priv;
+ int rc;
+
+ /* Transmit packet */
+ if ( ( rc = ncm_out_transmit ( ncm, iobuf ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/**
+ * Poll for completed and received packets
+ *
+ * @v netdev Network device
+ */
+static void ncm_poll ( struct net_device *netdev ) {
+ struct ncm_device *ncm = netdev->priv;
+ int rc;
+
+ /* Poll USB bus */
+ usb_poll ( ncm->bus );
+
+ /* Refill endpoints */
+ if ( ( rc = usbnet_refill ( &ncm->usbnet ) ) != 0 )
+ netdev_rx_err ( netdev, NULL, rc );
+
+}
+
+/** CDC-NCM network device operations */
+static struct net_device_operations ncm_operations = {
+ .open = ncm_open,
+ .close = ncm_close,
+ .transmit = ncm_transmit,
+ .poll = ncm_poll,
+};
+
+/******************************************************************************
+ *
+ * USB interface
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Probe device
+ *
+ * @v func USB function
+ * @v config Configuration descriptor
+ * @ret rc Return status code
+ */
+static int ncm_probe ( struct usb_function *func,
+ struct usb_configuration_descriptor *config ) {
+ struct usb_device *usb = func->usb;
+ struct net_device *netdev;
+ struct ncm_device *ncm;
+ struct usb_interface_descriptor *comms;
+ struct ecm_ethernet_descriptor *ethernet;
+ struct ncm_ntb_parameters params;
+ int rc;
+
+ /* Allocate and initialise structure */
+ netdev = alloc_etherdev ( sizeof ( *ncm ) );
+ if ( ! netdev ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ netdev_init ( netdev, &ncm_operations );
+ netdev->dev = &func->dev;
+ ncm = netdev->priv;
+ memset ( ncm, 0, sizeof ( *ncm ) );
+ ncm->usb = usb;
+ ncm->bus = usb->port->hub->bus;
+ ncm->netdev = netdev;
+ usbnet_init ( &ncm->usbnet, func, &ncm_intr_operations,
+ &ncm_in_operations, &ncm_out_operations );
+ usb_refill_init ( &ncm->usbnet.intr, 0, NCM_INTR_COUNT );
+ DBGC ( ncm, "NCM %p on %s\n", ncm, func->name );
+
+ /* Describe USB network device */
+ if ( ( rc = usbnet_describe ( &ncm->usbnet, config ) ) != 0 ) {
+ DBGC ( ncm, "NCM %p could not describe: %s\n",
+ ncm, strerror ( rc ) );
+ goto err_describe;
+ }
+
+ /* Locate Ethernet descriptor */
+ comms = usb_interface_descriptor ( config, ncm->usbnet.comms, 0 );
+ assert ( comms != NULL );
+ ethernet = ecm_ethernet_descriptor ( config, comms );
+ if ( ! ethernet ) {
+ DBGC ( ncm, "NCM %p has no Ethernet descriptor\n", ncm );
+ rc = -EINVAL;
+ goto err_ethernet;
+ }
+
+ /* Fetch MAC address */
+ if ( ( rc = ecm_fetch_mac ( usb, ethernet, netdev->hw_addr ) ) != 0 ) {
+ DBGC ( ncm, "NCM %p could not fetch MAC address: %s\n",
+ ncm, strerror ( rc ) );
+ goto err_fetch_mac;
+ }
+
+ /* Get NTB parameters */
+ if ( ( rc = usb_control ( usb, NCM_GET_NTB_PARAMETERS, 0,
+ ncm->usbnet.comms, &params,
+ sizeof ( params ) ) ) != 0 ) {
+ DBGC ( ncm, "NCM %p could not get NTB parameters: %s\n",
+ ncm, strerror ( rc ) );
+ goto err_ntb_parameters;
+ }
+
+ /* Get maximum supported input size */
+ ncm->mtu = le32_to_cpu ( params.in.mtu );
+ DBGC2 ( ncm, "NCM %p maximum IN size is %zd bytes\n", ncm, ncm->mtu );
+
+ /* Calculate transmit padding */
+ ncm->padding = ( ( le16_to_cpu ( params.out.remainder ) -
+ sizeof ( struct ncm_ntb_header ) - ETH_HLEN ) &
+ ( le16_to_cpu ( params.out.divisor ) - 1 ) );
+ DBGC2 ( ncm, "NCM %p using %zd-byte transmit padding\n",
+ ncm, ncm->padding );
+ assert ( ( ( sizeof ( struct ncm_ntb_header ) + ncm->padding +
+ ETH_HLEN ) % le16_to_cpu ( params.out.divisor ) ) ==
+ le16_to_cpu ( params.out.remainder ) );
+
+ /* Register network device */
+ if ( ( rc = register_netdev ( netdev ) ) != 0 )
+ goto err_register;
+
+ usb_func_set_drvdata ( func, ncm );
+ return 0;
+
+ unregister_netdev ( netdev );
+ err_register:
+ err_ntb_parameters:
+ err_fetch_mac:
+ err_ethernet:
+ err_describe:
+ netdev_nullify ( netdev );
+ netdev_put ( netdev );
+ err_alloc:
+ return rc;
+}
+
+/**
+ * Remove device
+ *
+ * @v func USB function
+ */
+static void ncm_remove ( struct usb_function *func ) {
+ struct ncm_device *ncm = usb_func_get_drvdata ( func );
+ struct net_device *netdev = ncm->netdev;
+
+ unregister_netdev ( netdev );
+ netdev_nullify ( netdev );
+ netdev_put ( netdev );
+}
+
+/** CDC-NCM device IDs */
+static struct usb_device_id ncm_ids[] = {
+ {
+ .name = "cdc-ncm",
+ .vendor = USB_ANY_ID,
+ .product = USB_ANY_ID,
+ .class = {
+ .class = USB_CLASS_CDC,
+ .subclass = USB_SUBCLASS_CDC_NCM,
+ .protocol = 0,
+ },
+ },
+};
+
+/** CDC-NCM driver */
+struct usb_driver ncm_driver __usb_driver = {
+ .ids = ncm_ids,
+ .id_count = ( sizeof ( ncm_ids ) / sizeof ( ncm_ids[0] ) ),
+ .probe = ncm_probe,
+ .remove = ncm_remove,
+};
diff --git a/roms/ipxe/src/drivers/net/ncm.h b/roms/ipxe/src/drivers/net/ncm.h
new file mode 100644
index 000000000..a9565a56b
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ncm.h
@@ -0,0 +1,173 @@
+#ifndef _NCM_H
+#define _NCM_H
+
+/** @file
+ *
+ * CDC-NCM USB Ethernet driver
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
+#include <ipxe/usb.h>
+#include <ipxe/cdc.h>
+#include <byteswap.h>
+#include "ecm.h"
+
+/** CDC-NCM subclass */
+#define USB_SUBCLASS_CDC_NCM 0x0d
+
+/** Get NTB parameters */
+#define NCM_GET_NTB_PARAMETERS \
+ ( USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE | \
+ USB_REQUEST_TYPE ( 0x80 ) )
+
+/** NTB datagram parameters */
+struct ncm_ntb_datagram_parameters {
+ /** Maximum size */
+ uint32_t mtu;
+ /** Alignment divisor */
+ uint16_t divisor;
+ /** Alignment remainder */
+ uint16_t remainder;
+ /** Alignment modulus */
+ uint16_t modulus;
+} __attribute__ (( packed ));
+
+/** NTB parameters */
+struct ncm_ntb_parameters {
+ /** Length */
+ uint16_t len;
+ /** Supported formats */
+ uint16_t formats;
+ /** IN datagram parameters */
+ struct ncm_ntb_datagram_parameters in;
+ /** Reserved */
+ uint16_t reserved;
+ /** OUT datagram parameters */
+ struct ncm_ntb_datagram_parameters out;
+ /** Maximum number of datagrams per OUT NTB */
+ uint16_t max;
+} __attribute__ (( packed ));
+
+/** Set NTB input size */
+#define NCM_SET_NTB_INPUT_SIZE \
+ ( USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE | \
+ USB_REQUEST_TYPE ( 0x86 ) )
+
+/** Set NTB input size */
+struct ncm_set_ntb_input_size {
+ /** Maximum size */
+ uint32_t mtu;
+} __attribute__ (( packed ));
+
+/** Minimum allowed NTB input size */
+#define NCM_MIN_NTB_INPUT_SIZE 2048
+
+/** Maximum allowed NTB input size (16-bit) */
+#define NCM_MAX_NTB_INPUT_SIZE 65536
+
+/** CDC-NCM transfer header (16-bit) */
+struct ncm_transfer_header {
+ /** Signature */
+ uint32_t magic;
+ /** Header length */
+ uint16_t header_len;
+ /** Sequence number */
+ uint16_t sequence;
+ /** Total length */
+ uint16_t len;
+ /** Offset of first datagram pointer */
+ uint16_t offset;
+} __attribute__ (( packed ));
+
+/** CDC-NCM transfer header magic */
+#define NCM_TRANSFER_HEADER_MAGIC 0x484d434eUL
+
+/** CDC-NCM datagram descriptor (16-bit) */
+struct ncm_datagram_descriptor {
+ /** Starting offset */
+ uint16_t offset;
+ /** Length */
+ uint16_t len;
+} __attribute__ (( packed ));
+
+/** CDC-NCM datagram pointer (16-bit) */
+struct ncm_datagram_pointer {
+ /** Signature */
+ uint32_t magic;
+ /** Header length */
+ uint16_t header_len;
+ /** Offset of next datagram pointer */
+ uint16_t offset;
+ /** Datagram descriptors
+ *
+ * Must be terminated by an empty descriptor.
+ */
+ struct ncm_datagram_descriptor desc[0];
+} __attribute__ (( packed ));
+
+/** CDC-NCM datagram pointer magic */
+#define NCM_DATAGRAM_POINTER_MAGIC 0x304d434eUL
+
+/** CDC-NCM datagram pointer CRC present flag */
+#define NCM_DATAGRAM_POINTER_MAGIC_CRC 0x01000000UL
+
+/** NTB constructed for transmitted packets (excluding padding)
+ *
+ * This is a policy decision.
+ */
+struct ncm_ntb_header {
+ /** Transfer header */
+ struct ncm_transfer_header nth;
+ /** Datagram pointer */
+ struct ncm_datagram_pointer ndp;
+ /** Datagram descriptors */
+ struct ncm_datagram_descriptor desc[2];
+} __attribute__ (( packed ));
+
+/** A CDC-NCM network device */
+struct ncm_device {
+ /** USB device */
+ struct usb_device *usb;
+ /** USB bus */
+ struct usb_bus *bus;
+ /** Network device */
+ struct net_device *netdev;
+ /** USB network device */
+ struct usbnet_device usbnet;
+
+ /** Maximum supported NTB input size */
+ size_t mtu;
+ /** Transmitted packet sequence number */
+ uint16_t sequence;
+ /** Alignment padding required on transmitted packets */
+ size_t padding;
+};
+
+/** Bulk IN ring minimum buffer count
+ *
+ * This is a policy decision.
+ */
+#define NCM_IN_MIN_COUNT 3
+
+/** Bulk IN ring minimum total buffer size
+ *
+ * This is a policy decision.
+ */
+#define NCM_IN_MIN_SIZE 16384
+
+/** Bulk IN ring maximum total buffer size
+ *
+ * This is a policy decision.
+ */
+#define NCM_IN_MAX_SIZE 131072
+
+/** Interrupt ring buffer count
+ *
+ * This is a policy decision.
+ */
+#define NCM_INTR_COUNT 2
+
+#endif /* _NCM_H */
diff --git a/roms/ipxe/src/drivers/net/netfront.c b/roms/ipxe/src/drivers/net/netfront.c
index 4b816329e..2f4bbf2a0 100644
--- a/roms/ipxe/src/drivers/net/netfront.c
+++ b/roms/ipxe/src/drivers/net/netfront.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
@@ -135,7 +139,7 @@ static int netfront_read_mac ( struct netfront_nic *netfront, void *hw_addr ) {
xendev->key, mac );
/* Decode MAC address */
- len = hex_decode ( mac, ':', hw_addr, ETH_ALEN );
+ len = hex_decode ( ':', mac, hw_addr, ETH_ALEN );
if ( len < 0 ) {
rc = len;
DBGC ( netfront, "NETFRONT %s could not decode MAC address "
@@ -593,6 +597,11 @@ static int netfront_open ( struct net_device *netdev ) {
"feature-no-csum-offload" ) ) != 0 )
goto err_feature_no_csum_offload;
+ /* Inform backend that we will send notifications for RX requests */
+ if ( ( rc = netfront_write_flag ( netfront,
+ "feature-rx-notify" ) ) != 0 )
+ goto err_feature_rx_notify;
+
/* Set state to Connected */
if ( ( rc = xenbus_set_state ( xendev, XenbusStateConnected ) ) != 0 ) {
DBGC ( netfront, "NETFRONT %s could not set state=\"%d\": %s\n",
@@ -618,6 +627,8 @@ static int netfront_open ( struct net_device *netdev ) {
err_backend_wait:
netfront_reset ( netfront );
err_set_state:
+ netfront_rm ( netfront, "feature-rx-notify" );
+ err_feature_rx_notify:
netfront_rm ( netfront, "feature-no-csum-offload" );
err_feature_no_csum_offload:
netfront_rm ( netfront, "request-rx-copy" );
@@ -661,6 +672,7 @@ static void netfront_close ( struct net_device *netdev ) {
}
/* Delete flags */
+ netfront_rm ( netfront, "feature-rx-notify" );
netfront_rm ( netfront, "feature-no-csum-offload" );
netfront_rm ( netfront, "request-rx-copy" );
diff --git a/roms/ipxe/src/drivers/net/netfront.h b/roms/ipxe/src/drivers/net/netfront.h
index b3f899f3c..38fd0a77e 100644
--- a/roms/ipxe/src/drivers/net/netfront.h
+++ b/roms/ipxe/src/drivers/net/netfront.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/xen.h>
#include <xen/io/netif.h>
diff --git a/roms/ipxe/src/drivers/net/netvsc.c b/roms/ipxe/src/drivers/net/netvsc.c
new file mode 100644
index 000000000..d269cd63e
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/netvsc.c
@@ -0,0 +1,848 @@
+/*
+ * Copyright (C) 2014 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/** @file
+ *
+ * Hyper-V network virtual service client
+ *
+ * The network virtual service client (NetVSC) connects to the network
+ * virtual service provider (NetVSP) via the Hyper-V virtual machine
+ * bus (VMBus). It provides a transport layer for RNDIS packets.
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <byteswap.h>
+#include <ipxe/umalloc.h>
+#include <ipxe/rndis.h>
+#include <ipxe/vmbus.h>
+#include "netvsc.h"
+
+/**
+ * Send control message and wait for completion
+ *
+ * @v netvsc NetVSC device
+ * @v xrid Relative transaction ID
+ * @v data Data
+ * @v len Length of data
+ * @ret rc Return status code
+ */
+static int netvsc_control ( struct netvsc_device *netvsc, unsigned int xrid,
+ const void *data, size_t len ) {
+ uint64_t xid = ( NETVSC_BASE_XID + xrid );
+ unsigned int i;
+ int rc;
+
+ /* Send control message */
+ if ( ( rc = vmbus_send_control ( netvsc->vmdev, xid, data, len ) ) !=0){
+ DBGC ( netvsc, "NETVSC %s could not send control message: %s\n",
+ netvsc->name, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Record transaction ID */
+ netvsc->wait_xrid = xrid;
+
+ /* Wait for operation to complete */
+ for ( i = 0 ; i < NETVSC_MAX_WAIT_MS ; i++ ) {
+
+ /* Check for completion */
+ if ( ! netvsc->wait_xrid )
+ return netvsc->wait_rc;
+
+ /* Poll VMBus device */
+ vmbus_poll ( netvsc->vmdev );
+
+ /* Delay for 1ms */
+ mdelay ( 1 );
+ }
+
+ DBGC ( netvsc, "NETVSC %s timed out waiting for XRID %d\n",
+ netvsc->name, xrid );
+ vmbus_dump_channel ( netvsc->vmdev );
+ return -ETIMEDOUT;
+}
+
+/**
+ * Handle generic completion
+ *
+ * @v netvsc NetVSC device
+ * @v data Data
+ * @v len Length of data
+ * @ret rc Return status code
+ */
+static int netvsc_completed ( struct netvsc_device *netvsc __unused,
+ const void *data __unused, size_t len __unused ) {
+ return 0;
+}
+
+/**
+ * Initialise communication
+ *
+ * @v netvsc NetVSC device
+ * @ret rc Return status code
+ */
+static int netvsc_initialise ( struct netvsc_device *netvsc ) {
+ struct netvsc_init_message msg;
+ int rc;
+
+ /* Construct message */
+ memset ( &msg, 0, sizeof ( msg ) );
+ msg.header.type = cpu_to_le32 ( NETVSC_INIT_MSG );
+ msg.min = cpu_to_le32 ( NETVSC_VERSION_1 );
+ msg.max = cpu_to_le32 ( NETVSC_VERSION_1 );
+
+ /* Send message and wait for completion */
+ if ( ( rc = netvsc_control ( netvsc, NETVSC_INIT_XRID, &msg,
+ sizeof ( msg ) ) ) != 0 ) {
+ DBGC ( netvsc, "NETVSC %s could not initialise: %s\n",
+ netvsc->name, strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Handle initialisation completion
+ *
+ * @v netvsc NetVSC device
+ * @v data Data
+ * @v len Length of data
+ * @ret rc Return status code
+ */
+static int
+netvsc_initialised ( struct netvsc_device *netvsc, const void *data,
+ size_t len ) {
+ const struct netvsc_init_completion *cmplt = data;
+
+ /* Check completion */
+ if ( len < sizeof ( *cmplt ) ) {
+ DBGC ( netvsc, "NETVSC %s underlength initialisation "
+ "completion (%zd bytes)\n", netvsc->name, len );
+ return -EINVAL;
+ }
+ if ( cmplt->header.type != cpu_to_le32 ( NETVSC_INIT_CMPLT ) ) {
+ DBGC ( netvsc, "NETVSC %s unexpected initialisation completion "
+ "type %d\n", netvsc->name,
+ le32_to_cpu ( cmplt->header.type ) );
+ return -EPROTO;
+ }
+ if ( cmplt->status != cpu_to_le32 ( NETVSC_OK ) ) {
+ DBGC ( netvsc, "NETVSC %s initialisation failure status %d\n",
+ netvsc->name, le32_to_cpu ( cmplt->status ) );
+ return -EPROTO;
+ }
+
+ return 0;
+}
+
+/**
+ * Set NDIS version
+ *
+ * @v netvsc NetVSC device
+ * @ret rc Return status code
+ */
+static int netvsc_ndis_version ( struct netvsc_device *netvsc ) {
+ struct netvsc_ndis_version_message msg;
+ int rc;
+
+ /* Construct message */
+ memset ( &msg, 0, sizeof ( msg ) );
+ msg.header.type = cpu_to_le32 ( NETVSC_NDIS_VERSION_MSG );
+ msg.major = cpu_to_le32 ( NETVSC_NDIS_MAJOR );
+ msg.minor = cpu_to_le32 ( NETVSC_NDIS_MINOR );
+
+ /* Send message and wait for completion */
+ if ( ( rc = netvsc_control ( netvsc, NETVSC_NDIS_VERSION_XRID,
+ &msg, sizeof ( msg ) ) ) != 0 ) {
+ DBGC ( netvsc, "NETVSC %s could not set NDIS version: %s\n",
+ netvsc->name, strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Establish data buffer
+ *
+ * @v netvsc NetVSC device
+ * @v buffer Data buffer
+ * @ret rc Return status code
+ */
+static int netvsc_establish_buffer ( struct netvsc_device *netvsc,
+ struct netvsc_buffer *buffer ) {
+ struct netvsc_establish_buffer_message msg;
+ int rc;
+
+ /* Construct message */
+ memset ( &msg, 0, sizeof ( msg ) );
+ msg.header.type = cpu_to_le32 ( buffer->establish_type );
+ msg.gpadl = cpu_to_le32 ( buffer->gpadl );
+ msg.pageset = buffer->pages.pageset; /* Already protocol-endian */
+
+ /* Send message and wait for completion */
+ if ( ( rc = netvsc_control ( netvsc, buffer->establish_xrid, &msg,
+ sizeof ( msg ) ) ) != 0 ) {
+ DBGC ( netvsc, "NETVSC %s could not establish buffer: %s\n",
+ netvsc->name, strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Handle establish receive data buffer completion
+ *
+ * @v netvsc NetVSC device
+ * @v data Data
+ * @v len Length of data
+ * @ret rc Return status code
+ */
+static int netvsc_rx_established_buffer ( struct netvsc_device *netvsc,
+ const void *data, size_t len ) {
+ const struct netvsc_rx_establish_buffer_completion *cmplt = data;
+
+ /* Check completion */
+ if ( len < sizeof ( *cmplt ) ) {
+ DBGC ( netvsc, "NETVSC %s underlength buffer completion (%zd "
+ "bytes)\n", netvsc->name, len );
+ return -EINVAL;
+ }
+ if ( cmplt->header.type != cpu_to_le32 ( NETVSC_RX_ESTABLISH_CMPLT ) ) {
+ DBGC ( netvsc, "NETVSC %s unexpected buffer completion type "
+ "%d\n", netvsc->name, le32_to_cpu ( cmplt->header.type));
+ return -EPROTO;
+ }
+ if ( cmplt->status != cpu_to_le32 ( NETVSC_OK ) ) {
+ DBGC ( netvsc, "NETVSC %s buffer failure status %d\n",
+ netvsc->name, le32_to_cpu ( cmplt->status ) );
+ return -EPROTO;
+ }
+
+ return 0;
+}
+
+/**
+ * Revoke data buffer
+ *
+ * @v netvsc NetVSC device
+ * @v buffer Data buffer
+ * @ret rc Return status code
+ */
+static int netvsc_revoke_buffer ( struct netvsc_device *netvsc,
+ struct netvsc_buffer *buffer ) {
+ struct netvsc_revoke_buffer_message msg;
+ int rc;
+
+ /* Construct message */
+ memset ( &msg, 0, sizeof ( msg ) );
+ msg.header.type = cpu_to_le32 ( buffer->revoke_type );
+ msg.pageset = buffer->pages.pageset; /* Already protocol-endian */
+
+ /* Send message and wait for completion */
+ if ( ( rc = netvsc_control ( netvsc, buffer->revoke_xrid,
+ &msg, sizeof ( msg ) ) ) != 0 ) {
+ DBGC ( netvsc, "NETVSC %s could not revoke buffer: %s\n",
+ netvsc->name, strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Handle received control packet
+ *
+ * @v vmdev VMBus device
+ * @v xid Transaction ID
+ * @v data Data
+ * @v len Length of data
+ * @ret rc Return status code
+ */
+static int netvsc_recv_control ( struct vmbus_device *vmdev, uint64_t xid,
+ const void *data, size_t len ) {
+ struct rndis_device *rndis = vmbus_get_drvdata ( vmdev );
+ struct netvsc_device *netvsc = rndis->priv;
+
+ DBGC ( netvsc, "NETVSC %s received unsupported control packet "
+ "(%08llx):\n", netvsc->name, xid );
+ DBGC_HDA ( netvsc, 0, data, len );
+ return -ENOTSUP;
+}
+
+/**
+ * Handle received data packet
+ *
+ * @v vmdev VMBus device
+ * @v xid Transaction ID
+ * @v data Data
+ * @v len Length of data
+ * @v list List of I/O buffers
+ * @ret rc Return status code
+ */
+static int netvsc_recv_data ( struct vmbus_device *vmdev, uint64_t xid,
+ const void *data, size_t len,
+ struct list_head *list ) {
+ struct rndis_device *rndis = vmbus_get_drvdata ( vmdev );
+ struct netvsc_device *netvsc = rndis->priv;
+ const struct netvsc_rndis_message *msg = data;
+ struct io_buffer *iobuf;
+ struct io_buffer *tmp;
+ int rc;
+
+ /* Sanity check */
+ if ( len < sizeof ( *msg ) ) {
+ DBGC ( netvsc, "NETVSC %s received underlength RNDIS packet "
+ "(%zd bytes)\n", netvsc->name, len );
+ rc = -EINVAL;
+ goto err_sanity;
+ }
+ if ( msg->header.type != cpu_to_le32 ( NETVSC_RNDIS_MSG ) ) {
+ DBGC ( netvsc, "NETVSC %s received unexpected RNDIS packet "
+ "type %d\n", netvsc->name,
+ le32_to_cpu ( msg->header.type ) );
+ rc = -EINVAL;
+ goto err_sanity;
+ }
+
+ /* Send completion back to host */
+ if ( ( rc = vmbus_send_completion ( vmdev, xid, NULL, 0 ) ) != 0 ) {
+ DBGC ( netvsc, "NETVSC %s could not send completion: %s\n",
+ netvsc->name, strerror ( rc ) );
+ goto err_completion;
+ }
+
+ /* Hand off to RNDIS */
+ list_for_each_entry_safe ( iobuf, tmp, list, list ) {
+ list_del ( &iobuf->list );
+ rndis_rx ( rndis, iob_disown ( iobuf ) );
+ }
+
+ return 0;
+
+ err_completion:
+ err_sanity:
+ list_for_each_entry_safe ( iobuf, tmp, list, list ) {
+ list_del ( &iobuf->list );
+ free_iob ( iobuf );
+ }
+ return rc;
+}
+
+/**
+ * Handle received completion packet
+ *
+ * @v vmdev VMBus device
+ * @v xid Transaction ID
+ * @v data Data
+ * @v len Length of data
+ * @ret rc Return status code
+ */
+static int netvsc_recv_completion ( struct vmbus_device *vmdev, uint64_t xid,
+ const void *data, size_t len ) {
+ struct rndis_device *rndis = vmbus_get_drvdata ( vmdev );
+ struct netvsc_device *netvsc = rndis->priv;
+ struct io_buffer *iobuf;
+ int ( * completion ) ( struct netvsc_device *netvsc,
+ const void *data, size_t len );
+ unsigned int xrid = ( xid - NETVSC_BASE_XID );
+ unsigned int tx_id;
+ int rc;
+
+ /* Handle transmit completion, if applicable */
+ tx_id = ( xrid - NETVSC_TX_BASE_XRID );
+ if ( ( tx_id < NETVSC_TX_NUM_DESC ) &&
+ ( ( iobuf = netvsc->tx.iobufs[tx_id] ) != NULL ) ) {
+
+ /* Free buffer ID */
+ netvsc->tx.iobufs[tx_id] = NULL;
+ netvsc->tx.ids[ ( netvsc->tx.id_cons++ ) &
+ ( netvsc->tx.count - 1 ) ] = tx_id;
+
+ /* Hand back to RNDIS */
+ rndis_tx_complete ( rndis, iobuf );
+ return 0;
+ }
+
+ /* Otherwise determine completion handler */
+ if ( xrid == NETVSC_INIT_XRID ) {
+ completion = netvsc_initialised;
+ } else if ( xrid == NETVSC_RX_ESTABLISH_XRID ) {
+ completion = netvsc_rx_established_buffer;
+ } else if ( ( netvsc->wait_xrid != 0 ) &&
+ ( xrid == netvsc->wait_xrid ) ) {
+ completion = netvsc_completed;
+ } else {
+ DBGC ( netvsc, "NETVSC %s received unexpected completion "
+ "(%08llx)\n", netvsc->name, xid );
+ return -EPIPE;
+ }
+
+ /* Hand off to completion handler */
+ rc = completion ( netvsc, data, len );
+
+ /* Record completion handler result if applicable */
+ if ( xrid == netvsc->wait_xrid ) {
+ netvsc->wait_xrid = 0;
+ netvsc->wait_rc = rc;
+ }
+
+ return rc;
+}
+
+/**
+ * Handle received cancellation packet
+ *
+ * @v vmdev VMBus device
+ * @v xid Transaction ID
+ * @ret rc Return status code
+ */
+static int netvsc_recv_cancellation ( struct vmbus_device *vmdev,
+ uint64_t xid ) {
+ struct rndis_device *rndis = vmbus_get_drvdata ( vmdev );
+ struct netvsc_device *netvsc = rndis->priv;
+
+ DBGC ( netvsc, "NETVSC %s received unsupported cancellation packet "
+ "(%08llx):\n", netvsc->name, xid );
+ return -ENOTSUP;
+}
+
+/** VMBus channel operations */
+static struct vmbus_channel_operations netvsc_channel_operations = {
+ .recv_control = netvsc_recv_control,
+ .recv_data = netvsc_recv_data,
+ .recv_completion = netvsc_recv_completion,
+ .recv_cancellation = netvsc_recv_cancellation,
+};
+
+/**
+ * Poll for completed and received packets
+ *
+ * @v rndis RNDIS device
+ */
+static void netvsc_poll ( struct rndis_device *rndis ) {
+ struct netvsc_device *netvsc = rndis->priv;
+ struct vmbus_device *vmdev = netvsc->vmdev;
+
+ /* Poll VMBus device */
+ while ( vmbus_has_data ( vmdev ) )
+ vmbus_poll ( vmdev );
+}
+
+/**
+ * Transmit packet
+ *
+ * @v rndis RNDIS device
+ * @v iobuf I/O buffer
+ * @ret rc Return status code
+ *
+ * If this method returns success then the RNDIS device must
+ * eventually report completion via rndis_tx_complete().
+ */
+static int netvsc_transmit ( struct rndis_device *rndis,
+ struct io_buffer *iobuf ) {
+ struct netvsc_device *netvsc = rndis->priv;
+ struct rndis_header *header = iobuf->data;
+ struct netvsc_rndis_message msg;
+ unsigned int tx_id;
+ unsigned int xrid;
+ uint64_t xid;
+ int rc;
+
+ /* Sanity check */
+ assert ( iob_len ( iobuf ) >= sizeof ( *header ) );
+ assert ( iob_len ( iobuf ) == le32_to_cpu ( header->len ) );
+
+ /* Check that we have space in the transmit ring */
+ if ( netvsc_ring_is_full ( &netvsc->tx ) )
+ return rndis_tx_defer ( rndis, iobuf );
+
+ /* Allocate buffer ID and calculate transaction ID */
+ tx_id = netvsc->tx.ids[ netvsc->tx.id_prod & ( netvsc->tx.count - 1 ) ];
+ assert ( netvsc->tx.iobufs[tx_id] == NULL );
+ xrid = ( NETVSC_TX_BASE_XRID + tx_id );
+ xid = ( NETVSC_BASE_XID + xrid );
+
+ /* Construct message */
+ memset ( &msg, 0, sizeof ( msg ) );
+ msg.header.type = cpu_to_le32 ( NETVSC_RNDIS_MSG );
+ msg.channel = ( ( header->type == cpu_to_le32 ( RNDIS_PACKET_MSG ) ) ?
+ NETVSC_RNDIS_DATA : NETVSC_RNDIS_CONTROL );
+ msg.buffer = cpu_to_le32 ( NETVSC_RNDIS_NO_BUFFER );
+
+ /* Send message */
+ if ( ( rc = vmbus_send_data ( netvsc->vmdev, xid, &msg, sizeof ( msg ),
+ iobuf ) ) != 0 ) {
+ DBGC ( netvsc, "NETVSC %s could not send RNDIS message: %s\n",
+ netvsc->name, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Store I/O buffer and consume buffer ID */
+ netvsc->tx.iobufs[tx_id] = iobuf;
+ netvsc->tx.id_prod++;
+
+ return 0;
+}
+
+/**
+ * Cancel transmission
+ *
+ * @v netvsc NetVSC device
+ * @v iobuf I/O buffer
+ * @v tx_id Transmission ID
+ */
+static void netvsc_cancel_transmit ( struct netvsc_device *netvsc,
+ struct io_buffer *iobuf,
+ unsigned int tx_id ) {
+ unsigned int xrid;
+ uint64_t xid;
+
+ /* Send cancellation */
+ xrid = ( NETVSC_TX_BASE_XRID + tx_id );
+ xid = ( NETVSC_BASE_XID + xrid );
+ DBGC ( netvsc, "NETVSC %s cancelling transmission %#x\n",
+ netvsc->name, tx_id );
+ vmbus_send_cancellation ( netvsc->vmdev, xid );
+
+ /* Report back to RNDIS */
+ rndis_tx_complete_err ( netvsc->rndis, iobuf, -ECANCELED );
+}
+
+/**
+ * Create descriptor ring
+ *
+ * @v netvsc NetVSC device
+ * @v ring Descriptor ring
+ * @ret rc Return status code
+ */
+static int netvsc_create_ring ( struct netvsc_device *netvsc __unused,
+ struct netvsc_ring *ring ) {
+ unsigned int i;
+
+ /* Initialise buffer ID ring */
+ for ( i = 0 ; i < ring->count ; i++ ) {
+ ring->ids[i] = i;
+ assert ( ring->iobufs[i] == NULL );
+ }
+ ring->id_prod = 0;
+ ring->id_cons = 0;
+
+ return 0;
+}
+
+/**
+ * Destroy descriptor ring
+ *
+ * @v netvsc NetVSC device
+ * @v ring Descriptor ring
+ * @v discard Method used to discard outstanding buffer, or NULL
+ */
+static void netvsc_destroy_ring ( struct netvsc_device *netvsc,
+ struct netvsc_ring *ring,
+ void ( * discard ) ( struct netvsc_device *,
+ struct io_buffer *,
+ unsigned int ) ) {
+ struct io_buffer *iobuf;
+ unsigned int i;
+
+ /* Flush any outstanding buffers */
+ for ( i = 0 ; i < ring->count ; i++ ) {
+ iobuf = ring->iobufs[i];
+ if ( ! iobuf )
+ continue;
+ ring->iobufs[i] = NULL;
+ ring->ids[ ( ring->id_cons++ ) & ( ring->count - 1 ) ] = i;
+ if ( discard )
+ discard ( netvsc, iobuf, i );
+ }
+
+ /* Sanity check */
+ assert ( netvsc_ring_is_empty ( ring ) );
+}
+
+/**
+ * Copy data from data buffer
+ *
+ * @v pages Transfer page set
+ * @v data Data buffer
+ * @v offset Offset within page set
+ * @v len Length within page set
+ * @ret rc Return status code
+ */
+static int netvsc_buffer_copy ( struct vmbus_xfer_pages *pages, void *data,
+ size_t offset, size_t len ) {
+ struct netvsc_buffer *buffer =
+ container_of ( pages, struct netvsc_buffer, pages );
+
+ /* Sanity check */
+ if ( ( offset > buffer->len ) || ( len > ( buffer->len - offset ) ) )
+ return -ERANGE;
+
+ /* Copy data from buffer */
+ copy_from_user ( data, buffer->data, offset, len );
+
+ return 0;
+}
+
+/** Transfer page set operations */
+static struct vmbus_xfer_pages_operations netvsc_xfer_pages_operations = {
+ .copy = netvsc_buffer_copy,
+};
+
+/**
+ * Create data buffer
+ *
+ * @v netvsc NetVSC device
+ * @v buffer Data buffer
+ * @ret rc Return status code
+ */
+static int netvsc_create_buffer ( struct netvsc_device *netvsc,
+ struct netvsc_buffer *buffer ) {
+ struct vmbus_device *vmdev = netvsc->vmdev;
+ int gpadl;
+ int rc;
+
+ /* Allocate receive buffer */
+ buffer->data = umalloc ( buffer->len );
+ if ( ! buffer->data ) {
+ DBGC ( netvsc, "NETVSC %s could not allocate %zd-byte buffer\n",
+ netvsc->name, buffer->len );
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+
+ /* Establish GPA descriptor list */
+ gpadl = vmbus_establish_gpadl ( vmdev, buffer->data, buffer->len );
+ if ( gpadl < 0 ) {
+ rc = gpadl;
+ DBGC ( netvsc, "NETVSC %s could not establish GPADL: %s\n",
+ netvsc->name, strerror ( rc ) );
+ goto err_establish_gpadl;
+ }
+ buffer->gpadl = gpadl;
+
+ /* Register transfer page set */
+ if ( ( rc = vmbus_register_pages ( vmdev, &buffer->pages ) ) != 0 ) {
+ DBGC ( netvsc, "NETVSC %s could not register transfer pages: "
+ "%s\n", netvsc->name, strerror ( rc ) );
+ goto err_register_pages;
+ }
+
+ return 0;
+
+ vmbus_unregister_pages ( vmdev, &buffer->pages );
+ err_register_pages:
+ vmbus_gpadl_teardown ( vmdev, gpadl );
+ err_establish_gpadl:
+ ufree ( buffer->data );
+ err_alloc:
+ return rc;
+}
+
+/**
+ * Destroy data buffer
+ *
+ * @v netvsc NetVSC device
+ * @v buffer Data buffer
+ */
+static void netvsc_destroy_buffer ( struct netvsc_device *netvsc,
+ struct netvsc_buffer *buffer ) {
+ struct vmbus_device *vmdev = netvsc->vmdev;
+ int rc;
+
+ /* Unregister transfer pages */
+ vmbus_unregister_pages ( vmdev, &buffer->pages );
+
+ /* Tear down GPA descriptor list */
+ if ( ( rc = vmbus_gpadl_teardown ( vmdev, buffer->gpadl ) ) != 0 ) {
+ DBGC ( netvsc, "NETVSC %s could not tear down GPADL: %s\n",
+ netvsc->name, strerror ( rc ) );
+ /* Death is imminent. The host may well continue to
+ * write to the data buffer. The best we can do is
+ * leak memory for now and hope that the host doesn't
+ * write to this region after we load an OS.
+ */
+ return;
+ }
+
+ /* Free buffer */
+ ufree ( buffer->data );
+}
+
+/**
+ * Open device
+ *
+ * @v rndis RNDIS device
+ * @ret rc Return status code
+ */
+static int netvsc_open ( struct rndis_device *rndis ) {
+ struct netvsc_device *netvsc = rndis->priv;
+ int rc;
+
+ /* Initialise receive buffer */
+ if ( ( rc = netvsc_create_buffer ( netvsc, &netvsc->rx ) ) != 0 )
+ goto err_create_rx;
+
+ /* Open channel */
+ if ( ( rc = vmbus_open ( netvsc->vmdev, &netvsc_channel_operations,
+ PAGE_SIZE, PAGE_SIZE, NETVSC_MTU ) ) != 0 ) {
+ DBGC ( netvsc, "NETVSC %s could not open VMBus: %s\n",
+ netvsc->name, strerror ( rc ) );
+ goto err_vmbus_open;
+ }
+
+ /* Initialise communication with NetVSP */
+ if ( ( rc = netvsc_initialise ( netvsc ) ) != 0 )
+ goto err_initialise;
+ if ( ( rc = netvsc_ndis_version ( netvsc ) ) != 0 )
+ goto err_ndis_version;
+
+ /* Initialise transmit ring */
+ if ( ( rc = netvsc_create_ring ( netvsc, &netvsc->tx ) ) != 0 )
+ goto err_create_tx;
+
+ /* Establish receive buffer */
+ if ( ( rc = netvsc_establish_buffer ( netvsc, &netvsc->rx ) ) != 0 )
+ goto err_establish_rx;
+
+ return 0;
+
+ netvsc_revoke_buffer ( netvsc, &netvsc->rx );
+ err_establish_rx:
+ netvsc_destroy_ring ( netvsc, &netvsc->tx, NULL );
+ err_create_tx:
+ err_ndis_version:
+ err_initialise:
+ vmbus_close ( netvsc->vmdev );
+ err_vmbus_open:
+ netvsc_destroy_buffer ( netvsc, &netvsc->rx );
+ err_create_rx:
+ return rc;
+}
+
+/**
+ * Close device
+ *
+ * @v rndis RNDIS device
+ */
+static void netvsc_close ( struct rndis_device *rndis ) {
+ struct netvsc_device *netvsc = rndis->priv;
+
+ /* Revoke receive buffer */
+ netvsc_revoke_buffer ( netvsc, &netvsc->rx );
+
+ /* Destroy transmit ring */
+ netvsc_destroy_ring ( netvsc, &netvsc->tx, netvsc_cancel_transmit );
+
+ /* Close channel */
+ vmbus_close ( netvsc->vmdev );
+
+ /* Destroy receive buffer */
+ netvsc_destroy_buffer ( netvsc, &netvsc->rx );
+}
+
+/** RNDIS operations */
+static struct rndis_operations netvsc_operations = {
+ .open = netvsc_open,
+ .close = netvsc_close,
+ .transmit = netvsc_transmit,
+ .poll = netvsc_poll,
+};
+
+/**
+ * Probe device
+ *
+ * @v vmdev VMBus device
+ * @ret rc Return status code
+ */
+static int netvsc_probe ( struct vmbus_device *vmdev ) {
+ struct netvsc_device *netvsc;
+ struct rndis_device *rndis;
+ int rc;
+
+ /* Allocate and initialise structure */
+ rndis = alloc_rndis ( sizeof ( *netvsc ) );
+ if ( ! rndis ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ rndis_init ( rndis, &netvsc_operations );
+ rndis->netdev->dev = &vmdev->dev;
+ netvsc = rndis->priv;
+ netvsc->vmdev = vmdev;
+ netvsc->rndis = rndis;
+ netvsc->name = vmdev->dev.name;
+ netvsc_init_ring ( &netvsc->tx, NETVSC_TX_NUM_DESC,
+ netvsc->tx_iobufs, netvsc->tx_ids );
+ netvsc_init_buffer ( &netvsc->rx, NETVSC_RX_BUF_PAGESET,
+ &netvsc_xfer_pages_operations,
+ NETVSC_RX_ESTABLISH_MSG, NETVSC_RX_ESTABLISH_XRID,
+ NETVSC_RX_REVOKE_MSG, NETVSC_RX_REVOKE_XRID,
+ NETVSC_RX_BUF_LEN );
+ vmbus_set_drvdata ( vmdev, rndis );
+
+ /* Register RNDIS device */
+ if ( ( rc = register_rndis ( rndis ) ) != 0 ) {
+ DBGC ( netvsc, "NETVSC %s could not register: %s\n",
+ netvsc->name, strerror ( rc ) );
+ goto err_register;
+ }
+
+ return 0;
+
+ unregister_rndis ( rndis );
+ err_register:
+ free_rndis ( rndis );
+ err_alloc:
+ return rc;
+}
+
+/**
+ * Remove device
+ *
+ * @v vmdev VMBus device
+ */
+static void netvsc_remove ( struct vmbus_device *vmdev ) {
+ struct rndis_device *rndis = vmbus_get_drvdata ( vmdev );
+
+ /* Unregister RNDIS device */
+ unregister_rndis ( rndis );
+
+ /* Free RNDIS device */
+ free_rndis ( rndis );
+}
+
+/** NetVSC driver */
+struct vmbus_driver netvsc_driver __vmbus_driver = {
+ .name = "netvsc",
+ .type = VMBUS_TYPE ( 0xf8615163, 0xdf3e, 0x46c5, 0x913f,
+ 0xf2, 0xd2, 0xf9, 0x65, 0xed, 0x0e ),
+ .probe = netvsc_probe,
+ .remove = netvsc_remove,
+};
diff --git a/roms/ipxe/src/drivers/net/netvsc.h b/roms/ipxe/src/drivers/net/netvsc.h
new file mode 100644
index 000000000..39eeb891c
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/netvsc.h
@@ -0,0 +1,365 @@
+#ifndef _NETVSC_H
+#define _NETVSC_H
+
+/** @file
+ *
+ * Hyper-V network virtual service client
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/** Maximum supported NetVSC message length */
+#define NETVSC_MTU 512
+
+/** Maximum time to wait for a transaction to complete
+ *
+ * This is a policy decision.
+ */
+#define NETVSC_MAX_WAIT_MS 1000
+
+/** Number of transmit ring entries
+ *
+ * Must be a power of two. This is a policy decision. This value
+ * must be sufficiently small to guarantee that we never run out of
+ * space in the VMBus outbound ring buffer.
+ */
+#define NETVSC_TX_NUM_DESC 32
+
+/** RX data buffer page set ID
+ *
+ * This is a policy decision.
+ */
+#define NETVSC_RX_BUF_PAGESET 0xbead
+
+/** RX data buffer length
+ *
+ * This is a policy decision.
+ */
+#define NETVSC_RX_BUF_LEN ( 16 * PAGE_SIZE )
+
+/** Base transaction ID
+ *
+ * This is a policy decision.
+ */
+#define NETVSC_BASE_XID 0x18ae0000UL
+
+/** Relative transaction IDs */
+enum netvsc_xrid {
+ /** Transmit descriptors (one per transmit buffer ID) */
+ NETVSC_TX_BASE_XRID = 0,
+ /** Initialisation */
+ NETVSC_INIT_XRID = ( NETVSC_TX_BASE_XRID + NETVSC_TX_NUM_DESC ),
+ /** NDIS version */
+ NETVSC_NDIS_VERSION_XRID,
+ /** Establish receive buffer */
+ NETVSC_RX_ESTABLISH_XRID,
+ /** Revoke receive buffer */
+ NETVSC_RX_REVOKE_XRID,
+};
+
+/** NetVSC status codes */
+enum netvsc_status {
+ NETVSC_NONE = 0,
+ NETVSC_OK = 1,
+ NETVSC_FAIL = 2,
+ NETVSC_TOO_NEW = 3,
+ NETVSC_TOO_OLD = 4,
+ NETVSC_BAD_PACKET = 5,
+ NETVSC_BUSY = 6,
+ NETVSC_UNSUPPORTED = 7,
+};
+
+/** NetVSC message header */
+struct netvsc_header {
+ /** Type */
+ uint32_t type;
+} __attribute__ (( packed ));
+
+/** NetVSC initialisation message */
+#define NETVSC_INIT_MSG 1
+
+/** NetVSC initialisation message */
+struct netvsc_init_message {
+ /** Message header */
+ struct netvsc_header header;
+ /** Minimum supported protocol version */
+ uint32_t min;
+ /** Maximum supported protocol version */
+ uint32_t max;
+ /** Reserved */
+ uint8_t reserved[20];
+} __attribute__ (( packed ));
+
+/** Oldest known NetVSC protocol version */
+#define NETVSC_VERSION_1 2 /* sic */
+
+/** NetVSC initialisation completion */
+#define NETVSC_INIT_CMPLT 2
+
+/** NetVSC initialisation completion */
+struct netvsc_init_completion {
+ /** Message header */
+ struct netvsc_header header;
+ /** Protocol version */
+ uint32_t version;
+ /** Maximum memory descriptor list length */
+ uint32_t max_mdl_len;
+ /** Status */
+ uint32_t status;
+ /** Reserved */
+ uint8_t reserved[16];
+} __attribute__ (( packed ));
+
+/** NetVSC NDIS version message */
+#define NETVSC_NDIS_VERSION_MSG 100
+
+/** NetVSC NDIS version message */
+struct netvsc_ndis_version_message {
+ /** Message header */
+ struct netvsc_header header;
+ /** Major version */
+ uint32_t major;
+ /** Minor version */
+ uint32_t minor;
+ /** Reserved */
+ uint8_t reserved[20];
+} __attribute__ (( packed ));
+
+/** NetVSC NDIS major version */
+#define NETVSC_NDIS_MAJOR 6
+
+/** NetVSC NDIS minor version */
+#define NETVSC_NDIS_MINOR 1
+
+/** NetVSC establish receive data buffer message */
+#define NETVSC_RX_ESTABLISH_MSG 101
+
+/** NetVSC establish receive data buffer completion */
+#define NETVSC_RX_ESTABLISH_CMPLT 102
+
+/** NetVSC revoke receive data buffer message */
+#define NETVSC_RX_REVOKE_MSG 103
+
+/** NetVSC establish transmit data buffer message */
+#define NETVSC_TX_ESTABLISH_MSG 104
+
+/** NetVSC establish transmit data buffer completion */
+#define NETVSC_TX_ESTABLISH_CMPLT 105
+
+/** NetVSC revoke transmit data buffer message */
+#define NETVSC_TX_REVOKE_MSG 106
+
+/** NetVSC establish data buffer message */
+struct netvsc_establish_buffer_message {
+ /** Message header */
+ struct netvsc_header header;
+ /** GPADL ID */
+ uint32_t gpadl;
+ /** Page set ID */
+ uint16_t pageset;
+ /** Reserved */
+ uint8_t reserved[22];
+} __attribute__ (( packed ));
+
+/** NetVSC receive data buffer section */
+struct netvsc_rx_buffer_section {
+ /** Starting offset */
+ uint32_t start;
+ /** Subsection length */
+ uint32_t len;
+ /** Number of subsections */
+ uint32_t count;
+ /** Ending offset */
+ uint32_t end;
+} __attribute__ (( packed ));
+
+/** NetVSC establish receive data buffer completion */
+struct netvsc_rx_establish_buffer_completion {
+ /** Message header */
+ struct netvsc_header header;
+ /** Status */
+ uint32_t status;
+ /** Number of sections (must be 1) */
+ uint32_t count;
+ /** Section descriptors */
+ struct netvsc_rx_buffer_section section[1];
+} __attribute__ (( packed ));
+
+/** NetVSC establish transmit data buffer completion */
+struct netvsc_tx_establish_buffer_completion {
+ /** Message header */
+ struct netvsc_header header;
+ /** Status */
+ uint32_t status;
+ /** Section length */
+ uint32_t len;
+} __attribute__ (( packed ));
+
+/** NetVSC revoke data buffer message */
+struct netvsc_revoke_buffer_message {
+ /** Message header */
+ struct netvsc_header header;
+ /** Page set ID */
+ uint16_t pageset;
+ /** Reserved */
+ uint8_t reserved[26];
+} __attribute__ (( packed ));
+
+/** NetVSC RNDIS message */
+#define NETVSC_RNDIS_MSG 107
+
+/** NetVSC RNDIS message */
+struct netvsc_rndis_message {
+ /** Message header */
+ struct netvsc_header header;
+ /** RNDIS channel */
+ uint32_t channel;
+ /** Buffer index (or NETVSC_RNDIS_NO_BUFFER) */
+ uint32_t buffer;
+ /** Buffer length */
+ uint32_t len;
+ /** Reserved */
+ uint8_t reserved[16];
+} __attribute__ (( packed ));
+
+/** RNDIS data channel (for RNDIS_PACKET_MSG only) */
+#define NETVSC_RNDIS_DATA 0
+
+/** RNDIS control channel (for all other RNDIS messages) */
+#define NETVSC_RNDIS_CONTROL 1
+
+/** "No buffer used" index */
+#define NETVSC_RNDIS_NO_BUFFER 0xffffffffUL
+
+/** A NetVSC descriptor ring */
+struct netvsc_ring {
+ /** Number of descriptors */
+ unsigned int count;
+ /** I/O buffers, indexed by buffer ID */
+ struct io_buffer **iobufs;
+ /** Buffer ID ring */
+ uint8_t *ids;
+ /** Buffer ID producer counter */
+ unsigned int id_prod;
+ /** Buffer ID consumer counter */
+ unsigned int id_cons;
+};
+
+/**
+ * Initialise descriptor ring
+ *
+ * @v ring Descriptor ring
+ * @v count Maximum number of used descriptors
+ * @v iobufs I/O buffers
+ * @v ids Buffer IDs
+ */
+static inline __attribute__ (( always_inline )) void
+netvsc_init_ring ( struct netvsc_ring *ring, unsigned int count,
+ struct io_buffer **iobufs, uint8_t *ids ) {
+
+ ring->count = count;
+ ring->iobufs = iobufs;
+ ring->ids = ids;
+}
+
+/**
+ * Check whether or not descriptor ring is full
+ *
+ * @v ring Descriptor ring
+ * @v is_full Ring is full
+ */
+static inline __attribute__ (( always_inline )) int
+netvsc_ring_is_full ( struct netvsc_ring *ring ) {
+ unsigned int fill_level;
+
+ fill_level = ( ring->id_prod - ring->id_cons );
+ assert ( fill_level <= ring->count );
+ return ( fill_level >= ring->count );
+}
+
+/**
+ * Check whether or not descriptor ring is empty
+ *
+ * @v ring Descriptor ring
+ * @v is_empty Ring is empty
+ */
+static inline __attribute__ (( always_inline )) int
+netvsc_ring_is_empty ( struct netvsc_ring *ring ) {
+
+ return ( ring->id_prod == ring->id_cons );
+}
+
+/** A NetVSC data buffer */
+struct netvsc_buffer {
+ /** Transfer page set */
+ struct vmbus_xfer_pages pages;
+ /** Establish data buffer message type */
+ uint8_t establish_type;
+ /** Establish data buffer relative transaction ID */
+ uint8_t establish_xrid;
+ /** Revoke data buffer message type */
+ uint8_t revoke_type;
+ /** Revoke data buffer relative transaction ID */
+ uint8_t revoke_xrid;
+ /** Buffer length */
+ size_t len;
+ /** Buffer */
+ userptr_t data;
+ /** GPADL ID */
+ unsigned int gpadl;
+};
+
+/**
+ * Initialise data buffer
+ *
+ * @v buffer Data buffer
+ * @v pageset Page set ID
+ * @v op Page set operations
+ * @v establish_type Establish data buffer message type
+ * @v establish_xrid Establish data buffer relative transaction ID
+ * @v revoke_type Revoke data buffer message type
+ * @v revoke_type Revoke data buffer relative transaction ID
+ * @v len Required length
+ */
+static inline __attribute__ (( always_inline )) void
+netvsc_init_buffer ( struct netvsc_buffer *buffer, uint16_t pageset,
+ struct vmbus_xfer_pages_operations *op,
+ uint8_t establish_type, uint8_t establish_xrid,
+ uint8_t revoke_type, uint8_t revoke_xrid, size_t len ) {
+
+ buffer->pages.pageset = cpu_to_le16 ( pageset );
+ buffer->pages.op = op;
+ buffer->establish_type = establish_type;
+ buffer->establish_xrid = establish_xrid;
+ buffer->revoke_type = revoke_type;
+ buffer->revoke_xrid = revoke_xrid;
+ buffer->len = len;
+}
+
+/** A NetVSC device */
+struct netvsc_device {
+ /** VMBus device */
+ struct vmbus_device *vmdev;
+ /** RNDIS device */
+ struct rndis_device *rndis;
+ /** Name */
+ const char *name;
+
+ /** Transmit ring */
+ struct netvsc_ring tx;
+ /** Transmit buffer IDs */
+ uint8_t tx_ids[NETVSC_TX_NUM_DESC];
+ /** Transmit I/O buffers */
+ struct io_buffer *tx_iobufs[NETVSC_TX_NUM_DESC];
+
+ /** Receive buffer */
+ struct netvsc_buffer rx;
+
+ /** Relative transaction ID for current blocking transaction */
+ unsigned int wait_xrid;
+ /** Return status code for current blocking transaction */
+ int wait_rc;
+};
+
+#endif /* _NETVSC_H */
diff --git a/roms/ipxe/src/drivers/net/phantom/nx_bitops.h b/roms/ipxe/src/drivers/net/phantom/nx_bitops.h
index 15f3d3767..1687b6952 100644
--- a/roms/ipxe/src/drivers/net/phantom/nx_bitops.h
+++ b/roms/ipxe/src/drivers/net/phantom/nx_bitops.h
@@ -18,9 +18,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @file
diff --git a/roms/ipxe/src/drivers/net/phantom/phantom.c b/roms/ipxe/src/drivers/net/phantom/phantom.c
index e70ded08c..38b66743c 100644
--- a/roms/ipxe/src/drivers/net/phantom/phantom.c
+++ b/roms/ipxe/src/drivers/net/phantom/phantom.c
@@ -16,9 +16,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/drivers/net/phantom/phantom.h b/roms/ipxe/src/drivers/net/phantom/phantom.h
index 1647168ba..967603409 100644
--- a/roms/ipxe/src/drivers/net/phantom/phantom.h
+++ b/roms/ipxe/src/drivers/net/phantom/phantom.h
@@ -19,9 +19,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @file
diff --git a/roms/ipxe/src/drivers/net/phantom/phantom_hw.h b/roms/ipxe/src/drivers/net/phantom/phantom_hw.h
index 7dfff52b2..016730de3 100644
--- a/roms/ipxe/src/drivers/net/phantom/phantom_hw.h
+++ b/roms/ipxe/src/drivers/net/phantom/phantom_hw.h
@@ -19,9 +19,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @file
diff --git a/roms/ipxe/src/drivers/net/pnic.c b/roms/ipxe/src/drivers/net/pnic.c
index 4170cc640..ca64299ea 100644
--- a/roms/ipxe/src/drivers/net/pnic.c
+++ b/roms/ipxe/src/drivers/net/pnic.c
@@ -6,8 +6,18 @@ Bochs Pseudo NIC driver for Etherboot
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2, or (at
- * your option) any later version.
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
*
* See pnic_api.h for an explanation of the Bochs Pseudo NIC.
*/
diff --git a/roms/ipxe/src/drivers/net/prism2.c b/roms/ipxe/src/drivers/net/prism2.c
index ab974264c..4331f2cd0 100644
--- a/roms/ipxe/src/drivers/net/prism2.c
+++ b/roms/ipxe/src/drivers/net/prism2.c
@@ -9,8 +9,18 @@ $Id$
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2, or (at
- * your option) any later version.
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/drivers/net/prism2_pci.c b/roms/ipxe/src/drivers/net/prism2_pci.c
index 72549babf..69ddf0fb0 100644
--- a/roms/ipxe/src/drivers/net/prism2_pci.c
+++ b/roms/ipxe/src/drivers/net/prism2_pci.c
@@ -10,8 +10,18 @@ $Id$
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2, or (at
- * your option) any later version.
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
@@ -40,8 +50,6 @@ static void prism2_pci_disable ( struct nic *nic ) {
static struct pci_device_id prism2_pci_nics[] = {
PCI_ROM(0x1260, 0x3873, "prism2_pci", "Harris Semiconductor Prism2.5 clone", 0),
-PCI_ROM(0x1260, 0x3873, "hwp01170", "ActionTec HWP01170", 0),
-PCI_ROM(0x1260, 0x3873, "dwl520", "DLink DWL-520", 0),
};
PCI_DRIVER ( prism2_pci_driver, prism2_pci_nics, PCI_NO_CLASS );
diff --git a/roms/ipxe/src/drivers/net/prism2_plx.c b/roms/ipxe/src/drivers/net/prism2_plx.c
index 2098f7f09..a73b0e087 100644
--- a/roms/ipxe/src/drivers/net/prism2_plx.c
+++ b/roms/ipxe/src/drivers/net/prism2_plx.c
@@ -10,8 +10,18 @@ $Id$
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2, or (at
- * your option) any later version.
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
@@ -44,10 +54,10 @@ static int prism2_find_plx ( hfa384x_t *hw, struct pci_device *p )
/* Obtain all memory and IO base addresses */
pci_read_config_dword( p, PLX_LOCAL_CONFIG_REGISTER_BASE, &plx_lcr);
- plx_lcr &= PCI_BASE_ADDRESS_IO_MASK;
+ plx_lcr &= ~PCI_BASE_ADDRESS_IO_MASK;
pci_read_config_dword( p, PRISM2_PLX_ATTR_MEM_BASE, &attr_mem);
pci_read_config_dword( p, PRISM2_PLX_IO_BASE, &iobase);
- iobase &= PCI_BASE_ADDRESS_IO_MASK;
+ iobase &= ~PCI_BASE_ADDRESS_IO_MASK;
/* Fill out hw structure */
hw->iobase = iobase;
diff --git a/roms/ipxe/src/drivers/net/realtek.c b/roms/ipxe/src/drivers/net/realtek.c
index 0aca8c77f..022b59324 100644
--- a/roms/ipxe/src/drivers/net/realtek.c
+++ b/roms/ipxe/src/drivers/net/realtek.c
@@ -17,9 +17,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <string.h>
@@ -194,7 +198,6 @@ static int realtek_init_eeprom ( struct net_device *netdev ) {
DBGC ( rtl, "REALTEK %p EEPROM is a 93C46\n", rtl );
init_at93c46 ( &rtl->eeprom, 16 );
}
- rtl->eeprom.bus = &rtl->spibit.bus;
/* Check for EEPROM presence. Some onboard NICs will have no
* EEPROM connected, with the BIOS being responsible for
@@ -1085,6 +1088,7 @@ static void realtek_detect ( struct realtek_nic *rtl ) {
rtl );
rtl->legacy = 1;
}
+ rtl->eeprom.bus = &rtl->spibit.bus;
}
}
@@ -1132,7 +1136,8 @@ static int realtek_probe ( struct pci_device *pci ) {
realtek_detect ( rtl );
/* Initialise EEPROM */
- if ( ( rc = realtek_init_eeprom ( netdev ) ) == 0 ) {
+ if ( rtl->eeprom.bus &&
+ ( ( rc = realtek_init_eeprom ( netdev ) ) == 0 ) ) {
/* Read MAC address from EEPROM */
if ( ( rc = nvs_read ( &rtl->eeprom.nvs, RTL_EEPROM_MAC,
diff --git a/roms/ipxe/src/drivers/net/realtek.h b/roms/ipxe/src/drivers/net/realtek.h
index ac33405e8..b1ce7f98f 100644
--- a/roms/ipxe/src/drivers/net/realtek.h
+++ b/roms/ipxe/src/drivers/net/realtek.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/spi.h>
#include <ipxe/spi_bit.h>
diff --git a/roms/ipxe/src/drivers/net/rtl818x/rtl8180.c b/roms/ipxe/src/drivers/net/rtl818x/rtl8180.c
index 8851d1bfb..5f97480fa 100644
--- a/roms/ipxe/src/drivers/net/rtl818x/rtl8180.c
+++ b/roms/ipxe/src/drivers/net/rtl818x/rtl8180.c
@@ -3,15 +3,23 @@
FILE_LICENCE(GPL2_OR_LATER);
#include <ipxe/pci.h>
+#include "rtl818x.h"
-REQUIRE_OBJECT(rtl818x);
-REQUIRE_OBJECT(rtl8180_grf5101);
-REQUIRE_OBJECT(rtl8180_max2820);
-REQUIRE_OBJECT(rtl8180_sa2400);
-
-static struct pci_device_id rtl8180_nics[] __unused = {
+static struct pci_device_id rtl8180_nics[] = {
PCI_ROM(0x10ec, 0x8180, "rtl8180", "Realtek 8180", 0),
PCI_ROM(0x1799, 0x6001, "f5d6001", "Belkin F5D6001", 0),
PCI_ROM(0x1799, 0x6020, "f5d6020", "Belkin F5D6020", 0),
PCI_ROM(0x1186, 0x3300, "dwl510", "D-Link DWL-510", 0),
};
+
+struct pci_driver rtl8180_driver __pci_driver = {
+ .ids = rtl8180_nics,
+ .id_count = sizeof(rtl8180_nics) / sizeof(rtl8180_nics[0]),
+ .probe = rtl818x_probe,
+ .remove = rtl818x_remove,
+};
+
+REQUIRING_SYMBOL(rtl8180_driver);
+REQUIRE_OBJECT(rtl8180_grf5101);
+REQUIRE_OBJECT(rtl8180_max2820);
+REQUIRE_OBJECT(rtl8180_sa2400);
diff --git a/roms/ipxe/src/drivers/net/rtl818x/rtl8185.c b/roms/ipxe/src/drivers/net/rtl818x/rtl8185.c
index fd27e5c8c..234978cea 100644
--- a/roms/ipxe/src/drivers/net/rtl818x/rtl8185.c
+++ b/roms/ipxe/src/drivers/net/rtl818x/rtl8185.c
@@ -3,12 +3,20 @@
FILE_LICENCE(GPL2_OR_LATER);
#include <ipxe/pci.h>
-
-REQUIRE_OBJECT(rtl818x);
-REQUIRE_OBJECT(rtl8185_rtl8225);
+#include "rtl818x.h"
static struct pci_device_id rtl8185_nics[] __unused = {
PCI_ROM(0x10ec, 0x8185, "rtl8185", "Realtek 8185", 0),
PCI_ROM(0x1799, 0x700f, "f5d7000", "Belkin F5D7000", 0),
PCI_ROM(0x1799, 0x701f, "f5d7010", "Belkin F5D7010", 0),
};
+
+struct pci_driver rtl8185_driver __pci_driver = {
+ .ids = rtl8185_nics,
+ .id_count = sizeof(rtl8185_nics) / sizeof(rtl8185_nics[0]),
+ .probe = rtl818x_probe,
+ .remove = rtl818x_remove,
+};
+
+REQUIRING_SYMBOL(rtl8185_driver);
+REQUIRE_OBJECT(rtl8185_rtl8225);
diff --git a/roms/ipxe/src/drivers/net/rtl818x/rtl818x.c b/roms/ipxe/src/drivers/net/rtl818x/rtl818x.c
index cf4c7556f..8b3c206d4 100644
--- a/roms/ipxe/src/drivers/net/rtl818x/rtl818x.c
+++ b/roms/ipxe/src/drivers/net/rtl818x/rtl818x.c
@@ -649,7 +649,7 @@ struct net80211_device_operations rtl818x_operations = {
.config = rtl818x_config,
};
-static int rtl818x_probe(struct pci_device *pdev )
+int rtl818x_probe(struct pci_device *pdev )
{
struct net80211_device *dev;
struct rtl818x_priv *priv;
@@ -820,7 +820,7 @@ static int rtl818x_probe(struct pci_device *pdev )
return err;
}
-static void rtl818x_remove(struct pci_device *pdev)
+void rtl818x_remove(struct pci_device *pdev)
{
struct net80211_device *dev = pci_get_drvdata(pdev);
@@ -830,25 +830,3 @@ static void rtl818x_remove(struct pci_device *pdev)
net80211_unregister(dev);
net80211_free(dev);
}
-
-/* Hide PCI_ROM definitions in here from parserom.pl; the definitions
- that should be used are in rtl8180.c and rtl8185.c. */
-#define RTL_ROM PCI_ROM
-
-static struct pci_device_id rtl818x_nics[] = {
- RTL_ROM(0x10ec, 0x8185, "rtl8185", "Realtek 8185", 0),
- RTL_ROM(0x1799, 0x700f, "f5d7000", "Belkin F5D7000", 0),
- RTL_ROM(0x1799, 0x701f, "f5d7010", "Belkin F5D7010", 0),
-
- RTL_ROM(0x10ec, 0x8180, "rtl8180", "Realtek 8180", 0),
- RTL_ROM(0x1799, 0x6001, "f5d6001", "Belkin F5D6001", 0),
- RTL_ROM(0x1799, 0x6020, "f5d6020", "Belkin F5D6020", 0),
- RTL_ROM(0x1186, 0x3300, "dwl510", "D-Link DWL-510", 0),
-};
-
-struct pci_driver rtl818x_driver __pci_driver = {
- .ids = rtl818x_nics,
- .id_count = sizeof(rtl818x_nics) / sizeof(rtl818x_nics[0]),
- .probe = rtl818x_probe,
- .remove = rtl818x_remove,
-};
diff --git a/roms/ipxe/src/drivers/net/rtl818x/rtl818x.h b/roms/ipxe/src/drivers/net/rtl818x/rtl818x.h
index 4e57d0bd3..ae4b8a96f 100644
--- a/roms/ipxe/src/drivers/net/rtl818x/rtl818x.h
+++ b/roms/ipxe/src/drivers/net/rtl818x/rtl818x.h
@@ -19,6 +19,7 @@
#include <ipxe/spi_bit.h>
#include <ipxe/tables.h>
+#include <ipxe/net80211.h>
FILE_LICENCE(GPL2_ONLY);
@@ -356,4 +357,7 @@ struct rtl818x_rf_ops {
void (*conf_erp)(struct net80211_device *dev); /* set based on dev->erp_flags */
};
+extern int rtl818x_probe(struct pci_device *pdev );
+extern void rtl818x_remove(struct pci_device *pdev);
+
#endif /* RTL818X_H */
diff --git a/roms/ipxe/src/drivers/net/skeleton.c b/roms/ipxe/src/drivers/net/skeleton.c
index 365111b8d..0435b9d0e 100644
--- a/roms/ipxe/src/drivers/net/skeleton.c
+++ b/roms/ipxe/src/drivers/net/skeleton.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <string.h>
diff --git a/roms/ipxe/src/drivers/net/skeleton.h b/roms/ipxe/src/drivers/net/skeleton.h
index 3de2afa5b..2ab01bd56 100644
--- a/roms/ipxe/src/drivers/net/skeleton.h
+++ b/roms/ipxe/src/drivers/net/skeleton.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** Skeleton BAR size */
#define SKELETON_BAR_SIZE 256
diff --git a/roms/ipxe/src/drivers/net/smsc75xx.c b/roms/ipxe/src/drivers/net/smsc75xx.c
new file mode 100644
index 000000000..017e02a59
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/smsc75xx.c
@@ -0,0 +1,1057 @@
+/*
+ * Copyright (C) 2015 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/usb.h>
+#include <ipxe/usbnet.h>
+#include <ipxe/profile.h>
+#include "smsc75xx.h"
+
+/** @file
+ *
+ * SMSC LAN75xx USB Ethernet driver
+ *
+ */
+
+/** Interrupt completion profiler */
+static struct profiler smsc75xx_intr_profiler __profiler =
+ { .name = "smsc75xx.intr" };
+
+/** Bulk IN completion profiler */
+static struct profiler smsc75xx_in_profiler __profiler =
+ { .name = "smsc75xx.in" };
+
+/** Bulk OUT profiler */
+static struct profiler smsc75xx_out_profiler __profiler =
+ { .name = "smsc75xx.out" };
+
+/******************************************************************************
+ *
+ * Register access
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Write register (without byte-swapping)
+ *
+ * @v smsc75xx SMSC75xx device
+ * @v address Register address
+ * @v value Register value
+ * @ret rc Return status code
+ */
+static int smsc75xx_raw_writel ( struct smsc75xx_device *smsc75xx,
+ unsigned int address, uint32_t value ) {
+ int rc;
+
+ /* Write register */
+ if ( ( rc = usb_control ( smsc75xx->usb, SMSC75XX_REGISTER_WRITE, 0,
+ address, &value, sizeof ( value ) ) ) != 0 ) {
+ DBGC ( smsc75xx, "SMSC75XX %p could not write %03x: %s\n",
+ smsc75xx, address, strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Write register
+ *
+ * @v smsc75xx SMSC75xx device
+ * @v address Register address
+ * @v value Register value
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+smsc75xx_writel ( struct smsc75xx_device *smsc75xx, unsigned int address,
+ uint32_t value ) {
+ int rc;
+
+ /* Write register */
+ if ( ( rc = smsc75xx_raw_writel ( smsc75xx, address,
+ cpu_to_le32 ( value ) ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/**
+ * Read register (without byte-swapping)
+ *
+ * @v smsc75xx SMSC75xx device
+ * @v address Register address
+ * @ret value Register value
+ * @ret rc Return status code
+ */
+static int smsc75xx_raw_readl ( struct smsc75xx_device *smsc75xx,
+ unsigned int address, uint32_t *value ) {
+ int rc;
+
+ /* Read register */
+ if ( ( rc = usb_control ( smsc75xx->usb, SMSC75XX_REGISTER_READ, 0,
+ address, value, sizeof ( *value ) ) ) != 0 ) {
+ DBGC ( smsc75xx, "SMSC75XX %p could not read %03x: %s\n",
+ smsc75xx, address, strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Read register
+ *
+ * @v smsc75xx SMSC75xx device
+ * @v address Register address
+ * @ret value Register value
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+smsc75xx_readl ( struct smsc75xx_device *smsc75xx, unsigned int address,
+ uint32_t *value ) {
+ int rc;
+
+ /* Read register */
+ if ( ( rc = smsc75xx_raw_readl ( smsc75xx, address, value ) ) != 0 )
+ return rc;
+ le32_to_cpus ( value );
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * EEPROM access
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Wait for EEPROM to become idle
+ *
+ * @v smsc75xx SMSC75xx device
+ * @ret rc Return status code
+ */
+static int smsc75xx_eeprom_wait ( struct smsc75xx_device *smsc75xx ) {
+ uint32_t e2p_cmd;
+ unsigned int i;
+ int rc;
+
+ /* Wait for EPC_BSY to become clear */
+ for ( i = 0 ; i < SMSC75XX_EEPROM_MAX_WAIT_MS ; i++ ) {
+
+ /* Read E2P_CMD and check EPC_BSY */
+ if ( ( rc = smsc75xx_readl ( smsc75xx, SMSC75XX_E2P_CMD,
+ &e2p_cmd ) ) != 0 )
+ return rc;
+ if ( ! ( e2p_cmd & SMSC75XX_E2P_CMD_EPC_BSY ) )
+ return 0;
+
+ /* Delay */
+ mdelay ( 1 );
+ }
+
+ DBGC ( smsc75xx, "SMSC75XX %p timed out waiting for EEPROM\n",
+ smsc75xx );
+ return -ETIMEDOUT;
+}
+
+/**
+ * Read byte from EEPROM
+ *
+ * @v smsc75xx SMSC75xx device
+ * @v address EEPROM address
+ * @ret byte Byte read, or negative error
+ */
+static int smsc75xx_eeprom_read_byte ( struct smsc75xx_device *smsc75xx,
+ unsigned int address ) {
+ uint32_t e2p_cmd;
+ uint32_t e2p_data;
+ int rc;
+
+ /* Wait for EEPROM to become idle */
+ if ( ( rc = smsc75xx_eeprom_wait ( smsc75xx ) ) != 0 )
+ return rc;
+
+ /* Initiate read command */
+ e2p_cmd = ( SMSC75XX_E2P_CMD_EPC_BSY | SMSC75XX_E2P_CMD_EPC_CMD_READ |
+ SMSC75XX_E2P_CMD_EPC_ADDR ( address ) );
+ if ( ( rc = smsc75xx_writel ( smsc75xx, SMSC75XX_E2P_CMD,
+ e2p_cmd ) ) != 0 )
+ return rc;
+
+ /* Wait for command to complete */
+ if ( ( rc = smsc75xx_eeprom_wait ( smsc75xx ) ) != 0 )
+ return rc;
+
+ /* Read EEPROM data */
+ if ( ( rc = smsc75xx_readl ( smsc75xx, SMSC75XX_E2P_DATA,
+ &e2p_data ) ) != 0 )
+ return rc;
+
+ return SMSC75XX_E2P_DATA_GET ( e2p_data );
+}
+
+/**
+ * Read data from EEPROM
+ *
+ * @v smsc75xx SMSC75xx device
+ * @v address EEPROM address
+ * @v data Data buffer
+ * @v len Length of data
+ * @ret rc Return status code
+ */
+static int smsc75xx_eeprom_read ( struct smsc75xx_device *smsc75xx,
+ unsigned int address, void *data,
+ size_t len ) {
+ uint8_t *bytes;
+ int byte;
+
+ /* Read bytes */
+ for ( bytes = data ; len-- ; address++, bytes++ ) {
+ byte = smsc75xx_eeprom_read_byte ( smsc75xx, address );
+ if ( byte < 0 )
+ return byte;
+ *bytes = byte;
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * MII access
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Wait for MII to become idle
+ *
+ * @v smsc75xx SMSC75xx device
+ * @ret rc Return status code
+ */
+static int smsc75xx_mii_wait ( struct smsc75xx_device *smsc75xx ) {
+ uint32_t mii_access;
+ unsigned int i;
+ int rc;
+
+ /* Wait for MIIBZY to become clear */
+ for ( i = 0 ; i < SMSC75XX_MII_MAX_WAIT_MS ; i++ ) {
+
+ /* Read MII_ACCESS and check MIIBZY */
+ if ( ( rc = smsc75xx_readl ( smsc75xx, SMSC75XX_MII_ACCESS,
+ &mii_access ) ) != 0 )
+ return rc;
+ if ( ! ( mii_access & SMSC75XX_MII_ACCESS_MIIBZY ) )
+ return 0;
+
+ /* Delay */
+ mdelay ( 1 );
+ }
+
+ DBGC ( smsc75xx, "SMSC75XX %p timed out waiting for MII\n",
+ smsc75xx );
+ return -ETIMEDOUT;
+}
+
+/**
+ * Read from MII register
+ *
+ * @v mii MII interface
+ * @v reg Register address
+ * @ret value Data read, or negative error
+ */
+static int smsc75xx_mii_read ( struct mii_interface *mii, unsigned int reg ) {
+ struct smsc75xx_device *smsc75xx =
+ container_of ( mii, struct smsc75xx_device, mii );
+ uint32_t mii_access;
+ uint32_t mii_data;
+ int rc;
+
+ /* Wait for MII to become idle */
+ if ( ( rc = smsc75xx_mii_wait ( smsc75xx ) ) != 0 )
+ return rc;
+
+ /* Initiate read command */
+ mii_access = ( SMSC75XX_MII_ACCESS_PHY_ADDRESS |
+ SMSC75XX_MII_ACCESS_MIIRINDA ( reg ) |
+ SMSC75XX_MII_ACCESS_MIIBZY );
+ if ( ( rc = smsc75xx_writel ( smsc75xx, SMSC75XX_MII_ACCESS,
+ mii_access ) ) != 0 )
+ return rc;
+
+ /* Wait for command to complete */
+ if ( ( rc = smsc75xx_mii_wait ( smsc75xx ) ) != 0 )
+ return rc;
+
+ /* Read MII data */
+ if ( ( rc = smsc75xx_readl ( smsc75xx, SMSC75XX_MII_DATA,
+ &mii_data ) ) != 0 )
+ return rc;
+
+ return SMSC75XX_MII_DATA_GET ( mii_data );
+}
+
+/**
+ * Write to MII register
+ *
+ * @v mii MII interface
+ * @v reg Register address
+ * @v data Data to write
+ * @ret rc Return status code
+ */
+static int smsc75xx_mii_write ( struct mii_interface *mii, unsigned int reg,
+ unsigned int data ) {
+ struct smsc75xx_device *smsc75xx =
+ container_of ( mii, struct smsc75xx_device, mii );
+ uint32_t mii_access;
+ uint32_t mii_data;
+ int rc;
+
+ /* Wait for MII to become idle */
+ if ( ( rc = smsc75xx_mii_wait ( smsc75xx ) ) != 0 )
+ return rc;
+
+ /* Write MII data */
+ mii_data = SMSC75XX_MII_DATA_SET ( data );
+ if ( ( rc = smsc75xx_writel ( smsc75xx, SMSC75XX_MII_DATA,
+ mii_data ) ) != 0 )
+ return rc;
+
+ /* Initiate write command */
+ mii_access = ( SMSC75XX_MII_ACCESS_PHY_ADDRESS |
+ SMSC75XX_MII_ACCESS_MIIRINDA ( reg ) |
+ SMSC75XX_MII_ACCESS_MIIWNR |
+ SMSC75XX_MII_ACCESS_MIIBZY );
+ if ( ( rc = smsc75xx_writel ( smsc75xx, SMSC75XX_MII_ACCESS,
+ mii_access ) ) != 0 )
+ return rc;
+
+ /* Wait for command to complete */
+ if ( ( rc = smsc75xx_mii_wait ( smsc75xx ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/** MII operations */
+static struct mii_operations smsc75xx_mii_operations = {
+ .read = smsc75xx_mii_read,
+ .write = smsc75xx_mii_write,
+};
+
+/**
+ * Check link status
+ *
+ * @v smsc75xx SMSC75xx device
+ * @ret rc Return status code
+ */
+static int smsc75xx_check_link ( struct smsc75xx_device *smsc75xx ) {
+ struct net_device *netdev = smsc75xx->netdev;
+ int intr;
+ int rc;
+
+ /* Read PHY interrupt source */
+ intr = mii_read ( &smsc75xx->mii, SMSC75XX_MII_PHY_INTR_SOURCE );
+ if ( intr < 0 ) {
+ rc = intr;
+ DBGC ( smsc75xx, "SMSC75XX %p could not get PHY interrupt "
+ "source: %s\n", smsc75xx, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Acknowledge PHY interrupt */
+ if ( ( rc = mii_write ( &smsc75xx->mii, SMSC75XX_MII_PHY_INTR_SOURCE,
+ intr ) ) != 0 ) {
+ DBGC ( smsc75xx, "SMSC75XX %p could not acknowledge PHY "
+ "interrupt: %s\n", smsc75xx, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Check link status */
+ if ( ( rc = mii_check_link ( &smsc75xx->mii, netdev ) ) != 0 ) {
+ DBGC ( smsc75xx, "SMSC75XX %p could not check link: %s\n",
+ smsc75xx, strerror ( rc ) );
+ return rc;
+ }
+
+ DBGC ( smsc75xx, "SMSC75XX %p link %s (intr %#04x)\n",
+ smsc75xx, ( netdev_link_ok ( netdev ) ? "up" : "down" ), intr );
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * Statistics (for debugging)
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Get statistics
+ *
+ * @v smsc75xx SMSC75xx device
+ * @v stats Statistics to fill in
+ * @ret rc Return status code
+ */
+static int smsc75xx_get_statistics ( struct smsc75xx_device *smsc75xx,
+ struct smsc75xx_statistics *stats ) {
+ int rc;
+
+ /* Get statistics */
+ if ( ( rc = usb_control ( smsc75xx->usb, SMSC75XX_GET_STATISTICS, 0, 0,
+ stats, sizeof ( *stats ) ) ) != 0 ) {
+ DBGC ( smsc75xx, "SMSC75XX %p could not get statistics: %s\n",
+ smsc75xx, strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Dump statistics (for debugging)
+ *
+ * @v smsc75xx SMSC75xx device
+ * @ret rc Return status code
+ */
+static int smsc75xx_dump_statistics ( struct smsc75xx_device *smsc75xx ) {
+ struct smsc75xx_statistics stats;
+ int rc;
+
+ /* Do nothing unless debugging is enabled */
+ if ( ! DBG_LOG )
+ return 0;
+
+ /* Get statistics */
+ if ( ( rc = smsc75xx_get_statistics ( smsc75xx, &stats ) ) != 0 )
+ return rc;
+
+ /* Dump statistics */
+ DBGC ( smsc75xx, "SMSC75XX %p RXE fcs %d aln %d frg %d jab %d und %d "
+ "ovr %d drp %d\n", smsc75xx, le32_to_cpu ( stats.rx.err.fcs ),
+ le32_to_cpu ( stats.rx.err.alignment ),
+ le32_to_cpu ( stats.rx.err.fragment ),
+ le32_to_cpu ( stats.rx.err.jabber ),
+ le32_to_cpu ( stats.rx.err.undersize ),
+ le32_to_cpu ( stats.rx.err.oversize ),
+ le32_to_cpu ( stats.rx.err.dropped ) );
+ DBGC ( smsc75xx, "SMSC75XX %p RXB ucast %d bcast %d mcast %d\n",
+ smsc75xx, le32_to_cpu ( stats.rx.byte.unicast ),
+ le32_to_cpu ( stats.rx.byte.broadcast ),
+ le32_to_cpu ( stats.rx.byte.multicast ) );
+ DBGC ( smsc75xx, "SMSC75XX %p RXF ucast %d bcast %d mcast %d pause "
+ "%d\n", smsc75xx, le32_to_cpu ( stats.rx.frame.unicast ),
+ le32_to_cpu ( stats.rx.frame.broadcast ),
+ le32_to_cpu ( stats.rx.frame.multicast ),
+ le32_to_cpu ( stats.rx.frame.pause ) );
+ DBGC ( smsc75xx, "SMSC75XX %p TXE fcs %d def %d car %d cnt %d sgl %d "
+ "mul %d exc %d lat %d\n", smsc75xx,
+ le32_to_cpu ( stats.tx.err.fcs ),
+ le32_to_cpu ( stats.tx.err.deferral ),
+ le32_to_cpu ( stats.tx.err.carrier ),
+ le32_to_cpu ( stats.tx.err.count ),
+ le32_to_cpu ( stats.tx.err.single ),
+ le32_to_cpu ( stats.tx.err.multiple ),
+ le32_to_cpu ( stats.tx.err.excessive ),
+ le32_to_cpu ( stats.tx.err.late ) );
+ DBGC ( smsc75xx, "SMSC75XX %p TXB ucast %d bcast %d mcast %d\n",
+ smsc75xx, le32_to_cpu ( stats.tx.byte.unicast ),
+ le32_to_cpu ( stats.tx.byte.broadcast ),
+ le32_to_cpu ( stats.tx.byte.multicast ) );
+ DBGC ( smsc75xx, "SMSC75XX %p TXF ucast %d bcast %d mcast %d pause "
+ "%d\n", smsc75xx, le32_to_cpu ( stats.tx.frame.unicast ),
+ le32_to_cpu ( stats.tx.frame.broadcast ),
+ le32_to_cpu ( stats.tx.frame.multicast ),
+ le32_to_cpu ( stats.tx.frame.pause ) );
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * Device reset
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Reset device
+ *
+ * @v smsc75xx SMSC75xx device
+ * @ret rc Return status code
+ */
+static int smsc75xx_reset ( struct smsc75xx_device *smsc75xx ) {
+ uint32_t hw_cfg;
+ int rc;
+
+ /* Reset device */
+ if ( ( rc = smsc75xx_writel ( smsc75xx, SMSC75XX_HW_CFG,
+ SMSC75XX_HW_CFG_LRST ) ) != 0 )
+ return rc;
+
+ /* Wait for reset to complete */
+ udelay ( SMSC75XX_RESET_DELAY_US );
+
+ /* Check that reset has completed */
+ if ( ( rc = smsc75xx_readl ( smsc75xx, SMSC75XX_HW_CFG,
+ &hw_cfg ) ) != 0 )
+ return rc;
+ if ( hw_cfg & SMSC75XX_HW_CFG_LRST ) {
+ DBGC ( smsc75xx, "SMSC75XX %p failed to reset\n", smsc75xx );
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * Endpoint operations
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Complete interrupt transfer
+ *
+ * @v ep USB endpoint
+ * @v iobuf I/O buffer
+ * @v rc Completion status code
+ */
+static void smsc75xx_intr_complete ( struct usb_endpoint *ep,
+ struct io_buffer *iobuf, int rc ) {
+ struct smsc75xx_device *smsc75xx =
+ container_of ( ep, struct smsc75xx_device, usbnet.intr );
+ struct net_device *netdev = smsc75xx->netdev;
+ struct smsc75xx_interrupt *intr;
+
+ /* Profile completions */
+ profile_start ( &smsc75xx_intr_profiler );
+
+ /* Ignore packets cancelled when the endpoint closes */
+ if ( ! ep->open )
+ goto done;
+
+ /* Record USB errors against the network device */
+ if ( rc != 0 ) {
+ DBGC ( smsc75xx, "SMSC75XX %p interrupt failed: %s\n",
+ smsc75xx, strerror ( rc ) );
+ DBGC_HDA ( smsc75xx, 0, iobuf->data, iob_len ( iobuf ) );
+ netdev_rx_err ( netdev, NULL, rc );
+ goto done;
+ }
+
+ /* Extract interrupt data */
+ if ( iob_len ( iobuf ) != sizeof ( *intr ) ) {
+ DBGC ( smsc75xx, "SMSC75XX %p malformed interrupt\n",
+ smsc75xx );
+ DBGC_HDA ( smsc75xx, 0, iobuf->data, iob_len ( iobuf ) );
+ netdev_rx_err ( netdev, NULL, rc );
+ goto done;
+ }
+ intr = iobuf->data;
+
+ /* Record interrupt status */
+ smsc75xx->int_sts = le32_to_cpu ( intr->int_sts );
+ profile_stop ( &smsc75xx_intr_profiler );
+
+ done:
+ /* Free I/O buffer */
+ free_iob ( iobuf );
+}
+
+/** Interrupt endpoint operations */
+static struct usb_endpoint_driver_operations smsc75xx_intr_operations = {
+ .complete = smsc75xx_intr_complete,
+};
+
+/**
+ * Complete bulk IN transfer
+ *
+ * @v ep USB endpoint
+ * @v iobuf I/O buffer
+ * @v rc Completion status code
+ */
+static void smsc75xx_in_complete ( struct usb_endpoint *ep,
+ struct io_buffer *iobuf, int rc ) {
+ struct smsc75xx_device *smsc75xx =
+ container_of ( ep, struct smsc75xx_device, usbnet.in );
+ struct net_device *netdev = smsc75xx->netdev;
+ struct smsc75xx_rx_header *header;
+
+ /* Profile completions */
+ profile_start ( &smsc75xx_in_profiler );
+
+ /* Ignore packets cancelled when the endpoint closes */
+ if ( ! ep->open ) {
+ free_iob ( iobuf );
+ return;
+ }
+
+ /* Record USB errors against the network device */
+ if ( rc != 0 ) {
+ DBGC ( smsc75xx, "SMSC75XX %p bulk IN failed: %s\n",
+ smsc75xx, strerror ( rc ) );
+ goto err;
+ }
+
+ /* Sanity check */
+ if ( iob_len ( iobuf ) < ( sizeof ( *header ) ) ) {
+ DBGC ( smsc75xx, "SMSC75XX %p underlength bulk IN\n",
+ smsc75xx );
+ DBGC_HDA ( smsc75xx, 0, iobuf->data, iob_len ( iobuf ) );
+ rc = -EINVAL;
+ goto err;
+ }
+
+ /* Strip header */
+ header = iobuf->data;
+ iob_pull ( iobuf, sizeof ( *header ) );
+
+ /* Check for errors */
+ if ( header->command & cpu_to_le32 ( SMSC75XX_RX_RED ) ) {
+ DBGC ( smsc75xx, "SMSC75XX %p receive error (%08x):\n",
+ smsc75xx, le32_to_cpu ( header->command ) );
+ DBGC_HDA ( smsc75xx, 0, iobuf->data, iob_len ( iobuf ) );
+ rc = -EIO;
+ goto err;
+ }
+
+ /* Hand off to network stack */
+ netdev_rx ( netdev, iob_disown ( iobuf ) );
+
+ profile_stop ( &smsc75xx_in_profiler );
+ return;
+
+ err:
+ /* Hand off to network stack */
+ netdev_rx_err ( netdev, iob_disown ( iobuf ), rc );
+}
+
+/** Bulk IN endpoint operations */
+static struct usb_endpoint_driver_operations smsc75xx_in_operations = {
+ .complete = smsc75xx_in_complete,
+};
+
+/**
+ * Transmit packet
+ *
+ * @v smsc75xx SMSC75xx device
+ * @v iobuf I/O buffer
+ * @ret rc Return status code
+ */
+static int smsc75xx_out_transmit ( struct smsc75xx_device *smsc75xx,
+ struct io_buffer *iobuf ) {
+ struct smsc75xx_tx_header *header;
+ size_t len = iob_len ( iobuf );
+ int rc;
+
+ /* Profile transmissions */
+ profile_start ( &smsc75xx_out_profiler );
+
+ /* Prepend header */
+ if ( ( rc = iob_ensure_headroom ( iobuf, sizeof ( *header ) ) ) != 0 )
+ return rc;
+ header = iob_push ( iobuf, sizeof ( *header ) );
+ header->command = cpu_to_le32 ( SMSC75XX_TX_FCS | len );
+ header->tag = 0;
+ header->mss = 0;
+
+ /* Enqueue I/O buffer */
+ if ( ( rc = usb_stream ( &smsc75xx->usbnet.out, iobuf, 0 ) ) != 0 )
+ return rc;
+
+ profile_stop ( &smsc75xx_out_profiler );
+ return 0;
+}
+
+/**
+ * Complete bulk OUT transfer
+ *
+ * @v ep USB endpoint
+ * @v iobuf I/O buffer
+ * @v rc Completion status code
+ */
+static void smsc75xx_out_complete ( struct usb_endpoint *ep,
+ struct io_buffer *iobuf, int rc ) {
+ struct smsc75xx_device *smsc75xx =
+ container_of ( ep, struct smsc75xx_device, usbnet.out );
+ struct net_device *netdev = smsc75xx->netdev;
+
+ /* Report TX completion */
+ netdev_tx_complete_err ( netdev, iobuf, rc );
+}
+
+/** Bulk OUT endpoint operations */
+static struct usb_endpoint_driver_operations smsc75xx_out_operations = {
+ .complete = smsc75xx_out_complete,
+};
+
+/******************************************************************************
+ *
+ * Network device interface
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Open network device
+ *
+ * @v netdev Network device
+ * @ret rc Return status code
+ */
+static int smsc75xx_open ( struct net_device *netdev ) {
+ struct smsc75xx_device *smsc75xx = netdev->priv;
+ union smsc75xx_mac mac;
+ int rc;
+
+ /* Clear stored interrupt status */
+ smsc75xx->int_sts = 0;
+
+ /* Copy MAC address */
+ memset ( &mac, 0, sizeof ( mac ) );
+ memcpy ( mac.raw, netdev->ll_addr, ETH_ALEN );
+
+ /* Configure bulk IN empty response */
+ if ( ( rc = smsc75xx_writel ( smsc75xx, SMSC75XX_HW_CFG,
+ SMSC75XX_HW_CFG_BIR ) ) != 0 )
+ goto err_hw_cfg;
+
+ /* Open USB network device */
+ if ( ( rc = usbnet_open ( &smsc75xx->usbnet ) ) != 0 ) {
+ DBGC ( smsc75xx, "SMSC75XX %p could not open: %s\n",
+ smsc75xx, strerror ( rc ) );
+ goto err_open;
+ }
+
+ /* Configure interrupt endpoint */
+ if ( ( rc = smsc75xx_writel ( smsc75xx, SMSC75XX_INT_EP_CTL,
+ ( SMSC75XX_INT_EP_CTL_RDFO_EN |
+ SMSC75XX_INT_EP_CTL_PHY_EN ) ) ) != 0 )
+ goto err_int_ep_ctl;
+
+ /* Configure bulk IN delay */
+ if ( ( rc = smsc75xx_writel ( smsc75xx, SMSC75XX_BULK_IN_DLY,
+ SMSC75XX_BULK_IN_DLY_SET ( 0 ) ) ) != 0 )
+ goto err_bulk_in_dly;
+
+ /* Configure receive filters */
+ if ( ( rc = smsc75xx_writel ( smsc75xx, SMSC75XX_RFE_CTL,
+ ( SMSC75XX_RFE_CTL_AB |
+ SMSC75XX_RFE_CTL_AM |
+ SMSC75XX_RFE_CTL_AU ) ) ) != 0 )
+ goto err_rfe_ctl;
+
+ /* Configure receive FIFO */
+ if ( ( rc = smsc75xx_writel ( smsc75xx, SMSC75XX_FCT_RX_CTL,
+ ( SMSC75XX_FCT_RX_CTL_EN |
+ SMSC75XX_FCT_RX_CTL_BAD ) ) ) != 0 )
+ goto err_fct_rx_ctl;
+
+ /* Configure transmit FIFO */
+ if ( ( rc = smsc75xx_writel ( smsc75xx, SMSC75XX_FCT_TX_CTL,
+ SMSC75XX_FCT_TX_CTL_EN ) ) != 0 )
+ goto err_fct_tx_ctl;
+
+ /* Configure receive datapath */
+ if ( ( rc = smsc75xx_writel ( smsc75xx, SMSC75XX_MAC_RX,
+ ( SMSC75XX_MAC_RX_MAX_SIZE_DEFAULT |
+ SMSC75XX_MAC_RX_FCS |
+ SMSC75XX_MAC_RX_EN ) ) ) != 0 )
+ goto err_mac_rx;
+
+ /* Configure transmit datapath */
+ if ( ( rc = smsc75xx_writel ( smsc75xx, SMSC75XX_MAC_TX,
+ SMSC75XX_MAC_TX_EN ) ) != 0 )
+ goto err_mac_tx;
+
+ /* Write MAC address high register */
+ if ( ( rc = smsc75xx_raw_writel ( smsc75xx, SMSC75XX_RX_ADDRH,
+ mac.addr.h ) ) != 0 )
+ goto err_rx_addrh;
+
+ /* Write MAC address low register */
+ if ( ( rc = smsc75xx_raw_writel ( smsc75xx, SMSC75XX_RX_ADDRL,
+ mac.addr.l ) ) != 0 )
+ goto err_rx_addrl;
+
+ /* Write MAC address perfect filter high register */
+ mac.addr.h |= cpu_to_le32 ( SMSC75XX_ADDR_FILTH_VALID );
+ if ( ( rc = smsc75xx_raw_writel ( smsc75xx, SMSC75XX_ADDR_FILTH ( 0 ),
+ mac.addr.h ) ) != 0 )
+ goto err_addr_filth;
+
+ /* Write MAC address perfect filter low register */
+ if ( ( rc = smsc75xx_raw_writel ( smsc75xx, SMSC75XX_ADDR_FILTL ( 0 ),
+ mac.addr.l ) ) != 0 )
+ goto err_addr_filtl;
+
+ /* Enable PHY interrupts */
+ if ( ( rc = mii_write ( &smsc75xx->mii, SMSC75XX_MII_PHY_INTR_MASK,
+ ( SMSC75XX_PHY_INTR_ANEG_DONE |
+ SMSC75XX_PHY_INTR_LINK_DOWN ) ) ) != 0 ) {
+ DBGC ( smsc75xx, "SMSC75XX %p could not set PHY interrupt "
+ "mask: %s\n", smsc75xx, strerror ( rc ) );
+ goto err_phy_intr_mask;
+ }
+
+ /* Update link status */
+ smsc75xx_check_link ( smsc75xx );
+
+ return 0;
+
+ err_phy_intr_mask:
+ err_addr_filtl:
+ err_addr_filth:
+ err_rx_addrl:
+ err_rx_addrh:
+ err_mac_tx:
+ err_mac_rx:
+ err_fct_tx_ctl:
+ err_fct_rx_ctl:
+ err_rfe_ctl:
+ err_bulk_in_dly:
+ err_int_ep_ctl:
+ usbnet_close ( &smsc75xx->usbnet );
+ err_open:
+ err_hw_cfg:
+ smsc75xx_reset ( smsc75xx );
+ return rc;
+}
+
+/**
+ * Close network device
+ *
+ * @v netdev Network device
+ */
+static void smsc75xx_close ( struct net_device *netdev ) {
+ struct smsc75xx_device *smsc75xx = netdev->priv;
+
+ /* Close USB network device */
+ usbnet_close ( &smsc75xx->usbnet );
+
+ /* Dump statistics (for debugging) */
+ smsc75xx_dump_statistics ( smsc75xx );
+
+ /* Reset device */
+ smsc75xx_reset ( smsc75xx );
+}
+
+/**
+ * Transmit packet
+ *
+ * @v netdev Network device
+ * @v iobuf I/O buffer
+ * @ret rc Return status code
+ */
+static int smsc75xx_transmit ( struct net_device *netdev,
+ struct io_buffer *iobuf ) {
+ struct smsc75xx_device *smsc75xx = netdev->priv;
+ int rc;
+
+ /* Transmit packet */
+ if ( ( rc = smsc75xx_out_transmit ( smsc75xx, iobuf ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/**
+ * Poll for completed and received packets
+ *
+ * @v netdev Network device
+ */
+static void smsc75xx_poll ( struct net_device *netdev ) {
+ struct smsc75xx_device *smsc75xx = netdev->priv;
+ uint32_t int_sts;
+ int rc;
+
+ /* Poll USB bus */
+ usb_poll ( smsc75xx->bus );
+
+ /* Refill endpoints */
+ if ( ( rc = usbnet_refill ( &smsc75xx->usbnet ) ) != 0 )
+ netdev_rx_err ( netdev, NULL, rc );
+
+ /* Do nothing more unless there are interrupts to handle */
+ int_sts = smsc75xx->int_sts;
+ if ( ! int_sts )
+ return;
+
+ /* Check link status if applicable */
+ if ( int_sts & SMSC75XX_INT_STS_PHY_INT ) {
+ smsc75xx_check_link ( smsc75xx );
+ int_sts &= ~SMSC75XX_INT_STS_PHY_INT;
+ }
+
+ /* Record RX FIFO overflow if applicable */
+ if ( int_sts & SMSC75XX_INT_STS_RDFO_INT ) {
+ DBGC2 ( smsc75xx, "SMSC75XX %p RX FIFO overflowed\n",
+ smsc75xx );
+ netdev_rx_err ( netdev, NULL, -ENOBUFS );
+ int_sts &= ~SMSC75XX_INT_STS_RDFO_INT;
+ }
+
+ /* Check for unexpected interrupts */
+ if ( int_sts ) {
+ DBGC ( smsc75xx, "SMSC75XX %p unexpected interrupt %#08x\n",
+ smsc75xx, int_sts );
+ netdev_rx_err ( netdev, NULL, -ENOTTY );
+ }
+
+ /* Clear interrupts */
+ if ( ( rc = smsc75xx_writel ( smsc75xx, SMSC75XX_INT_STS,
+ smsc75xx->int_sts ) ) != 0 )
+ netdev_rx_err ( netdev, NULL, rc );
+ smsc75xx->int_sts = 0;
+}
+
+/** SMSC75xx network device operations */
+static struct net_device_operations smsc75xx_operations = {
+ .open = smsc75xx_open,
+ .close = smsc75xx_close,
+ .transmit = smsc75xx_transmit,
+ .poll = smsc75xx_poll,
+};
+
+/******************************************************************************
+ *
+ * USB interface
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Probe device
+ *
+ * @v func USB function
+ * @v config Configuration descriptor
+ * @ret rc Return status code
+ */
+static int smsc75xx_probe ( struct usb_function *func,
+ struct usb_configuration_descriptor *config ) {
+ struct usb_device *usb = func->usb;
+ struct net_device *netdev;
+ struct smsc75xx_device *smsc75xx;
+ int rc;
+
+ /* Allocate and initialise structure */
+ netdev = alloc_etherdev ( sizeof ( *smsc75xx ) );
+ if ( ! netdev ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ netdev_init ( netdev, &smsc75xx_operations );
+ netdev->dev = &func->dev;
+ smsc75xx = netdev->priv;
+ memset ( smsc75xx, 0, sizeof ( *smsc75xx ) );
+ smsc75xx->usb = usb;
+ smsc75xx->bus = usb->port->hub->bus;
+ smsc75xx->netdev = netdev;
+ usbnet_init ( &smsc75xx->usbnet, func, &smsc75xx_intr_operations,
+ &smsc75xx_in_operations, &smsc75xx_out_operations );
+ usb_refill_init ( &smsc75xx->usbnet.intr, 0, SMSC75XX_INTR_MAX_FILL );
+ usb_refill_init ( &smsc75xx->usbnet.in, SMSC75XX_IN_MTU,
+ SMSC75XX_IN_MAX_FILL );
+ mii_init ( &smsc75xx->mii, &smsc75xx_mii_operations );
+ DBGC ( smsc75xx, "SMSC75XX %p on %s\n", smsc75xx, func->name );
+
+ /* Describe USB network device */
+ if ( ( rc = usbnet_describe ( &smsc75xx->usbnet, config ) ) != 0 ) {
+ DBGC ( smsc75xx, "SMSC75XX %p could not describe: %s\n",
+ smsc75xx, strerror ( rc ) );
+ goto err_describe;
+ }
+
+ /* Reset device */
+ if ( ( rc = smsc75xx_reset ( smsc75xx ) ) != 0 )
+ goto err_reset;
+
+ /* Read MAC address */
+ if ( ( rc = smsc75xx_eeprom_read ( smsc75xx, SMSC75XX_EEPROM_MAC,
+ netdev->hw_addr, ETH_ALEN ) ) != 0 )
+ goto err_eeprom_read;
+
+ /* Register network device */
+ if ( ( rc = register_netdev ( netdev ) ) != 0 )
+ goto err_register;
+
+ usb_func_set_drvdata ( func, netdev );
+ return 0;
+
+ unregister_netdev ( netdev );
+ err_register:
+ err_eeprom_read:
+ err_reset:
+ err_describe:
+ netdev_nullify ( netdev );
+ netdev_put ( netdev );
+ err_alloc:
+ return rc;
+}
+
+/**
+ * Remove device
+ *
+ * @v func USB function
+ */
+static void smsc75xx_remove ( struct usb_function *func ) {
+ struct net_device *netdev = usb_func_get_drvdata ( func );
+
+ unregister_netdev ( netdev );
+ netdev_nullify ( netdev );
+ netdev_put ( netdev );
+}
+
+/** SMSC75xx device IDs */
+static struct usb_device_id smsc75xx_ids[] = {
+ {
+ .name = "smsc7500",
+ .vendor = 0x0424,
+ .product = 0x7500,
+ .class = { 0xff, 0x00, 0xff },
+ },
+ {
+ .name = "smsc7505",
+ .vendor = 0x0424,
+ .product = 0x7505,
+ .class = { 0xff, 0x00, 0xff },
+ },
+};
+
+/** SMSC LAN75xx driver */
+struct usb_driver smsc75xx_driver __usb_driver = {
+ .ids = smsc75xx_ids,
+ .id_count = ( sizeof ( smsc75xx_ids ) / sizeof ( smsc75xx_ids[0] ) ),
+ .probe = smsc75xx_probe,
+ .remove = smsc75xx_remove,
+};
diff --git a/roms/ipxe/src/drivers/net/smsc75xx.h b/roms/ipxe/src/drivers/net/smsc75xx.h
new file mode 100644
index 000000000..2463b72a1
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/smsc75xx.h
@@ -0,0 +1,309 @@
+#ifndef _SMSC75XX_H
+#define _SMSC75XX_H
+
+/** @file
+ *
+ * SMSC LAN75xx USB Ethernet driver
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <ipxe/usb.h>
+#include <ipxe/usbnet.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/mii.h>
+
+/** Register write command */
+#define SMSC75XX_REGISTER_WRITE \
+ ( USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE | \
+ USB_REQUEST_TYPE ( 0xa0 ) )
+
+/** Register read command */
+#define SMSC75XX_REGISTER_READ \
+ ( USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE | \
+ USB_REQUEST_TYPE ( 0xa1 ) )
+
+/** Get statistics command */
+#define SMSC75XX_GET_STATISTICS \
+ ( USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE | \
+ USB_REQUEST_TYPE ( 0xa2 ) )
+
+/** Interrupt status register */
+#define SMSC75XX_INT_STS 0x00c
+#define SMSC75XX_INT_STS_RDFO_INT 0x00400000UL /**< RX FIFO overflow */
+#define SMSC75XX_INT_STS_PHY_INT 0x00020000UL /**< PHY interrupt */
+
+/** Hardware configuration register */
+#define SMSC75XX_HW_CFG 0x010
+#define SMSC75XX_HW_CFG_BIR 0x00000080UL /**< Bulk IN use NAK */
+#define SMSC75XX_HW_CFG_LRST 0x00000002UL /**< Soft lite reset */
+
+/** Interrupt endpoint control register */
+#define SMSC75XX_INT_EP_CTL 0x038
+#define SMSC75XX_INT_EP_CTL_RDFO_EN 0x00400000UL /**< RX FIFO overflow */
+#define SMSC75XX_INT_EP_CTL_PHY_EN 0x00020000UL /**< PHY interrupt */
+
+/** Bulk IN delay register */
+#define SMSC75XX_BULK_IN_DLY 0x03c
+#define SMSC75XX_BULK_IN_DLY_SET(ticks) ( (ticks) << 0 ) /**< Delay / 16.7ns */
+
+/** EEPROM command register */
+#define SMSC75XX_E2P_CMD 0x040
+#define SMSC75XX_E2P_CMD_EPC_BSY 0x80000000UL /**< EPC busy */
+#define SMSC75XX_E2P_CMD_EPC_CMD_READ 0x00000000UL /**< READ command */
+#define SMSC75XX_E2P_CMD_EPC_ADDR(addr) ( (addr) << 0 ) /**< EPC address */
+
+/** EEPROM data register */
+#define SMSC75XX_E2P_DATA 0x044
+#define SMSC75XX_E2P_DATA_GET(e2p_data) \
+ ( ( (e2p_data) >> 0 ) & 0xff ) /**< EEPROM data */
+
+/** MAC address EEPROM address */
+#define SMSC75XX_EEPROM_MAC 0x01
+
+/** Receive filtering engine control register */
+#define SMSC75XX_RFE_CTL 0x060
+#define SMSC75XX_RFE_CTL_AB 0x00000400UL /**< Accept broadcast */
+#define SMSC75XX_RFE_CTL_AM 0x00000200UL /**< Accept multicast */
+#define SMSC75XX_RFE_CTL_AU 0x00000100UL /**< Accept unicast */
+
+/** FIFO controller RX FIFO control register */
+#define SMSC75XX_FCT_RX_CTL 0x090
+#define SMSC75XX_FCT_RX_CTL_EN 0x80000000UL /**< FCT RX enable */
+#define SMSC75XX_FCT_RX_CTL_BAD 0x02000000UL /**< Store bad frames */
+
+/** FIFO controller TX FIFO control register */
+#define SMSC75XX_FCT_TX_CTL 0x094
+#define SMSC75XX_FCT_TX_CTL_EN 0x80000000UL /**< FCT TX enable */
+
+/** MAC receive register */
+#define SMSC75XX_MAC_RX 0x104
+#define SMSC75XX_MAC_RX_MAX_SIZE(mtu) ( (mtu) << 16 ) /**< Max frame size */
+#define SMSC75XX_MAC_RX_MAX_SIZE_DEFAULT \
+ SMSC75XX_MAC_RX_MAX_SIZE ( ETH_FRAME_LEN + 4 /* VLAN */ + 4 /* CRC */ )
+#define SMSC75XX_MAC_RX_FCS 0x00000010UL /**< FCS stripping */
+#define SMSC75XX_MAC_RX_EN 0x00000001UL /**< RX enable */
+
+/** MAC transmit register */
+#define SMSC75XX_MAC_TX 0x108
+#define SMSC75XX_MAC_TX_EN 0x00000001UL /**< TX enable */
+
+/** MAC receive address high register */
+#define SMSC75XX_RX_ADDRH 0x118
+
+/** MAC receive address low register */
+#define SMSC75XX_RX_ADDRL 0x11c
+
+/** MII access register */
+#define SMSC75XX_MII_ACCESS 0x120
+#define SMSC75XX_MII_ACCESS_PHY_ADDRESS 0x00000800UL /**< PHY address */
+#define SMSC75XX_MII_ACCESS_MIIRINDA(addr) ( (addr) << 6 ) /**< MII register */
+#define SMSC75XX_MII_ACCESS_MIIWNR 0x00000002UL /**< MII write */
+#define SMSC75XX_MII_ACCESS_MIIBZY 0x00000001UL /**< MII busy */
+
+/** MII data register */
+#define SMSC75XX_MII_DATA 0x124
+#define SMSC75XX_MII_DATA_SET(data) ( (data) << 0 ) /**< Set data */
+#define SMSC75XX_MII_DATA_GET(mii_data) \
+ ( ( (mii_data) >> 0 ) & 0xffff ) /**< Get data */
+
+/** PHY interrupt source MII register */
+#define SMSC75XX_MII_PHY_INTR_SOURCE 29
+
+/** PHY interrupt mask MII register */
+#define SMSC75XX_MII_PHY_INTR_MASK 30
+
+/** PHY interrupt: auto-negotiation complete */
+#define SMSC75XX_PHY_INTR_ANEG_DONE 0x0040
+
+/** PHY interrupt: link down */
+#define SMSC75XX_PHY_INTR_LINK_DOWN 0x0010
+
+/** MAC address perfect filter N high register */
+#define SMSC75XX_ADDR_FILTH(n) ( 0x300 + ( 8 * (n) ) )
+#define SMSC75XX_ADDR_FILTH_VALID 0x80000000UL /**< Address valid */
+
+/** MAC address perfect filter N low register */
+#define SMSC75XX_ADDR_FILTL(n) ( 0x304 + ( 8 * (n) ) )
+
+/** MAC address */
+union smsc75xx_mac {
+ /** MAC receive address registers */
+ struct {
+ /** MAC receive address low register */
+ uint32_t l;
+ /** MAC receive address high register */
+ uint32_t h;
+ } __attribute__ (( packed )) addr;
+ /** Raw MAC address */
+ uint8_t raw[ETH_ALEN];
+};
+
+/** Receive packet header */
+struct smsc75xx_rx_header {
+ /** RX command word */
+ uint32_t command;
+ /** VLAN tag */
+ uint16_t vtag;
+ /** Checksum */
+ uint16_t csum;
+ /** Two-byte padding used to align Ethernet payload */
+ uint16_t pad;
+} __attribute__ (( packed ));
+
+/** Receive error detected */
+#define SMSC75XX_RX_RED 0x00400000UL
+
+/** Transmit packet header */
+struct smsc75xx_tx_header {
+ /** TX command word */
+ uint32_t command;
+ /** VLAN tag */
+ uint16_t tag;
+ /** Maximum segment size */
+ uint16_t mss;
+} __attribute__ (( packed ));
+
+/** Insert frame checksum and pad */
+#define SMSC75XX_TX_FCS 0x00400000UL
+
+/** Interrupt packet format */
+struct smsc75xx_interrupt {
+ /** Current value of INT_STS register */
+ uint32_t int_sts;
+} __attribute__ (( packed ));
+
+/** Byte count statistics */
+struct smsc75xx_byte_statistics {
+ /** Unicast byte count */
+ uint32_t unicast;
+ /** Broadcast byte count */
+ uint32_t broadcast;
+ /** Multicast byte count */
+ uint32_t multicast;
+} __attribute__ (( packed ));
+
+/** Frame count statistics */
+struct smsc75xx_frame_statistics {
+ /** Unicast frames */
+ uint32_t unicast;
+ /** Broadcast frames */
+ uint32_t broadcast;
+ /** Multicast frames */
+ uint32_t multicast;
+ /** Pause frames */
+ uint32_t pause;
+ /** Frames by length category */
+ uint32_t len[7];
+} __attribute__ (( packed ));
+
+/** Receive error statistics */
+struct smsc75xx_rx_error_statistics {
+ /** FCS errors */
+ uint32_t fcs;
+ /** Alignment errors */
+ uint32_t alignment;
+ /** Fragment errors */
+ uint32_t fragment;
+ /** Jabber errors */
+ uint32_t jabber;
+ /** Undersize frame errors */
+ uint32_t undersize;
+ /** Oversize frame errors */
+ uint32_t oversize;
+ /** Dropped frame errors */
+ uint32_t dropped;
+} __attribute__ (( packed ));
+
+/** Receive statistics */
+struct smsc75xx_rx_statistics {
+ /** Error statistics */
+ struct smsc75xx_rx_error_statistics err;
+ /** Byte count statistics */
+ struct smsc75xx_byte_statistics byte;
+ /** Frame count statistics */
+ struct smsc75xx_frame_statistics frame;
+} __attribute__ (( packed ));
+
+/** Transmit error statistics */
+struct smsc75xx_tx_error_statistics {
+ /** FCS errors */
+ uint32_t fcs;
+ /** Excess deferral errors */
+ uint32_t deferral;
+ /** Carrier errors */
+ uint32_t carrier;
+ /** Bad byte count */
+ uint32_t count;
+ /** Single collisions */
+ uint32_t single;
+ /** Multiple collisions */
+ uint32_t multiple;
+ /** Excession collisions */
+ uint32_t excessive;
+ /** Late collisions */
+ uint32_t late;
+} __attribute__ (( packed ));
+
+/** Transmit statistics */
+struct smsc75xx_tx_statistics {
+ /** Error statistics */
+ struct smsc75xx_tx_error_statistics err;
+ /** Byte count statistics */
+ struct smsc75xx_byte_statistics byte;
+ /** Frame count statistics */
+ struct smsc75xx_frame_statistics frame;
+} __attribute__ (( packed ));
+
+/** Statistics */
+struct smsc75xx_statistics {
+ /** Receive statistics */
+ struct smsc75xx_rx_statistics rx;
+ /** Transmit statistics */
+ struct smsc75xx_tx_statistics tx;
+} __attribute__ (( packed ));
+
+/** A SMSC75xx network device */
+struct smsc75xx_device {
+ /** USB device */
+ struct usb_device *usb;
+ /** USB bus */
+ struct usb_bus *bus;
+ /** Network device */
+ struct net_device *netdev;
+ /** USB network device */
+ struct usbnet_device usbnet;
+ /** MII interface */
+ struct mii_interface mii;
+ /** Interrupt status */
+ uint32_t int_sts;
+};
+
+/** Reset delay (in microseconds) */
+#define SMSC75XX_RESET_DELAY_US 2
+
+/** Maximum time to wait for EEPROM (in milliseconds) */
+#define SMSC75XX_EEPROM_MAX_WAIT_MS 100
+
+/** Maximum time to wait for MII (in milliseconds) */
+#define SMSC75XX_MII_MAX_WAIT_MS 100
+
+/** Interrupt maximum fill level
+ *
+ * This is a policy decision.
+ */
+#define SMSC75XX_INTR_MAX_FILL 2
+
+/** Bulk IN maximum fill level
+ *
+ * This is a policy decision.
+ */
+#define SMSC75XX_IN_MAX_FILL 8
+
+/** Bulk IN buffer size */
+#define SMSC75XX_IN_MTU \
+ ( sizeof ( struct smsc75xx_rx_header ) + \
+ ETH_FRAME_LEN + 4 /* possible VLAN header */ )
+
+#endif /* _SMSC75XX_H */
diff --git a/roms/ipxe/src/drivers/net/sundance.c b/roms/ipxe/src/drivers/net/sundance.c
index eef7c9c7c..9127fa2cd 100644
--- a/roms/ipxe/src/drivers/net/sundance.c
+++ b/roms/ipxe/src/drivers/net/sundance.c
@@ -601,7 +601,7 @@ static int sundance_probe ( struct nic *nic, struct pci_device *pci ) {
sdc->nic_name = pci->id->name;
sdc->mtu = mtu;
- pci_read_config_byte(pci, PCI_REVISION_ID, &sdc->pci_rev_id);
+ pci_read_config_byte(pci, PCI_REVISION, &sdc->pci_rev_id);
DBG ( "Device revision id: %hx\n", sdc->pci_rev_id );
diff --git a/roms/ipxe/src/drivers/net/tg3/tg3.c b/roms/ipxe/src/drivers/net/tg3/tg3.c
index 32ca1609c..42bfa2d99 100644
--- a/roms/ipxe/src/drivers/net/tg3/tg3.c
+++ b/roms/ipxe/src/drivers/net/tg3/tg3.c
@@ -928,6 +928,7 @@ static struct pci_device_id tg3_nics[] = {
PCI_ROM(0x14e4, 0x16b6, "14e4-16b6", "14e4-16b6", 0),
PCI_ROM(0x14e4, 0x1657, "14e4-1657", "14e4-1657", 0),
PCI_ROM(0x14e4, 0x165f, "14e4-165f", "14e4-165f", 0),
+ PCI_ROM(0x14e4, 0x1686, "14e4-1686", "14e4-1686", 0),
PCI_ROM(0x1148, 0x4400, "1148-4400", "1148-4400", 0),
PCI_ROM(0x1148, 0x4500, "1148-4500", "1148-4500", 0),
PCI_ROM(0x173b, 0x03e8, "173b-03e8", "173b-03e8", 0),
diff --git a/roms/ipxe/src/drivers/net/tg3/tg3.h b/roms/ipxe/src/drivers/net/tg3/tg3.h
index 660368394..2b85b065b 100644
--- a/roms/ipxe/src/drivers/net/tg3/tg3.h
+++ b/roms/ipxe/src/drivers/net/tg3/tg3.h
@@ -131,6 +131,10 @@
#define PCI_DEVICE_ID_TIGON3_5901_2 0x170e
#define PCI_DEVICE_ID_TIGON3_5906 0x1712
#define PCI_DEVICE_ID_TIGON3_5906M 0x1713
+#define PCI_VENDOR_ID_COMPAQ 0x0e11
+#define PCI_VENDOR_ID_IBM 0x1014
+#define PCI_VENDOR_ID_DELL 0x1028
+#define PCI_VENDOR_ID_3COM 0x10b7
/* </pci_ids.h> */
#define SPEED_10 10
@@ -185,6 +189,7 @@
#define TG3PCI_DEVICE_TIGON3_57761 0x16b0
#define TG3PCI_DEVICE_TIGON3_57762 0x1682
#define TG3PCI_DEVICE_TIGON3_57765 0x16b4
+#define TG3PCI_DEVICE_TIGON3_57766 0x1686
#define TG3PCI_DEVICE_TIGON3_57791 0x16b2
#define TG3PCI_DEVICE_TIGON3_57795 0x16b6
#define TG3PCI_DEVICE_TIGON3_5719 0x1657
diff --git a/roms/ipxe/src/drivers/net/tg3/tg3_hw.c b/roms/ipxe/src/drivers/net/tg3/tg3_hw.c
index 3a481aba3..50353cf36 100644
--- a/roms/ipxe/src/drivers/net/tg3/tg3_hw.c
+++ b/roms/ipxe/src/drivers/net/tg3/tg3_hw.c
@@ -436,6 +436,7 @@ int tg3_get_invariants(struct tg3 *tp)
tp->pdev->device == TG3PCI_DEVICE_TIGON3_57761 ||
tp->pdev->device == TG3PCI_DEVICE_TIGON3_57762 ||
tp->pdev->device == TG3PCI_DEVICE_TIGON3_57765 ||
+ tp->pdev->device == TG3PCI_DEVICE_TIGON3_57766 ||
tp->pdev->device == TG3PCI_DEVICE_TIGON3_57791 ||
tp->pdev->device == TG3PCI_DEVICE_TIGON3_57795)
pci_read_config_dword(tp->pdev,
diff --git a/roms/ipxe/src/drivers/net/virtio-net.c b/roms/ipxe/src/drivers/net/virtio-net.c
index d5fd81979..533ccb0c6 100644
--- a/roms/ipxe/src/drivers/net/virtio-net.c
+++ b/roms/ipxe/src/drivers/net/virtio-net.c
@@ -20,7 +20,7 @@
* See the COPYING file in the top-level directory.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <errno.h>
#include <stdlib.h>
@@ -131,8 +131,8 @@ static void virtnet_enqueue_iob ( struct net_device *netdev,
},
};
- DBGC ( virtnet, "VIRTIO-NET %p enqueuing iobuf %p on vq %d\n",
- virtnet, iobuf, vq_idx );
+ DBGC2 ( virtnet, "VIRTIO-NET %p enqueuing iobuf %p on vq %d\n",
+ virtnet, iobuf, vq_idx );
vring_add_buf ( vq, list, out, in, iobuf, 0 );
vring_kick ( virtnet->ioaddr, vq, 1 );
@@ -256,8 +256,8 @@ static void virtnet_process_tx_packets ( struct net_device *netdev ) {
while ( vring_more_used ( tx_vq ) ) {
struct io_buffer *iobuf = vring_get_buf ( tx_vq, NULL );
- DBGC ( virtnet, "VIRTIO-NET %p tx complete iobuf %p\n",
- virtnet, iobuf );
+ DBGC2 ( virtnet, "VIRTIO-NET %p tx complete iobuf %p\n",
+ virtnet, iobuf );
netdev_tx_complete ( netdev, iobuf );
}
@@ -283,8 +283,8 @@ static void virtnet_process_rx_packets ( struct net_device *netdev ) {
iob_unput ( iobuf, RX_BUF_SIZE );
iob_put ( iobuf, len - sizeof ( struct virtio_net_hdr ) );
- DBGC ( virtnet, "VIRTIO-NET %p rx complete iobuf %p len %zd\n",
- virtnet, iobuf, iob_len ( iobuf ) );
+ DBGC2 ( virtnet, "VIRTIO-NET %p rx complete iobuf %p len %zd\n",
+ virtnet, iobuf, iob_len ( iobuf ) );
/* Pass completed packet to the network stack */
netdev_rx ( netdev, iobuf );
diff --git a/roms/ipxe/src/drivers/net/vmxnet3.c b/roms/ipxe/src/drivers/net/vmxnet3.c
index 31082bf6f..8d4f4b843 100644
--- a/roms/ipxe/src/drivers/net/vmxnet3.c
+++ b/roms/ipxe/src/drivers/net/vmxnet3.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <errno.h>
diff --git a/roms/ipxe/src/drivers/net/vmxnet3.h b/roms/ipxe/src/drivers/net/vmxnet3.h
index db313d4b8..a1671d9dd 100644
--- a/roms/ipxe/src/drivers/net/vmxnet3.h
+++ b/roms/ipxe/src/drivers/net/vmxnet3.h
@@ -18,9 +18,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @file
diff --git a/roms/ipxe/src/drivers/net/vxge/vxge.c b/roms/ipxe/src/drivers/net/vxge/vxge.c
index bf20ec43c..d50ac05b5 100644
--- a/roms/ipxe/src/drivers/net/vxge/vxge.c
+++ b/roms/ipxe/src/drivers/net/vxge/vxge.c
@@ -5,10 +5,11 @@
* as "vxge" even though the code is in vxge_* named files.
*/
-FILE_LICENCE(GPL2_OR_LATER);
+FILE_LICENCE(GPL2_OR_LATER_OR_UBDL);
#include <ipxe/pci.h>
+PROVIDE_REQUIRING_SYMBOL();
REQUIRE_OBJECT(vxge_main);
/** vxge PCI IDs for util/parserom.pl which are put into bin/NIC */
diff --git a/roms/ipxe/src/drivers/net/vxge/vxge_main.c b/roms/ipxe/src/drivers/net/vxge/vxge_main.c
index 130eab617..8b099c0e2 100644
--- a/roms/ipxe/src/drivers/net/vxge/vxge_main.c
+++ b/roms/ipxe/src/drivers/net/vxge/vxge_main.c
@@ -509,7 +509,7 @@ vxge_probe(struct pci_device *pdev)
vxge_debug(VXGE_INFO, "vxge_probe for device " PCI_FMT "\n",
PCI_ARGS(pdev));
- pci_read_config_byte(pdev, PCI_REVISION_ID, &revision);
+ pci_read_config_byte(pdev, PCI_REVISION, &revision);
titan1 = is_titan1(pdev->device, revision);
mmio_start = pci_bar_start(pdev, PCI_BASE_ADDRESS_0);
diff --git a/roms/ipxe/src/drivers/net/w89c840.c b/roms/ipxe/src/drivers/net/w89c840.c
index ce638ab99..d8144a8ce 100644
--- a/roms/ipxe/src/drivers/net/w89c840.c
+++ b/roms/ipxe/src/drivers/net/w89c840.c
@@ -641,7 +641,9 @@ static int w89c840_probe ( struct nic *nic, struct pci_device *p ) {
ioaddr = ioaddr & ~3; /* Mask the bit that says "this is an io addr" */
+#define PCI_VENDOR_ID_WINBOND2 0x1050
#define PCI_DEVICE_ID_WINBOND2_89C840 0x0840
+#define PCI_VENDOR_ID_COMPEX 0x11f6
#define PCI_DEVICE_ID_COMPEX_RL100ATX 0x2011
/* From Matt Hortman <mbhortman@acpthinclient.com> */
diff --git a/roms/ipxe/src/drivers/nvs/nvs.c b/roms/ipxe/src/drivers/nvs/nvs.c
index ccb2145bd..af7c466c4 100644
--- a/roms/ipxe/src/drivers/nvs/nvs.c
+++ b/roms/ipxe/src/drivers/nvs/nvs.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <string.h>
diff --git a/roms/ipxe/src/drivers/nvs/nvsvpd.c b/roms/ipxe/src/drivers/nvs/nvsvpd.c
index 33148d5b9..3e88531c7 100644
--- a/roms/ipxe/src/drivers/nvs/nvsvpd.c
+++ b/roms/ipxe/src/drivers/nvs/nvsvpd.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdio.h>
#include <errno.h>
diff --git a/roms/ipxe/src/drivers/nvs/spi.c b/roms/ipxe/src/drivers/nvs/spi.c
index 84613b9dd..dcfe1af91 100644
--- a/roms/ipxe/src/drivers/nvs/spi.c
+++ b/roms/ipxe/src/drivers/nvs/spi.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <errno.h>
diff --git a/roms/ipxe/src/drivers/nvs/threewire.c b/roms/ipxe/src/drivers/nvs/threewire.c
index 53f1ad8de..547f35382 100644
--- a/roms/ipxe/src/drivers/nvs/threewire.c
+++ b/roms/ipxe/src/drivers/nvs/threewire.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <string.h>
diff --git a/roms/ipxe/src/drivers/usb/ehci.c b/roms/ipxe/src/drivers/usb/ehci.c
new file mode 100644
index 000000000..4124692a6
--- /dev/null
+++ b/roms/ipxe/src/drivers/usb/ehci.c
@@ -0,0 +1,1994 @@
+/*
+ * Copyright (C) 2014 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/malloc.h>
+#include <ipxe/pci.h>
+#include <ipxe/usb.h>
+#include <ipxe/init.h>
+#include "ehci.h"
+
+/** @file
+ *
+ * USB Enhanced Host Controller Interface (EHCI) driver
+ *
+ */
+
+/**
+ * Construct error code from transfer descriptor status
+ *
+ * @v status Transfer descriptor status
+ * @ret rc Error code
+ *
+ * Bits 2-5 of the status code provide some indication as to the root
+ * cause of the error. We incorporate these into the error code as
+ * reported to usb_complete_err().
+ */
+#define EIO_STATUS( status ) EUNIQ ( EINFO_EIO, ( ( (status) >> 2 ) & 0xf ) )
+
+/******************************************************************************
+ *
+ * Register access
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Initialise device
+ *
+ * @v ehci EHCI device
+ * @v regs MMIO registers
+ */
+static void ehci_init ( struct ehci_device *ehci, void *regs ) {
+ uint32_t hcsparams;
+ uint32_t hccparams;
+ size_t caplength;
+
+ /* Locate capability and operational registers */
+ ehci->cap = regs;
+ caplength = readb ( ehci->cap + EHCI_CAP_CAPLENGTH );
+ ehci->op = ( ehci->cap + caplength );
+ DBGC2 ( ehci, "EHCI %s cap %08lx op %08lx\n", ehci->name,
+ virt_to_phys ( ehci->cap ), virt_to_phys ( ehci->op ) );
+
+ /* Read structural parameters */
+ hcsparams = readl ( ehci->cap + EHCI_CAP_HCSPARAMS );
+ ehci->ports = EHCI_HCSPARAMS_PORTS ( hcsparams );
+ DBGC ( ehci, "EHCI %s has %d ports\n", ehci->name, ehci->ports );
+
+ /* Read capability parameters 1 */
+ hccparams = readl ( ehci->cap + EHCI_CAP_HCCPARAMS );
+ ehci->addr64 = EHCI_HCCPARAMS_ADDR64 ( hccparams );
+ ehci->flsize = ( EHCI_HCCPARAMS_FLSIZE ( hccparams ) ?
+ EHCI_FLSIZE_SMALL : EHCI_FLSIZE_DEFAULT );
+ ehci->eecp = EHCI_HCCPARAMS_EECP ( hccparams );
+ DBGC2 ( ehci, "EHCI %s %d-bit flsize %d\n", ehci->name,
+ ( ehci->addr64 ? 64 : 32 ), ehci->flsize );
+}
+
+/**
+ * Find extended capability
+ *
+ * @v ehci EHCI device
+ * @v pci PCI device
+ * @v id Capability ID
+ * @v offset Offset to previous extended capability instance, or zero
+ * @ret offset Offset to extended capability, or zero if not found
+ */
+static unsigned int ehci_extended_capability ( struct ehci_device *ehci,
+ struct pci_device *pci,
+ unsigned int id,
+ unsigned int offset ) {
+ uint32_t eecp;
+
+ /* Locate the extended capability */
+ while ( 1 ) {
+
+ /* Locate first or next capability as applicable */
+ if ( offset ) {
+ pci_read_config_dword ( pci, offset, &eecp );
+ offset = EHCI_EECP_NEXT ( eecp );
+ } else {
+ offset = ehci->eecp;
+ }
+ if ( ! offset )
+ return 0;
+
+ /* Check if this is the requested capability */
+ pci_read_config_dword ( pci, offset, &eecp );
+ if ( EHCI_EECP_ID ( eecp ) == id )
+ return offset;
+ }
+}
+
+/**
+ * Calculate buffer alignment
+ *
+ * @v len Length
+ * @ret align Buffer alignment
+ *
+ * Determine alignment required for a buffer which must be aligned to
+ * at least EHCI_MIN_ALIGN and which must not cross a page boundary.
+ */
+static inline size_t ehci_align ( size_t len ) {
+ size_t align;
+
+ /* Align to own length (rounded up to a power of two) */
+ align = ( 1 << fls ( len - 1 ) );
+
+ /* Round up to EHCI_MIN_ALIGN if needed */
+ if ( align < EHCI_MIN_ALIGN )
+ align = EHCI_MIN_ALIGN;
+
+ return align;
+}
+
+/**
+ * Check control data structure reachability
+ *
+ * @v ehci EHCI device
+ * @v ptr Data structure pointer
+ * @ret rc Return status code
+ */
+static int ehci_ctrl_reachable ( struct ehci_device *ehci, void *ptr ) {
+ physaddr_t phys = virt_to_phys ( ptr );
+ uint32_t segment;
+
+ /* Always reachable in a 32-bit build */
+ if ( sizeof ( physaddr_t ) <= sizeof ( uint32_t ) )
+ return 0;
+
+ /* Reachable only if control segment matches in a 64-bit build */
+ segment = ( ( ( uint64_t ) phys ) >> 32 );
+ if ( segment == ehci->ctrldssegment )
+ return 0;
+
+ return -ENOTSUP;
+}
+
+/******************************************************************************
+ *
+ * USB legacy support
+ *
+ ******************************************************************************
+ */
+
+/** Prevent the release of ownership back to BIOS */
+static int ehci_legacy_prevent_release;
+
+/**
+ * Initialise USB legacy support
+ *
+ * @v ehci EHCI device
+ * @v pci PCI device
+ */
+static void ehci_legacy_init ( struct ehci_device *ehci,
+ struct pci_device *pci ) {
+ unsigned int legacy;
+ uint8_t bios;
+
+ /* Locate USB legacy support capability (if present) */
+ legacy = ehci_extended_capability ( ehci, pci, EHCI_EECP_ID_LEGACY, 0 );
+ if ( ! legacy ) {
+ /* Not an error; capability may not be present */
+ DBGC ( ehci, "EHCI %s has no USB legacy support capability\n",
+ ehci->name );
+ return;
+ }
+
+ /* Check if legacy USB support is enabled */
+ pci_read_config_byte ( pci, ( legacy + EHCI_USBLEGSUP_BIOS ), &bios );
+ if ( ! ( bios & EHCI_USBLEGSUP_BIOS_OWNED ) ) {
+ /* Not an error; already owned by OS */
+ DBGC ( ehci, "EHCI %s USB legacy support already disabled\n",
+ ehci->name );
+ return;
+ }
+
+ /* Record presence of USB legacy support capability */
+ ehci->legacy = legacy;
+}
+
+/**
+ * Claim ownership from BIOS
+ *
+ * @v ehci EHCI device
+ * @v pci PCI device
+ */
+static void ehci_legacy_claim ( struct ehci_device *ehci,
+ struct pci_device *pci ) {
+ unsigned int legacy = ehci->legacy;
+ uint32_t ctlsts;
+ uint8_t bios;
+ unsigned int i;
+
+ /* Do nothing unless legacy support capability is present */
+ if ( ! legacy )
+ return;
+
+ /* Claim ownership */
+ pci_write_config_byte ( pci, ( legacy + EHCI_USBLEGSUP_OS ),
+ EHCI_USBLEGSUP_OS_OWNED );
+
+ /* Wait for BIOS to release ownership */
+ for ( i = 0 ; i < EHCI_USBLEGSUP_MAX_WAIT_MS ; i++ ) {
+
+ /* Check if BIOS has released ownership */
+ pci_read_config_byte ( pci, ( legacy + EHCI_USBLEGSUP_BIOS ),
+ &bios );
+ if ( ! ( bios & EHCI_USBLEGSUP_BIOS_OWNED ) ) {
+ DBGC ( ehci, "EHCI %s claimed ownership from BIOS\n",
+ ehci->name );
+ pci_read_config_dword ( pci, ( legacy +
+ EHCI_USBLEGSUP_CTLSTS ),
+ &ctlsts );
+ if ( ctlsts ) {
+ DBGC ( ehci, "EHCI %s warning: BIOS retained "
+ "SMIs: %08x\n", ehci->name, ctlsts );
+ }
+ return;
+ }
+
+ /* Delay */
+ mdelay ( 1 );
+ }
+
+ /* BIOS did not release ownership. Claim it forcibly by
+ * disabling all SMIs.
+ */
+ DBGC ( ehci, "EHCI %s could not claim ownership from BIOS: forcibly "
+ "disabling SMIs\n", ehci->name );
+ pci_write_config_dword ( pci, ( legacy + EHCI_USBLEGSUP_CTLSTS ), 0 );
+}
+
+/**
+ * Release ownership back to BIOS
+ *
+ * @v ehci EHCI device
+ * @v pci PCI device
+ */
+static void ehci_legacy_release ( struct ehci_device *ehci,
+ struct pci_device *pci ) {
+
+ /* Do nothing unless legacy support capability is present */
+ if ( ! ehci->legacy )
+ return;
+
+ /* Do nothing if releasing ownership is prevented */
+ if ( ehci_legacy_prevent_release ) {
+ DBGC ( ehci, "EHCI %s not releasing ownership to BIOS\n",
+ ehci->name );
+ return;
+ }
+
+ /* Release ownership */
+ pci_write_config_byte ( pci, ( ehci->legacy + EHCI_USBLEGSUP_OS ), 0 );
+ DBGC ( ehci, "EHCI %s released ownership to BIOS\n", ehci->name );
+}
+
+/******************************************************************************
+ *
+ * Companion controllers
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Poll child companion controllers
+ *
+ * @v ehci EHCI device
+ */
+static void ehci_poll_companions ( struct ehci_device *ehci ) {
+ struct usb_bus *bus;
+ struct device_description *desc;
+
+ /* Poll any USB buses belonging to child companion controllers */
+ for_each_usb_bus ( bus ) {
+
+ /* Get underlying devices description */
+ desc = &bus->dev->desc;
+
+ /* Skip buses that are not PCI devices */
+ if ( desc->bus_type != BUS_TYPE_PCI )
+ continue;
+
+ /* Skip buses that are not part of the same PCI device */
+ if ( PCI_FIRST_FUNC ( desc->location ) !=
+ PCI_FIRST_FUNC ( ehci->bus->dev->desc.location ) )
+ continue;
+
+ /* Skip buses that are not UHCI or OHCI PCI devices */
+ if ( ( desc->class != PCI_CLASS ( PCI_CLASS_SERIAL,
+ PCI_CLASS_SERIAL_USB,
+ PCI_CLASS_SERIAL_USB_UHCI ))&&
+ ( desc->class != PCI_CLASS ( PCI_CLASS_SERIAL,
+ PCI_CLASS_SERIAL_USB,
+ PCI_CLASS_SERIAL_USB_OHCI ) ))
+ continue;
+
+ /* Poll child companion controller bus */
+ DBGC2 ( ehci, "EHCI %s polling companion %s\n",
+ ehci->name, bus->name );
+ usb_poll ( bus );
+ }
+}
+
+/**
+ * Locate EHCI companion controller
+ *
+ * @v pci PCI device
+ * @ret busdevfn EHCI companion controller bus:dev.fn (if any)
+ */
+unsigned int ehci_companion ( struct pci_device *pci ) {
+ struct pci_device tmp;
+ unsigned int busdevfn;
+ int rc;
+
+ /* Look for an EHCI function on the same PCI device */
+ busdevfn = pci->busdevfn;
+ while ( ++busdevfn <= PCI_LAST_FUNC ( pci->busdevfn ) ) {
+ pci_init ( &tmp, busdevfn );
+ if ( ( rc = pci_read_config ( &tmp ) ) != 0 )
+ continue;
+ if ( tmp.class == PCI_CLASS ( PCI_CLASS_SERIAL,
+ PCI_CLASS_SERIAL_USB,
+ PCI_CLASS_SERIAL_USB_EHCI ) )
+ return busdevfn;
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * Run / stop / reset
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Start EHCI device
+ *
+ * @v ehci EHCI device
+ */
+static void ehci_run ( struct ehci_device *ehci ) {
+ uint32_t usbcmd;
+
+ /* Set run/stop bit */
+ usbcmd = readl ( ehci->op + EHCI_OP_USBCMD );
+ usbcmd &= ~EHCI_USBCMD_FLSIZE_MASK;
+ usbcmd |= ( EHCI_USBCMD_RUN | EHCI_USBCMD_FLSIZE ( ehci->flsize ) |
+ EHCI_USBCMD_PERIODIC | EHCI_USBCMD_ASYNC );
+ writel ( usbcmd, ehci->op + EHCI_OP_USBCMD );
+}
+
+/**
+ * Stop EHCI device
+ *
+ * @v ehci EHCI device
+ * @ret rc Return status code
+ */
+static int ehci_stop ( struct ehci_device *ehci ) {
+ uint32_t usbcmd;
+ uint32_t usbsts;
+ unsigned int i;
+
+ /* Clear run/stop bit */
+ usbcmd = readl ( ehci->op + EHCI_OP_USBCMD );
+ usbcmd &= ~( EHCI_USBCMD_RUN | EHCI_USBCMD_PERIODIC |
+ EHCI_USBCMD_ASYNC );
+ writel ( usbcmd, ehci->op + EHCI_OP_USBCMD );
+
+ /* Wait for device to stop */
+ for ( i = 0 ; i < EHCI_STOP_MAX_WAIT_MS ; i++ ) {
+
+ /* Check if device is stopped */
+ usbsts = readl ( ehci->op + EHCI_OP_USBSTS );
+ if ( usbsts & EHCI_USBSTS_HCH )
+ return 0;
+
+ /* Delay */
+ mdelay ( 1 );
+ }
+
+ DBGC ( ehci, "EHCI %s timed out waiting for stop\n", ehci->name );
+ return -ETIMEDOUT;
+}
+
+/**
+ * Reset EHCI device
+ *
+ * @v ehci EHCI device
+ * @ret rc Return status code
+ */
+static int ehci_reset ( struct ehci_device *ehci ) {
+ uint32_t usbcmd;
+ unsigned int i;
+ int rc;
+
+ /* The EHCI specification states that resetting a running
+ * device may result in undefined behaviour, so try stopping
+ * it first.
+ */
+ if ( ( rc = ehci_stop ( ehci ) ) != 0 ) {
+ /* Ignore errors and attempt to reset the device anyway */
+ }
+
+ /* Reset device */
+ writel ( EHCI_USBCMD_HCRST, ehci->op + EHCI_OP_USBCMD );
+
+ /* Wait for reset to complete */
+ for ( i = 0 ; i < EHCI_RESET_MAX_WAIT_MS ; i++ ) {
+
+ /* Check if reset is complete */
+ usbcmd = readl ( ehci->op + EHCI_OP_USBCMD );
+ if ( ! ( usbcmd & EHCI_USBCMD_HCRST ) )
+ return 0;
+
+ /* Delay */
+ mdelay ( 1 );
+ }
+
+ DBGC ( ehci, "EHCI %s timed out waiting for reset\n", ehci->name );
+ return -ETIMEDOUT;
+}
+
+/******************************************************************************
+ *
+ * Transfer descriptor rings
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Allocate transfer descriptor ring
+ *
+ * @v ehci EHCI device
+ * @v ring Transfer descriptor ring
+ * @ret rc Return status code
+ */
+static int ehci_ring_alloc ( struct ehci_device *ehci,
+ struct ehci_ring *ring ) {
+ struct ehci_transfer_descriptor *desc;
+ struct ehci_transfer_descriptor *next;
+ unsigned int i;
+ size_t len;
+ uint32_t link;
+ int rc;
+
+ /* Initialise structure */
+ memset ( ring, 0, sizeof ( *ring ) );
+
+ /* Allocate I/O buffers */
+ ring->iobuf = zalloc ( EHCI_RING_COUNT * sizeof ( ring->iobuf[0] ) );
+ if ( ! ring->iobuf ) {
+ rc = -ENOMEM;
+ goto err_alloc_iobuf;
+ }
+
+ /* Allocate queue head */
+ ring->head = malloc_dma ( sizeof ( *ring->head ),
+ ehci_align ( sizeof ( *ring->head ) ) );
+ if ( ! ring->head ) {
+ rc = -ENOMEM;
+ goto err_alloc_queue;
+ }
+ if ( ( rc = ehci_ctrl_reachable ( ehci, ring->head ) ) != 0 ) {
+ DBGC ( ehci, "EHCI %s queue head unreachable\n", ehci->name );
+ goto err_unreachable_queue;
+ }
+ memset ( ring->head, 0, sizeof ( *ring->head ) );
+
+ /* Allocate transfer descriptors */
+ len = ( EHCI_RING_COUNT * sizeof ( ring->desc[0] ) );
+ ring->desc = malloc_dma ( len, sizeof ( ring->desc[0] ) );
+ if ( ! ring->desc ) {
+ rc = -ENOMEM;
+ goto err_alloc_desc;
+ }
+ memset ( ring->desc, 0, len );
+
+ /* Initialise transfer descriptors */
+ for ( i = 0 ; i < EHCI_RING_COUNT ; i++ ) {
+ desc = &ring->desc[i];
+ if ( ( rc = ehci_ctrl_reachable ( ehci, desc ) ) != 0 ) {
+ DBGC ( ehci, "EHCI %s descriptor unreachable\n",
+ ehci->name );
+ goto err_unreachable_desc;
+ }
+ next = &ring->desc[ ( i + 1 ) % EHCI_RING_COUNT ];
+ link = virt_to_phys ( next );
+ desc->next = cpu_to_le32 ( link );
+ desc->alt = cpu_to_le32 ( link );
+ }
+
+ /* Initialise queue head */
+ link = virt_to_phys ( &ring->desc[0] );
+ ring->head->cache.next = cpu_to_le32 ( link );
+
+ return 0;
+
+ err_unreachable_desc:
+ free_dma ( ring->desc, len );
+ err_alloc_desc:
+ err_unreachable_queue:
+ free_dma ( ring->head, sizeof ( *ring->head ) );
+ err_alloc_queue:
+ free ( ring->iobuf );
+ err_alloc_iobuf:
+ return rc;
+}
+
+/**
+ * Free transfer descriptor ring
+ *
+ * @v ring Transfer descriptor ring
+ */
+static void ehci_ring_free ( struct ehci_ring *ring ) {
+ unsigned int i;
+
+ /* Sanity checks */
+ assert ( ehci_ring_fill ( ring ) == 0 );
+ for ( i = 0 ; i < EHCI_RING_COUNT ; i++ )
+ assert ( ring->iobuf[i] == NULL );
+
+ /* Free transfer descriptors */
+ free_dma ( ring->desc, ( EHCI_RING_COUNT * sizeof ( ring->desc[0] ) ) );
+
+ /* Free queue head */
+ free_dma ( ring->head, sizeof ( *ring->head ) );
+
+ /* Free I/O buffers */
+ free ( ring->iobuf );
+}
+
+/**
+ * Enqueue transfer descriptors
+ *
+ * @v ehci EHCI device
+ * @v ring Transfer descriptor ring
+ * @v iobuf I/O buffer
+ * @v xfers Transfers
+ * @v count Number of transfers
+ * @ret rc Return status code
+ */
+static int ehci_enqueue ( struct ehci_device *ehci, struct ehci_ring *ring,
+ struct io_buffer *iobuf,
+ const struct ehci_transfer *xfer,
+ unsigned int count ) {
+ struct ehci_transfer_descriptor *desc;
+ physaddr_t phys;
+ void *data;
+ size_t len;
+ size_t offset;
+ size_t frag_len;
+ unsigned int toggle;
+ unsigned int index;
+ unsigned int i;
+
+ /* Sanity check */
+ assert ( iobuf != NULL );
+ assert ( count > 0 );
+
+ /* Fail if ring does not have sufficient space */
+ if ( ehci_ring_remaining ( ring ) < count )
+ return -ENOBUFS;
+
+ /* Fail if any portion is unreachable */
+ for ( i = 0 ; i < count ; i++ ) {
+ phys = ( virt_to_phys ( xfer[i].data ) + xfer[i].len - 1 );
+ if ( ( phys > 0xffffffffUL ) && ( ! ehci->addr64 ) )
+ return -ENOTSUP;
+ }
+
+ /* Enqueue each transfer, recording the I/O buffer with the last */
+ for ( ; count ; ring->prod++, xfer++ ) {
+
+ /* Populate descriptor header */
+ index = ( ring->prod % EHCI_RING_COUNT );
+ desc = &ring->desc[index];
+ toggle = ( xfer->flags & EHCI_FL_TOGGLE );
+ assert ( xfer->len <= EHCI_LEN_MASK );
+ assert ( EHCI_FL_TOGGLE == EHCI_LEN_TOGGLE );
+ desc->len = cpu_to_le16 ( xfer->len | toggle );
+ desc->flags = ( xfer->flags | EHCI_FL_CERR_MAX );
+
+ /* Populate buffer pointers */
+ data = xfer->data;
+ len = xfer->len;
+ for ( i = 0 ; len ; i++ ) {
+
+ /* Calculate length of this fragment */
+ phys = virt_to_phys ( data );
+ offset = ( phys & ( EHCI_PAGE_ALIGN - 1 ) );
+ frag_len = ( EHCI_PAGE_ALIGN - offset );
+ if ( frag_len > len )
+ frag_len = len;
+
+ /* Sanity checks */
+ assert ( ( i == 0 ) || ( offset == 0 ) );
+ assert ( i < ( sizeof ( desc->low ) /
+ sizeof ( desc->low[0] ) ) );
+
+ /* Populate buffer pointer */
+ desc->low[i] = cpu_to_le32 ( phys );
+ if ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) ) {
+ desc->high[i] =
+ cpu_to_le32 ( ((uint64_t) phys) >> 32 );
+ }
+
+ /* Move to next fragment */
+ data += frag_len;
+ len -= frag_len;
+ }
+
+ /* Ensure everything is valid before activating descriptor */
+ wmb();
+ desc->status = EHCI_STATUS_ACTIVE;
+
+ /* Record I/O buffer against last ring index */
+ if ( --count == 0 )
+ ring->iobuf[index] = iobuf;
+ }
+
+ return 0;
+}
+
+/**
+ * Dequeue a transfer descriptor
+ *
+ * @v ring Transfer descriptor ring
+ * @ret iobuf I/O buffer (or NULL)
+ */
+static struct io_buffer * ehci_dequeue ( struct ehci_ring *ring ) {
+ struct ehci_transfer_descriptor *desc;
+ struct io_buffer *iobuf;
+ unsigned int index = ( ring->cons % EHCI_RING_COUNT );
+
+ /* Sanity check */
+ assert ( ehci_ring_fill ( ring ) > 0 );
+
+ /* Mark descriptor as inactive (and not halted) */
+ desc = &ring->desc[index];
+ desc->status = 0;
+
+ /* Retrieve I/O buffer */
+ iobuf = ring->iobuf[index];
+ ring->iobuf[index] = NULL;
+
+ /* Update consumer counter */
+ ring->cons++;
+
+ return iobuf;
+}
+
+/******************************************************************************
+ *
+ * Schedule management
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Get link value for a queue head
+ *
+ * @v queue Queue head
+ * @ret link Link value
+ */
+static inline uint32_t ehci_link_qh ( struct ehci_queue_head *queue ) {
+
+ return ( virt_to_phys ( queue ) | EHCI_LINK_TYPE_QH );
+}
+
+/**
+ * (Re)build asynchronous schedule
+ *
+ * @v ehci EHCI device
+ */
+static void ehci_async_schedule ( struct ehci_device *ehci ) {
+ struct ehci_endpoint *endpoint;
+ struct ehci_queue_head *queue;
+ uint32_t link;
+
+ /* Build schedule in reverse order of execution. Provided
+ * that we only ever add or remove single endpoints, this can
+ * safely run concurrently with hardware execution of the
+ * schedule.
+ */
+ link = ehci_link_qh ( ehci->head );
+ list_for_each_entry_reverse ( endpoint, &ehci->async, schedule ) {
+ queue = endpoint->ring.head;
+ queue->link = cpu_to_le32 ( link );
+ wmb();
+ link = ehci_link_qh ( queue );
+ }
+ ehci->head->link = cpu_to_le32 ( link );
+ wmb();
+}
+
+/**
+ * Add endpoint to asynchronous schedule
+ *
+ * @v endpoint Endpoint
+ */
+static void ehci_async_add ( struct ehci_endpoint *endpoint ) {
+ struct ehci_device *ehci = endpoint->ehci;
+
+ /* Add to end of schedule */
+ list_add_tail ( &endpoint->schedule, &ehci->async );
+
+ /* Rebuild schedule */
+ ehci_async_schedule ( ehci );
+}
+
+/**
+ * Remove endpoint from asynchronous schedule
+ *
+ * @v endpoint Endpoint
+ * @ret rc Return status code
+ */
+static int ehci_async_del ( struct ehci_endpoint *endpoint ) {
+ struct ehci_device *ehci = endpoint->ehci;
+ uint32_t usbcmd;
+ uint32_t usbsts;
+ unsigned int i;
+
+ /* Remove from schedule */
+ list_check_contains_entry ( endpoint, &ehci->async, schedule );
+ list_del ( &endpoint->schedule );
+
+ /* Rebuild schedule */
+ ehci_async_schedule ( ehci );
+
+ /* Request notification when asynchronous schedule advances */
+ usbcmd = readl ( ehci->op + EHCI_OP_USBCMD );
+ usbcmd |= EHCI_USBCMD_ASYNC_ADVANCE;
+ writel ( usbcmd, ehci->op + EHCI_OP_USBCMD );
+
+ /* Wait for asynchronous schedule to advance */
+ for ( i = 0 ; i < EHCI_ASYNC_ADVANCE_MAX_WAIT_MS ; i++ ) {
+
+ /* Check for asynchronous schedule advancing */
+ usbsts = readl ( ehci->op + EHCI_OP_USBSTS );
+ if ( usbsts & EHCI_USBSTS_ASYNC_ADVANCE ) {
+ usbsts &= ~EHCI_USBSTS_CHANGE;
+ usbsts |= EHCI_USBSTS_ASYNC_ADVANCE;
+ writel ( usbsts, ehci->op + EHCI_OP_USBSTS );
+ return 0;
+ }
+
+ /* Delay */
+ mdelay ( 1 );
+ }
+
+ /* Bad things will probably happen now */
+ DBGC ( ehci, "EHCI %s timed out waiting for asynchronous schedule "
+ "to advance\n", ehci->name );
+ return -ETIMEDOUT;
+}
+
+/**
+ * (Re)build periodic schedule
+ *
+ * @v ehci EHCI device
+ */
+static void ehci_periodic_schedule ( struct ehci_device *ehci ) {
+ struct ehci_endpoint *endpoint;
+ struct ehci_queue_head *queue;
+ uint32_t link;
+ unsigned int frames;
+ unsigned int max_interval;
+ unsigned int i;
+
+ /* Build schedule in reverse order of execution. Provided
+ * that we only ever add or remove single endpoints, this can
+ * safely run concurrently with hardware execution of the
+ * schedule.
+ */
+ DBGCP ( ehci, "EHCI %s periodic schedule: ", ehci->name );
+ link = EHCI_LINK_TERMINATE;
+ list_for_each_entry_reverse ( endpoint, &ehci->periodic, schedule ) {
+ queue = endpoint->ring.head;
+ queue->link = cpu_to_le32 ( link );
+ wmb();
+ DBGCP ( ehci, "%s%d",
+ ( ( link == EHCI_LINK_TERMINATE ) ? "" : "<-" ),
+ endpoint->ep->interval );
+ link = ehci_link_qh ( queue );
+ }
+ DBGCP ( ehci, "\n" );
+
+ /* Populate periodic frame list */
+ DBGCP ( ehci, "EHCI %s periodic frame list:", ehci->name );
+ frames = EHCI_PERIODIC_FRAMES ( ehci->flsize );
+ for ( i = 0 ; i < frames ; i++ ) {
+
+ /* Calculate maximum interval (in microframes) which
+ * may appear as part of this frame list.
+ */
+ if ( i == 0 ) {
+ /* Start of list: include all endpoints */
+ max_interval = -1U;
+ } else {
+ /* Calculate highest power-of-two frame interval */
+ max_interval = ( 1 << ( ffs ( i ) - 1 ) );
+ /* Convert to microframes */
+ max_interval <<= 3;
+ /* Round up to nearest 2^n-1 */
+ max_interval = ( ( max_interval << 1 ) - 1 );
+ }
+
+ /* Find first endpoint in schedule satisfying this
+ * maximum interval constraint.
+ */
+ link = EHCI_LINK_TERMINATE;
+ list_for_each_entry ( endpoint, &ehci->periodic, schedule ) {
+ if ( endpoint->ep->interval <= max_interval ) {
+ queue = endpoint->ring.head;
+ link = ehci_link_qh ( queue );
+ DBGCP ( ehci, " %d:%d",
+ i, endpoint->ep->interval );
+ break;
+ }
+ }
+ ehci->frame[i].link = cpu_to_le32 ( link );
+ }
+ wmb();
+ DBGCP ( ehci, "\n" );
+}
+
+/**
+ * Add endpoint to periodic schedule
+ *
+ * @v endpoint Endpoint
+ */
+static void ehci_periodic_add ( struct ehci_endpoint *endpoint ) {
+ struct ehci_device *ehci = endpoint->ehci;
+ struct ehci_endpoint *before;
+ unsigned int interval = endpoint->ep->interval;
+
+ /* Find first endpoint with a smaller interval */
+ list_for_each_entry ( before, &ehci->periodic, schedule ) {
+ if ( before->ep->interval < interval )
+ break;
+ }
+ list_add_tail ( &endpoint->schedule, &before->schedule );
+
+ /* Rebuild schedule */
+ ehci_periodic_schedule ( ehci );
+}
+
+/**
+ * Remove endpoint from periodic schedule
+ *
+ * @v endpoint Endpoint
+ * @ret rc Return status code
+ */
+static int ehci_periodic_del ( struct ehci_endpoint *endpoint ) {
+ struct ehci_device *ehci = endpoint->ehci;
+
+ /* Remove from schedule */
+ list_check_contains_entry ( endpoint, &ehci->periodic, schedule );
+ list_del ( &endpoint->schedule );
+
+ /* Rebuild schedule */
+ ehci_periodic_schedule ( ehci );
+
+ /* Delay for a whole USB frame (with a 100% safety margin) */
+ mdelay ( 2 );
+
+ return 0;
+}
+
+/**
+ * Add endpoint to appropriate schedule
+ *
+ * @v endpoint Endpoint
+ */
+static void ehci_schedule_add ( struct ehci_endpoint *endpoint ) {
+ struct usb_endpoint *ep = endpoint->ep;
+ unsigned int attr = ( ep->attributes & USB_ENDPOINT_ATTR_TYPE_MASK );
+
+ if ( attr == USB_ENDPOINT_ATTR_INTERRUPT ) {
+ ehci_periodic_add ( endpoint );
+ } else {
+ ehci_async_add ( endpoint );
+ }
+}
+
+/**
+ * Remove endpoint from appropriate schedule
+ *
+ * @v endpoint Endpoint
+ * @ret rc Return status code
+ */
+static int ehci_schedule_del ( struct ehci_endpoint *endpoint ) {
+ struct usb_endpoint *ep = endpoint->ep;
+ unsigned int attr = ( ep->attributes & USB_ENDPOINT_ATTR_TYPE_MASK );
+
+ if ( attr == USB_ENDPOINT_ATTR_INTERRUPT ) {
+ return ehci_periodic_del ( endpoint );
+ } else {
+ return ehci_async_del ( endpoint );
+ }
+}
+
+/******************************************************************************
+ *
+ * Endpoint operations
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Determine endpoint characteristics
+ *
+ * @v ep USB endpoint
+ * @ret chr Endpoint characteristics
+ */
+static uint32_t ehci_endpoint_characteristics ( struct usb_endpoint *ep ) {
+ struct usb_device *usb = ep->usb;
+ unsigned int attr = ( ep->attributes & USB_ENDPOINT_ATTR_TYPE_MASK );
+ uint32_t chr;
+
+ /* Determine basic characteristics */
+ chr = ( EHCI_CHR_ADDRESS ( usb->address ) |
+ EHCI_CHR_ENDPOINT ( ep->address ) |
+ EHCI_CHR_MAX_LEN ( ep->mtu ) );
+
+ /* Control endpoints require manual control of the data toggle */
+ if ( attr == USB_ENDPOINT_ATTR_CONTROL )
+ chr |= EHCI_CHR_TOGGLE;
+
+ /* Determine endpoint speed */
+ if ( usb->port->speed == USB_SPEED_HIGH ) {
+ chr |= EHCI_CHR_EPS_HIGH;
+ } else {
+ if ( usb->port->speed == USB_SPEED_FULL ) {
+ chr |= EHCI_CHR_EPS_FULL;
+ } else {
+ chr |= EHCI_CHR_EPS_LOW;
+ }
+ if ( attr == USB_ENDPOINT_ATTR_CONTROL )
+ chr |= EHCI_CHR_CONTROL;
+ }
+
+ return chr;
+}
+
+/**
+ * Determine endpoint capabilities
+ *
+ * @v ep USB endpoint
+ * @ret cap Endpoint capabilities
+ */
+static uint32_t ehci_endpoint_capabilities ( struct usb_endpoint *ep ) {
+ struct usb_device *usb = ep->usb;
+ struct usb_port *tt = usb_transaction_translator ( usb );
+ unsigned int attr = ( ep->attributes & USB_ENDPOINT_ATTR_TYPE_MASK );
+ uint32_t cap;
+ unsigned int i;
+
+ /* Determine basic capabilities */
+ cap = EHCI_CAP_MULT ( ep->burst + 1 );
+
+ /* Determine interrupt schedule mask, if applicable */
+ if ( ( attr == USB_ENDPOINT_ATTR_INTERRUPT ) &&
+ ( ( ep->interval != 0 ) /* avoid infinite loop */ ) ) {
+ for ( i = 0 ; i < 8 /* microframes per frame */ ;
+ i += ep->interval ) {
+ cap |= EHCI_CAP_INTR_SCHED ( i );
+ }
+ }
+
+ /* Set transaction translator hub address and port, if applicable */
+ if ( tt ) {
+ assert ( tt->hub->usb );
+ cap |= ( EHCI_CAP_TT_HUB ( tt->hub->usb->address ) |
+ EHCI_CAP_TT_PORT ( tt->address ) );
+ if ( attr == USB_ENDPOINT_ATTR_INTERRUPT )
+ cap |= EHCI_CAP_SPLIT_SCHED_DEFAULT;
+ }
+
+ return cap;
+}
+
+/**
+ * Update endpoint characteristics and capabilities
+ *
+ * @v ep USB endpoint
+ */
+static void ehci_endpoint_update ( struct usb_endpoint *ep ) {
+ struct ehci_endpoint *endpoint = usb_endpoint_get_hostdata ( ep );
+ struct ehci_queue_head *head;
+
+ /* Update queue characteristics and capabilities */
+ head = endpoint->ring.head;
+ head->chr = cpu_to_le32 ( ehci_endpoint_characteristics ( ep ) );
+ head->cap = cpu_to_le32 ( ehci_endpoint_capabilities ( ep ) );
+}
+
+/**
+ * Open endpoint
+ *
+ * @v ep USB endpoint
+ * @ret rc Return status code
+ */
+static int ehci_endpoint_open ( struct usb_endpoint *ep ) {
+ struct usb_device *usb = ep->usb;
+ struct ehci_device *ehci = usb_get_hostdata ( usb );
+ struct ehci_endpoint *endpoint;
+ int rc;
+
+ /* Allocate and initialise structure */
+ endpoint = zalloc ( sizeof ( *endpoint ) );
+ if ( ! endpoint ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ endpoint->ehci = ehci;
+ endpoint->ep = ep;
+ usb_endpoint_set_hostdata ( ep, endpoint );
+
+ /* Initialise descriptor ring */
+ if ( ( rc = ehci_ring_alloc ( ehci, &endpoint->ring ) ) != 0 )
+ goto err_ring_alloc;
+
+ /* Update queue characteristics and capabilities */
+ ehci_endpoint_update ( ep );
+
+ /* Add to list of endpoints */
+ list_add_tail ( &endpoint->list, &ehci->endpoints );
+
+ /* Add to schedule */
+ ehci_schedule_add ( endpoint );
+
+ return 0;
+
+ ehci_ring_free ( &endpoint->ring );
+ err_ring_alloc:
+ free ( endpoint );
+ err_alloc:
+ return rc;
+}
+
+/**
+ * Close endpoint
+ *
+ * @v ep USB endpoint
+ */
+static void ehci_endpoint_close ( struct usb_endpoint *ep ) {
+ struct ehci_endpoint *endpoint = usb_endpoint_get_hostdata ( ep );
+ struct ehci_device *ehci = endpoint->ehci;
+ struct usb_device *usb = ep->usb;
+ struct io_buffer *iobuf;
+ int rc;
+
+ /* Remove from schedule */
+ if ( ( rc = ehci_schedule_del ( endpoint ) ) != 0 ) {
+ /* No way to prevent hardware from continuing to
+ * access the memory, so leak it.
+ */
+ DBGC ( ehci, "EHCI %s %s could not unschedule: %s\n",
+ usb->name, usb_endpoint_name ( ep ), strerror ( rc ) );
+ return;
+ }
+
+ /* Cancel any incomplete transfers */
+ while ( ehci_ring_fill ( &endpoint->ring ) ) {
+ iobuf = ehci_dequeue ( &endpoint->ring );
+ if ( iobuf )
+ usb_complete_err ( ep, iobuf, -ECANCELED );
+ }
+
+ /* Remove from list of endpoints */
+ list_del ( &endpoint->list );
+
+ /* Free descriptor ring */
+ ehci_ring_free ( &endpoint->ring );
+
+ /* Free endpoint */
+ free ( endpoint );
+}
+
+/**
+ * Reset endpoint
+ *
+ * @v ep USB endpoint
+ * @ret rc Return status code
+ */
+static int ehci_endpoint_reset ( struct usb_endpoint *ep ) {
+ struct ehci_endpoint *endpoint = usb_endpoint_get_hostdata ( ep );
+ struct ehci_ring *ring = &endpoint->ring;
+ struct ehci_transfer_descriptor *cache = &ring->head->cache;
+ uint32_t link;
+
+ /* Sanity checks */
+ assert ( ! ( cache->status & EHCI_STATUS_ACTIVE ) );
+ assert ( cache->status & EHCI_STATUS_HALTED );
+
+ /* Reset residual count */
+ ring->residual = 0;
+
+ /* Reset data toggle */
+ cache->len = 0;
+
+ /* Prepare to restart at next unconsumed descriptor */
+ link = virt_to_phys ( &ring->desc[ ring->cons % EHCI_RING_COUNT ] );
+ cache->next = cpu_to_le32 ( link );
+
+ /* Restart ring */
+ wmb();
+ cache->status = 0;
+
+ return 0;
+}
+
+/**
+ * Update MTU
+ *
+ * @v ep USB endpoint
+ * @ret rc Return status code
+ */
+static int ehci_endpoint_mtu ( struct usb_endpoint *ep ) {
+
+ /* Update endpoint characteristics and capabilities */
+ ehci_endpoint_update ( ep );
+
+ return 0;
+}
+
+/**
+ * Enqueue message transfer
+ *
+ * @v ep USB endpoint
+ * @v iobuf I/O buffer
+ * @ret rc Return status code
+ */
+static int ehci_endpoint_message ( struct usb_endpoint *ep,
+ struct io_buffer *iobuf ) {
+ struct ehci_endpoint *endpoint = usb_endpoint_get_hostdata ( ep );
+ struct ehci_device *ehci = endpoint->ehci;
+ struct usb_setup_packet *packet;
+ unsigned int input;
+ struct ehci_transfer xfers[3];
+ struct ehci_transfer *xfer = xfers;
+ size_t len;
+ int rc;
+
+ /* Construct setup stage */
+ assert ( iob_len ( iobuf ) >= sizeof ( *packet ) );
+ packet = iobuf->data;
+ iob_pull ( iobuf, sizeof ( *packet ) );
+ xfer->data = packet;
+ xfer->len = sizeof ( *packet );
+ xfer->flags = EHCI_FL_PID_SETUP;
+ xfer++;
+
+ /* Construct data stage, if applicable */
+ len = iob_len ( iobuf );
+ input = ( packet->request & cpu_to_le16 ( USB_DIR_IN ) );
+ if ( len ) {
+ xfer->data = iobuf->data;
+ xfer->len = len;
+ xfer->flags = ( EHCI_FL_TOGGLE |
+ ( input ? EHCI_FL_PID_IN : EHCI_FL_PID_OUT ) );
+ xfer++;
+ }
+
+ /* Construct status stage */
+ xfer->data = NULL;
+ xfer->len = 0;
+ xfer->flags = ( EHCI_FL_TOGGLE | EHCI_FL_IOC |
+ ( ( len && input ) ? EHCI_FL_PID_OUT : EHCI_FL_PID_IN));
+ xfer++;
+
+ /* Enqueue transfer */
+ if ( ( rc = ehci_enqueue ( ehci, &endpoint->ring, iobuf, xfers,
+ ( xfer - xfers ) ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/**
+ * Enqueue stream transfer
+ *
+ * @v ep USB endpoint
+ * @v iobuf I/O buffer
+ * @v terminate Terminate using a short packet
+ * @ret rc Return status code
+ */
+static int ehci_endpoint_stream ( struct usb_endpoint *ep,
+ struct io_buffer *iobuf, int terminate ) {
+ struct ehci_endpoint *endpoint = usb_endpoint_get_hostdata ( ep );
+ struct ehci_device *ehci = endpoint->ehci;
+ unsigned int input = ( ep->address & USB_DIR_IN );
+ struct ehci_transfer xfers[2];
+ struct ehci_transfer *xfer = xfers;
+ size_t len = iob_len ( iobuf );
+ int rc;
+
+ /* Create transfer */
+ xfer->data = iobuf->data;
+ xfer->len = len;
+ xfer->flags = ( EHCI_FL_IOC |
+ ( input ? EHCI_FL_PID_IN : EHCI_FL_PID_OUT ) );
+ xfer++;
+ if ( terminate && ( ( len & ( ep->mtu - 1 ) ) == 0 ) ) {
+ xfer->data = NULL;
+ xfer->len = 0;
+ assert ( ! input );
+ xfer->flags = ( EHCI_FL_IOC | EHCI_FL_PID_OUT );
+ xfer++;
+ }
+
+ /* Enqueue transfer */
+ if ( ( rc = ehci_enqueue ( ehci, &endpoint->ring, iobuf, xfers,
+ ( xfer - xfers ) ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/**
+ * Poll for completions
+ *
+ * @v endpoint Endpoint
+ */
+static void ehci_endpoint_poll ( struct ehci_endpoint *endpoint ) {
+ struct ehci_device *ehci = endpoint->ehci;
+ struct ehci_ring *ring = &endpoint->ring;
+ struct ehci_transfer_descriptor *desc;
+ struct usb_endpoint *ep = endpoint->ep;
+ struct usb_device *usb = ep->usb;
+ struct io_buffer *iobuf;
+ unsigned int index;
+ unsigned int status;
+ int rc;
+
+ /* Consume all completed descriptors */
+ while ( ehci_ring_fill ( &endpoint->ring ) ) {
+
+ /* Stop if we reach an uncompleted descriptor */
+ rmb();
+ index = ( ring->cons % EHCI_RING_COUNT );
+ desc = &ring->desc[index];
+ status = desc->status;
+ if ( status & EHCI_STATUS_ACTIVE )
+ break;
+
+ /* Consume this descriptor */
+ iobuf = ehci_dequeue ( ring );
+
+ /* If we have encountered an error, then consume all
+ * remaining descriptors in this transaction, report
+ * the error to the USB core, and stop further
+ * processing.
+ */
+ if ( status & EHCI_STATUS_HALTED ) {
+ rc = -EIO_STATUS ( status );
+ DBGC ( ehci, "EHCI %s %s completion %d failed (status "
+ "%02x): %s\n", usb->name,
+ usb_endpoint_name ( ep ), index, status,
+ strerror ( rc ) );
+ while ( ! iobuf )
+ iobuf = ehci_dequeue ( ring );
+ usb_complete_err ( endpoint->ep, iobuf, rc );
+ return;
+ }
+
+ /* Accumulate residual data count */
+ ring->residual += ( le16_to_cpu ( desc->len ) & EHCI_LEN_MASK );
+
+ /* If this is not the end of a transaction (i.e. has
+ * no I/O buffer), then continue to next descriptor.
+ */
+ if ( ! iobuf )
+ continue;
+
+ /* Update I/O buffer length */
+ iob_unput ( iobuf, ring->residual );
+ ring->residual = 0;
+
+ /* Report completion to USB core */
+ usb_complete ( endpoint->ep, iobuf );
+ }
+}
+
+/******************************************************************************
+ *
+ * Device operations
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Open device
+ *
+ * @v usb USB device
+ * @ret rc Return status code
+ */
+static int ehci_device_open ( struct usb_device *usb ) {
+ struct ehci_device *ehci = usb_bus_get_hostdata ( usb->port->hub->bus );
+
+ usb_set_hostdata ( usb, ehci );
+ return 0;
+}
+
+/**
+ * Close device
+ *
+ * @v usb USB device
+ */
+static void ehci_device_close ( struct usb_device *usb ) {
+ struct ehci_device *ehci = usb_get_hostdata ( usb );
+ struct usb_bus *bus = ehci->bus;
+
+ /* Free device address, if assigned */
+ if ( usb->address )
+ usb_free_address ( bus, usb->address );
+}
+
+/**
+ * Assign device address
+ *
+ * @v usb USB device
+ * @ret rc Return status code
+ */
+static int ehci_device_address ( struct usb_device *usb ) {
+ struct ehci_device *ehci = usb_get_hostdata ( usb );
+ struct usb_bus *bus = ehci->bus;
+ struct usb_endpoint *ep0 = usb_endpoint ( usb, USB_EP0_ADDRESS );
+ int address;
+ int rc;
+
+ /* Sanity checks */
+ assert ( usb->address == 0 );
+ assert ( ep0 != NULL );
+
+ /* Allocate device address */
+ address = usb_alloc_address ( bus );
+ if ( address < 0 ) {
+ rc = address;
+ DBGC ( ehci, "EHCI %s could not allocate address: %s\n",
+ usb->name, strerror ( rc ) );
+ goto err_alloc_address;
+ }
+
+ /* Set address */
+ if ( ( rc = usb_set_address ( usb, address ) ) != 0 )
+ goto err_set_address;
+
+ /* Update device address */
+ usb->address = address;
+
+ /* Update control endpoint characteristics and capabilities */
+ ehci_endpoint_update ( ep0 );
+
+ return 0;
+
+ err_set_address:
+ usb_free_address ( bus, address );
+ err_alloc_address:
+ return rc;
+}
+
+/******************************************************************************
+ *
+ * Hub operations
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Open hub
+ *
+ * @v hub USB hub
+ * @ret rc Return status code
+ */
+static int ehci_hub_open ( struct usb_hub *hub __unused ) {
+
+ /* Nothing to do */
+ return 0;
+}
+
+/**
+ * Close hub
+ *
+ * @v hub USB hub
+ */
+static void ehci_hub_close ( struct usb_hub *hub __unused ) {
+
+ /* Nothing to do */
+}
+
+/******************************************************************************
+ *
+ * Root hub operations
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Open root hub
+ *
+ * @v hub USB hub
+ * @ret rc Return status code
+ */
+static int ehci_root_open ( struct usb_hub *hub ) {
+ struct usb_bus *bus = hub->bus;
+ struct ehci_device *ehci = usb_bus_get_hostdata ( bus );
+ uint32_t portsc;
+ unsigned int i;
+
+ /* Route all ports to EHCI controller */
+ writel ( EHCI_CONFIGFLAG_CF, ehci->op + EHCI_OP_CONFIGFLAG );
+
+ /* Enable power to all ports */
+ for ( i = 1 ; i <= ehci->ports ; i++ ) {
+ portsc = readl ( ehci->op + EHCI_OP_PORTSC ( i ) );
+ portsc &= ~EHCI_PORTSC_CHANGE;
+ portsc |= EHCI_PORTSC_PP;
+ writel ( portsc, ehci->op + EHCI_OP_PORTSC ( i ) );
+ }
+
+ /* Wait 20ms after potentially enabling power to a port */
+ mdelay ( EHCI_PORT_POWER_DELAY_MS );
+
+ /* Record hub driver private data */
+ usb_hub_set_drvdata ( hub, ehci );
+
+ return 0;
+}
+
+/**
+ * Close root hub
+ *
+ * @v hub USB hub
+ */
+static void ehci_root_close ( struct usb_hub *hub ) {
+ struct ehci_device *ehci = usb_hub_get_drvdata ( hub );
+
+ /* Route all ports back to companion controllers */
+ writel ( 0, ehci->op + EHCI_OP_CONFIGFLAG );
+
+ /* Clear hub driver private data */
+ usb_hub_set_drvdata ( hub, NULL );
+}
+
+/**
+ * Enable port
+ *
+ * @v hub USB hub
+ * @v port USB port
+ * @ret rc Return status code
+ */
+static int ehci_root_enable ( struct usb_hub *hub, struct usb_port *port ) {
+ struct ehci_device *ehci = usb_hub_get_drvdata ( hub );
+ uint32_t portsc;
+ unsigned int line;
+ unsigned int i;
+
+ /* Check for a low-speed device */
+ portsc = readl ( ehci->op + EHCI_OP_PORTSC ( port->address ) );
+ line = EHCI_PORTSC_LINE_STATUS ( portsc );
+ if ( line == EHCI_PORTSC_LINE_STATUS_LOW ) {
+ DBGC ( ehci, "EHCI %s-%d detected low-speed device: "
+ "disowning\n", ehci->name, port->address );
+ goto disown;
+ }
+
+ /* Reset port */
+ portsc &= ~( EHCI_PORTSC_PED | EHCI_PORTSC_CHANGE );
+ portsc |= EHCI_PORTSC_PR;
+ writel ( portsc, ehci->op + EHCI_OP_PORTSC ( port->address ) );
+ mdelay ( USB_RESET_DELAY_MS );
+ portsc &= ~EHCI_PORTSC_PR;
+ writel ( portsc, ehci->op + EHCI_OP_PORTSC ( port->address ) );
+
+ /* Wait for reset to complete */
+ for ( i = 0 ; i < EHCI_PORT_RESET_MAX_WAIT_MS ; i++ ) {
+
+ /* Check port status */
+ portsc = readl ( ehci->op + EHCI_OP_PORTSC ( port->address ) );
+ if ( ! ( portsc & EHCI_PORTSC_PR ) ) {
+ if ( portsc & EHCI_PORTSC_PED )
+ return 0;
+ DBGC ( ehci, "EHCI %s-%d not enabled after reset: "
+ "disowning\n", ehci->name, port->address );
+ goto disown;
+ }
+
+ /* Delay */
+ mdelay ( 1 );
+ }
+
+ DBGC ( ehci, "EHCI %s-%d timed out waiting for port to reset\n",
+ ehci->name, port->address );
+ return -ETIMEDOUT;
+
+ disown:
+ /* Disown port */
+ portsc &= ~EHCI_PORTSC_CHANGE;
+ portsc |= EHCI_PORTSC_OWNER;
+ writel ( portsc, ehci->op + EHCI_OP_PORTSC ( port->address ) );
+
+ /* Delay to allow child companion controllers to settle */
+ mdelay ( EHCI_DISOWN_DELAY_MS );
+
+ /* Poll child companion controllers */
+ ehci_poll_companions ( ehci );
+
+ return -ENODEV;
+}
+
+/**
+ * Disable port
+ *
+ * @v hub USB hub
+ * @v port USB port
+ * @ret rc Return status code
+ */
+static int ehci_root_disable ( struct usb_hub *hub, struct usb_port *port ) {
+ struct ehci_device *ehci = usb_hub_get_drvdata ( hub );
+ uint32_t portsc;
+
+ /* Disable port */
+ portsc = readl ( ehci->op + EHCI_OP_PORTSC ( port->address ) );
+ portsc &= ~( EHCI_PORTSC_PED | EHCI_PORTSC_CHANGE );
+ writel ( portsc, ehci->op + EHCI_OP_PORTSC ( port->address ) );
+
+ return 0;
+}
+
+/**
+ * Update root hub port speed
+ *
+ * @v hub USB hub
+ * @v port USB port
+ * @ret rc Return status code
+ */
+static int ehci_root_speed ( struct usb_hub *hub, struct usb_port *port ) {
+ struct ehci_device *ehci = usb_hub_get_drvdata ( hub );
+ uint32_t portsc;
+ unsigned int speed;
+ unsigned int line;
+ int ccs;
+ int csc;
+ int ped;
+
+ /* Read port status */
+ portsc = readl ( ehci->op + EHCI_OP_PORTSC ( port->address ) );
+ DBGC2 ( ehci, "EHCI %s-%d status is %08x\n",
+ ehci->name, port->address, portsc );
+ ccs = ( portsc & EHCI_PORTSC_CCS );
+ csc = ( portsc & EHCI_PORTSC_CSC );
+ ped = ( portsc & EHCI_PORTSC_PED );
+ line = EHCI_PORTSC_LINE_STATUS ( portsc );
+
+ /* Record disconnections and clear changes */
+ port->disconnected |= csc;
+ writel ( portsc, ehci->op + EHCI_OP_PORTSC ( port->address ) );
+
+ /* Determine port speed */
+ if ( ! ccs ) {
+ /* Port not connected */
+ speed = USB_SPEED_NONE;
+ } else if ( line == EHCI_PORTSC_LINE_STATUS_LOW ) {
+ /* Detected as low-speed */
+ speed = USB_SPEED_LOW;
+ } else if ( ped ) {
+ /* Port already enabled: must be high-speed */
+ speed = USB_SPEED_HIGH;
+ } else {
+ /* Not low-speed and not yet enabled. Could be either
+ * full-speed or high-speed; we can't yet tell.
+ */
+ speed = USB_SPEED_FULL;
+ }
+ port->speed = speed;
+ return 0;
+}
+
+/**
+ * Clear transaction translator buffer
+ *
+ * @v hub USB hub
+ * @v port USB port
+ * @v ep USB endpoint
+ * @ret rc Return status code
+ */
+static int ehci_root_clear_tt ( struct usb_hub *hub, struct usb_port *port,
+ struct usb_endpoint *ep ) {
+ struct ehci_device *ehci = usb_hub_get_drvdata ( hub );
+
+ /* Should never be called; this is a root hub */
+ DBGC ( ehci, "EHCI %s-%d nonsensical CLEAR_TT for %s %s\n", ehci->name,
+ port->address, ep->usb->name, usb_endpoint_name ( ep ) );
+
+ return -ENOTSUP;
+}
+
+/**
+ * Poll for port status changes
+ *
+ * @v hub USB hub
+ * @v port USB port
+ */
+static void ehci_root_poll ( struct usb_hub *hub, struct usb_port *port ) {
+ struct ehci_device *ehci = usb_hub_get_drvdata ( hub );
+ uint32_t portsc;
+ uint32_t change;
+
+ /* Do nothing unless something has changed */
+ portsc = readl ( ehci->op + EHCI_OP_PORTSC ( port->address ) );
+ change = ( portsc & EHCI_PORTSC_CHANGE );
+ if ( ! change )
+ return;
+
+ /* Record disconnections and clear changes */
+ port->disconnected |= ( portsc & EHCI_PORTSC_CSC );
+ writel ( portsc, ehci->op + EHCI_OP_PORTSC ( port->address ) );
+
+ /* Report port status change */
+ usb_port_changed ( port );
+}
+
+/******************************************************************************
+ *
+ * Bus operations
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Open USB bus
+ *
+ * @v bus USB bus
+ * @ret rc Return status code
+ */
+static int ehci_bus_open ( struct usb_bus *bus ) {
+ struct ehci_device *ehci = usb_bus_get_hostdata ( bus );
+ unsigned int frames;
+ size_t len;
+ int rc;
+
+ /* Sanity checks */
+ assert ( list_empty ( &ehci->async ) );
+ assert ( list_empty ( &ehci->periodic ) );
+
+ /* Allocate and initialise asynchronous queue head */
+ ehci->head = malloc_dma ( sizeof ( *ehci->head ),
+ ehci_align ( sizeof ( *ehci->head ) ) );
+ if ( ! ehci->head ) {
+ rc = -ENOMEM;
+ goto err_alloc_head;
+ }
+ memset ( ehci->head, 0, sizeof ( *ehci->head ) );
+ ehci->head->chr = cpu_to_le32 ( EHCI_CHR_HEAD );
+ ehci->head->cache.next = cpu_to_le32 ( EHCI_LINK_TERMINATE );
+ ehci->head->cache.status = EHCI_STATUS_HALTED;
+ ehci_async_schedule ( ehci );
+ writel ( virt_to_phys ( ehci->head ),
+ ehci->op + EHCI_OP_ASYNCLISTADDR );
+
+ /* Use async queue head to determine control data structure segment */
+ ehci->ctrldssegment =
+ ( ( ( uint64_t ) virt_to_phys ( ehci->head ) ) >> 32 );
+ if ( ehci->addr64 ) {
+ writel ( ehci->ctrldssegment, ehci->op + EHCI_OP_CTRLDSSEGMENT);
+ } else if ( ehci->ctrldssegment ) {
+ DBGC ( ehci, "EHCI %s CTRLDSSEGMENT not supported\n",
+ ehci->name );
+ rc = -ENOTSUP;
+ goto err_ctrldssegment;
+ }
+
+ /* Allocate periodic frame list */
+ frames = EHCI_PERIODIC_FRAMES ( ehci->flsize );
+ len = ( frames * sizeof ( ehci->frame[0] ) );
+ ehci->frame = malloc_dma ( len, EHCI_PAGE_ALIGN );
+ if ( ! ehci->frame ) {
+ rc = -ENOMEM;
+ goto err_alloc_frame;
+ }
+ if ( ( rc = ehci_ctrl_reachable ( ehci, ehci->frame ) ) != 0 ) {
+ DBGC ( ehci, "EHCI %s frame list unreachable\n", ehci->name );
+ goto err_unreachable_frame;
+ }
+ ehci_periodic_schedule ( ehci );
+ writel ( virt_to_phys ( ehci->frame ),
+ ehci->op + EHCI_OP_PERIODICLISTBASE );
+
+ /* Start controller */
+ ehci_run ( ehci );
+
+ return 0;
+
+ ehci_stop ( ehci );
+ err_unreachable_frame:
+ free_dma ( ehci->frame, len );
+ err_alloc_frame:
+ err_ctrldssegment:
+ free_dma ( ehci->head, sizeof ( *ehci->head ) );
+ err_alloc_head:
+ return rc;
+}
+
+/**
+ * Close USB bus
+ *
+ * @v bus USB bus
+ */
+static void ehci_bus_close ( struct usb_bus *bus ) {
+ struct ehci_device *ehci = usb_bus_get_hostdata ( bus );
+ unsigned int frames = EHCI_PERIODIC_FRAMES ( ehci->flsize );
+
+ /* Sanity checks */
+ assert ( list_empty ( &ehci->async ) );
+ assert ( list_empty ( &ehci->periodic ) );
+
+ /* Stop controller */
+ ehci_stop ( ehci );
+
+ /* Free periodic frame list */
+ free_dma ( ehci->frame, ( frames * sizeof ( ehci->frame[0] ) ) );
+
+ /* Free asynchronous schedule */
+ free_dma ( ehci->head, sizeof ( *ehci->head ) );
+}
+
+/**
+ * Poll USB bus
+ *
+ * @v bus USB bus
+ */
+static void ehci_bus_poll ( struct usb_bus *bus ) {
+ struct ehci_device *ehci = usb_bus_get_hostdata ( bus );
+ struct usb_hub *hub = bus->hub;
+ struct ehci_endpoint *endpoint;
+ unsigned int i;
+ uint32_t usbsts;
+ uint32_t change;
+
+ /* Do nothing unless something has changed */
+ usbsts = readl ( ehci->op + EHCI_OP_USBSTS );
+ assert ( usbsts & EHCI_USBSTS_ASYNC );
+ assert ( usbsts & EHCI_USBSTS_PERIODIC );
+ assert ( ! ( usbsts & EHCI_USBSTS_HCH ) );
+ change = ( usbsts & EHCI_USBSTS_CHANGE );
+ if ( ! change )
+ return;
+
+ /* Acknowledge changes */
+ writel ( usbsts, ehci->op + EHCI_OP_USBSTS );
+
+ /* Process completions, if applicable */
+ if ( change & ( EHCI_USBSTS_USBINT | EHCI_USBSTS_USBERRINT ) ) {
+
+ /* Iterate over all endpoints looking for completed
+ * descriptors. We trust that completion handlers are
+ * minimal and will not do anything that could
+ * plausibly affect the endpoint list itself.
+ */
+ list_for_each_entry ( endpoint, &ehci->endpoints, list )
+ ehci_endpoint_poll ( endpoint );
+ }
+
+ /* Process port status changes, if applicable */
+ if ( change & EHCI_USBSTS_PORT ) {
+
+ /* Iterate over all ports looking for status changes */
+ for ( i = 1 ; i <= ehci->ports ; i++ )
+ ehci_root_poll ( hub, usb_port ( hub, i ) );
+ }
+
+ /* Report fatal errors */
+ if ( change & EHCI_USBSTS_SYSERR )
+ DBGC ( ehci, "EHCI %s host system error\n", ehci->name );
+}
+
+/******************************************************************************
+ *
+ * PCI interface
+ *
+ ******************************************************************************
+ */
+
+/** USB host controller operations */
+static struct usb_host_operations ehci_operations = {
+ .endpoint = {
+ .open = ehci_endpoint_open,
+ .close = ehci_endpoint_close,
+ .reset = ehci_endpoint_reset,
+ .mtu = ehci_endpoint_mtu,
+ .message = ehci_endpoint_message,
+ .stream = ehci_endpoint_stream,
+ },
+ .device = {
+ .open = ehci_device_open,
+ .close = ehci_device_close,
+ .address = ehci_device_address,
+ },
+ .bus = {
+ .open = ehci_bus_open,
+ .close = ehci_bus_close,
+ .poll = ehci_bus_poll,
+ },
+ .hub = {
+ .open = ehci_hub_open,
+ .close = ehci_hub_close,
+ },
+ .root = {
+ .open = ehci_root_open,
+ .close = ehci_root_close,
+ .enable = ehci_root_enable,
+ .disable = ehci_root_disable,
+ .speed = ehci_root_speed,
+ .clear_tt = ehci_root_clear_tt,
+ },
+};
+
+/**
+ * Probe PCI device
+ *
+ * @v pci PCI device
+ * @ret rc Return status code
+ */
+static int ehci_probe ( struct pci_device *pci ) {
+ struct ehci_device *ehci;
+ struct usb_port *port;
+ unsigned long bar_start;
+ size_t bar_size;
+ unsigned int i;
+ int rc;
+
+ /* Allocate and initialise structure */
+ ehci = zalloc ( sizeof ( *ehci ) );
+ if ( ! ehci ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ ehci->name = pci->dev.name;
+ INIT_LIST_HEAD ( &ehci->endpoints );
+ INIT_LIST_HEAD ( &ehci->async );
+ INIT_LIST_HEAD ( &ehci->periodic );
+
+ /* Fix up PCI device */
+ adjust_pci_device ( pci );
+
+ /* Map registers */
+ bar_start = pci_bar_start ( pci, EHCI_BAR );
+ bar_size = pci_bar_size ( pci, EHCI_BAR );
+ ehci->regs = ioremap ( bar_start, bar_size );
+ if ( ! ehci->regs ) {
+ rc = -ENODEV;
+ goto err_ioremap;
+ }
+
+ /* Initialise EHCI device */
+ ehci_init ( ehci, ehci->regs );
+
+ /* Initialise USB legacy support and claim ownership */
+ ehci_legacy_init ( ehci, pci );
+ ehci_legacy_claim ( ehci, pci );
+
+ /* Reset device */
+ if ( ( rc = ehci_reset ( ehci ) ) != 0 )
+ goto err_reset;
+
+ /* Allocate USB bus */
+ ehci->bus = alloc_usb_bus ( &pci->dev, ehci->ports, EHCI_MTU,
+ &ehci_operations );
+ if ( ! ehci->bus ) {
+ rc = -ENOMEM;
+ goto err_alloc_bus;
+ }
+ usb_bus_set_hostdata ( ehci->bus, ehci );
+ usb_hub_set_drvdata ( ehci->bus->hub, ehci );
+
+ /* Set port protocols */
+ for ( i = 1 ; i <= ehci->ports ; i++ ) {
+ port = usb_port ( ehci->bus->hub, i );
+ port->protocol = USB_PROTO_2_0;
+ }
+
+ /* Register USB bus */
+ if ( ( rc = register_usb_bus ( ehci->bus ) ) != 0 )
+ goto err_register;
+
+ pci_set_drvdata ( pci, ehci );
+ return 0;
+
+ unregister_usb_bus ( ehci->bus );
+ err_register:
+ free_usb_bus ( ehci->bus );
+ err_alloc_bus:
+ ehci_reset ( ehci );
+ err_reset:
+ ehci_legacy_release ( ehci, pci );
+ iounmap ( ehci->regs );
+ err_ioremap:
+ free ( ehci );
+ err_alloc:
+ return rc;
+}
+
+/**
+ * Remove PCI device
+ *
+ * @v pci PCI device
+ */
+static void ehci_remove ( struct pci_device *pci ) {
+ struct ehci_device *ehci = pci_get_drvdata ( pci );
+ struct usb_bus *bus = ehci->bus;
+
+ unregister_usb_bus ( bus );
+ assert ( list_empty ( &ehci->async ) );
+ assert ( list_empty ( &ehci->periodic ) );
+ free_usb_bus ( bus );
+ ehci_reset ( ehci );
+ ehci_legacy_release ( ehci, pci );
+ iounmap ( ehci->regs );
+ free ( ehci );
+}
+
+/** EHCI PCI device IDs */
+static struct pci_device_id ehci_ids[] = {
+ PCI_ROM ( 0xffff, 0xffff, "ehci", "EHCI", 0 ),
+};
+
+/** EHCI PCI driver */
+struct pci_driver ehci_driver __pci_driver = {
+ .ids = ehci_ids,
+ .id_count = ( sizeof ( ehci_ids ) / sizeof ( ehci_ids[0] ) ),
+ .class = PCI_CLASS_ID ( PCI_CLASS_SERIAL, PCI_CLASS_SERIAL_USB,
+ PCI_CLASS_SERIAL_USB_EHCI ),
+ .probe = ehci_probe,
+ .remove = ehci_remove,
+};
+
+/**
+ * Prepare for exit
+ *
+ * @v booting System is shutting down for OS boot
+ */
+static void ehci_shutdown ( int booting ) {
+ /* If we are shutting down to boot an OS, then prevent the
+ * release of ownership back to BIOS.
+ */
+ ehci_legacy_prevent_release = booting;
+}
+
+/** Startup/shutdown function */
+struct startup_fn ehci_startup __startup_fn ( STARTUP_LATE ) = {
+ .shutdown = ehci_shutdown,
+};
diff --git a/roms/ipxe/src/drivers/usb/ehci.h b/roms/ipxe/src/drivers/usb/ehci.h
new file mode 100644
index 000000000..42e282e92
--- /dev/null
+++ b/roms/ipxe/src/drivers/usb/ehci.h
@@ -0,0 +1,544 @@
+#ifndef _IPXE_EHCI_H
+#define _IPXE_EHCI_H
+
+/** @file
+ *
+ * USB Enhanced Host Controller Interface (EHCI) driver
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <ipxe/pci.h>
+#include <ipxe/usb.h>
+
+/** Minimum alignment required for data structures
+ *
+ * With the exception of the periodic frame list (which is
+ * page-aligned), data structures used by EHCI generally require
+ * 32-byte alignment and must not cross a 4kB page boundary. We
+ * simplify this requirement by aligning each structure on its own
+ * size, with a minimum of a 32 byte alignment.
+ */
+#define EHCI_MIN_ALIGN 32
+
+/** Maximum transfer size
+ *
+ * EHCI allows for transfers of up to 20kB with page-alignment, or
+ * 16kB with arbitrary alignment.
+ */
+#define EHCI_MTU 16384
+
+/** Page-alignment required for some data structures */
+#define EHCI_PAGE_ALIGN 4096
+
+/** EHCI PCI BAR */
+#define EHCI_BAR PCI_BASE_ADDRESS_0
+
+/** Capability register length */
+#define EHCI_CAP_CAPLENGTH 0x00
+
+/** Host controller interface version number */
+#define EHCI_CAP_HCIVERSION 0x02
+
+/** Structural parameters */
+#define EHCI_CAP_HCSPARAMS 0x04
+
+/** Number of ports */
+#define EHCI_HCSPARAMS_PORTS(params) ( ( (params) >> 0 ) & 0x0f )
+
+/** Capability parameters */
+#define EHCI_CAP_HCCPARAMS 0x08
+
+/** 64-bit addressing capability */
+#define EHCI_HCCPARAMS_ADDR64(params) ( ( (params) >> 0 ) & 0x1 )
+
+/** Programmable frame list flag */
+#define EHCI_HCCPARAMS_FLSIZE(params) ( ( (params) >> 1 ) & 0x1 )
+
+/** EHCI extended capabilities pointer */
+#define EHCI_HCCPARAMS_EECP(params) ( ( ( (params) >> 8 ) & 0xff ) )
+
+/** EHCI extended capability ID */
+#define EHCI_EECP_ID(eecp) ( ( (eecp) >> 0 ) & 0xff )
+
+/** Next EHCI extended capability pointer */
+#define EHCI_EECP_NEXT(eecp) ( ( ( (eecp) >> 8 ) & 0xff ) )
+
+/** USB legacy support extended capability */
+#define EHCI_EECP_ID_LEGACY 1
+
+/** USB legacy support BIOS owned semaphore */
+#define EHCI_USBLEGSUP_BIOS 0x02
+
+/** USB legacy support BIOS ownership flag */
+#define EHCI_USBLEGSUP_BIOS_OWNED 0x01
+
+/** USB legacy support OS owned semaphore */
+#define EHCI_USBLEGSUP_OS 0x03
+
+/** USB legacy support OS ownership flag */
+#define EHCI_USBLEGSUP_OS_OWNED 0x01
+
+/** USB legacy support control/status */
+#define EHCI_USBLEGSUP_CTLSTS 0x04
+
+/** USB command register */
+#define EHCI_OP_USBCMD 0x00
+
+/** Run/stop */
+#define EHCI_USBCMD_RUN 0x00000001UL
+
+/** Host controller reset */
+#define EHCI_USBCMD_HCRST 0x00000002UL
+
+/** Frame list size */
+#define EHCI_USBCMD_FLSIZE(flsize) ( (flsize) << 2 )
+
+/** Frame list size mask */
+#define EHCI_USBCMD_FLSIZE_MASK EHCI_USBCMD_FLSIZE ( 3 )
+
+/** Default frame list size */
+#define EHCI_FLSIZE_DEFAULT 0
+
+/** Smallest allowed frame list size */
+#define EHCI_FLSIZE_SMALL 2
+
+/** Number of elements in frame list */
+#define EHCI_PERIODIC_FRAMES(flsize) ( 1024 >> (flsize) )
+
+/** Periodic schedule enable */
+#define EHCI_USBCMD_PERIODIC 0x00000010UL
+
+/** Asynchronous schedule enable */
+#define EHCI_USBCMD_ASYNC 0x00000020UL
+
+/** Asyncchronous schedule advance doorbell */
+#define EHCI_USBCMD_ASYNC_ADVANCE 0x000040UL
+
+/** USB status register */
+#define EHCI_OP_USBSTS 0x04
+
+/** USB interrupt */
+#define EHCI_USBSTS_USBINT 0x00000001UL
+
+/** USB error interrupt */
+#define EHCI_USBSTS_USBERRINT 0x00000002UL
+
+/** Port change detect */
+#define EHCI_USBSTS_PORT 0x00000004UL
+
+/** Frame list rollover */
+#define EHCI_USBSTS_ROLLOVER 0x00000008UL
+
+/** Host system error */
+#define EHCI_USBSTS_SYSERR 0x00000010UL
+
+/** Asynchronous schedule advanced */
+#define EHCI_USBSTS_ASYNC_ADVANCE 0x00000020UL
+
+/** Periodic schedule enabled */
+#define EHCI_USBSTS_PERIODIC 0x00004000UL
+
+/** Asynchronous schedule enabled */
+#define EHCI_USBSTS_ASYNC 0x00008000UL
+
+/** Host controller halted */
+#define EHCI_USBSTS_HCH 0x00001000UL
+
+/** USB status change mask */
+#define EHCI_USBSTS_CHANGE \
+ ( EHCI_USBSTS_USBINT | EHCI_USBSTS_USBERRINT | \
+ EHCI_USBSTS_PORT | EHCI_USBSTS_ROLLOVER | \
+ EHCI_USBSTS_SYSERR | EHCI_USBSTS_ASYNC_ADVANCE )
+
+/** USB interrupt enable register */
+#define EHCI_OP_USBINTR 0x08
+
+/** Frame index register */
+#define EHCI_OP_FRINDEX 0x0c
+
+/** Control data structure segment register */
+#define EHCI_OP_CTRLDSSEGMENT 0x10
+
+/** Periodic frame list base address register */
+#define EHCI_OP_PERIODICLISTBASE 0x14
+
+/** Current asynchronous list address register */
+#define EHCI_OP_ASYNCLISTADDR 0x18
+
+/** Configure flag register */
+#define EHCI_OP_CONFIGFLAG 0x40
+
+/** Configure flag */
+#define EHCI_CONFIGFLAG_CF 0x00000001UL
+
+/** Port status and control register */
+#define EHCI_OP_PORTSC(port) ( 0x40 + ( (port) << 2 ) )
+
+/** Current connect status */
+#define EHCI_PORTSC_CCS 0x00000001UL
+
+/** Connect status change */
+#define EHCI_PORTSC_CSC 0x00000002UL
+
+/** Port enabled */
+#define EHCI_PORTSC_PED 0x00000004UL
+
+/** Port enabled/disabled change */
+#define EHCI_PORTSC_PEC 0x00000008UL
+
+/** Over-current change */
+#define EHCI_PORTSC_OCC 0x00000020UL
+
+/** Port reset */
+#define EHCI_PORTSC_PR 0x00000100UL
+
+/** Line status */
+#define EHCI_PORTSC_LINE_STATUS(portsc) ( ( (portsc) >> 10 ) & 0x3 )
+
+/** Line status: low-speed device */
+#define EHCI_PORTSC_LINE_STATUS_LOW 0x1
+
+/** Port power */
+#define EHCI_PORTSC_PP 0x00001000UL
+
+/** Port owner */
+#define EHCI_PORTSC_OWNER 0x00002000UL
+
+/** Port status change mask */
+#define EHCI_PORTSC_CHANGE \
+ ( EHCI_PORTSC_CSC | EHCI_PORTSC_PEC | EHCI_PORTSC_OCC )
+
+/** List terminator */
+#define EHCI_LINK_TERMINATE 0x00000001UL
+
+/** Frame list type */
+#define EHCI_LINK_TYPE(type) ( (type) << 1 )
+
+/** Queue head type */
+#define EHCI_LINK_TYPE_QH EHCI_LINK_TYPE ( 1 )
+
+/** A periodic frame list entry */
+struct ehci_periodic_frame {
+ /** First queue head */
+ uint32_t link;
+} __attribute__ (( packed ));
+
+/** A transfer descriptor */
+struct ehci_transfer_descriptor {
+ /** Next transfer descriptor */
+ uint32_t next;
+ /** Alternate next transfer descriptor */
+ uint32_t alt;
+ /** Status */
+ uint8_t status;
+ /** Flags */
+ uint8_t flags;
+ /** Transfer length */
+ uint16_t len;
+ /** Buffer pointers (low 32 bits) */
+ uint32_t low[5];
+ /** Extended buffer pointers (high 32 bits) */
+ uint32_t high[5];
+ /** Reserved */
+ uint8_t reserved[12];
+} __attribute__ (( packed ));
+
+/** Transaction error */
+#define EHCI_STATUS_XACT_ERR 0x08
+
+/** Babble detected */
+#define EHCI_STATUS_BABBLE 0x10
+
+/** Data buffer error */
+#define EHCI_STATUS_BUFFER 0x20
+
+/** Halted */
+#define EHCI_STATUS_HALTED 0x40
+
+/** Active */
+#define EHCI_STATUS_ACTIVE 0x80
+
+/** PID code */
+#define EHCI_FL_PID(code) ( (code) << 0 )
+
+/** OUT token */
+#define EHCI_FL_PID_OUT EHCI_FL_PID ( 0 )
+
+/** IN token */
+#define EHCI_FL_PID_IN EHCI_FL_PID ( 1 )
+
+/** SETUP token */
+#define EHCI_FL_PID_SETUP EHCI_FL_PID ( 2 )
+
+/** Error counter */
+#define EHCI_FL_CERR( count ) ( (count) << 2 )
+
+/** Error counter maximum value */
+#define EHCI_FL_CERR_MAX EHCI_FL_CERR ( 3 )
+
+/** Interrupt on completion */
+#define EHCI_FL_IOC 0x80
+
+/** Length mask */
+#define EHCI_LEN_MASK 0x7fff
+
+/** Data toggle */
+#define EHCI_LEN_TOGGLE 0x8000
+
+/** A queue head */
+struct ehci_queue_head {
+ /** Horizontal link pointer */
+ uint32_t link;
+ /** Endpoint characteristics */
+ uint32_t chr;
+ /** Endpoint capabilities */
+ uint32_t cap;
+ /** Current transfer descriptor */
+ uint32_t current;
+ /** Transfer descriptor cache */
+ struct ehci_transfer_descriptor cache;
+} __attribute__ (( packed ));
+
+/** Device address */
+#define EHCI_CHR_ADDRESS( address ) ( (address) << 0 )
+
+/** Endpoint number */
+#define EHCI_CHR_ENDPOINT( address ) ( ( (address) & 0xf ) << 8 )
+
+/** Endpoint speed */
+#define EHCI_CHR_EPS( eps ) ( (eps) << 12 )
+
+/** Full-speed endpoint */
+#define EHCI_CHR_EPS_FULL EHCI_CHR_EPS ( 0 )
+
+/** Low-speed endpoint */
+#define EHCI_CHR_EPS_LOW EHCI_CHR_EPS ( 1 )
+
+/** High-speed endpoint */
+#define EHCI_CHR_EPS_HIGH EHCI_CHR_EPS ( 2 )
+
+/** Explicit data toggles */
+#define EHCI_CHR_TOGGLE 0x00004000UL
+
+/** Head of reclamation list flag */
+#define EHCI_CHR_HEAD 0x00008000UL
+
+/** Maximum packet length */
+#define EHCI_CHR_MAX_LEN( len ) ( (len) << 16 )
+
+/** Control endpoint flag */
+#define EHCI_CHR_CONTROL 0x08000000UL
+
+/** Interrupt schedule mask */
+#define EHCI_CAP_INTR_SCHED( uframe ) ( 1 << ( (uframe) + 0 ) )
+
+/** Split completion schedule mask */
+#define EHCI_CAP_SPLIT_SCHED( uframe ) ( 1 << ( (uframe) + 8 ) )
+
+/** Default split completion schedule mask
+ *
+ * We schedule all split starts in microframe 0, on the assumption
+ * that we will never have to deal with more than sixteen actively
+ * interrupting devices via the same transaction translator. We
+ * schedule split completions for all remaining microframes after
+ * microframe 1 (in which the low-speed or full-speed transaction is
+ * assumed to execute). This is a very crude approximation designed
+ * to avoid the need for calculating exactly when low-speed and
+ * full-speed transactions will execute. Since we only ever deal with
+ * interrupt endpoints (rather than isochronous endpoints), the volume
+ * of periodic traffic is extremely low, and this approximation should
+ * remain valid.
+ */
+#define EHCI_CAP_SPLIT_SCHED_DEFAULT \
+ ( EHCI_CAP_SPLIT_SCHED ( 2 ) | EHCI_CAP_SPLIT_SCHED ( 3 ) | \
+ EHCI_CAP_SPLIT_SCHED ( 4 ) | EHCI_CAP_SPLIT_SCHED ( 5 ) | \
+ EHCI_CAP_SPLIT_SCHED ( 6 ) | EHCI_CAP_SPLIT_SCHED ( 7 ) )
+
+/** Transaction translator hub address */
+#define EHCI_CAP_TT_HUB( address ) ( (address) << 16 )
+
+/** Transaction translator port number */
+#define EHCI_CAP_TT_PORT( port ) ( (port) << 23 )
+
+/** High-bandwidth pipe multiplier */
+#define EHCI_CAP_MULT( mult ) ( (mult) << 30 )
+
+/** A transfer descriptor ring */
+struct ehci_ring {
+ /** Producer counter */
+ unsigned int prod;
+ /** Consumer counter */
+ unsigned int cons;
+
+ /** Residual untransferred data */
+ size_t residual;
+
+ /** I/O buffers */
+ struct io_buffer **iobuf;
+
+ /** Queue head */
+ struct ehci_queue_head *head;
+ /** Transfer descriptors */
+ struct ehci_transfer_descriptor *desc;
+};
+
+/** Number of transfer descriptors in a ring
+ *
+ * This is a policy decision.
+ */
+#define EHCI_RING_COUNT 64
+
+/**
+ * Calculate space used in transfer descriptor ring
+ *
+ * @v ring Transfer descriptor ring
+ * @ret fill Number of entries used
+ */
+static inline __attribute__ (( always_inline )) unsigned int
+ehci_ring_fill ( struct ehci_ring *ring ) {
+ unsigned int fill;
+
+ fill = ( ring->prod - ring->cons );
+ assert ( fill <= EHCI_RING_COUNT );
+ return fill;
+}
+
+/**
+ * Calculate space remaining in transfer descriptor ring
+ *
+ * @v ring Transfer descriptor ring
+ * @ret remaining Number of entries remaining
+ */
+static inline __attribute__ (( always_inline )) unsigned int
+ehci_ring_remaining ( struct ehci_ring *ring ) {
+ unsigned int fill = ehci_ring_fill ( ring );
+
+ return ( EHCI_RING_COUNT - fill );
+}
+
+/** Time to delay after enabling power to a port
+ *
+ * This is not mandated by EHCI; we use the value given for xHCI.
+ */
+#define EHCI_PORT_POWER_DELAY_MS 20
+
+/** Time to delay after releasing ownership of a port
+ *
+ * This is a policy decision.
+ */
+#define EHCI_DISOWN_DELAY_MS 100
+
+/** Maximum time to wait for BIOS to release ownership
+ *
+ * This is a policy decision.
+ */
+#define EHCI_USBLEGSUP_MAX_WAIT_MS 100
+
+/** Maximum time to wait for asynchronous schedule to advance
+ *
+ * This is a policy decision.
+ */
+#define EHCI_ASYNC_ADVANCE_MAX_WAIT_MS 100
+
+/** Maximum time to wait for host controller to stop
+ *
+ * This is a policy decision.
+ */
+#define EHCI_STOP_MAX_WAIT_MS 100
+
+/** Maximum time to wait for reset to complete
+ *
+ * This is a policy decision.
+ */
+#define EHCI_RESET_MAX_WAIT_MS 500
+
+/** Maximum time to wait for a port reset to complete
+ *
+ * This is a policy decision.
+ */
+#define EHCI_PORT_RESET_MAX_WAIT_MS 500
+
+/** An EHCI transfer */
+struct ehci_transfer {
+ /** Data buffer */
+ void *data;
+ /** Length */
+ size_t len;
+ /** Flags
+ *
+ * This is the bitwise OR of zero or more EHCI_FL_XXX values.
+ * The low 8 bits are copied to the flags byte within the
+ * transfer descriptor; the remaining bits hold flags
+ * meaningful only to our driver code.
+ */
+ unsigned int flags;
+};
+
+/** Set initial data toggle */
+#define EHCI_FL_TOGGLE 0x8000
+
+/** An EHCI device */
+struct ehci_device {
+ /** Registers */
+ void *regs;
+ /** Name */
+ const char *name;
+
+ /** Capability registers */
+ void *cap;
+ /** Operational registers */
+ void *op;
+
+ /** Number of ports */
+ unsigned int ports;
+ /** 64-bit addressing capability */
+ int addr64;
+ /** Frame list size */
+ unsigned int flsize;
+ /** EHCI extended capabilities offset */
+ unsigned int eecp;
+
+ /** USB legacy support capability (if present and enabled) */
+ unsigned int legacy;
+
+ /** Control data structure segment */
+ uint32_t ctrldssegment;
+ /** Asynchronous queue head */
+ struct ehci_queue_head *head;
+ /** Periodic frame list */
+ struct ehci_periodic_frame *frame;
+
+ /** List of all endpoints */
+ struct list_head endpoints;
+ /** Asynchronous schedule */
+ struct list_head async;
+ /** Periodic schedule
+ *
+ * Listed in decreasing order of endpoint interval.
+ */
+ struct list_head periodic;
+
+ /** USB bus */
+ struct usb_bus *bus;
+};
+
+/** An EHCI endpoint */
+struct ehci_endpoint {
+ /** EHCI device */
+ struct ehci_device *ehci;
+ /** USB endpoint */
+ struct usb_endpoint *ep;
+ /** List of all endpoints */
+ struct list_head list;
+ /** Endpoint schedule */
+ struct list_head schedule;
+
+ /** Transfer descriptor ring */
+ struct ehci_ring ring;
+};
+
+extern unsigned int ehci_companion ( struct pci_device *pci );
+
+#endif /* _IPXE_EHCI_H */
diff --git a/roms/ipxe/src/drivers/usb/uhci.c b/roms/ipxe/src/drivers/usb/uhci.c
new file mode 100644
index 000000000..b6bb92560
--- /dev/null
+++ b/roms/ipxe/src/drivers/usb/uhci.c
@@ -0,0 +1,1577 @@
+/*
+ * Copyright (C) 2015 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <strings.h>
+#include <unistd.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/malloc.h>
+#include <ipxe/pci.h>
+#include <ipxe/usb.h>
+#include "ehci.h"
+#include "uhci.h"
+
+/** @file
+ *
+ * USB Universal Host Controller Interface (UHCI) driver
+ *
+ */
+
+/******************************************************************************
+ *
+ * Register access
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Check that address is reachable
+ *
+ * @v addr Address
+ * @v len Length
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline)) int
+uhci_reachable ( void *addr, size_t len ) {
+ physaddr_t phys = virt_to_phys ( addr );
+
+ /* Always reachable in a 32-bit build */
+ if ( sizeof ( physaddr_t ) <= sizeof ( uint32_t ) )
+ return 0;
+
+ /* Reachable if below 4GB */
+ if ( ( ( phys + len - 1 ) & ~0xffffffffULL ) == 0 )
+ return 0;
+
+ return -ENOTSUP;
+}
+
+/******************************************************************************
+ *
+ * Run / stop / reset
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Start UHCI device
+ *
+ * @v uhci UHCI device
+ */
+static void uhci_run ( struct uhci_device *uhci ) {
+ uint16_t usbcmd;
+
+ /* Set run/stop bit */
+ usbcmd = inw ( uhci->regs + UHCI_USBCMD );
+ usbcmd |= ( UHCI_USBCMD_RUN | UHCI_USBCMD_MAX64 );
+ outw ( usbcmd, uhci->regs + UHCI_USBCMD );
+}
+
+/**
+ * Stop UHCI device
+ *
+ * @v uhci UHCI device
+ * @ret rc Return status code
+ */
+static int uhci_stop ( struct uhci_device *uhci ) {
+ uint16_t usbcmd;
+ uint16_t usbsts;
+ unsigned int i;
+
+ /* Clear run/stop bit */
+ usbcmd = inw ( uhci->regs + UHCI_USBCMD );
+ usbcmd &= ~UHCI_USBCMD_RUN;
+ outw ( usbcmd, uhci->regs + UHCI_USBCMD );
+
+ /* Wait for device to stop */
+ for ( i = 0 ; i < UHCI_STOP_MAX_WAIT_MS ; i++ ) {
+
+ /* Check if device is stopped */
+ usbsts = inw ( uhci->regs + UHCI_USBSTS );
+ if ( usbsts & UHCI_USBSTS_HCHALTED )
+ return 0;
+
+ /* Delay */
+ mdelay ( 1 );
+ }
+
+ DBGC ( uhci, "UHCI %s timed out waiting for stop\n", uhci->name );
+ return -ETIMEDOUT;
+}
+
+/**
+ * Reset UHCI device
+ *
+ * @v uhci UHCI device
+ * @ret rc Return status code
+ */
+static int uhci_reset ( struct uhci_device *uhci ) {
+ uint16_t usbcmd;
+ unsigned int i;
+ int rc;
+
+ /* The UHCI specification states that resetting a running
+ * device may result in undefined behaviour, so try stopping
+ * it first.
+ */
+ if ( ( rc = uhci_stop ( uhci ) ) != 0 ) {
+ /* Ignore errors and attempt to reset the device anyway */
+ }
+
+ /* Reset device */
+ outw ( UHCI_USBCMD_HCRESET, uhci->regs + UHCI_USBCMD );
+
+ /* Wait for reset to complete */
+ for ( i = 0 ; i < UHCI_RESET_MAX_WAIT_MS ; i++ ) {
+
+ /* Check if reset is complete */
+ usbcmd = inw ( uhci->regs + UHCI_USBCMD );
+ if ( ! ( usbcmd & UHCI_USBCMD_HCRESET ) )
+ return 0;
+
+ /* Delay */
+ mdelay ( 1 );
+ }
+
+ DBGC ( uhci, "UHCI %s timed out waiting for reset\n", uhci->name );
+ return -ETIMEDOUT;
+}
+
+/******************************************************************************
+ *
+ * Transfer descriptor rings
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Allocate transfer ring
+ *
+ * @v ring Transfer ring
+ * @ret rc Return status code
+ */
+static int uhci_ring_alloc ( struct uhci_ring *ring ) {
+ int rc;
+
+ /* Initialise structure */
+ memset ( ring, 0, sizeof ( *ring ) );
+
+ /* Allocate queue head */
+ ring->head = malloc_dma ( sizeof ( *ring->head ), UHCI_ALIGN );
+ if ( ! ring->head ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ if ( ( rc = uhci_reachable ( ring->head,
+ sizeof ( *ring->head ) ) ) != 0 )
+ goto err_unreachable;
+
+ /* Initialise queue head */
+ ring->head->current = cpu_to_le32 ( UHCI_LINK_TERMINATE );
+
+ return 0;
+
+ err_unreachable:
+ free_dma ( ring->head, sizeof ( *ring->head ) );
+ err_alloc:
+ return rc;
+}
+
+/**
+ * Free transfer ring
+ *
+ * @v ring Transfer ring
+ */
+static void uhci_ring_free ( struct uhci_ring *ring ) {
+ unsigned int i;
+
+ /* Sanity checks */
+ assert ( uhci_ring_fill ( ring ) == 0 );
+ for ( i = 0 ; i < UHCI_RING_COUNT ; i++ )
+ assert ( ring->xfer[i] == NULL );
+
+ /* Free queue head */
+ free_dma ( ring->head, sizeof ( *ring->head ) );
+}
+
+/**
+ * Enqueue new transfer
+ *
+ * @v ring Transfer ring
+ * @v iobuf I/O buffer
+ * @v count Number of descriptors
+ * @ret rc Return status code
+ */
+static int uhci_enqueue ( struct uhci_ring *ring, struct io_buffer *iobuf,
+ unsigned int count ) {
+ struct uhci_transfer *xfer;
+ struct uhci_transfer *end;
+ struct uhci_transfer_descriptor *desc;
+ unsigned int index = ( ring->prod % UHCI_RING_COUNT );
+ uint32_t link;
+ size_t len;
+ int rc;
+
+ /* Sanity check */
+ assert ( count > 0 );
+ assert ( iobuf != NULL );
+
+ /* Check for space in ring */
+ if ( ! uhci_ring_remaining ( ring ) ) {
+ rc = -ENOBUFS;
+ goto err_ring_full;
+ }
+
+ /* Check for reachability of I/O buffer */
+ if ( ( rc = uhci_reachable ( iobuf->data, iob_len ( iobuf ) ) ) != 0 )
+ goto err_unreachable_iobuf;
+
+ /* Allocate transfer */
+ xfer = malloc ( sizeof ( *xfer ) );
+ if ( ! xfer ) {
+ rc = -ENOMEM;
+ goto err_alloc_xfer;
+ }
+
+ /* Initialise transfer */
+ xfer->prod = 0;
+ xfer->cons = 0;
+ xfer->len = 0;
+ xfer->iobuf = iobuf;
+
+ /* Allocate transfer descriptors */
+ len = ( count * sizeof ( xfer->desc[0] ) );
+ xfer->desc = malloc_dma ( len, UHCI_ALIGN );
+ if ( ! xfer->desc ) {
+ rc = -ENOMEM;
+ goto err_alloc_desc;
+ }
+ if ( ( rc = uhci_reachable ( xfer->desc, len ) ) != 0 )
+ goto err_unreachable_desc;
+
+ /* Initialise transfer descriptors */
+ memset ( xfer->desc, 0, len );
+ desc = xfer->desc;
+ for ( ; --count ; desc++ ) {
+ link = ( virt_to_phys ( desc + 1 ) | UHCI_LINK_DEPTH_FIRST );
+ desc->link = cpu_to_le32 ( link );
+ desc->flags = ring->flags;
+ }
+ desc->link = cpu_to_le32 ( UHCI_LINK_TERMINATE );
+ desc->flags = ( ring->flags | UHCI_FL_IOC );
+
+ /* Add to ring */
+ wmb();
+ link = virt_to_phys ( xfer->desc );
+ if ( uhci_ring_fill ( ring ) > 0 ) {
+ end = ring->end;
+ end->desc[ end->prod - 1 ].link = cpu_to_le32 ( link );
+ } else {
+ ring->head->current = cpu_to_le32 ( link );
+ }
+ assert ( ring->xfer[index] == NULL );
+ ring->xfer[index] = xfer;
+ ring->end = xfer;
+ ring->prod++;
+
+ return 0;
+
+ err_unreachable_desc:
+ free_dma ( xfer->desc, len );
+ err_alloc_desc:
+ free ( xfer );
+ err_alloc_xfer:
+ err_unreachable_iobuf:
+ err_ring_full:
+ return rc;
+}
+
+/**
+ * Describe transfer
+ *
+ * @v ring Transfer ring
+ * @v data Data
+ * @v len Length of data
+ * @v pid Packet ID
+ */
+static void uhci_describe ( struct uhci_ring *ring, void *data,
+ size_t len, uint8_t pid ) {
+ struct uhci_transfer *xfer = ring->end;
+ struct uhci_transfer_descriptor *desc;
+ size_t frag_len;
+ uint32_t control;
+
+ do {
+ /* Calculate fragment length */
+ frag_len = len;
+ if ( frag_len > ring->mtu )
+ frag_len = ring->mtu;
+
+ /* Populate descriptor */
+ desc = &xfer->desc[xfer->prod++];
+ if ( pid == USB_PID_IN )
+ desc->flags |= UHCI_FL_SPD;
+ control = ( ring->control | UHCI_CONTROL_PID ( pid ) |
+ UHCI_CONTROL_LEN ( frag_len ) );
+ desc->control = cpu_to_le32 ( control );
+ if ( data )
+ desc->data = virt_to_phys ( data );
+ wmb();
+ desc->status = UHCI_STATUS_ACTIVE;
+
+ /* Update data toggle */
+ ring->control ^= UHCI_CONTROL_TOGGLE;
+
+ /* Move to next descriptor */
+ data += frag_len;
+ len -= frag_len;
+
+ } while ( len );
+}
+
+/**
+ * Dequeue transfer
+ *
+ * @v ring Transfer ring
+ * @ret iobuf I/O buffer
+ */
+static struct io_buffer * uhci_dequeue ( struct uhci_ring *ring ) {
+ unsigned int index = ( ring->cons % UHCI_RING_COUNT );
+ struct io_buffer *iobuf;
+ struct uhci_transfer *xfer;
+ size_t len;
+
+ /* Sanity checks */
+ assert ( uhci_ring_fill ( ring ) > 0 );
+
+ /* Consume transfer */
+ xfer = ring->xfer[index];
+ assert ( xfer != NULL );
+ assert ( xfer->desc != NULL );
+ iobuf = xfer->iobuf;
+ assert ( iobuf != NULL );
+ ring->xfer[index] = NULL;
+ ring->cons++;
+
+ /* Free transfer descriptors */
+ len = ( xfer->prod * sizeof ( xfer->desc[0] ) );
+ free_dma ( xfer->desc, len );
+
+ /* Free transfer */
+ free ( xfer );
+
+ return iobuf;
+}
+
+/**
+ * Restart ring
+ *
+ * @v ring Transfer ring
+ * @v toggle Expected data toggle for next descriptor
+ */
+static void uhci_restart ( struct uhci_ring *ring, uint32_t toggle ) {
+ struct uhci_transfer *xfer;
+ struct uhci_transfer_descriptor *desc;
+ struct uhci_transfer_descriptor *first;
+ uint32_t link;
+ unsigned int i;
+ unsigned int j;
+
+ /* Sanity check */
+ assert ( ring->head->current == cpu_to_le32 ( UHCI_LINK_TERMINATE ) );
+
+ /* If ring is empty, then just update the data toggle for the
+ * next descriptor.
+ */
+ if ( uhci_ring_fill ( ring ) == 0 ) {
+ ring->control &= ~UHCI_CONTROL_TOGGLE;
+ ring->control |= toggle;
+ return;
+ }
+
+ /* If expected toggle does not match the toggle in the first
+ * unconsumed descriptor, then invert all toggles.
+ */
+ xfer = ring->xfer[ ring->cons % UHCI_RING_COUNT ];
+ assert ( xfer != NULL );
+ assert ( xfer->cons == 0 );
+ first = &xfer->desc[0];
+ if ( ( le32_to_cpu ( first->control ) ^ toggle ) & UHCI_CONTROL_TOGGLE){
+
+ /* Invert toggle on all unconsumed transfer descriptors */
+ for ( i = ring->cons ; i != ring->prod ; i++ ) {
+ xfer = ring->xfer[ i % UHCI_RING_COUNT ];
+ assert ( xfer != NULL );
+ assert ( xfer->cons == 0 );
+ for ( j = 0 ; j < xfer->prod ; j++ ) {
+ desc = &xfer->desc[j];
+ desc->control ^=
+ cpu_to_le32 ( UHCI_CONTROL_TOGGLE );
+ }
+ }
+
+ /* Invert toggle for next descriptor to be enqueued */
+ ring->control ^= UHCI_CONTROL_TOGGLE;
+ }
+
+ /* Restart ring at first unconsumed transfer */
+ link = virt_to_phys ( first );
+ wmb();
+ ring->head->current = cpu_to_le32 ( link );
+}
+
+/******************************************************************************
+ *
+ * Schedule management
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Get link value for a queue head
+ *
+ * @v queue Queue head
+ * @ret link Link value
+ */
+static inline uint32_t uhci_link_qh ( struct uhci_queue_head *queue ) {
+
+ return ( virt_to_phys ( queue ) | UHCI_LINK_TYPE_QH );
+}
+
+/**
+ * (Re)build asynchronous schedule
+ *
+ * @v uhci UHCI device
+ */
+static void uhci_async_schedule ( struct uhci_device *uhci ) {
+ struct uhci_endpoint *endpoint;
+ struct uhci_queue_head *queue;
+ uint32_t end;
+ uint32_t link;
+
+ /* Build schedule in reverse order of execution. Provided
+ * that we only ever add or remove single endpoints, this can
+ * safely run concurrently with hardware execution of the
+ * schedule.
+ */
+ link = end = uhci_link_qh ( uhci->head );
+ list_for_each_entry_reverse ( endpoint, &uhci->async, schedule ) {
+ queue = endpoint->ring.head;
+ queue->link = cpu_to_le32 ( link );
+ wmb();
+ link = uhci_link_qh ( queue );
+ }
+ if ( link == end )
+ link = UHCI_LINK_TERMINATE;
+ uhci->head->link = cpu_to_le32 ( link );
+ wmb();
+}
+
+/**
+ * Add endpoint to asynchronous schedule
+ *
+ * @v endpoint Endpoint
+ */
+static void uhci_async_add ( struct uhci_endpoint *endpoint ) {
+ struct uhci_device *uhci = endpoint->uhci;
+
+ /* Add to end of schedule */
+ list_add_tail ( &endpoint->schedule, &uhci->async );
+
+ /* Rebuild schedule */
+ uhci_async_schedule ( uhci );
+}
+
+/**
+ * Remove endpoint from asynchronous schedule
+ *
+ * @v endpoint Endpoint
+ */
+static void uhci_async_del ( struct uhci_endpoint *endpoint ) {
+ struct uhci_device *uhci = endpoint->uhci;
+
+ /* Remove from schedule */
+ list_check_contains_entry ( endpoint, &uhci->async, schedule );
+ list_del ( &endpoint->schedule );
+
+ /* Rebuild schedule */
+ uhci_async_schedule ( uhci );
+
+ /* Delay for a whole USB frame (with a 100% safety margin) */
+ mdelay ( 2 );
+}
+
+/**
+ * (Re)build periodic schedule
+ *
+ * @v uhci UHCI device
+ */
+static void uhci_periodic_schedule ( struct uhci_device *uhci ) {
+ struct uhci_endpoint *endpoint;
+ struct uhci_queue_head *queue;
+ uint32_t link;
+ uint32_t end;
+ unsigned int max_interval;
+ unsigned int i;
+
+ /* Build schedule in reverse order of execution. Provided
+ * that we only ever add or remove single endpoints, this can
+ * safely run concurrently with hardware execution of the
+ * schedule.
+ */
+ DBGCP ( uhci, "UHCI %s periodic schedule: ", uhci->name );
+ link = end = uhci_link_qh ( uhci->head );
+ list_for_each_entry_reverse ( endpoint, &uhci->periodic, schedule ) {
+ queue = endpoint->ring.head;
+ queue->link = cpu_to_le32 ( link );
+ wmb();
+ DBGCP ( uhci, "%s%d", ( ( link == end ) ? "" : "<-" ),
+ endpoint->ep->interval );
+ link = uhci_link_qh ( queue );
+ }
+ DBGCP ( uhci, "\n" );
+
+ /* Populate periodic frame list */
+ DBGCP ( uhci, "UHCI %s periodic frame list:", uhci->name );
+ for ( i = 0 ; i < UHCI_FRAMES ; i++ ) {
+
+ /* Calculate maximum interval (in microframes) which
+ * may appear as part of this frame list.
+ */
+ if ( i == 0 ) {
+ /* Start of list: include all endpoints */
+ max_interval = -1U;
+ } else {
+ /* Calculate highest power-of-two frame interval */
+ max_interval = ( 1 << ( ffs ( i ) - 1 ) );
+ /* Convert to microframes */
+ max_interval <<= 3;
+ /* Round up to nearest 2^n-1 */
+ max_interval = ( ( max_interval << 1 ) - 1 );
+ }
+
+ /* Find first endpoint in schedule satisfying this
+ * maximum interval constraint.
+ */
+ link = uhci_link_qh ( uhci->head );
+ list_for_each_entry ( endpoint, &uhci->periodic, schedule ) {
+ if ( endpoint->ep->interval <= max_interval ) {
+ queue = endpoint->ring.head;
+ link = uhci_link_qh ( queue );
+ DBGCP ( uhci, " %d:%d",
+ i, endpoint->ep->interval );
+ break;
+ }
+ }
+ uhci->frame->link[i] = cpu_to_le32 ( link );
+ }
+ wmb();
+ DBGCP ( uhci, "\n" );
+}
+
+/**
+ * Add endpoint to periodic schedule
+ *
+ * @v endpoint Endpoint
+ */
+static void uhci_periodic_add ( struct uhci_endpoint *endpoint ) {
+ struct uhci_device *uhci = endpoint->uhci;
+ struct uhci_endpoint *before;
+ unsigned int interval = endpoint->ep->interval;
+
+ /* Find first endpoint with a smaller interval */
+ list_for_each_entry ( before, &uhci->periodic, schedule ) {
+ if ( before->ep->interval < interval )
+ break;
+ }
+ list_add_tail ( &endpoint->schedule, &before->schedule );
+
+ /* Rebuild schedule */
+ uhci_periodic_schedule ( uhci );
+}
+
+/**
+ * Remove endpoint from periodic schedule
+ *
+ * @v endpoint Endpoint
+ */
+static void uhci_periodic_del ( struct uhci_endpoint *endpoint ) {
+ struct uhci_device *uhci = endpoint->uhci;
+
+ /* Remove from schedule */
+ list_check_contains_entry ( endpoint, &uhci->periodic, schedule );
+ list_del ( &endpoint->schedule );
+
+ /* Rebuild schedule */
+ uhci_periodic_schedule ( uhci );
+
+ /* Delay for a whole USB frame (with a 100% safety margin) */
+ mdelay ( 2 );
+}
+
+/**
+ * Add endpoint to appropriate schedule
+ *
+ * @v endpoint Endpoint
+ */
+static void uhci_schedule_add ( struct uhci_endpoint *endpoint ) {
+ struct usb_endpoint *ep = endpoint->ep;
+ unsigned int attr = ( ep->attributes & USB_ENDPOINT_ATTR_TYPE_MASK );
+
+ if ( attr == USB_ENDPOINT_ATTR_INTERRUPT ) {
+ uhci_periodic_add ( endpoint );
+ } else {
+ uhci_async_add ( endpoint );
+ }
+}
+
+/**
+ * Remove endpoint from appropriate schedule
+ *
+ * @v endpoint Endpoint
+ */
+static void uhci_schedule_del ( struct uhci_endpoint *endpoint ) {
+ struct usb_endpoint *ep = endpoint->ep;
+ unsigned int attr = ( ep->attributes & USB_ENDPOINT_ATTR_TYPE_MASK );
+
+ if ( attr == USB_ENDPOINT_ATTR_INTERRUPT ) {
+ uhci_periodic_del ( endpoint );
+ } else {
+ uhci_async_del ( endpoint );
+ }
+}
+
+/******************************************************************************
+ *
+ * Endpoint operations
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Open endpoint
+ *
+ * @v ep USB endpoint
+ * @ret rc Return status code
+ */
+static int uhci_endpoint_open ( struct usb_endpoint *ep ) {
+ struct usb_device *usb = ep->usb;
+ struct uhci_device *uhci = usb_get_hostdata ( usb );
+ struct uhci_endpoint *endpoint;
+ int rc;
+
+ /* Allocate and initialise structure */
+ endpoint = zalloc ( sizeof ( *endpoint ) );
+ if ( ! endpoint ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ endpoint->uhci = uhci;
+ endpoint->ep = ep;
+ usb_endpoint_set_hostdata ( ep, endpoint );
+
+ /* Initialise descriptor ring */
+ if ( ( rc = uhci_ring_alloc ( &endpoint->ring ) ) != 0 )
+ goto err_ring_alloc;
+ endpoint->ring.mtu = ep->mtu;
+ endpoint->ring.flags = UHCI_FL_CERR_MAX;
+ if ( usb->port->speed < USB_SPEED_FULL )
+ endpoint->ring.flags |= UHCI_FL_LS;
+ endpoint->ring.control = ( UHCI_CONTROL_DEVICE ( usb->address ) |
+ UHCI_CONTROL_ENDPOINT ( ep->address ) );
+
+ /* Add to list of endpoints */
+ list_add_tail ( &endpoint->list, &uhci->endpoints );
+
+ /* Add to schedule */
+ uhci_schedule_add ( endpoint );
+
+ return 0;
+
+ uhci_ring_free ( &endpoint->ring );
+ err_ring_alloc:
+ free ( endpoint );
+ err_alloc:
+ return rc;
+}
+
+/**
+ * Close endpoint
+ *
+ * @v ep USB endpoint
+ */
+static void uhci_endpoint_close ( struct usb_endpoint *ep ) {
+ struct uhci_endpoint *endpoint = usb_endpoint_get_hostdata ( ep );
+ struct io_buffer *iobuf;
+
+ /* Remove from schedule */
+ uhci_schedule_del ( endpoint );
+
+ /* Cancel any incomplete transfers */
+ while ( uhci_ring_fill ( &endpoint->ring ) ) {
+ iobuf = uhci_dequeue ( &endpoint->ring );
+ if ( iobuf )
+ usb_complete_err ( ep, iobuf, -ECANCELED );
+ }
+
+ /* Remove from list of endpoints */
+ list_del ( &endpoint->list );
+
+ /* Free descriptor ring */
+ uhci_ring_free ( &endpoint->ring );
+
+ /* Free endpoint */
+ free ( endpoint );
+}
+
+/**
+ * Reset endpoint
+ *
+ * @v ep USB endpoint
+ * @ret rc Return status code
+ */
+static int uhci_endpoint_reset ( struct usb_endpoint *ep ) {
+ struct uhci_endpoint *endpoint = usb_endpoint_get_hostdata ( ep );
+ struct uhci_ring *ring = &endpoint->ring;
+
+ /* Restart ring */
+ uhci_restart ( ring, 0 );
+
+ return 0;
+}
+
+/**
+ * Update MTU
+ *
+ * @v ep USB endpoint
+ * @ret rc Return status code
+ */
+static int uhci_endpoint_mtu ( struct usb_endpoint *ep ) {
+ struct uhci_endpoint *endpoint = usb_endpoint_get_hostdata ( ep );
+
+ /* Update endpoint MTU */
+ endpoint->ring.mtu = ep->mtu;
+
+ return 0;
+}
+
+/**
+ * Enqueue message transfer
+ *
+ * @v ep USB endpoint
+ * @v iobuf I/O buffer
+ * @ret rc Return status code
+ */
+static int uhci_endpoint_message ( struct usb_endpoint *ep,
+ struct io_buffer *iobuf ) {
+ struct uhci_endpoint *endpoint = usb_endpoint_get_hostdata ( ep );
+ struct uhci_ring *ring = &endpoint->ring;
+ struct usb_setup_packet *packet;
+ unsigned int count;
+ size_t len;
+ int input;
+ int rc;
+
+ /* Calculate number of descriptors */
+ assert ( iob_len ( iobuf ) >= sizeof ( *packet ) );
+ len = ( iob_len ( iobuf ) - sizeof ( *packet ) );
+ count = ( 1 /* setup stage */ +
+ ( ( len + ring->mtu - 1 ) / ring->mtu ) /* data stage */ +
+ 1 /* status stage */ );
+
+ /* Enqueue transfer */
+ if ( ( rc = uhci_enqueue ( ring, iobuf, count ) ) != 0 )
+ return rc;
+
+ /* Describe setup stage */
+ packet = iobuf->data;
+ ring->control &= ~UHCI_CONTROL_TOGGLE;
+ uhci_describe ( ring, packet, sizeof ( *packet ), USB_PID_SETUP );
+ iob_pull ( iobuf, sizeof ( *packet ) );
+
+ /* Describe data stage, if applicable */
+ assert ( ring->control & UHCI_CONTROL_TOGGLE );
+ input = ( packet->request & cpu_to_le16 ( USB_DIR_IN ) );
+ if ( len ) {
+ uhci_describe ( ring, iobuf->data, len,
+ ( input ? USB_PID_IN : USB_PID_OUT ) );
+ }
+
+ /* Describe status stage */
+ ring->control |= UHCI_CONTROL_TOGGLE;
+ uhci_describe ( ring, NULL, 0,
+ ( ( len && input ) ? USB_PID_OUT : USB_PID_IN ) );
+
+ /* Sanity check */
+ assert ( ring->end->prod == count );
+
+ return 0;
+}
+
+/**
+ * Enqueue stream transfer
+ *
+ * @v ep USB endpoint
+ * @v iobuf I/O buffer
+ * @v terminate Terminate using a short packet
+ * @ret rc Return status code
+ */
+static int uhci_endpoint_stream ( struct usb_endpoint *ep,
+ struct io_buffer *iobuf, int terminate ) {
+ struct uhci_endpoint *endpoint = usb_endpoint_get_hostdata ( ep );
+ struct uhci_ring *ring = &endpoint->ring;
+ unsigned int count;
+ size_t len;
+ int input;
+ int zlp;
+ int rc;
+
+ /* Calculate number of descriptors */
+ len = iob_len ( iobuf );
+ zlp = ( terminate && ( ( len & ( ring->mtu - 1 ) ) == 0 ) );
+ count = ( ( ( len + ring->mtu - 1 ) / ring->mtu ) + ( zlp ? 1 : 0 ) );
+
+ /* Enqueue transfer */
+ if ( ( rc = uhci_enqueue ( ring, iobuf, count ) ) != 0 )
+ return rc;
+
+ /* Describe data packet */
+ input = ( ep->address & USB_DIR_IN );
+ uhci_describe ( ring, iobuf->data, len,
+ ( input ? USB_PID_IN : USB_PID_OUT ) );
+
+ /* Describe zero-length packet, if applicable */
+ if ( zlp )
+ uhci_describe ( ring, NULL, 0, USB_PID_OUT );
+
+ /* Sanity check */
+ assert ( ring->end->prod == count );
+
+ return 0;
+}
+
+/**
+ * Check if transfer is a message transfer
+ *
+ * @v xfer UHCI transfer
+ * @ret is_message Transfer is a message transfer
+ */
+static inline int uhci_is_message ( struct uhci_transfer *xfer ) {
+ struct uhci_transfer_descriptor *desc = &xfer->desc[0];
+
+ return ( ( desc->control & cpu_to_le32 ( UHCI_CONTROL_PID_MASK ) ) ==
+ cpu_to_le32 ( UHCI_CONTROL_PID ( USB_PID_SETUP ) ) );
+}
+
+/**
+ * Poll for completions
+ *
+ * @v endpoint Endpoint
+ */
+static void uhci_endpoint_poll ( struct uhci_endpoint *endpoint ) {
+ struct uhci_ring *ring = &endpoint->ring;
+ struct uhci_device *uhci = endpoint->uhci;
+ struct usb_endpoint *ep = endpoint->ep;
+ struct usb_device *usb = ep->usb;
+ struct uhci_transfer *xfer;
+ struct uhci_transfer_descriptor *desc;
+ struct io_buffer *iobuf;
+ unsigned int index;
+ uint32_t link;
+ uint32_t toggle;
+ uint32_t control;
+ uint16_t actual;
+ size_t len;
+
+ /* Consume all completed descriptors */
+ while ( uhci_ring_fill ( ring ) ) {
+
+ /* Stop if we reach an uncompleted descriptor */
+ index = ( ring->cons % UHCI_RING_COUNT );
+ xfer = ring->xfer[index];
+ assert ( xfer != NULL );
+ assert ( xfer->cons < xfer->prod );
+ desc = &xfer->desc[xfer->cons];
+ rmb();
+ if ( desc->status & UHCI_STATUS_ACTIVE )
+ break;
+ control = le32_to_cpu ( desc->control );
+ actual = le16_to_cpu ( desc->actual );
+
+ /* Update data length, if applicable */
+ if ( UHCI_DATA_PACKET ( control ) )
+ xfer->len += UHCI_ACTUAL_LEN ( actual );
+
+ /* If we have encountered an error, then deactivate
+ * the queue head (to prevent further hardware
+ * accesses to this transfer), consume the transfer,
+ * and report the error to the USB core.
+ */
+ if ( desc->status & UHCI_STATUS_STALLED ) {
+ DBGC ( uhci, "UHCI %s %s completion %d.%d failed "
+ "(status %02x)\n", usb->name,
+ usb_endpoint_name ( ep ), index,
+ xfer->cons, desc->status );
+ link = UHCI_LINK_TERMINATE;
+ ring->head->current = cpu_to_le32 ( link );
+ wmb();
+ iobuf = uhci_dequeue ( ring );
+ usb_complete_err ( ep, iobuf, -EIO );
+ break;
+ }
+
+ /* Consume this descriptor */
+ xfer->cons++;
+
+ /* Check for short packets */
+ if ( UHCI_SHORT_PACKET ( control, actual ) ) {
+
+ /* Sanity checks */
+ assert ( desc->flags & UHCI_FL_SPD );
+ link = virt_to_phys ( desc );
+ assert ( ( le32_to_cpu ( ring->head->current ) &
+ ~( UHCI_ALIGN - 1 ) ) == link );
+
+ /* If this is a message transfer, then restart
+ * at the status stage.
+ */
+ if ( uhci_is_message ( xfer ) ) {
+ xfer->cons = ( xfer->prod - 1 );
+ link = virt_to_phys ( &xfer->desc[xfer->cons] );
+ ring->head->current = cpu_to_le32 ( link );
+ break;
+ }
+
+ /* Otherwise, this is a stream transfer.
+ * First, prevent further hardware access to
+ * this transfer.
+ */
+ link = UHCI_LINK_TERMINATE;
+ ring->head->current = cpu_to_le32 ( link );
+ wmb();
+
+ /* Determine expected data toggle for next descriptor */
+ toggle = ( ( control ^ UHCI_CONTROL_TOGGLE ) &
+ UHCI_CONTROL_TOGGLE );
+
+ /* Consume this transfer */
+ len = xfer->len;
+ iobuf = uhci_dequeue ( ring );
+
+ /* Update packet length */
+ assert ( len <= iob_len ( iobuf ) );
+ iob_unput ( iobuf, ( iob_len ( iobuf ) - len ) );
+
+ /* Restart ring */
+ uhci_restart ( ring, toggle );
+
+ } else if ( xfer->cons == xfer->prod ) {
+
+ /* Completed a transfer: consume it */
+ len = xfer->len;
+ iobuf = uhci_dequeue ( ring );
+ assert ( len == iob_len ( iobuf ) );
+
+ } else {
+
+ /* Not a short packet and not yet complete:
+ * continue processing.
+ */
+ continue;
+ }
+
+ /* Report completion to USB core */
+ usb_complete ( ep, iobuf );
+ }
+}
+
+/******************************************************************************
+ *
+ * Device operations
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Open device
+ *
+ * @v usb USB device
+ * @ret rc Return status code
+ */
+static int uhci_device_open ( struct usb_device *usb ) {
+ struct uhci_device *uhci = usb_bus_get_hostdata ( usb->port->hub->bus );
+
+ usb_set_hostdata ( usb, uhci );
+ return 0;
+}
+
+/**
+ * Close device
+ *
+ * @v usb USB device
+ */
+static void uhci_device_close ( struct usb_device *usb ) {
+ struct uhci_device *uhci = usb_get_hostdata ( usb );
+ struct usb_bus *bus = uhci->bus;
+
+ /* Free device address, if assigned */
+ if ( usb->address )
+ usb_free_address ( bus, usb->address );
+}
+
+/**
+ * Assign device address
+ *
+ * @v usb USB device
+ * @ret rc Return status code
+ */
+static int uhci_device_address ( struct usb_device *usb ) {
+ struct uhci_device *uhci = usb_get_hostdata ( usb );
+ struct usb_bus *bus = uhci->bus;
+ struct usb_endpoint *ep0 = usb_endpoint ( usb, USB_EP0_ADDRESS );
+ struct uhci_endpoint *endpoint0 = usb_endpoint_get_hostdata ( ep0 );
+ int address;
+ int rc;
+
+ /* Sanity checks */
+ assert ( usb->address == 0 );
+ assert ( ep0 != NULL );
+
+ /* Allocate device address */
+ address = usb_alloc_address ( bus );
+ if ( address < 0 ) {
+ rc = address;
+ DBGC ( uhci, "UHCI %s could not allocate address: %s\n",
+ usb->name, strerror ( rc ) );
+ goto err_alloc_address;
+ }
+
+ /* Set address */
+ if ( ( rc = usb_set_address ( usb, address ) ) != 0 )
+ goto err_set_address;
+
+ /* Update device address */
+ usb->address = address;
+ endpoint0->ring.control |= UHCI_CONTROL_DEVICE ( address );
+
+ return 0;
+
+ err_set_address:
+ usb_free_address ( bus, address );
+ err_alloc_address:
+ return rc;
+}
+
+/******************************************************************************
+ *
+ * Hub operations
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Open hub
+ *
+ * @v hub USB hub
+ * @ret rc Return status code
+ */
+static int uhci_hub_open ( struct usb_hub *hub __unused ) {
+
+ /* Nothing to do */
+ return 0;
+}
+
+/**
+ * Close hub
+ *
+ * @v hub USB hub
+ */
+static void uhci_hub_close ( struct usb_hub *hub __unused ) {
+
+ /* Nothing to do */
+}
+
+/******************************************************************************
+ *
+ * Root hub operations
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Open root hub
+ *
+ * @v hub USB hub
+ * @ret rc Return status code
+ */
+static int uhci_root_open ( struct usb_hub *hub ) {
+ struct usb_bus *bus = hub->bus;
+ struct uhci_device *uhci = usb_bus_get_hostdata ( bus );
+
+ /* Record hub driver private data */
+ usb_hub_set_drvdata ( hub, uhci );
+
+ return 0;
+}
+
+/**
+ * Close root hub
+ *
+ * @v hub USB hub
+ */
+static void uhci_root_close ( struct usb_hub *hub ) {
+
+ /* Clear hub driver private data */
+ usb_hub_set_drvdata ( hub, NULL );
+}
+
+/**
+ * Enable port
+ *
+ * @v hub USB hub
+ * @v port USB port
+ * @ret rc Return status code
+ */
+static int uhci_root_enable ( struct usb_hub *hub, struct usb_port *port ) {
+ struct uhci_device *uhci = usb_hub_get_drvdata ( hub );
+ uint16_t portsc;
+ unsigned int i;
+
+ /* Reset port */
+ portsc = inw ( uhci->regs + UHCI_PORTSC ( port->address ) );
+ portsc |= UHCI_PORTSC_PR;
+ outw ( portsc, uhci->regs + UHCI_PORTSC ( port->address ) );
+ mdelay ( USB_RESET_DELAY_MS );
+ portsc &= ~UHCI_PORTSC_PR;
+ outw ( portsc, uhci->regs + UHCI_PORTSC ( port->address ) );
+ mdelay ( USB_RESET_RECOVER_DELAY_MS );
+
+ /* Enable port */
+ portsc |= UHCI_PORTSC_PED;
+ outw ( portsc, uhci->regs + UHCI_PORTSC ( port->address ) );
+ mdelay ( USB_RESET_RECOVER_DELAY_MS );
+
+ /* Wait for port to become enabled */
+ for ( i = 0 ; i < UHCI_PORT_ENABLE_MAX_WAIT_MS ; i++ ) {
+
+ /* Check port status */
+ portsc = inw ( uhci->regs + UHCI_PORTSC ( port->address ) );
+ if ( portsc & UHCI_PORTSC_PED )
+ return 0;
+
+ /* Delay */
+ mdelay ( 1 );
+ }
+
+ DBGC ( uhci, "UHCI %s-%d timed out waiting for port to enable "
+ "(status %04x)\n", uhci->name, port->address, portsc );
+ return -ETIMEDOUT;
+}
+
+/**
+ * Disable port
+ *
+ * @v hub USB hub
+ * @v port USB port
+ * @ret rc Return status code
+ */
+static int uhci_root_disable ( struct usb_hub *hub, struct usb_port *port ) {
+ struct uhci_device *uhci = usb_hub_get_drvdata ( hub );
+ uint16_t portsc;
+
+ /* Disable port */
+ portsc = inw ( uhci->regs + UHCI_PORTSC ( port->address ) );
+ portsc &= ~UHCI_PORTSC_PED;
+ outw ( portsc, uhci->regs + UHCI_PORTSC ( port->address ) );
+
+ return 0;
+}
+
+/**
+ * Update root hub port speed
+ *
+ * @v hub USB hub
+ * @v port USB port
+ * @ret rc Return status code
+ */
+static int uhci_root_speed ( struct usb_hub *hub, struct usb_port *port ) {
+ struct uhci_device *uhci = usb_hub_get_drvdata ( hub );
+ struct pci_device pci;
+ uint16_t portsc;
+ unsigned int speed;
+
+ /* Read port status */
+ portsc = inw ( uhci->regs + UHCI_PORTSC ( port->address ) );
+ if ( ! ( portsc & UHCI_PORTSC_CCS ) ) {
+ /* Port not connected */
+ speed = USB_SPEED_NONE;
+ } else if ( uhci->companion &&
+ ! find_usb_bus_by_location ( BUS_TYPE_PCI,
+ uhci->companion ) ) {
+ /* Defer connection detection until companion
+ * controller has been enumerated.
+ */
+ pci_init ( &pci, uhci->companion );
+ DBGC ( uhci, "UHCI %s-%d deferring for companion " PCI_FMT "\n",
+ uhci->name, port->address, PCI_ARGS ( &pci ) );
+ speed = USB_SPEED_NONE;
+ } else if ( portsc & UHCI_PORTSC_LS ) {
+ /* Low-speed device */
+ speed = USB_SPEED_LOW;
+ } else {
+ /* Full-speed device */
+ speed = USB_SPEED_FULL;
+ }
+ port->speed = speed;
+
+ /* Record disconnections and clear changes */
+ port->disconnected |= ( portsc & UHCI_PORTSC_CSC );
+ outw ( portsc, uhci->regs + UHCI_PORTSC ( port->address ) );
+
+ return 0;
+}
+
+/**
+ * Clear transaction translator buffer
+ *
+ * @v hub USB hub
+ * @v port USB port
+ * @v ep USB endpoint
+ * @ret rc Return status code
+ */
+static int uhci_root_clear_tt ( struct usb_hub *hub, struct usb_port *port,
+ struct usb_endpoint *ep ) {
+ struct uhci_device *uhci = usb_hub_get_drvdata ( hub );
+
+ /* Should never be called; this is a root hub */
+ DBGC ( uhci, "UHCI %s-%d nonsensical CLEAR_TT for %s %s\n", uhci->name,
+ port->address, ep->usb->name, usb_endpoint_name ( ep ) );
+
+ return -ENOTSUP;
+}
+
+/**
+ * Poll for port status changes
+ *
+ * @v hub USB hub
+ * @v port USB port
+ */
+static void uhci_root_poll ( struct usb_hub *hub, struct usb_port *port ) {
+ struct uhci_device *uhci = usb_hub_get_drvdata ( hub );
+ uint16_t portsc;
+ uint16_t change;
+
+ /* Do nothing unless something has changed */
+ portsc = inw ( uhci->regs + UHCI_PORTSC ( port->address ) );
+ change = ( portsc & UHCI_PORTSC_CHANGE );
+ if ( ! change )
+ return;
+
+ /* Record disconnections and clear changes */
+ port->disconnected |= ( portsc & UHCI_PORTSC_CSC );
+ outw ( portsc, uhci->regs + UHCI_PORTSC ( port->address ) );
+
+ /* Report port status change */
+ usb_port_changed ( port );
+}
+
+/******************************************************************************
+ *
+ * Bus operations
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Open USB bus
+ *
+ * @v bus USB bus
+ * @ret rc Return status code
+ */
+static int uhci_bus_open ( struct usb_bus *bus ) {
+ struct uhci_device *uhci = usb_bus_get_hostdata ( bus );
+ int rc;
+
+ /* Sanity checks */
+ assert ( list_empty ( &uhci->async ) );
+ assert ( list_empty ( &uhci->periodic ) );
+
+ /* Allocate and initialise asynchronous queue head */
+ uhci->head = malloc_dma ( sizeof ( *uhci->head ), UHCI_ALIGN );
+ if ( ! uhci->head ) {
+ rc = -ENOMEM;
+ goto err_alloc_head;
+ }
+ if ( ( rc = uhci_reachable ( uhci->head, sizeof ( *uhci->head ) ) ) !=0)
+ goto err_unreachable_head;
+ memset ( uhci->head, 0, sizeof ( *uhci->head ) );
+ uhci->head->current = cpu_to_le32 ( UHCI_LINK_TERMINATE );
+ uhci_async_schedule ( uhci );
+
+ /* Allocate periodic frame list */
+ uhci->frame = malloc_dma ( sizeof ( *uhci->frame ),
+ sizeof ( *uhci->frame ) );
+ if ( ! uhci->frame ) {
+ rc = -ENOMEM;
+ goto err_alloc_frame;
+ }
+ if ( ( rc = uhci_reachable ( uhci->frame,
+ sizeof ( *uhci->frame ) ) ) != 0 )
+ goto err_unreachable_frame;
+ uhci_periodic_schedule ( uhci );
+ outl ( virt_to_phys ( uhci->frame ), uhci->regs + UHCI_FLBASEADD );
+
+ /* Start controller */
+ uhci_run ( uhci );
+
+ return 0;
+
+ uhci_stop ( uhci );
+ err_unreachable_frame:
+ free_dma ( uhci->frame, sizeof ( *uhci->frame ) );
+ err_alloc_frame:
+ err_unreachable_head:
+ free_dma ( uhci->head, sizeof ( *uhci->head ) );
+ err_alloc_head:
+ return rc;
+}
+
+/**
+ * Close USB bus
+ *
+ * @v bus USB bus
+ */
+static void uhci_bus_close ( struct usb_bus *bus ) {
+ struct uhci_device *uhci = usb_bus_get_hostdata ( bus );
+
+ /* Sanity checks */
+ assert ( list_empty ( &uhci->async ) );
+ assert ( list_empty ( &uhci->periodic ) );
+
+ /* Stop controller */
+ uhci_stop ( uhci );
+
+ /* Free periodic frame list */
+ free_dma ( uhci->frame, sizeof ( *uhci->frame ) );
+
+ /* Free asynchronous schedule */
+ free_dma ( uhci->head, sizeof ( *uhci->head ) );
+}
+
+/**
+ * Poll USB bus
+ *
+ * @v bus USB bus
+ */
+static void uhci_bus_poll ( struct usb_bus *bus ) {
+ struct uhci_device *uhci = usb_bus_get_hostdata ( bus );
+ struct usb_hub *hub = bus->hub;
+ struct uhci_endpoint *endpoint;
+ unsigned int i;
+
+ /* UHCI defers interrupts (including short packet detection)
+ * until the end of the frame. This can result in bulk IN
+ * endpoints remaining halted for much of the time, waiting
+ * for software action to reset the data toggles. We
+ * therefore ignore USBSTS and unconditionally poll all
+ * endpoints for completed transfer descriptors.
+ *
+ * As with EHCI, we trust that completion handlers are minimal
+ * and will not do anything that could plausibly affect the
+ * endpoint list itself.
+ */
+ list_for_each_entry ( endpoint, &uhci->endpoints, list )
+ uhci_endpoint_poll ( endpoint );
+
+ /* UHCI provides no single bit to indicate that a port status
+ * change has occurred. We therefore unconditionally iterate
+ * over all ports looking for status changes.
+ */
+ for ( i = 1 ; i <= UHCI_PORTS ; i++ )
+ uhci_root_poll ( hub, usb_port ( hub, i ) );
+}
+
+/******************************************************************************
+ *
+ * PCI interface
+ *
+ ******************************************************************************
+ */
+
+/** USB host controller operations */
+static struct usb_host_operations uhci_operations = {
+ .endpoint = {
+ .open = uhci_endpoint_open,
+ .close = uhci_endpoint_close,
+ .reset = uhci_endpoint_reset,
+ .mtu = uhci_endpoint_mtu,
+ .message = uhci_endpoint_message,
+ .stream = uhci_endpoint_stream,
+ },
+ .device = {
+ .open = uhci_device_open,
+ .close = uhci_device_close,
+ .address = uhci_device_address,
+ },
+ .bus = {
+ .open = uhci_bus_open,
+ .close = uhci_bus_close,
+ .poll = uhci_bus_poll,
+ },
+ .hub = {
+ .open = uhci_hub_open,
+ .close = uhci_hub_close,
+ },
+ .root = {
+ .open = uhci_root_open,
+ .close = uhci_root_close,
+ .enable = uhci_root_enable,
+ .disable = uhci_root_disable,
+ .speed = uhci_root_speed,
+ .clear_tt = uhci_root_clear_tt,
+ },
+};
+
+/**
+ * Locate EHCI companion controller (when no EHCI support is present)
+ *
+ * @v pci PCI device
+ * @ret busdevfn EHCI companion controller bus:dev.fn (if any)
+ */
+__weak unsigned int ehci_companion ( struct pci_device *pci __unused ) {
+ return 0;
+}
+
+/**
+ * Probe PCI device
+ *
+ * @v pci PCI device
+ * @ret rc Return status code
+ */
+static int uhci_probe ( struct pci_device *pci ) {
+ struct uhci_device *uhci;
+ struct usb_port *port;
+ unsigned int i;
+ int rc;
+
+ /* Allocate and initialise structure */
+ uhci = zalloc ( sizeof ( *uhci ) );
+ if ( ! uhci ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ uhci->name = pci->dev.name;
+ INIT_LIST_HEAD ( &uhci->endpoints );
+ INIT_LIST_HEAD ( &uhci->async );
+ INIT_LIST_HEAD ( &uhci->periodic );
+
+ /* Fix up PCI device */
+ adjust_pci_device ( pci );
+
+ /* Identify EHCI companion controller, if any */
+ uhci->companion = ehci_companion ( pci );
+
+ /* Claim ownership from BIOS. (There is no release mechanism
+ * for UHCI.)
+ */
+ pci_write_config_word ( pci, UHCI_USBLEGSUP, UHCI_USBLEGSUP_DEFAULT );
+
+ /* Map registers */
+ uhci->regs = pci->ioaddr;
+ if ( ! uhci->regs ) {
+ rc = -ENODEV;
+ goto err_ioremap;
+ }
+
+ /* Reset device */
+ if ( ( rc = uhci_reset ( uhci ) ) != 0 )
+ goto err_reset;
+
+ /* Allocate USB bus */
+ uhci->bus = alloc_usb_bus ( &pci->dev, UHCI_PORTS, UHCI_MTU,
+ &uhci_operations );
+ if ( ! uhci->bus ) {
+ rc = -ENOMEM;
+ goto err_alloc_bus;
+ }
+ usb_bus_set_hostdata ( uhci->bus, uhci );
+ usb_hub_set_drvdata ( uhci->bus->hub, uhci );
+
+ /* Set port protocols */
+ for ( i = 1 ; i <= UHCI_PORTS ; i++ ) {
+ port = usb_port ( uhci->bus->hub, i );
+ port->protocol = USB_PROTO_2_0;
+ }
+
+ /* Register USB bus */
+ if ( ( rc = register_usb_bus ( uhci->bus ) ) != 0 )
+ goto err_register;
+
+ pci_set_drvdata ( pci, uhci );
+ return 0;
+
+ unregister_usb_bus ( uhci->bus );
+ err_register:
+ free_usb_bus ( uhci->bus );
+ err_alloc_bus:
+ uhci_reset ( uhci );
+ err_reset:
+ err_ioremap:
+ free ( uhci );
+ err_alloc:
+ return rc;
+}
+
+/**
+ * Remove PCI device
+ *
+ * @v pci PCI device
+ */
+static void uhci_remove ( struct pci_device *pci ) {
+ struct uhci_device *uhci = pci_get_drvdata ( pci );
+ struct usb_bus *bus = uhci->bus;
+
+ unregister_usb_bus ( bus );
+ assert ( list_empty ( &uhci->async ) );
+ assert ( list_empty ( &uhci->periodic ) );
+ free_usb_bus ( bus );
+ uhci_reset ( uhci );
+ free ( uhci );
+}
+
+/** UHCI PCI device IDs */
+static struct pci_device_id uhci_ids[] = {
+ PCI_ROM ( 0xffff, 0xffff, "uhci", "UHCI", 0 ),
+};
+
+/** UHCI PCI driver */
+struct pci_driver uhci_driver __pci_driver = {
+ .ids = uhci_ids,
+ .id_count = ( sizeof ( uhci_ids ) / sizeof ( uhci_ids[0] ) ),
+ .class = PCI_CLASS_ID ( PCI_CLASS_SERIAL, PCI_CLASS_SERIAL_USB,
+ PCI_CLASS_SERIAL_USB_UHCI ),
+ .probe = uhci_probe,
+ .remove = uhci_remove,
+};
diff --git a/roms/ipxe/src/drivers/usb/uhci.h b/roms/ipxe/src/drivers/usb/uhci.h
new file mode 100644
index 000000000..ba4c28f7e
--- /dev/null
+++ b/roms/ipxe/src/drivers/usb/uhci.h
@@ -0,0 +1,350 @@
+#ifndef _IPXE_UHCI_H
+#define _IPXE_UHCI_H
+
+/** @file
+ *
+ * USB Universal Host Controller Interface (UHCI) driver
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <assert.h>
+#include <ipxe/pci.h>
+#include <ipxe/usb.h>
+
+/** Minimum alignment required for data structures
+ *
+ * With the exception of the frame list (which is page-aligned), data
+ * structures used by UHCI generally require 16-byte alignment.
+ */
+#define UHCI_ALIGN 16
+
+/** Number of ports */
+#define UHCI_PORTS 2
+
+/** Maximum transfer size */
+#define UHCI_MTU 1280
+
+/** I/O BAR size */
+#define UHCI_BAR_SIZE 0x14
+
+/** USB command register */
+#define UHCI_USBCMD 0x00
+
+/** Max packet is 64 bytes */
+#define UHCI_USBCMD_MAX64 0x0080
+
+/** Host controller reset */
+#define UHCI_USBCMD_HCRESET 0x0002
+
+/** Run/stop */
+#define UHCI_USBCMD_RUN 0x0001
+
+/** USB status register */
+#define UHCI_USBSTS 0x02
+
+/** Host controller halted */
+#define UHCI_USBSTS_HCHALTED 0x0020
+
+/** USB interrupt */
+#define UHCI_USBSTS_USBINT 0x0001
+
+/** Frame list base address register */
+#define UHCI_FLBASEADD 0x08
+
+/** Port status and control register */
+#define UHCI_PORTSC(port) ( 0x0e + ( (port) << 1 ) )
+
+/** Port reset */
+#define UHCI_PORTSC_PR 0x0200
+
+/** Low-speed device attached */
+#define UHCI_PORTSC_LS 0x0100
+
+/** Port enabled/disabled change */
+#define UHCI_PORTSC_PEC 0x0008
+
+/** Port enabled */
+#define UHCI_PORTSC_PED 0x0004
+
+/** Connect status change */
+#define UHCI_PORTSC_CSC 0x0002
+
+/** Current connect status */
+#define UHCI_PORTSC_CCS 0x0001
+
+/** Port status change mask */
+#define UHCI_PORTSC_CHANGE ( UHCI_PORTSC_CSC | UHCI_PORTSC_PEC )
+
+/** Depth-first processing */
+#define UHCI_LINK_DEPTH_FIRST 0x00000004UL
+
+/** Queue head type */
+#define UHCI_LINK_TYPE_QH 0x00000002UL
+
+/** List terminator */
+#define UHCI_LINK_TERMINATE 0x00000001UL
+
+/** Number of frames in frame list */
+#define UHCI_FRAMES 1024
+
+/** A frame list */
+struct uhci_frame_list {
+ /** Link pointer */
+ uint32_t link[UHCI_FRAMES];
+} __attribute__ (( packed ));
+
+/** A transfer descriptor */
+struct uhci_transfer_descriptor {
+ /** Link pointer */
+ uint32_t link;
+ /** Actual length */
+ uint16_t actual;
+ /** Status */
+ uint8_t status;
+ /** Flags */
+ uint8_t flags;
+ /** Control */
+ uint32_t control;
+ /** Buffer pointer */
+ uint32_t data;
+} __attribute__ (( packed ));
+
+/** Length mask */
+#define UHCI_LEN_MASK 0x7ff
+
+/** Actual length */
+#define UHCI_ACTUAL_LEN( actual ) ( ( (actual) + 1 ) & UHCI_LEN_MASK )
+
+/** Active */
+#define UHCI_STATUS_ACTIVE 0x80
+
+/** Stalled */
+#define UHCI_STATUS_STALLED 0x40
+
+/** Data buffer error */
+#define UHCI_STATUS_BUFFER 0x20
+
+/** Babble detected */
+#define UHCI_STATUS_BABBLE 0x10
+
+/** NAK received */
+#define UHCI_STATUS_NAK 0x08
+
+/** CRC/timeout error */
+#define UHCI_STATUS_CRC_TIMEOUT 0x04
+
+/** Bitstuff error */
+#define UHCI_STATUS_BITSTUFF 0x02
+
+/** Short packet detect */
+#define UHCI_FL_SPD 0x20
+
+/** Error counter */
+#define UHCI_FL_CERR( count ) ( (count) << 3 )
+
+/** Error counter maximum value */
+#define UHCI_FL_CERR_MAX UHCI_FL_CERR ( 3 )
+
+/** Low speed device */
+#define UHCI_FL_LS 0x04
+
+/** Interrupt on completion */
+#define UHCI_FL_IOC 0x01
+
+/** Packet ID */
+#define UHCI_CONTROL_PID( pid ) ( (pid) << 0 )
+
+/** Packet ID mask */
+#define UHCI_CONTROL_PID_MASK UHCI_CONTROL_PID ( 0xff )
+
+/** Device address */
+#define UHCI_CONTROL_DEVICE( address ) ( (address) << 8 )
+
+/** Endpoint address */
+#define UHCI_CONTROL_ENDPOINT( address ) ( (address) << 15 )
+
+/** Data toggle */
+#define UHCI_CONTROL_TOGGLE ( 1 << 19 )
+
+/** Data length */
+#define UHCI_CONTROL_LEN( len ) ( ( ( (len) - 1 ) & UHCI_LEN_MASK ) << 21 )
+
+/** Check for data packet
+ *
+ * This check is based on the fact that only USB_PID_SETUP has bit 2
+ * set.
+ */
+#define UHCI_DATA_PACKET( control ) ( ! ( control & 0x04 ) )
+
+/** Check for short packet */
+#define UHCI_SHORT_PACKET( control, actual ) \
+ ( ( ( (control) >> 21 ) ^ (actual) ) & UHCI_LEN_MASK )
+
+/** USB legacy support register (in PCI configuration space) */
+#define UHCI_USBLEGSUP 0xc0
+
+/** USB legacy support default value */
+#define UHCI_USBLEGSUP_DEFAULT 0x2000
+
+/** A queue head */
+struct uhci_queue_head {
+ /** Horizontal link pointer */
+ uint32_t link;
+ /** Current transfer descriptor */
+ uint32_t current;
+} __attribute__ (( packed ));
+
+/** A single UHCI transfer
+ *
+ * UHCI hardware is extremely simple, and requires software to build
+ * the entire packet schedule (including manually handling all of the
+ * data toggles). The hardware requires at least 16 bytes of transfer
+ * descriptors per 64 bytes of transmitted/received data. We allocate
+ * the transfer descriptors at the time that the transfer is enqueued,
+ * to avoid the need to allocate unreasonably large blocks when the
+ * endpoint is opened.
+ */
+struct uhci_transfer {
+ /** Producer counter */
+ unsigned int prod;
+ /** Consumer counter */
+ unsigned int cons;
+ /** Completed data length */
+ size_t len;
+
+ /** Transfer descriptors */
+ struct uhci_transfer_descriptor *desc;
+
+ /** I/O buffer */
+ struct io_buffer *iobuf;
+};
+
+/** Number of transfer descriptors in a ring
+ *
+ * This is a policy decision.
+ */
+#define UHCI_RING_COUNT 16
+
+/** A transfer ring */
+struct uhci_ring {
+ /** Producer counter */
+ unsigned int prod;
+ /** Consumer counter */
+ unsigned int cons;
+
+ /** Maximum packet length */
+ size_t mtu;
+ /** Base flags
+ *
+ * This incorporates the CERR and LS bits
+ */
+ uint8_t flags;
+ /** Base control word
+ *
+ * This incorporates the device address, the endpoint address,
+ * and the data toggle for the next descriptor to be enqueued.
+ */
+ uint32_t control;
+
+ /** Transfers */
+ struct uhci_transfer *xfer[UHCI_RING_COUNT];
+ /** End of transfer ring (if non-empty) */
+ struct uhci_transfer *end;
+
+ /** Queue head */
+ struct uhci_queue_head *head;
+};
+
+/**
+ * Calculate space used in transfer ring
+ *
+ * @v ring Transfer ring
+ * @ret fill Number of entries used
+ */
+static inline __attribute__ (( always_inline )) unsigned int
+uhci_ring_fill ( struct uhci_ring *ring ) {
+ unsigned int fill;
+
+ fill = ( ring->prod - ring->cons );
+ assert ( fill <= UHCI_RING_COUNT );
+ return fill;
+}
+
+/**
+ * Calculate space remaining in transfer ring
+ *
+ * @v ring Transfer ring
+ * @ret remaining Number of entries remaining
+ */
+static inline __attribute__ (( always_inline )) unsigned int
+uhci_ring_remaining ( struct uhci_ring *ring ) {
+ unsigned int fill = uhci_ring_fill ( ring );
+
+ return ( UHCI_RING_COUNT - fill );
+}
+
+/** Maximum time to wait for host controller to stop
+ *
+ * This is a policy decision.
+ */
+#define UHCI_STOP_MAX_WAIT_MS 100
+
+/** Maximum time to wait for reset to complete
+ *
+ * This is a policy decision.
+ */
+#define UHCI_RESET_MAX_WAIT_MS 500
+
+/** Maximum time to wait for a port to be enabled
+ *
+ * This is a policy decision.
+ */
+#define UHCI_PORT_ENABLE_MAX_WAIT_MS 500
+
+/** A UHCI device */
+struct uhci_device {
+ /** Registers */
+ unsigned long regs;
+ /** Name */
+ const char *name;
+
+ /** EHCI companion controller bus:dev.fn address (if any) */
+ unsigned int companion;
+
+ /** Asynchronous queue head */
+ struct uhci_queue_head *head;
+ /** Frame list */
+ struct uhci_frame_list *frame;
+
+ /** List of all endpoints */
+ struct list_head endpoints;
+ /** Asynchronous schedule */
+ struct list_head async;
+ /** Periodic schedule
+ *
+ * Listed in decreasing order of endpoint interval.
+ */
+ struct list_head periodic;
+
+ /** USB bus */
+ struct usb_bus *bus;
+};
+
+/** A UHCI endpoint */
+struct uhci_endpoint {
+ /** UHCI device */
+ struct uhci_device *uhci;
+ /** USB endpoint */
+ struct usb_endpoint *ep;
+ /** List of all endpoints */
+ struct list_head list;
+ /** Endpoint schedule */
+ struct list_head schedule;
+
+ /** Transfer ring */
+ struct uhci_ring ring;
+};
+
+#endif /* _IPXE_UHCI_H */
diff --git a/roms/ipxe/src/drivers/usb/usbhid.c b/roms/ipxe/src/drivers/usb/usbhid.c
new file mode 100644
index 000000000..c74535a05
--- /dev/null
+++ b/roms/ipxe/src/drivers/usb/usbhid.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2015 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <string.h>
+#include <errno.h>
+#include <ipxe/usb.h>
+#include <ipxe/usbhid.h>
+
+/** @file
+ *
+ * USB human interface devices (HID)
+ *
+ */
+
+/**
+ * Open USB human interface device
+ *
+ * @v hid USB human interface device
+ * @ret rc Return status code
+ */
+int usbhid_open ( struct usb_hid *hid ) {
+ int rc;
+
+ /* Open interrupt IN endpoint */
+ if ( ( rc = usb_endpoint_open ( &hid->in ) ) != 0 ) {
+ DBGC ( hid, "HID %s could not open interrupt IN: %s\n",
+ hid->func->name, strerror ( rc ) );
+ goto err_open_in;
+ }
+
+ /* Refill interrupt IN endpoint */
+ if ( ( rc = usb_refill ( &hid->in ) ) != 0 ) {
+ DBGC ( hid, "HID %s could not refill interrupt IN: %s\n",
+ hid->func->name, strerror ( rc ) );
+ goto err_refill_in;
+ }
+
+ /* Open interrupt OUT endpoint, if applicable */
+ if ( hid->out.usb &&
+ ( ( rc = usb_endpoint_open ( &hid->out ) ) != 0 ) ) {
+ DBGC ( hid, "HID %s could not open interrupt OUT: %s\n",
+ hid->func->name, strerror ( rc ) );
+ goto err_open_out;
+ }
+
+ return 0;
+
+ usb_endpoint_close ( &hid->out );
+ err_open_out:
+ err_refill_in:
+ usb_endpoint_close ( &hid->in );
+ err_open_in:
+ return rc;
+}
+
+/**
+ * Close USB human interface device
+ *
+ * @v hid USB human interface device
+ */
+void usbhid_close ( struct usb_hid *hid ) {
+
+ /* Close interrupt OUT endpoint, if applicable */
+ if ( hid->out.usb )
+ usb_endpoint_close ( &hid->out );
+
+ /* Close interrupt IN endpoint */
+ usb_endpoint_close ( &hid->in );
+}
+
+/**
+ * Refill USB human interface device endpoints
+ *
+ * @v hid USB human interface device
+ * @ret rc Return status code
+ */
+int usbhid_refill ( struct usb_hid *hid ) {
+ int rc;
+
+ /* Refill interrupt IN endpoint */
+ if ( ( rc = usb_refill ( &hid->in ) ) != 0 )
+ return rc;
+
+ /* Refill interrupt OUT endpoint, if applicable */
+ if ( hid->out.usb && ( ( rc = usb_refill ( &hid->out ) ) != 0 ) )
+ return rc;
+
+ return 0;
+}
+
+/**
+ * Describe USB human interface device
+ *
+ * @v hid USB human interface device
+ * @v config Configuration descriptor
+ * @ret rc Return status code
+ */
+int usbhid_describe ( struct usb_hid *hid,
+ struct usb_configuration_descriptor *config ) {
+ struct usb_interface_descriptor *desc;
+ int rc;
+
+ /* Locate interface descriptor */
+ desc = usb_interface_descriptor ( config, hid->func->interface[0], 0 );
+ if ( ! desc ) {
+ DBGC ( hid, "HID %s has no interface descriptor\n",
+ hid->func->name );
+ return -EINVAL;
+ }
+
+ /* Describe interrupt IN endpoint */
+ if ( ( rc = usb_endpoint_described ( &hid->in, config, desc,
+ USB_INTERRUPT_IN, 0 ) ) != 0 ) {
+ DBGC ( hid, "HID %s could not describe interrupt IN: %s\n",
+ hid->func->name, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Describe interrupt OUT endpoint, if applicable */
+ if ( hid->out.usb &&
+ ( ( rc = usb_endpoint_described ( &hid->out, config, desc,
+ USB_INTERRUPT_OUT, 0 ) ) != 0 )){
+ DBGC ( hid, "HID %s could not describe interrupt OUT: %s\n",
+ hid->func->name, strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
diff --git a/roms/ipxe/src/drivers/usb/usbhub.c b/roms/ipxe/src/drivers/usb/usbhub.c
new file mode 100644
index 000000000..bf2a20005
--- /dev/null
+++ b/roms/ipxe/src/drivers/usb/usbhub.c
@@ -0,0 +1,547 @@
+/*
+ * Copyright (C) 2014 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <ipxe/usb.h>
+#include "usbhub.h"
+
+/** @file
+ *
+ * USB hub driver
+ *
+ */
+
+/**
+ * Refill interrupt ring
+ *
+ * @v hubdev Hub device
+ */
+static void hub_refill ( struct usb_hub_device *hubdev ) {
+ int rc;
+
+ /* Refill interrupt endpoint */
+ if ( ( rc = usb_refill ( &hubdev->intr ) ) != 0 ) {
+ DBGC ( hubdev, "HUB %s could not refill interrupt: %s\n",
+ hubdev->name, strerror ( rc ) );
+ /* Continue attempting to refill */
+ return;
+ }
+
+ /* Stop refill process */
+ process_del ( &hubdev->refill );
+}
+
+/** Refill process descriptor */
+static struct process_descriptor hub_refill_desc =
+ PROC_DESC ( struct usb_hub_device, refill, hub_refill );
+
+/**
+ * Complete interrupt transfer
+ *
+ * @v ep USB endpoint
+ * @v iobuf I/O buffer
+ * @v rc Completion status code
+ */
+static void hub_complete ( struct usb_endpoint *ep,
+ struct io_buffer *iobuf, int rc ) {
+ struct usb_hub_device *hubdev =
+ container_of ( ep, struct usb_hub_device, intr );
+ struct usb_hub *hub = hubdev->hub;
+ uint8_t *data = iobuf->data;
+ unsigned int bits = ( 8 * iob_len ( iobuf ) );
+ unsigned int i;
+
+ /* Ignore packets cancelled when the endpoint closes */
+ if ( ! ep->open )
+ goto done;
+
+ /* Ignore packets with errors */
+ if ( rc != 0 ) {
+ DBGC ( hubdev, "HUB %s interrupt failed: %s\n",
+ hubdev->name, strerror ( rc ) );
+ DBGC_HDA ( hubdev, 0, iobuf->data, iob_len ( iobuf ) );
+ goto done;
+ }
+
+ /* Report any port status changes */
+ for ( i = 1 ; i <= hub->ports ; i++ ) {
+
+ /* Sanity check */
+ if ( i > bits ) {
+ DBGC ( hubdev, "HUB %s underlength interrupt:\n",
+ hubdev->name );
+ DBGC_HDA ( hubdev, 0, iobuf->data, iob_len ( iobuf ) );
+ goto done;
+ }
+
+ /* Report port status change if applicable */
+ if ( data[ i / 8 ] & ( 1 << ( i % 8 ) ) ) {
+ DBGC2 ( hubdev, "HUB %s port %d status changed\n",
+ hubdev->name, i );
+ usb_port_changed ( usb_port ( hub, i ) );
+ }
+ }
+
+ done:
+ /* Start refill process */
+ process_add ( &hubdev->refill );
+}
+
+/** Interrupt endpoint operations */
+static struct usb_endpoint_driver_operations usb_hub_intr_operations = {
+ .complete = hub_complete,
+};
+
+/**
+ * Open hub
+ *
+ * @v hub USB hub
+ * @ret rc Return status code
+ */
+static int hub_open ( struct usb_hub *hub ) {
+ struct usb_hub_device *hubdev = usb_hub_get_drvdata ( hub );
+ struct usb_device *usb = hubdev->usb;
+ unsigned int i;
+ int rc;
+
+ /* Ensure ports are powered */
+ for ( i = 1 ; i <= hub->ports ; i++ ) {
+ if ( ( rc = usb_hub_set_port_feature ( usb, i,
+ USB_HUB_PORT_POWER,
+ 0 ) ) != 0 ) {
+ DBGC ( hubdev, "HUB %s port %d could not apply power: "
+ "%s\n", hubdev->name, i, strerror ( rc ) );
+ goto err_power;
+ }
+ }
+
+ /* Open interrupt endpoint */
+ if ( ( rc = usb_endpoint_open ( &hubdev->intr ) ) != 0 ) {
+ DBGC ( hubdev, "HUB %s could not register interrupt: %s\n",
+ hubdev->name, strerror ( rc ) );
+ goto err_open;
+ }
+
+ /* Start refill process */
+ process_add ( &hubdev->refill );
+
+ /* Refill interrupt ring */
+ hub_refill ( hubdev );
+
+ return 0;
+
+ usb_endpoint_close ( &hubdev->intr );
+ err_open:
+ err_power:
+ return rc;
+}
+
+/**
+ * Close hub
+ *
+ * @v hub USB hub
+ */
+static void hub_close ( struct usb_hub *hub ) {
+ struct usb_hub_device *hubdev = usb_hub_get_drvdata ( hub );
+
+ /* Close interrupt endpoint */
+ usb_endpoint_close ( &hubdev->intr );
+
+ /* Stop refill process */
+ process_del ( &hubdev->refill );
+}
+
+/**
+ * Enable port
+ *
+ * @v hub USB hub
+ * @v port USB port
+ * @ret rc Return status code
+ */
+static int hub_enable ( struct usb_hub *hub, struct usb_port *port ) {
+ struct usb_hub_device *hubdev = usb_hub_get_drvdata ( hub );
+ struct usb_device *usb = hubdev->usb;
+ struct usb_hub_port_status status;
+ unsigned int current;
+ unsigned int i;
+ int rc;
+
+ /* Initiate reset if applicable */
+ if ( ( hub->protocol < USB_PROTO_3_0 ) &&
+ ( ( rc = usb_hub_set_port_feature ( usb, port->address,
+ USB_HUB_PORT_RESET, 0 ) )!=0)){
+ DBGC ( hubdev, "HUB %s port %d could not initiate reset: %s\n",
+ hubdev->name, port->address, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Wait for port to become enabled */
+ for ( i = 0 ; i < USB_HUB_ENABLE_MAX_WAIT_MS ; i++ ) {
+
+ /* Check for port being enabled */
+ if ( ( rc = usb_hub_get_port_status ( usb, port->address,
+ &status ) ) != 0 ) {
+ DBGC ( hubdev, "HUB %s port %d could not get status: "
+ "%s\n", hubdev->name, port->address,
+ strerror ( rc ) );
+ return rc;
+ }
+ current = le16_to_cpu ( status.current );
+ if ( current & ( 1 << USB_HUB_PORT_ENABLE ) )
+ return 0;
+
+ /* Delay */
+ mdelay ( 1 );
+ }
+
+ DBGC ( hubdev, "HUB %s port %d timed out waiting for enable\n",
+ hubdev->name, port->address );
+ return -ETIMEDOUT;
+}
+
+/**
+ * Disable port
+ *
+ * @v hub USB hub
+ * @v port USB port
+ * @ret rc Return status code
+ */
+static int hub_disable ( struct usb_hub *hub, struct usb_port *port ) {
+ struct usb_hub_device *hubdev = usb_hub_get_drvdata ( hub );
+ struct usb_device *usb = hubdev->usb;
+ int rc;
+
+ /* Disable port */
+ if ( ( rc = usb_hub_clear_port_feature ( usb, port->address,
+ USB_HUB_PORT_ENABLE, 0 ) )!=0){
+ DBGC ( hubdev, "HUB %s port %d could not disable: %s\n",
+ hubdev->name, port->address, strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Clear port status change bits
+ *
+ * @v hubdev USB hub device
+ * @v port Port number
+ * @v changed Port status change bits
+ * @ret rc Return status code
+ */
+static int hub_clear_changes ( struct usb_hub_device *hubdev,
+ unsigned int port, uint16_t changed ) {
+ struct usb_device *usb = hubdev->usb;
+ unsigned int bit;
+ unsigned int feature;
+ int rc;
+
+ /* Clear each set bit */
+ for ( bit = 0 ; bit < 16 ; bit++ ) {
+
+ /* Skip unset bits */
+ if ( ! ( changed & ( 1 << bit ) ) )
+ continue;
+
+ /* Skip unused features */
+ feature = USB_HUB_C_FEATURE ( bit );
+ if ( ! ( hubdev->features & ( 1 << feature ) ) )
+ continue;
+
+ /* Clear bit */
+ if ( ( rc = usb_hub_clear_port_feature ( usb, port,
+ feature, 0 ) ) != 0 ) {
+ DBGC ( hubdev, "HUB %s port %d could not clear feature "
+ "%d: %s\n", hubdev->name, port, feature,
+ strerror ( rc ) );
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Update port speed
+ *
+ * @v hub USB hub
+ * @v port USB port
+ * @ret rc Return status code
+ */
+static int hub_speed ( struct usb_hub *hub, struct usb_port *port ) {
+ struct usb_hub_device *hubdev = usb_hub_get_drvdata ( hub );
+ struct usb_device *usb = hubdev->usb;
+ struct usb_hub_port_status status;
+ unsigned int current;
+ unsigned int changed;
+ int rc;
+
+ /* Get port status */
+ if ( ( rc = usb_hub_get_port_status ( usb, port->address,
+ &status ) ) != 0 ) {
+ DBGC ( hubdev, "HUB %s port %d could not get status: %s\n",
+ hubdev->name, port->address, strerror ( rc ) );
+ return rc;
+ }
+ current = le16_to_cpu ( status.current );
+ changed = le16_to_cpu ( status.changed );
+ DBGC2 ( hubdev, "HUB %s port %d status is %04x:%04x\n",
+ hubdev->name, port->address, changed, current );
+
+ /* Update port speed */
+ if ( current & ( 1 << USB_HUB_PORT_CONNECTION ) ) {
+ if ( hub->protocol >= USB_PROTO_3_0 ) {
+ port->speed = USB_SPEED_SUPER;
+ } else if ( current & ( 1 << USB_HUB_PORT_LOW_SPEED ) ) {
+ port->speed = USB_SPEED_LOW;
+ } else if ( current & ( 1 << USB_HUB_PORT_HIGH_SPEED ) ) {
+ port->speed = USB_SPEED_HIGH;
+ } else {
+ port->speed = USB_SPEED_FULL;
+ }
+ } else {
+ port->speed = USB_SPEED_NONE;
+ }
+
+ /* Record disconnections */
+ port->disconnected |= ( changed & ( 1 << USB_HUB_PORT_CONNECTION ) );
+
+ /* Clear port status change bits */
+ if ( ( rc = hub_clear_changes ( hubdev, port->address, changed ) ) != 0)
+ return rc;
+
+ return 0;
+}
+
+/**
+ * Clear transaction translator buffer
+ *
+ * @v hub USB hub
+ * @v port USB port
+ * @v ep USB endpoint
+ * @ret rc Return status code
+ */
+static int hub_clear_tt ( struct usb_hub *hub, struct usb_port *port,
+ struct usb_endpoint *ep ) {
+ struct usb_hub_device *hubdev = usb_hub_get_drvdata ( hub );
+ struct usb_device *usb = hubdev->usb;
+ int rc;
+
+ /* Clear transaction translator buffer. All hubs must support
+ * single-TT operation; we simplify our code by supporting
+ * only this configuration.
+ */
+ if ( ( rc = usb_hub_clear_tt_buffer ( usb, ep->usb->address,
+ ep->address, ep->attributes,
+ USB_HUB_TT_SINGLE ) ) != 0 ) {
+ DBGC ( hubdev, "HUB %s port %d could not clear TT buffer: %s\n",
+ hubdev->name, port->address, strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/** USB hub operations */
+static struct usb_hub_driver_operations hub_operations = {
+ .open = hub_open,
+ .close = hub_close,
+ .enable = hub_enable,
+ .disable = hub_disable,
+ .speed = hub_speed,
+ .clear_tt = hub_clear_tt,
+};
+
+/**
+ * Probe USB hub
+ *
+ * @v func USB function
+ * @v config Configuration descriptor
+ * @ret rc Return status code
+ */
+static int hub_probe ( struct usb_function *func,
+ struct usb_configuration_descriptor *config ) {
+ struct usb_device *usb = func->usb;
+ struct usb_bus *bus = usb->port->hub->bus;
+ struct usb_hub_device *hubdev;
+ struct usb_interface_descriptor *interface;
+ union usb_hub_descriptor desc;
+ unsigned int depth;
+ unsigned int ports;
+ int enhanced;
+ int rc;
+
+ /* Allocate and initialise structure */
+ hubdev = zalloc ( sizeof ( *hubdev ) );
+ if ( ! hubdev ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ enhanced = ( usb->port->protocol >= USB_PROTO_3_0 );
+ hubdev->name = func->name;
+ hubdev->usb = usb;
+ hubdev->features =
+ ( enhanced ? USB_HUB_FEATURES_ENHANCED : USB_HUB_FEATURES );
+ usb_endpoint_init ( &hubdev->intr, usb, &usb_hub_intr_operations );
+ usb_refill_init ( &hubdev->intr, 0, USB_HUB_INTR_FILL );
+ process_init_stopped ( &hubdev->refill, &hub_refill_desc, NULL );
+
+ /* Locate hub interface descriptor */
+ interface = usb_interface_descriptor ( config, func->interface[0], 0 );
+ if ( ! interface ) {
+ DBGC ( hubdev, "HUB %s has no interface descriptor\n",
+ hubdev->name );
+ rc = -EINVAL;
+ goto err_interface;
+ }
+
+ /* Locate interrupt endpoint descriptor */
+ if ( ( rc = usb_endpoint_described ( &hubdev->intr, config, interface,
+ USB_INTERRUPT_IN, 0 ) ) != 0 ) {
+ DBGC ( hubdev, "HUB %s could not describe interrupt endpoint: "
+ "%s\n", hubdev->name, strerror ( rc ) );
+ goto err_endpoint;
+ }
+
+ /* Set hub depth */
+ depth = usb_depth ( usb );
+ if ( enhanced ) {
+ if ( ( rc = usb_hub_set_hub_depth ( usb, depth ) ) != 0 ) {
+ DBGC ( hubdev, "HUB %s could not set hub depth to %d: "
+ "%s\n", hubdev->name, depth, strerror ( rc ) );
+ goto err_set_hub_depth;
+ }
+ }
+
+ /* Get hub descriptor */
+ if ( ( rc = usb_hub_get_descriptor ( usb, enhanced, &desc ) ) != 0 ) {
+ DBGC ( hubdev, "HUB %s could not get hub descriptor: %s\n",
+ hubdev->name, strerror ( rc ) );
+ goto err_hub_descriptor;
+ }
+ ports = desc.basic.ports;
+ DBGC ( hubdev, "HUB %s has %d ports at depth %d%s\n", hubdev->name,
+ ports, depth, ( enhanced ? " (enhanced)" : "" ) );
+
+ /* Allocate hub */
+ hubdev->hub = alloc_usb_hub ( bus, usb, ports, &hub_operations );
+ if ( ! hubdev->hub ) {
+ rc = -ENOMEM;
+ goto err_alloc_hub;
+ }
+ usb_hub_set_drvdata ( hubdev->hub, hubdev );
+
+ /* Register hub */
+ if ( ( rc = register_usb_hub ( hubdev->hub ) ) != 0 ) {
+ DBGC ( hubdev, "HUB %s could not register: %s\n",
+ hubdev->name, strerror ( rc ) );
+ goto err_register_hub;
+ }
+
+ usb_func_set_drvdata ( func, hubdev );
+ return 0;
+
+ unregister_usb_hub ( hubdev->hub );
+ err_register_hub:
+ free_usb_hub ( hubdev->hub );
+ err_alloc_hub:
+ err_hub_descriptor:
+ err_set_hub_depth:
+ err_endpoint:
+ err_interface:
+ free ( hubdev );
+ err_alloc:
+ return rc;
+}
+
+/**
+ * Remove USB hub
+ *
+ * @v func USB function
+ * @ret rc Return status code
+ */
+static void hub_remove ( struct usb_function *func ) {
+ struct usb_hub_device *hubdev = usb_func_get_drvdata ( func );
+ struct usb_hub *hub = hubdev->hub;
+ struct usb_device *usb = hubdev->usb;
+ struct usb_port *port;
+ unsigned int i;
+
+ /* If hub has been unplugged, mark all ports as unplugged */
+ if ( usb->port->speed == USB_SPEED_NONE ) {
+ for ( i = 1 ; i <= hub->ports ; i++ ) {
+ port = usb_port ( hub, i );
+ port->speed = USB_SPEED_NONE;
+ }
+ }
+
+ /* Unregister hub */
+ unregister_usb_hub ( hubdev->hub );
+ assert ( ! process_running ( &hubdev->refill ) );
+
+ /* Free hub */
+ free_usb_hub ( hubdev->hub );
+
+ /* Free hub device */
+ free ( hubdev );
+}
+
+/** USB hub device IDs */
+static struct usb_device_id hub_ids[] = {
+ {
+ .name = "hub-1",
+ .vendor = USB_ANY_ID,
+ .product = USB_ANY_ID,
+ .class = {
+ .class = USB_CLASS_HUB,
+ .subclass = 0,
+ .protocol = 0,
+ },
+ },
+ {
+ .name = "hub-2",
+ .vendor = USB_ANY_ID,
+ .product = USB_ANY_ID,
+ .class = {
+ .class = USB_CLASS_HUB,
+ .subclass = 0,
+ .protocol = 1,
+ },
+ },
+};
+
+/** USB hub driver */
+struct usb_driver usb_hub_driver __usb_driver = {
+ .ids = hub_ids,
+ .id_count = ( sizeof ( hub_ids ) / sizeof ( hub_ids[0] ) ),
+ .probe = hub_probe,
+ .remove = hub_remove,
+};
diff --git a/roms/ipxe/src/drivers/usb/usbhub.h b/roms/ipxe/src/drivers/usb/usbhub.h
new file mode 100644
index 000000000..d7d8f9610
--- /dev/null
+++ b/roms/ipxe/src/drivers/usb/usbhub.h
@@ -0,0 +1,279 @@
+#ifndef _USBHUB_H
+#define _USBHUB_H
+
+/** @file
+ *
+ * USB hubs
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <ipxe/usb.h>
+#include <ipxe/list.h>
+#include <ipxe/process.h>
+
+/** Request recipient is a port */
+#define USB_HUB_RECIP_PORT ( 3 << 0 )
+
+/** A basic USB hub descriptor */
+struct usb_hub_descriptor_basic {
+ /** Descriptor header */
+ struct usb_descriptor_header header;
+ /** Number of ports */
+ uint8_t ports;
+ /** Characteristics */
+ uint16_t characteristics;
+ /** Power-on delay (in 2ms intervals */
+ uint8_t delay;
+ /** Controller current (in mA) */
+ uint8_t current;
+} __attribute__ (( packed ));
+
+/** A basic USB hub descriptor */
+#define USB_HUB_DESCRIPTOR 41
+
+/** An enhanced USB hub descriptor */
+struct usb_hub_descriptor_enhanced {
+ /** Basic USB hub descriptor */
+ struct usb_hub_descriptor_basic basic;
+ /** Header decode latency */
+ uint8_t latency;
+ /** Maximum delay */
+ uint16_t delay;
+ /** Removable device bitmask */
+ uint16_t removable;
+} __attribute__ (( packed ));
+
+/** An enhanced USB hub descriptor */
+#define USB_HUB_DESCRIPTOR_ENHANCED 42
+
+/** A USB hub descriptor */
+union usb_hub_descriptor {
+ /** Descriptor header */
+ struct usb_descriptor_header header;
+ /** Basic hub descriptor */
+ struct usb_hub_descriptor_basic basic;
+ /** Enhanced hub descriptor */
+ struct usb_hub_descriptor_enhanced enhanced;
+} __attribute__ (( packed ));
+
+/** Port status */
+struct usb_hub_port_status {
+ /** Current status */
+ uint16_t current;
+ /** Changed status */
+ uint16_t changed;
+} __attribute__ (( packed ));
+
+/** Current connect status feature */
+#define USB_HUB_PORT_CONNECTION 0
+
+/** Port enabled/disabled feature */
+#define USB_HUB_PORT_ENABLE 1
+
+/** Port reset feature */
+#define USB_HUB_PORT_RESET 4
+
+/** Port power feature */
+#define USB_HUB_PORT_POWER 8
+
+/** Low-speed device attached */
+#define USB_HUB_PORT_LOW_SPEED 9
+
+/** High-speed device attached */
+#define USB_HUB_PORT_HIGH_SPEED 10
+
+/** Connect status changed */
+#define USB_HUB_C_PORT_CONNECTION 16
+
+/** Port enable/disable changed */
+#define USB_HUB_C_PORT_ENABLE 17
+
+/** Suspend changed */
+#define USB_HUB_C_PORT_SUSPEND 18
+
+/** Over-current indicator changed */
+#define USB_HUB_C_PORT_OVER_CURRENT 19
+
+/** Reset changed */
+#define USB_HUB_C_PORT_RESET 20
+
+/** Link state changed */
+#define USB_HUB_C_PORT_LINK_STATE 25
+
+/** Configuration error */
+#define USB_HUB_C_PORT_CONFIG_ERROR 26
+
+/** Calculate feature from change bit number */
+#define USB_HUB_C_FEATURE( bit ) ( 16 + (bit) )
+
+/** USB features */
+#define USB_HUB_FEATURES \
+ ( ( 1 << USB_HUB_C_PORT_CONNECTION ) | \
+ ( 1 << USB_HUB_C_PORT_ENABLE ) | \
+ ( 1 << USB_HUB_C_PORT_SUSPEND ) | \
+ ( 1 << USB_HUB_C_PORT_OVER_CURRENT ) | \
+ ( 1 << USB_HUB_C_PORT_RESET ) )
+
+/** USB features for enhanced hubs */
+#define USB_HUB_FEATURES_ENHANCED \
+ ( ( 1 << USB_HUB_C_PORT_CONNECTION ) | \
+ ( 1 << USB_HUB_C_PORT_OVER_CURRENT ) | \
+ ( 1 << USB_HUB_C_PORT_RESET ) | \
+ ( 1 << USB_HUB_C_PORT_LINK_STATE ) | \
+ ( 1 << USB_HUB_C_PORT_CONFIG_ERROR ) )
+
+/** Set hub depth */
+#define USB_HUB_SET_HUB_DEPTH \
+ ( USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_DEVICE | \
+ USB_REQUEST_TYPE ( 12 ) )
+
+/** Clear transaction translator buffer */
+#define USB_HUB_CLEAR_TT_BUFFER \
+ ( USB_DIR_OUT | USB_TYPE_CLASS | USB_HUB_RECIP_PORT | \
+ USB_REQUEST_TYPE ( 8 ) )
+
+/**
+ * Get hub descriptor
+ *
+ * @v usb USB device
+ * @v enhanced Hub is an enhanced hub
+ * @v data Hub descriptor to fill in
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+usb_hub_get_descriptor ( struct usb_device *usb, int enhanced,
+ union usb_hub_descriptor *data ) {
+ unsigned int desc;
+ size_t len;
+
+ /* Determine descriptor type and length */
+ desc = ( enhanced ? USB_HUB_DESCRIPTOR_ENHANCED : USB_HUB_DESCRIPTOR );
+ len = ( enhanced ? sizeof ( data->enhanced ) : sizeof ( data->basic ) );
+
+ return usb_get_descriptor ( usb, USB_TYPE_CLASS, desc, 0, 0,
+ &data->header, len );
+}
+
+/**
+ * Get port status
+ *
+ * @v usb USB device
+ * @v port Port address
+ * @v status Port status descriptor to fill in
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+usb_hub_get_port_status ( struct usb_device *usb, unsigned int port,
+ struct usb_hub_port_status *status ) {
+
+ return usb_get_status ( usb, ( USB_TYPE_CLASS | USB_HUB_RECIP_PORT ),
+ port, status, sizeof ( *status ) );
+}
+
+/**
+ * Clear port feature
+ *
+ * @v usb USB device
+ * @v port Port address
+ * @v feature Feature to clear
+ * @v index Index (when clearing a port indicator)
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+usb_hub_clear_port_feature ( struct usb_device *usb, unsigned int port,
+ unsigned int feature, unsigned int index ) {
+
+ return usb_clear_feature ( usb, ( USB_TYPE_CLASS | USB_HUB_RECIP_PORT ),
+ feature, ( ( index << 8 ) | port ) );
+}
+
+/**
+ * Set port feature
+ *
+ * @v usb USB device
+ * @v port Port address
+ * @v feature Feature to clear
+ * @v index Index (when clearing a port indicator)
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+usb_hub_set_port_feature ( struct usb_device *usb, unsigned int port,
+ unsigned int feature, unsigned int index ) {
+
+ return usb_set_feature ( usb, ( USB_TYPE_CLASS | USB_HUB_RECIP_PORT ),
+ feature, ( ( index << 8 ) | port ) );
+}
+
+/**
+ * Set hub depth
+ *
+ * @v usb USB device
+ * @v depth Hub depth
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+usb_hub_set_hub_depth ( struct usb_device *usb, unsigned int depth ) {
+
+ return usb_control ( usb, USB_HUB_SET_HUB_DEPTH, depth, 0, NULL, 0 );
+}
+
+/**
+ * Clear transaction translator buffer
+ *
+ * @v usb USB device
+ * @v device Device address
+ * @v endpoint Endpoint address
+ * @v attributes Endpoint attributes
+ * @v tt_port Transaction translator port (or 1 for single-TT hubs)
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+usb_hub_clear_tt_buffer ( struct usb_device *usb, unsigned int device,
+ unsigned int endpoint, unsigned int attributes,
+ unsigned int tt_port ) {
+ unsigned int value;
+
+ /* Calculate value */
+ value = ( ( ( endpoint & USB_ENDPOINT_MAX ) << 0 ) | ( device << 4 ) |
+ ( ( attributes & USB_ENDPOINT_ATTR_TYPE_MASK ) << 11 ) |
+ ( ( endpoint & USB_ENDPOINT_IN ) << 8 ) );
+
+ return usb_control ( usb, USB_HUB_CLEAR_TT_BUFFER, value,
+ tt_port, NULL, 0 );
+}
+
+/** Transaction translator port value for single-TT hubs */
+#define USB_HUB_TT_SINGLE 1
+
+/** A USB hub device */
+struct usb_hub_device {
+ /** Name */
+ const char *name;
+ /** USB device */
+ struct usb_device *usb;
+ /** USB hub */
+ struct usb_hub *hub;
+ /** Features */
+ unsigned int features;
+
+ /** Interrupt endpoint */
+ struct usb_endpoint intr;
+ /** Interrupt endpoint refill process */
+ struct process refill;
+};
+
+/** Interrupt ring fill level
+ *
+ * This is a policy decision.
+ */
+#define USB_HUB_INTR_FILL 4
+
+/** Maximum time to wait for port to become enabled
+ *
+ * This is a policy decision.
+ */
+#define USB_HUB_ENABLE_MAX_WAIT_MS 100
+
+#endif /* _USBHUB_H */
diff --git a/roms/ipxe/src/drivers/usb/usbkbd.c b/roms/ipxe/src/drivers/usb/usbkbd.c
new file mode 100644
index 000000000..ea94f2e63
--- /dev/null
+++ b/roms/ipxe/src/drivers/usb/usbkbd.c
@@ -0,0 +1,509 @@
+/*
+ * Copyright (C) 2015 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <ipxe/console.h>
+#include <ipxe/keys.h>
+#include <ipxe/usb.h>
+#include "usbkbd.h"
+
+/** @file
+ *
+ * USB keyboard driver
+ *
+ */
+
+/** List of USB keyboards */
+static LIST_HEAD ( usb_keyboards );
+
+/******************************************************************************
+ *
+ * Keyboard map
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Map USB keycode to iPXE key
+ *
+ * @v keycode Keycode
+ * @v modifiers Modifiers
+ * @ret key iPXE key
+ *
+ * Key codes are defined in the USB HID Usage Tables Keyboard/Keypad
+ * page.
+ */
+static unsigned int usbkbd_map ( unsigned int keycode,
+ unsigned int modifiers ) {
+ unsigned int key;
+
+ if ( keycode < USBKBD_KEY_A ) {
+ /* Not keys */
+ key = 0;
+ } else if ( keycode <= USBKBD_KEY_Z ) {
+ /* Alphabetic keys */
+ key = ( keycode - USBKBD_KEY_A + 'a' );
+ if ( modifiers & USBKBD_CTRL ) {
+ key -= ( 'a' - CTRL_A );
+ } else if ( modifiers & USBKBD_SHIFT ) {
+ key -= ( 'a' - 'A' );
+ }
+ } else if ( keycode <= USBKBD_KEY_0 ) {
+ /* Numeric key row */
+ if ( modifiers & USBKBD_SHIFT ) {
+ key = "!@#$%^&*()" [ keycode - USBKBD_KEY_1 ];
+ } else {
+ key = ( ( ( keycode - USBKBD_KEY_1 + 1 ) % 10 ) + '0' );
+ }
+ } else if ( keycode <= USBKBD_KEY_SPACE ) {
+ /* Unmodifiable keys */
+ static const uint8_t unmodifable[] =
+ { LF, ESC, BACKSPACE, TAB, ' ' };
+ key = unmodifable[ keycode - USBKBD_KEY_ENTER ];
+ } else if ( keycode <= USBKBD_KEY_SLASH ) {
+ /* Punctuation keys */
+ if ( modifiers & USBKBD_SHIFT ) {
+ key = "_+{}|~:\"~<>?" [ keycode - USBKBD_KEY_MINUS ];
+ } else {
+ key = "-=[]\\#;'`,./" [ keycode - USBKBD_KEY_MINUS ];
+ }
+ } else if ( keycode <= USBKBD_KEY_UP ) {
+ /* Special keys */
+ static const uint16_t special[] = {
+ 0, 0, 0, 0, 0, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9,
+ KEY_F10, KEY_F11, KEY_F12, 0, 0, 0, KEY_IC, KEY_HOME,
+ KEY_PPAGE, KEY_DC, KEY_END, KEY_NPAGE, KEY_RIGHT,
+ KEY_LEFT, KEY_DOWN, KEY_UP
+ };
+ key = special[ keycode - USBKBD_KEY_CAPSLOCK ];
+ } else {
+ key = 0;
+ }
+
+ return key;
+}
+
+/******************************************************************************
+ *
+ * Keyboard buffer
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Insert keypress into keyboard buffer
+ *
+ * @v kbd USB keyboard
+ * @v keycode Keycode
+ * @v modifiers Modifiers
+ */
+static void usbkbd_produce ( struct usb_keyboard *kbd, unsigned int keycode,
+ unsigned int modifiers ) {
+ unsigned int key;
+
+ /* Map to iPXE key */
+ key = usbkbd_map ( keycode, modifiers );
+
+ /* Do nothing if this keycode has no corresponding iPXE key */
+ if ( ! key ) {
+ DBGC ( kbd, "KBD %s has no key for keycode %#02x:%#02x\n",
+ kbd->name, modifiers, keycode );
+ return;
+ }
+
+ /* Check for buffer overrun */
+ if ( usbkbd_fill ( kbd ) >= USBKBD_BUFSIZE ) {
+ DBGC ( kbd, "KBD %s buffer overrun (key %#02x)\n",
+ kbd->name, key );
+ return;
+ }
+
+ /* Insert into buffer */
+ kbd->key[ ( kbd->prod++ ) % USBKBD_BUFSIZE ] = key;
+ DBGC2 ( kbd, "KBD %s key %#02x produced\n", kbd->name, key );
+}
+
+/**
+ * Consume character from keyboard buffer
+ *
+ * @v kbd USB keyboard
+ * @ret character Character
+ */
+static unsigned int usbkbd_consume ( struct usb_keyboard *kbd ) {
+ static char buf[] = "\x1b[xx~";
+ char *tmp = &buf[2];
+ unsigned int key;
+ unsigned int character;
+ unsigned int ansi_n;
+ unsigned int len;
+
+ /* Sanity check */
+ assert ( usbkbd_fill ( kbd ) > 0 );
+
+ /* Get current keypress */
+ key = kbd->key[ kbd->cons % USBKBD_BUFSIZE ];
+
+ /* If this is a straightforward key, just consume and return it */
+ if ( key < KEY_MIN ) {
+ kbd->cons++;
+ DBGC2 ( kbd, "KBD %s key %#02x consumed\n", kbd->name, key );
+ return key;
+ }
+
+ /* Construct ANSI sequence */
+ ansi_n = KEY_ANSI_N ( key );
+ if ( ansi_n )
+ tmp += sprintf ( tmp, "%d", ansi_n );
+ *(tmp++) = KEY_ANSI_TERMINATOR ( key );
+ *tmp = '\0';
+ len = ( tmp - buf );
+ assert ( len < sizeof ( buf ) );
+ if ( kbd->subcons == 0 ) {
+ DBGC2 ( kbd, "KBD %s key %#02x consumed as ^[%s\n",
+ kbd->name, key, &buf[1] );
+ }
+
+ /* Extract character from ANSI sequence */
+ assert ( kbd->subcons < len );
+ character = buf[ kbd->subcons++ ];
+
+ /* Consume key if applicable */
+ if ( kbd->subcons == len ) {
+ kbd->cons++;
+ kbd->subcons = 0;
+ }
+
+ return character;
+}
+
+/******************************************************************************
+ *
+ * Keyboard report
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Check for presence of keycode in report
+ *
+ * @v report Keyboard report
+ * @v keycode Keycode (must be non-zero)
+ * @ret has_keycode Keycode is present in report
+ */
+static int usbkbd_has_keycode ( struct usb_keyboard_report *report,
+ unsigned int keycode ) {
+ unsigned int i;
+
+ /* Check for keycode */
+ for ( i = 0 ; i < ( sizeof ( report->keycode ) /
+ sizeof ( report->keycode[0] ) ) ; i++ ) {
+ if ( report->keycode[i] == keycode )
+ return keycode;
+ }
+
+ return 0;
+}
+
+/**
+ * Handle keyboard report
+ *
+ * @v kbd USB keyboard
+ * @v new New keyboard report
+ */
+static void usbkbd_report ( struct usb_keyboard *kbd,
+ struct usb_keyboard_report *new ) {
+ struct usb_keyboard_report *old = &kbd->report;
+ unsigned int keycode;
+ unsigned int i;
+
+ /* Check if current key has been released */
+ if ( kbd->keycode && ! usbkbd_has_keycode ( new, kbd->keycode ) ) {
+ DBGC2 ( kbd, "KBD %s keycode %#02x released\n",
+ kbd->name, kbd->keycode );
+ kbd->keycode = 0;
+ }
+
+ /* Decrement auto-repeat hold-off timer, if applicable */
+ if ( kbd->holdoff )
+ kbd->holdoff--;
+
+ /* Check if a new key has been pressed */
+ for ( i = 0 ; i < ( sizeof ( new->keycode ) /
+ sizeof ( new->keycode[0] ) ) ; i++ ) {
+
+ /* Ignore keys present in the previous report */
+ keycode = new->keycode[i];
+ if ( ( keycode == 0 ) || usbkbd_has_keycode ( old, keycode ) )
+ continue;
+ DBGC2 ( kbd, "KBD %s keycode %#02x pressed\n",
+ kbd->name, keycode );
+
+ /* Insert keypress into keyboard buffer */
+ usbkbd_produce ( kbd, keycode, new->modifiers );
+
+ /* Record as most recent keycode */
+ kbd->keycode = keycode;
+
+ /* Start auto-repeat hold-off timer */
+ kbd->holdoff = USBKBD_HOLDOFF;
+ }
+
+ /* Insert auto-repeated keypress into keyboard buffer, if applicable */
+ if ( kbd->keycode && ! kbd->holdoff )
+ usbkbd_produce ( kbd, kbd->keycode, new->modifiers );
+
+ /* Record report */
+ memcpy ( old, new, sizeof ( *old ) );
+}
+
+/******************************************************************************
+ *
+ * Interrupt endpoint
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Complete interrupt transfer
+ *
+ * @v ep USB endpoint
+ * @v iobuf I/O buffer
+ * @v rc Completion status code
+ */
+static void usbkbd_complete ( struct usb_endpoint *ep,
+ struct io_buffer *iobuf, int rc ) {
+ struct usb_keyboard *kbd = container_of ( ep, struct usb_keyboard,
+ hid.in );
+ struct usb_keyboard_report *report;
+
+ /* Ignore packets cancelled when the endpoint closes */
+ if ( ! ep->open )
+ goto drop;
+
+ /* Ignore packets with errors */
+ if ( rc != 0 ) {
+ DBGC ( kbd, "KBD %s interrupt IN failed: %s\n",
+ kbd->name, strerror ( rc ) );
+ goto drop;
+ }
+
+ /* Ignore underlength packets */
+ if ( iob_len ( iobuf ) < sizeof ( *report ) ) {
+ DBGC ( kbd, "KBD %s underlength report:\n", kbd->name );
+ DBGC_HDA ( kbd, 0, iobuf->data, iob_len ( iobuf ) );
+ goto drop;
+ }
+ report = iobuf->data;
+
+ /* Handle keyboard report */
+ usbkbd_report ( kbd, report );
+
+ drop:
+ /* Recycle I/O buffer */
+ usb_recycle ( &kbd->hid.in, iobuf );
+}
+
+/** Interrupt endpoint operations */
+static struct usb_endpoint_driver_operations usbkbd_operations = {
+ .complete = usbkbd_complete,
+};
+
+/******************************************************************************
+ *
+ * USB interface
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Probe device
+ *
+ * @v func USB function
+ * @v config Configuration descriptor
+ * @ret rc Return status code
+ */
+static int usbkbd_probe ( struct usb_function *func,
+ struct usb_configuration_descriptor *config ) {
+ struct usb_device *usb = func->usb;
+ struct usb_keyboard *kbd;
+ int rc;
+
+ /* Allocate and initialise structure */
+ kbd = zalloc ( sizeof ( *kbd ) );
+ if ( ! kbd ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ kbd->name = func->name;
+ kbd->bus = usb->port->hub->bus;
+ usbhid_init ( &kbd->hid, func, &usbkbd_operations, NULL );
+ usb_refill_init ( &kbd->hid.in, sizeof ( kbd->report ),
+ USBKBD_INTR_MAX_FILL );
+
+ /* Describe USB human interface device */
+ if ( ( rc = usbhid_describe ( &kbd->hid, config ) ) != 0 ) {
+ DBGC ( kbd, "KBD %s could not describe: %s\n",
+ kbd->name, strerror ( rc ) );
+ goto err_describe;
+ }
+ DBGC ( kbd, "KBD %s using %s (len %zd)\n",
+ kbd->name, usb_endpoint_name ( &kbd->hid.in ), kbd->hid.in.mtu );
+
+ /* Set boot protocol */
+ if ( ( rc = usbhid_set_protocol ( usb, func->interface[0],
+ USBHID_PROTOCOL_BOOT ) ) != 0 ) {
+ DBGC ( kbd, "KBD %s could not set boot protocol: %s\n",
+ kbd->name, strerror ( rc ) );
+ goto err_set_protocol;
+ }
+
+ /* Set idle time */
+ if ( ( rc = usbhid_set_idle ( usb, func->interface[0], 0,
+ USBKBD_IDLE_DURATION ) ) != 0 ) {
+ DBGC ( kbd, "KBD %s could not set idle time: %s\n",
+ kbd->name, strerror ( rc ) );
+ goto err_set_idle;
+ }
+
+ /* Open USB human interface device */
+ if ( ( rc = usbhid_open ( &kbd->hid ) ) != 0 ) {
+ DBGC ( kbd, "KBD %s could not open: %s\n",
+ kbd->name, strerror ( rc ) );
+ goto err_open;
+ }
+
+ /* Add to list of USB keyboards */
+ list_add_tail ( &kbd->list, &usb_keyboards );
+
+ usb_func_set_drvdata ( func, kbd );
+ return 0;
+
+ usbhid_close ( &kbd->hid );
+ err_open:
+ err_set_idle:
+ err_set_protocol:
+ err_describe:
+ free ( kbd );
+ err_alloc:
+ return rc;
+}
+
+/**
+ * Remove device
+ *
+ * @v func USB function
+ */
+static void usbkbd_remove ( struct usb_function *func ) {
+ struct usb_keyboard *kbd = usb_func_get_drvdata ( func );
+
+ /* Remove from list of USB keyboards */
+ list_del ( &kbd->list );
+
+ /* Close USB human interface device */
+ usbhid_close ( &kbd->hid );
+
+ /* Free device */
+ free ( kbd );
+}
+
+/** USB keyboard device IDs */
+static struct usb_device_id usbkbd_ids[] = {
+ {
+ .name = "kbd",
+ .vendor = USB_ANY_ID,
+ .product = USB_ANY_ID,
+ .class = {
+ .class = USB_CLASS_HID,
+ .subclass = USB_SUBCLASS_HID_BOOT,
+ .protocol = USBKBD_PROTOCOL,
+ },
+ },
+};
+
+/** USB keyboard driver */
+struct usb_driver usbkbd_driver __usb_driver = {
+ .ids = usbkbd_ids,
+ .id_count = ( sizeof ( usbkbd_ids ) / sizeof ( usbkbd_ids[0] ) ),
+ .probe = usbkbd_probe,
+ .remove = usbkbd_remove,
+};
+
+/******************************************************************************
+ *
+ * Console interface
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Read a character from the console
+ *
+ * @ret character Character read
+ */
+static int usbkbd_getchar ( void ) {
+ struct usb_keyboard *kbd;
+
+ /* Consume first available key */
+ list_for_each_entry ( kbd, &usb_keyboards, list ) {
+ if ( usbkbd_fill ( kbd ) )
+ return usbkbd_consume ( kbd );
+ }
+
+ return 0;
+}
+
+/**
+ * Check for available input
+ *
+ * @ret is_available Input is available
+ */
+static int usbkbd_iskey ( void ) {
+ struct usb_keyboard *kbd;
+ unsigned int fill;
+
+ /* Poll all USB keyboards and refill endpoints */
+ list_for_each_entry ( kbd, &usb_keyboards, list ) {
+ usb_poll ( kbd->bus );
+ usb_refill ( &kbd->hid.in );
+ }
+
+ /* Check for a non-empty keyboard buffer */
+ list_for_each_entry ( kbd, &usb_keyboards, list ) {
+ fill = usbkbd_fill ( kbd );
+ if ( fill )
+ return fill;
+ }
+
+ return 0;
+}
+
+/** USB keyboard console */
+struct console_driver usbkbd_console __console_driver = {
+ .getchar = usbkbd_getchar,
+ .iskey = usbkbd_iskey,
+};
diff --git a/roms/ipxe/src/drivers/usb/usbkbd.h b/roms/ipxe/src/drivers/usb/usbkbd.h
new file mode 100644
index 000000000..7eab24e46
--- /dev/null
+++ b/roms/ipxe/src/drivers/usb/usbkbd.h
@@ -0,0 +1,154 @@
+#ifndef _USBKBD_H
+#define _USBKBD_H
+
+/** @file
+ *
+ * USB keyboard driver
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <assert.h>
+#include <ipxe/usb.h>
+#include <ipxe/usbhid.h>
+
+/** Keyboard protocol */
+#define USBKBD_PROTOCOL 1
+
+/** A USB keyboard report */
+struct usb_keyboard_report {
+ /** Modifier keys */
+ uint8_t modifiers;
+ /** Reserved */
+ uint8_t reserved;
+ /** Keycodes */
+ uint8_t keycode[6];
+} __attribute__ (( packed ));
+
+/** USB modifier keys */
+enum usb_keyboard_modifier {
+ /** Left Ctrl key */
+ USBKBD_CTRL_LEFT = 0x01,
+ /** Left Shift key */
+ USBKBD_SHIFT_LEFT = 0x02,
+ /** Left Alt key */
+ USBKBD_ALT_LEFT = 0x04,
+ /** Left GUI key */
+ USBKBD_GUI_LEFT = 0x08,
+ /** Right Ctrl key */
+ USBKBD_CTRL_RIGHT = 0x10,
+ /** Right Shift key */
+ USBKBD_SHIFT_RIGHT = 0x20,
+ /** Right Alt key */
+ USBKBD_ALT_RIGHT = 0x40,
+ /** Right GUI key */
+ USBKBD_GUI_RIGHT = 0x80,
+};
+
+/** Either Ctrl key */
+#define USBKBD_CTRL ( USBKBD_CTRL_LEFT | USBKBD_CTRL_RIGHT )
+
+/** Either Shift key */
+#define USBKBD_SHIFT ( USBKBD_SHIFT_LEFT | USBKBD_SHIFT_RIGHT )
+
+/** Either Alt key */
+#define USBKBD_ALT ( USBKBD_ALT_LEFT | USBKBD_ALT_RIGHT )
+
+/** Either GUI key */
+#define USBKBD_GUI ( USBKBD_GUI_LEFT | USBKBD_GUI_RIGHT )
+
+/** USB keycodes */
+enum usb_keycode {
+ USBKBD_KEY_A = 0x04,
+ USBKBD_KEY_Z = 0x1d,
+ USBKBD_KEY_1 = 0x1e,
+ USBKBD_KEY_0 = 0x27,
+ USBKBD_KEY_ENTER = 0x28,
+ USBKBD_KEY_SPACE = 0x2c,
+ USBKBD_KEY_MINUS = 0x2d,
+ USBKBD_KEY_SLASH = 0x38,
+ USBKBD_KEY_CAPSLOCK = 0x39,
+ USBKBD_KEY_UP = 0x52,
+};
+
+/** Keyboard idle duration (in 4ms units)
+ *
+ * This is a policy decision. We choose to use an autorepeat rate of
+ * approximately 40ms.
+ */
+#define USBKBD_IDLE_DURATION 10 /* 10 x 4ms = 40ms */
+
+/** Keyboard auto-repeat hold-off (in units of USBKBD_IDLE_DURATION)
+ *
+ * This is a policy decision. We choose to use an autorepeat delay of
+ * approximately 500ms.
+ */
+#define USBKBD_HOLDOFF 12 /* 12 x 40ms = 480ms */
+
+/** Interrupt endpoint maximum fill level
+ *
+ * When idling, we are likely to poll the USB endpoint at only the
+ * 18.2Hz system timer tick rate. With a typical observed bInterval
+ * of 10ms (which will be rounded down to 8ms by the HCI drivers),
+ * this gives approximately 7 completions per poll.
+ */
+#define USBKBD_INTR_MAX_FILL 8
+
+/** Keyboard buffer size
+ *
+ * Must be a power of two.
+ */
+#define USBKBD_BUFSIZE 8
+
+/** A USB keyboard device */
+struct usb_keyboard {
+ /** Name */
+ const char *name;
+ /** List of all USB keyboards */
+ struct list_head list;
+
+ /** USB bus */
+ struct usb_bus *bus;
+ /** USB human interface device */
+ struct usb_hid hid;
+
+ /** Most recent keyboard report */
+ struct usb_keyboard_report report;
+ /** Most recently pressed non-modifier key (if any) */
+ unsigned int keycode;
+ /** Autorepeat hold-off time (in number of completions reported) */
+ unsigned int holdoff;
+
+ /** Keyboard buffer
+ *
+ * This stores iPXE key values.
+ */
+ unsigned int key[USBKBD_BUFSIZE];
+ /** Keyboard buffer producer counter */
+ unsigned int prod;
+ /** Keyboard buffer consumer counter */
+ unsigned int cons;
+ /** Keyboard buffer sub-consumer counter
+ *
+ * This represents the index within the ANSI escape sequence
+ * corresponding to an iPXE key value.
+ */
+ unsigned int subcons;
+};
+
+/**
+ * Calculate keyboard buffer fill level
+ *
+ * @v kbd USB keyboard
+ * @ret fill Keyboard buffer fill level
+ */
+static inline __attribute__ (( always_inline )) unsigned int
+usbkbd_fill ( struct usb_keyboard *kbd ) {
+ unsigned int fill = ( kbd->prod - kbd->cons );
+
+ assert ( fill <= USBKBD_BUFSIZE );
+ return fill;
+}
+
+#endif /* _USBKBD_H */
diff --git a/roms/ipxe/src/drivers/usb/usbnet.c b/roms/ipxe/src/drivers/usb/usbnet.c
new file mode 100644
index 000000000..b92336d05
--- /dev/null
+++ b/roms/ipxe/src/drivers/usb/usbnet.c
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2015 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <string.h>
+#include <errno.h>
+#include <ipxe/usb.h>
+#include <ipxe/usbnet.h>
+
+/** @file
+ *
+ * USB network devices
+ *
+ * USB network devices use a variety of packet formats and interface
+ * descriptors, but tend to have several features in common:
+ *
+ * - a single interrupt endpoint using the generic refill mechanism
+ *
+ * - a single bulk IN endpoint using the generic refill mechanism
+ *
+ * - a single bulk OUT endpoint
+ *
+ * - optional use of an alternate setting to enable the data interface
+ *
+ */
+
+/**
+ * Open USB network device
+ *
+ * @v usbnet USB network device
+ * @ret rc Return status code
+ */
+int usbnet_open ( struct usbnet_device *usbnet ) {
+ struct usb_device *usb = usbnet->func->usb;
+ int rc;
+
+ /* Open interrupt endpoint */
+ if ( ( rc = usb_endpoint_open ( &usbnet->intr ) ) != 0 ) {
+ DBGC ( usbnet, "USBNET %s could not open interrupt: %s\n",
+ usbnet->func->name, strerror ( rc ) );
+ goto err_open_intr;
+ }
+
+ /* Refill interrupt endpoint */
+ if ( ( rc = usb_refill ( &usbnet->intr ) ) != 0 ) {
+ DBGC ( usbnet, "USBNET %s could not refill interrupt: %s\n",
+ usbnet->func->name, strerror ( rc ) );
+ goto err_refill_intr;
+ }
+
+ /* Select alternate setting for data interface, if applicable */
+ if ( usbnet->alternate &&
+ ( ( rc = usb_set_interface ( usb, usbnet->data,
+ usbnet->alternate ) ) != 0 ) ) {
+ DBGC ( usbnet, "USBNET %s could not set alternate interface "
+ "%d: %s\n", usbnet->func->name, usbnet->alternate,
+ strerror ( rc ) );
+ goto err_set_interface;
+ }
+
+ /* Open bulk IN endpoint */
+ if ( ( rc = usb_endpoint_open ( &usbnet->in ) ) != 0 ) {
+ DBGC ( usbnet, "USBNET %s could not open bulk IN: %s\n",
+ usbnet->func->name, strerror ( rc ) );
+ goto err_open_in;
+ }
+
+ /* Open bulk OUT endpoint */
+ if ( ( rc = usb_endpoint_open ( &usbnet->out ) ) != 0 ) {
+ DBGC ( usbnet, "USBNET %s could not open bulk OUT: %s\n",
+ usbnet->func->name, strerror ( rc ) );
+ goto err_open_out;
+ }
+
+ /* Refill bulk IN endpoint */
+ if ( ( rc = usb_refill ( &usbnet->in ) ) != 0 ) {
+ DBGC ( usbnet, "USBNET %s could not refill bulk IN: %s\n",
+ usbnet->func->name, strerror ( rc ) );
+ goto err_refill_in;
+ }
+
+ return 0;
+
+ err_refill_in:
+ usb_endpoint_close ( &usbnet->out );
+ err_open_out:
+ usb_endpoint_close ( &usbnet->in );
+ err_open_in:
+ if ( usbnet->alternate )
+ usb_set_interface ( usb, usbnet->data, 0 );
+ err_set_interface:
+ err_refill_intr:
+ usb_endpoint_close ( &usbnet->intr );
+ err_open_intr:
+ return rc;
+}
+
+/**
+ * Close USB network device
+ *
+ * @v usbnet USB network device
+ */
+void usbnet_close ( struct usbnet_device *usbnet ) {
+ struct usb_device *usb = usbnet->func->usb;
+
+ /* Close bulk OUT endpoint */
+ usb_endpoint_close ( &usbnet->out );
+
+ /* Close bulk IN endpoint */
+ usb_endpoint_close ( &usbnet->in );
+
+ /* Reset alternate setting for data interface, if applicable */
+ if ( usbnet->alternate )
+ usb_set_interface ( usb, usbnet->data, 0 );
+
+ /* Close interrupt endpoint */
+ usb_endpoint_close ( &usbnet->intr );
+}
+
+/**
+ * Refill USB network device bulk IN and interrupt endpoints
+ *
+ * @v usbnet USB network device
+ * @ret rc Return status code
+ */
+int usbnet_refill ( struct usbnet_device *usbnet ) {
+ int rc;
+
+ /* Refill bulk IN endpoint */
+ if ( ( rc = usb_refill ( &usbnet->in ) ) != 0 )
+ return rc;
+
+ /* Refill interrupt endpoint */
+ if ( ( rc = usb_refill ( &usbnet->intr ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/**
+ * Describe communications interface and interrupt endpoint
+ *
+ * @v usbnet USB network device
+ * @v config Configuration descriptor
+ * @ret rc Return status code
+ */
+static int usbnet_comms_describe ( struct usbnet_device *usbnet,
+ struct usb_configuration_descriptor *config){
+ struct usb_interface_descriptor *desc;
+ unsigned int comms;
+ unsigned int i;
+ int rc;
+
+ /* Iterate over all available interfaces */
+ for ( i = 0 ; i < usbnet->func->count ; i++ ) {
+
+ /* Get interface number */
+ comms = usbnet->func->interface[i];
+
+ /* Locate interface descriptor */
+ desc = usb_interface_descriptor ( config, comms, 0 );
+ if ( ! desc )
+ continue;
+
+ /* Describe interrupt endpoint */
+ if ( ( rc = usb_endpoint_described ( &usbnet->intr, config,
+ desc, USB_INTERRUPT_IN,
+ 0 ) ) != 0 )
+ continue;
+
+ /* Record communications interface */
+ usbnet->comms = comms;
+ DBGC ( usbnet, "USBNET %s found communications interface %d\n",
+ usbnet->func->name, comms );
+ return 0;
+ }
+
+ DBGC ( usbnet, "USBNET %s found no communications interface\n",
+ usbnet->func->name );
+ return -ENOENT;
+}
+
+/**
+ * Describe data interface and bulk endpoints
+ *
+ * @v usbnet USB network device
+ * @v config Configuration descriptor
+ * @ret rc Return status code
+ */
+static int usbnet_data_describe ( struct usbnet_device *usbnet,
+ struct usb_configuration_descriptor *config ){
+ struct usb_interface_descriptor *desc;
+ unsigned int data;
+ unsigned int alt;
+ unsigned int i;
+ int rc;
+
+ /* Iterate over all available interfaces */
+ for ( i = 0 ; i < usbnet->func->count ; i++ ) {
+
+ /* Get interface number */
+ data = usbnet->func->interface[i];
+
+ /* Iterate over all existent alternate settings */
+ for ( alt = 0 ; ; alt++ ) {
+
+ /* Locate interface descriptor */
+ desc = usb_interface_descriptor ( config, data, alt );
+ if ( ! desc )
+ break;
+
+ /* Describe bulk IN endpoint */
+ if ( ( rc = usb_endpoint_described ( &usbnet->in,
+ config, desc,
+ USB_BULK_IN,
+ 0 ) ) != 0 )
+ continue;
+
+ /* Describe bulk OUT endpoint */
+ if ( ( rc = usb_endpoint_described ( &usbnet->out,
+ config, desc,
+ USB_BULK_OUT,
+ 0 ) ) != 0 )
+ continue;
+
+ /* Record data interface and alternate setting */
+ usbnet->data = data;
+ usbnet->alternate = alt;
+ DBGC ( usbnet, "USBNET %s found data interface %d",
+ usbnet->func->name, data );
+ if ( alt )
+ DBGC ( usbnet, " using alternate %d", alt );
+ DBGC ( usbnet, "\n" );
+ return 0;
+ }
+ }
+
+ DBGC ( usbnet, "USBNET %s found no data interface\n",
+ usbnet->func->name );
+ return -ENOENT;
+}
+
+/**
+ * Describe USB network device interfaces
+ *
+ * @v usbnet USB network device
+ * @v config Configuration descriptor
+ * @ret rc Return status code
+ */
+int usbnet_describe ( struct usbnet_device *usbnet,
+ struct usb_configuration_descriptor *config ) {
+ int rc;
+
+ /* Describe communications interface */
+ if ( ( rc = usbnet_comms_describe ( usbnet, config ) ) != 0 )
+ return rc;
+
+ /* Describe data interface */
+ if ( ( rc = usbnet_data_describe ( usbnet, config ) ) != 0 )
+ return rc;
+
+ return 0;
+}
diff --git a/roms/ipxe/src/drivers/usb/xhci.c b/roms/ipxe/src/drivers/usb/xhci.c
new file mode 100644
index 000000000..49e67316b
--- /dev/null
+++ b/roms/ipxe/src/drivers/usb/xhci.c
@@ -0,0 +1,3321 @@
+/*
+ * Copyright (C) 2014 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/malloc.h>
+#include <ipxe/umalloc.h>
+#include <ipxe/pci.h>
+#include <ipxe/usb.h>
+#include <ipxe/init.h>
+#include <ipxe/profile.h>
+#include "xhci.h"
+
+/** @file
+ *
+ * USB eXtensible Host Controller Interface (xHCI) driver
+ *
+ */
+
+/** Message transfer profiler */
+static struct profiler xhci_message_profiler __profiler =
+ { .name = "xhci.message" };
+
+/** Stream transfer profiler */
+static struct profiler xhci_stream_profiler __profiler =
+ { .name = "xhci.stream" };
+
+/** Event ring profiler */
+static struct profiler xhci_event_profiler __profiler =
+ { .name = "xhci.event" };
+
+/** Transfer event profiler */
+static struct profiler xhci_transfer_profiler __profiler =
+ { .name = "xhci.transfer" };
+
+/* Disambiguate the various error causes */
+#define EIO_DATA \
+ __einfo_error ( EINFO_EIO_DATA )
+#define EINFO_EIO_DATA \
+ __einfo_uniqify ( EINFO_EIO, ( 2 - 0 ), \
+ "Data buffer error" )
+#define EIO_BABBLE \
+ __einfo_error ( EINFO_EIO_BABBLE )
+#define EINFO_EIO_BABBLE \
+ __einfo_uniqify ( EINFO_EIO, ( 3 - 0 ), \
+ "Babble detected" )
+#define EIO_USB \
+ __einfo_error ( EINFO_EIO_USB )
+#define EINFO_EIO_USB \
+ __einfo_uniqify ( EINFO_EIO, ( 4 - 0 ), \
+ "USB transaction error" )
+#define EIO_TRB \
+ __einfo_error ( EINFO_EIO_TRB )
+#define EINFO_EIO_TRB \
+ __einfo_uniqify ( EINFO_EIO, ( 5 - 0 ), \
+ "TRB error" )
+#define EIO_STALL \
+ __einfo_error ( EINFO_EIO_STALL )
+#define EINFO_EIO_STALL \
+ __einfo_uniqify ( EINFO_EIO, ( 6 - 0 ), \
+ "Stall error" )
+#define EIO_RESOURCE \
+ __einfo_error ( EINFO_EIO_RESOURCE )
+#define EINFO_EIO_RESOURCE \
+ __einfo_uniqify ( EINFO_EIO, ( 7 - 0 ), \
+ "Resource error" )
+#define EIO_BANDWIDTH \
+ __einfo_error ( EINFO_EIO_BANDWIDTH )
+#define EINFO_EIO_BANDWIDTH \
+ __einfo_uniqify ( EINFO_EIO, ( 8 - 0 ), \
+ "Bandwidth error" )
+#define EIO_NO_SLOTS \
+ __einfo_error ( EINFO_EIO_NO_SLOTS )
+#define EINFO_EIO_NO_SLOTS \
+ __einfo_uniqify ( EINFO_EIO, ( 9 - 0 ), \
+ "No slots available" )
+#define EIO_STREAM_TYPE \
+ __einfo_error ( EINFO_EIO_STREAM_TYPE )
+#define EINFO_EIO_STREAM_TYPE \
+ __einfo_uniqify ( EINFO_EIO, ( 10 - 0 ), \
+ "Invalid stream type" )
+#define EIO_SLOT \
+ __einfo_error ( EINFO_EIO_SLOT )
+#define EINFO_EIO_SLOT \
+ __einfo_uniqify ( EINFO_EIO, ( 11 - 0 ), \
+ "Slot not enabled" )
+#define EIO_ENDPOINT \
+ __einfo_error ( EINFO_EIO_ENDPOINT )
+#define EINFO_EIO_ENDPOINT \
+ __einfo_uniqify ( EINFO_EIO, ( 12 - 0 ), \
+ "Endpoint not enabled" )
+#define EIO_SHORT \
+ __einfo_error ( EINFO_EIO_SHORT )
+#define EINFO_EIO_SHORT \
+ __einfo_uniqify ( EINFO_EIO, ( 13 - 0 ), \
+ "Short packet" )
+#define EIO_UNDERRUN \
+ __einfo_error ( EINFO_EIO_UNDERRUN )
+#define EINFO_EIO_UNDERRUN \
+ __einfo_uniqify ( EINFO_EIO, ( 14 - 0 ), \
+ "Ring underrun" )
+#define EIO_OVERRUN \
+ __einfo_error ( EINFO_EIO_OVERRUN )
+#define EINFO_EIO_OVERRUN \
+ __einfo_uniqify ( EINFO_EIO, ( 15 - 0 ), \
+ "Ring overrun" )
+#define EIO_VF_RING_FULL \
+ __einfo_error ( EINFO_EIO_VF_RING_FULL )
+#define EINFO_EIO_VF_RING_FULL \
+ __einfo_uniqify ( EINFO_EIO, ( 16 - 0 ), \
+ "Virtual function event ring full" )
+#define EIO_PARAMETER \
+ __einfo_error ( EINFO_EIO_PARAMETER )
+#define EINFO_EIO_PARAMETER \
+ __einfo_uniqify ( EINFO_EIO, ( 17 - 0 ), \
+ "Parameter error" )
+#define EIO_BANDWIDTH_OVERRUN \
+ __einfo_error ( EINFO_EIO_BANDWIDTH_OVERRUN )
+#define EINFO_EIO_BANDWIDTH_OVERRUN \
+ __einfo_uniqify ( EINFO_EIO, ( 18 - 0 ), \
+ "Bandwidth overrun" )
+#define EIO_CONTEXT \
+ __einfo_error ( EINFO_EIO_CONTEXT )
+#define EINFO_EIO_CONTEXT \
+ __einfo_uniqify ( EINFO_EIO, ( 19 - 0 ), \
+ "Context state error" )
+#define EIO_NO_PING \
+ __einfo_error ( EINFO_EIO_NO_PING )
+#define EINFO_EIO_NO_PING \
+ __einfo_uniqify ( EINFO_EIO, ( 20 - 0 ), \
+ "No ping response" )
+#define EIO_RING_FULL \
+ __einfo_error ( EINFO_EIO_RING_FULL )
+#define EINFO_EIO_RING_FULL \
+ __einfo_uniqify ( EINFO_EIO, ( 21 - 0 ), \
+ "Event ring full" )
+#define EIO_INCOMPATIBLE \
+ __einfo_error ( EINFO_EIO_INCOMPATIBLE )
+#define EINFO_EIO_INCOMPATIBLE \
+ __einfo_uniqify ( EINFO_EIO, ( 22 - 0 ), \
+ "Incompatible device" )
+#define EIO_MISSED \
+ __einfo_error ( EINFO_EIO_MISSED )
+#define EINFO_EIO_MISSED \
+ __einfo_uniqify ( EINFO_EIO, ( 23 - 0 ), \
+ "Missed service error" )
+#define EIO_CMD_STOPPED \
+ __einfo_error ( EINFO_EIO_CMD_STOPPED )
+#define EINFO_EIO_CMD_STOPPED \
+ __einfo_uniqify ( EINFO_EIO, ( 24 - 0 ), \
+ "Command ring stopped" )
+#define EIO_CMD_ABORTED \
+ __einfo_error ( EINFO_EIO_CMD_ABORTED )
+#define EINFO_EIO_CMD_ABORTED \
+ __einfo_uniqify ( EINFO_EIO, ( 25 - 0 ), \
+ "Command aborted" )
+#define EIO_STOP \
+ __einfo_error ( EINFO_EIO_STOP )
+#define EINFO_EIO_STOP \
+ __einfo_uniqify ( EINFO_EIO, ( 26 - 0 ), \
+ "Stopped" )
+#define EIO_STOP_LEN \
+ __einfo_error ( EINFO_EIO_STOP_LEN )
+#define EINFO_EIO_STOP_LEN \
+ __einfo_uniqify ( EINFO_EIO, ( 27 - 0 ), \
+ "Stopped - length invalid" )
+#define EIO_STOP_SHORT \
+ __einfo_error ( EINFO_EIO_STOP_SHORT )
+#define EINFO_EIO_STOP_SHORT \
+ __einfo_uniqify ( EINFO_EIO, ( 28 - 0 ), \
+ "Stopped - short packet" )
+#define EIO_LATENCY \
+ __einfo_error ( EINFO_EIO_LATENCY )
+#define EINFO_EIO_LATENCY \
+ __einfo_uniqify ( EINFO_EIO, ( 29 - 0 ), \
+ "Maximum exit latency too large" )
+#define EIO_ISOCH \
+ __einfo_error ( EINFO_EIO_ISOCH )
+#define EINFO_EIO_ISOCH \
+ __einfo_uniqify ( EINFO_EIO, ( 31 - 0 ), \
+ "Isochronous buffer overrun" )
+#define EPROTO_LOST \
+ __einfo_error ( EINFO_EPROTO_LOST )
+#define EINFO_EPROTO_LOST \
+ __einfo_uniqify ( EINFO_EPROTO, ( 32 - 32 ), \
+ "Event lost" )
+#define EPROTO_UNDEFINED \
+ __einfo_error ( EINFO_EPROTO_UNDEFINED )
+#define EINFO_EPROTO_UNDEFINED \
+ __einfo_uniqify ( EINFO_EPROTO, ( 33 - 32 ), \
+ "Undefined error" )
+#define EPROTO_STREAM_ID \
+ __einfo_error ( EINFO_EPROTO_STREAM_ID )
+#define EINFO_EPROTO_STREAM_ID \
+ __einfo_uniqify ( EINFO_EPROTO, ( 34 - 32 ), \
+ "Invalid stream ID" )
+#define EPROTO_SECONDARY \
+ __einfo_error ( EINFO_EPROTO_SECONDARY )
+#define EINFO_EPROTO_SECONDARY \
+ __einfo_uniqify ( EINFO_EPROTO, ( 35 - 32 ), \
+ "Secondary bandwidth error" )
+#define EPROTO_SPLIT \
+ __einfo_error ( EINFO_EPROTO_SPLIT )
+#define EINFO_EPROTO_SPLIT \
+ __einfo_uniqify ( EINFO_EPROTO, ( 36 - 32 ), \
+ "Split transaction error" )
+#define ECODE(code) \
+ ( ( (code) < 32 ) ? \
+ EUNIQ ( EINFO_EIO, ( (code) & 31 ), EIO_DATA, EIO_BABBLE, \
+ EIO_USB, EIO_TRB, EIO_STALL, EIO_RESOURCE, \
+ EIO_BANDWIDTH, EIO_NO_SLOTS, EIO_STREAM_TYPE, \
+ EIO_SLOT, EIO_ENDPOINT, EIO_SHORT, EIO_UNDERRUN, \
+ EIO_OVERRUN, EIO_VF_RING_FULL, EIO_PARAMETER, \
+ EIO_BANDWIDTH_OVERRUN, EIO_CONTEXT, EIO_NO_PING, \
+ EIO_RING_FULL, EIO_INCOMPATIBLE, EIO_MISSED, \
+ EIO_CMD_STOPPED, EIO_CMD_ABORTED, EIO_STOP, \
+ EIO_STOP_LEN, EIO_STOP_SHORT, EIO_LATENCY, \
+ EIO_ISOCH ) : \
+ ( (code) < 64 ) ? \
+ EUNIQ ( EINFO_EPROTO, ( (code) & 31 ), EPROTO_LOST, \
+ EPROTO_UNDEFINED, EPROTO_STREAM_ID, \
+ EPROTO_SECONDARY, EPROTO_SPLIT ) : \
+ EFAULT )
+
+/******************************************************************************
+ *
+ * Register access
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Initialise device
+ *
+ * @v xhci xHCI device
+ * @v regs MMIO registers
+ */
+static void xhci_init ( struct xhci_device *xhci, void *regs ) {
+ uint32_t hcsparams1;
+ uint32_t hcsparams2;
+ uint32_t hccparams1;
+ uint32_t pagesize;
+ size_t caplength;
+ size_t rtsoff;
+ size_t dboff;
+
+ /* Locate capability, operational, runtime, and doorbell registers */
+ xhci->cap = regs;
+ caplength = readb ( xhci->cap + XHCI_CAP_CAPLENGTH );
+ rtsoff = readl ( xhci->cap + XHCI_CAP_RTSOFF );
+ dboff = readl ( xhci->cap + XHCI_CAP_DBOFF );
+ xhci->op = ( xhci->cap + caplength );
+ xhci->run = ( xhci->cap + rtsoff );
+ xhci->db = ( xhci->cap + dboff );
+ DBGC2 ( xhci, "XHCI %s cap %08lx op %08lx run %08lx db %08lx\n",
+ xhci->name, virt_to_phys ( xhci->cap ),
+ virt_to_phys ( xhci->op ), virt_to_phys ( xhci->run ),
+ virt_to_phys ( xhci->db ) );
+
+ /* Read structural parameters 1 */
+ hcsparams1 = readl ( xhci->cap + XHCI_CAP_HCSPARAMS1 );
+ xhci->slots = XHCI_HCSPARAMS1_SLOTS ( hcsparams1 );
+ xhci->intrs = XHCI_HCSPARAMS1_INTRS ( hcsparams1 );
+ xhci->ports = XHCI_HCSPARAMS1_PORTS ( hcsparams1 );
+ DBGC ( xhci, "XHCI %s has %d slots %d intrs %d ports\n",
+ xhci->name, xhci->slots, xhci->intrs, xhci->ports );
+
+ /* Read structural parameters 2 */
+ hcsparams2 = readl ( xhci->cap + XHCI_CAP_HCSPARAMS2 );
+ xhci->scratchpads = XHCI_HCSPARAMS2_SCRATCHPADS ( hcsparams2 );
+ DBGC2 ( xhci, "XHCI %s needs %d scratchpads\n",
+ xhci->name, xhci->scratchpads );
+
+ /* Read capability parameters 1 */
+ hccparams1 = readl ( xhci->cap + XHCI_CAP_HCCPARAMS1 );
+ xhci->addr64 = XHCI_HCCPARAMS1_ADDR64 ( hccparams1 );
+ xhci->csz_shift = XHCI_HCCPARAMS1_CSZ_SHIFT ( hccparams1 );
+ xhci->xecp = XHCI_HCCPARAMS1_XECP ( hccparams1 );
+
+ /* Read page size */
+ pagesize = readl ( xhci->op + XHCI_OP_PAGESIZE );
+ xhci->pagesize = XHCI_PAGESIZE ( pagesize );
+ assert ( xhci->pagesize != 0 );
+ assert ( ( ( xhci->pagesize ) & ( xhci->pagesize - 1 ) ) == 0 );
+ DBGC2 ( xhci, "XHCI %s page size %zd bytes\n",
+ xhci->name, xhci->pagesize );
+}
+
+/**
+ * Find extended capability
+ *
+ * @v xhci xHCI device
+ * @v id Capability ID
+ * @v offset Offset to previous extended capability instance, or zero
+ * @ret offset Offset to extended capability, or zero if not found
+ */
+static unsigned int xhci_extended_capability ( struct xhci_device *xhci,
+ unsigned int id,
+ unsigned int offset ) {
+ uint32_t xecp;
+ unsigned int next;
+
+ /* Locate the extended capability */
+ while ( 1 ) {
+
+ /* Locate first or next capability as applicable */
+ if ( offset ) {
+ xecp = readl ( xhci->cap + offset );
+ next = XHCI_XECP_NEXT ( xecp );
+ } else {
+ next = xhci->xecp;
+ }
+ if ( ! next )
+ return 0;
+ offset += next;
+
+ /* Check if this is the requested capability */
+ xecp = readl ( xhci->cap + offset );
+ if ( XHCI_XECP_ID ( xecp ) == id )
+ return offset;
+ }
+}
+
+/**
+ * Write potentially 64-bit register
+ *
+ * @v xhci xHCI device
+ * @v value Value
+ * @v reg Register address
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+xhci_writeq ( struct xhci_device *xhci, physaddr_t value, void *reg ) {
+
+ /* If this is a 32-bit build, then this can never fail
+ * (allowing the compiler to optimise out the error path).
+ */
+ if ( sizeof ( value ) <= sizeof ( uint32_t ) ) {
+ writel ( value, reg );
+ writel ( 0, ( reg + sizeof ( uint32_t ) ) );
+ return 0;
+ }
+
+ /* If the device does not support 64-bit addresses and this
+ * address is outside the 32-bit address space, then fail.
+ */
+ if ( ( value & ~0xffffffffULL ) && ! xhci->addr64 ) {
+ DBGC ( xhci, "XHCI %s cannot access address %lx\n",
+ xhci->name, value );
+ return -ENOTSUP;
+ }
+
+ /* If this is a 64-bit build, then writeq() is available */
+ writeq ( value, reg );
+ return 0;
+}
+
+/**
+ * Calculate buffer alignment
+ *
+ * @v len Length
+ * @ret align Buffer alignment
+ *
+ * Determine alignment required for a buffer which must be aligned to
+ * at least XHCI_MIN_ALIGN and which must not cross a page boundary.
+ */
+static inline size_t xhci_align ( size_t len ) {
+ size_t align;
+
+ /* Align to own length (rounded up to a power of two) */
+ align = ( 1 << fls ( len - 1 ) );
+
+ /* Round up to XHCI_MIN_ALIGN if needed */
+ if ( align < XHCI_MIN_ALIGN )
+ align = XHCI_MIN_ALIGN;
+
+ return align;
+}
+
+/**
+ * Calculate device context offset
+ *
+ * @v xhci xHCI device
+ * @v ctx Context index
+ */
+static inline size_t xhci_device_context_offset ( struct xhci_device *xhci,
+ unsigned int ctx ) {
+
+ return ( XHCI_DCI ( ctx ) << xhci->csz_shift );
+}
+
+/**
+ * Calculate input context offset
+ *
+ * @v xhci xHCI device
+ * @v ctx Context index
+ */
+static inline size_t xhci_input_context_offset ( struct xhci_device *xhci,
+ unsigned int ctx ) {
+
+ return ( XHCI_ICI ( ctx ) << xhci->csz_shift );
+}
+
+/******************************************************************************
+ *
+ * Diagnostics
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Dump host controller registers
+ *
+ * @v xhci xHCI device
+ */
+static inline void xhci_dump ( struct xhci_device *xhci ) {
+ uint32_t usbcmd;
+ uint32_t usbsts;
+ uint32_t pagesize;
+ uint32_t dnctrl;
+ uint32_t config;
+
+ /* Do nothing unless debugging is enabled */
+ if ( ! DBG_LOG )
+ return;
+
+ /* Dump USBCMD */
+ usbcmd = readl ( xhci->op + XHCI_OP_USBCMD );
+ DBGC ( xhci, "XHCI %s USBCMD %08x%s%s\n", xhci->name, usbcmd,
+ ( ( usbcmd & XHCI_USBCMD_RUN ) ? " run" : "" ),
+ ( ( usbcmd & XHCI_USBCMD_HCRST ) ? " hcrst" : "" ) );
+
+ /* Dump USBSTS */
+ usbsts = readl ( xhci->op + XHCI_OP_USBSTS );
+ DBGC ( xhci, "XHCI %s USBSTS %08x%s\n", xhci->name, usbsts,
+ ( ( usbsts & XHCI_USBSTS_HCH ) ? " hch" : "" ) );
+
+ /* Dump PAGESIZE */
+ pagesize = readl ( xhci->op + XHCI_OP_PAGESIZE );
+ DBGC ( xhci, "XHCI %s PAGESIZE %08x\n", xhci->name, pagesize );
+
+ /* Dump DNCTRL */
+ dnctrl = readl ( xhci->op + XHCI_OP_DNCTRL );
+ DBGC ( xhci, "XHCI %s DNCTRL %08x\n", xhci->name, dnctrl );
+
+ /* Dump CONFIG */
+ config = readl ( xhci->op + XHCI_OP_CONFIG );
+ DBGC ( xhci, "XHCI %s CONFIG %08x\n", xhci->name, config );
+}
+
+/**
+ * Dump port registers
+ *
+ * @v xhci xHCI device
+ * @v port Port number
+ */
+static inline void xhci_dump_port ( struct xhci_device *xhci,
+ unsigned int port ) {
+ uint32_t portsc;
+ uint32_t portpmsc;
+ uint32_t portli;
+ uint32_t porthlpmc;
+
+ /* Do nothing unless debugging is enabled */
+ if ( ! DBG_LOG )
+ return;
+
+ /* Dump PORTSC */
+ portsc = readl ( xhci->op + XHCI_OP_PORTSC ( port ) );
+ DBGC ( xhci, "XHCI %s-%d PORTSC %08x%s%s%s%s psiv=%d\n",
+ xhci->name, port, portsc,
+ ( ( portsc & XHCI_PORTSC_CCS ) ? " ccs" : "" ),
+ ( ( portsc & XHCI_PORTSC_PED ) ? " ped" : "" ),
+ ( ( portsc & XHCI_PORTSC_PR ) ? " pr" : "" ),
+ ( ( portsc & XHCI_PORTSC_PP ) ? " pp" : "" ),
+ XHCI_PORTSC_PSIV ( portsc ) );
+
+ /* Dump PORTPMSC */
+ portpmsc = readl ( xhci->op + XHCI_OP_PORTPMSC ( port ) );
+ DBGC ( xhci, "XHCI %s-%d PORTPMSC %08x\n", xhci->name, port, portpmsc );
+
+ /* Dump PORTLI */
+ portli = readl ( xhci->op + XHCI_OP_PORTLI ( port ) );
+ DBGC ( xhci, "XHCI %s-%d PORTLI %08x\n", xhci->name, port, portli );
+
+ /* Dump PORTHLPMC */
+ porthlpmc = readl ( xhci->op + XHCI_OP_PORTHLPMC ( port ) );
+ DBGC ( xhci, "XHCI %s-%d PORTHLPMC %08x\n",
+ xhci->name, port, porthlpmc );
+}
+
+/******************************************************************************
+ *
+ * USB legacy support
+ *
+ ******************************************************************************
+ */
+
+/** Prevent the release of ownership back to BIOS */
+static int xhci_legacy_prevent_release;
+
+/**
+ * Initialise USB legacy support
+ *
+ * @v xhci xHCI device
+ */
+static void xhci_legacy_init ( struct xhci_device *xhci ) {
+ unsigned int legacy;
+ uint8_t bios;
+
+ /* Locate USB legacy support capability (if present) */
+ legacy = xhci_extended_capability ( xhci, XHCI_XECP_ID_LEGACY, 0 );
+ if ( ! legacy ) {
+ /* Not an error; capability may not be present */
+ DBGC ( xhci, "XHCI %s has no USB legacy support capability\n",
+ xhci->name );
+ return;
+ }
+
+ /* Check if legacy USB support is enabled */
+ bios = readb ( xhci->cap + legacy + XHCI_USBLEGSUP_BIOS );
+ if ( ! ( bios & XHCI_USBLEGSUP_BIOS_OWNED ) ) {
+ /* Not an error; already owned by OS */
+ DBGC ( xhci, "XHCI %s USB legacy support already disabled\n",
+ xhci->name );
+ return;
+ }
+
+ /* Record presence of USB legacy support capability */
+ xhci->legacy = legacy;
+}
+
+/**
+ * Claim ownership from BIOS
+ *
+ * @v xhci xHCI device
+ */
+static void xhci_legacy_claim ( struct xhci_device *xhci ) {
+ uint32_t ctlsts;
+ uint8_t bios;
+ unsigned int i;
+
+ /* Do nothing unless legacy support capability is present */
+ if ( ! xhci->legacy )
+ return;
+
+ /* Claim ownership */
+ writeb ( XHCI_USBLEGSUP_OS_OWNED,
+ xhci->cap + xhci->legacy + XHCI_USBLEGSUP_OS );
+
+ /* Wait for BIOS to release ownership */
+ for ( i = 0 ; i < XHCI_USBLEGSUP_MAX_WAIT_MS ; i++ ) {
+
+ /* Check if BIOS has released ownership */
+ bios = readb ( xhci->cap + xhci->legacy + XHCI_USBLEGSUP_BIOS );
+ if ( ! ( bios & XHCI_USBLEGSUP_BIOS_OWNED ) ) {
+ DBGC ( xhci, "XHCI %s claimed ownership from BIOS\n",
+ xhci->name );
+ ctlsts = readl ( xhci->cap + xhci->legacy +
+ XHCI_USBLEGSUP_CTLSTS );
+ if ( ctlsts ) {
+ DBGC ( xhci, "XHCI %s warning: BIOS retained "
+ "SMIs: %08x\n", xhci->name, ctlsts );
+ }
+ return;
+ }
+
+ /* Delay */
+ mdelay ( 1 );
+ }
+
+ /* BIOS did not release ownership. Claim it forcibly by
+ * disabling all SMIs.
+ */
+ DBGC ( xhci, "XHCI %s could not claim ownership from BIOS: forcibly "
+ "disabling SMIs\n", xhci->name );
+ writel ( 0, xhci->cap + xhci->legacy + XHCI_USBLEGSUP_CTLSTS );
+}
+
+/**
+ * Release ownership back to BIOS
+ *
+ * @v xhci xHCI device
+ */
+static void xhci_legacy_release ( struct xhci_device *xhci ) {
+
+ /* Do nothing unless legacy support capability is present */
+ if ( ! xhci->legacy )
+ return;
+
+ /* Do nothing if releasing ownership is prevented */
+ if ( xhci_legacy_prevent_release ) {
+ DBGC ( xhci, "XHCI %s not releasing ownership to BIOS\n",
+ xhci->name );
+ return;
+ }
+
+ /* Release ownership */
+ writeb ( 0, xhci->cap + xhci->legacy + XHCI_USBLEGSUP_OS );
+ DBGC ( xhci, "XHCI %s released ownership to BIOS\n", xhci->name );
+}
+
+/******************************************************************************
+ *
+ * Supported protocols
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Transcribe port speed (for debugging)
+ *
+ * @v psi Protocol speed ID
+ * @ret speed Transcribed speed
+ */
+static inline const char * xhci_speed_name ( uint32_t psi ) {
+ static const char *exponents[4] = { "", "k", "M", "G" };
+ static char buf[ 10 /* "xxxxxXbps" + NUL */ ];
+ unsigned int mantissa;
+ unsigned int exponent;
+
+ /* Extract mantissa and exponent */
+ mantissa = XHCI_SUPPORTED_PSI_MANTISSA ( psi );
+ exponent = XHCI_SUPPORTED_PSI_EXPONENT ( psi );
+
+ /* Transcribe speed */
+ snprintf ( buf, sizeof ( buf ), "%d%sbps",
+ mantissa, exponents[exponent] );
+ return buf;
+}
+
+/**
+ * Find supported protocol extended capability for a port
+ *
+ * @v xhci xHCI device
+ * @v port Port number
+ * @ret supported Offset to extended capability, or zero if not found
+ */
+static unsigned int xhci_supported_protocol ( struct xhci_device *xhci,
+ unsigned int port ) {
+ unsigned int supported = 0;
+ unsigned int offset;
+ unsigned int count;
+ uint32_t ports;
+
+ /* Iterate over all supported protocol structures */
+ while ( ( supported = xhci_extended_capability ( xhci,
+ XHCI_XECP_ID_SUPPORTED,
+ supported ) ) ) {
+
+ /* Determine port range */
+ ports = readl ( xhci->cap + supported + XHCI_SUPPORTED_PORTS );
+ offset = XHCI_SUPPORTED_PORTS_OFFSET ( ports );
+ count = XHCI_SUPPORTED_PORTS_COUNT ( ports );
+
+ /* Check if port lies within this range */
+ if ( ( port - offset ) < count )
+ return supported;
+ }
+
+ DBGC ( xhci, "XHCI %s-%d has no supported protocol\n",
+ xhci->name, port );
+ return 0;
+}
+
+/**
+ * Find port protocol
+ *
+ * @v xhci xHCI device
+ * @v port Port number
+ * @ret protocol USB protocol, or zero if not found
+ */
+static unsigned int xhci_port_protocol ( struct xhci_device *xhci,
+ unsigned int port ) {
+ unsigned int supported = xhci_supported_protocol ( xhci, port );
+ union {
+ uint32_t raw;
+ char text[5];
+ } name;
+ unsigned int protocol;
+ unsigned int type;
+ unsigned int psic;
+ unsigned int psiv;
+ unsigned int i;
+ uint32_t revision;
+ uint32_t ports;
+ uint32_t slot;
+ uint32_t psi;
+
+ /* Fail if there is no supported protocol */
+ if ( ! supported )
+ return 0;
+
+ /* Determine protocol version */
+ revision = readl ( xhci->cap + supported + XHCI_SUPPORTED_REVISION );
+ protocol = XHCI_SUPPORTED_REVISION_VER ( revision );
+
+ /* Describe port protocol */
+ if ( DBG_EXTRA ) {
+ name.raw = cpu_to_le32 ( readl ( xhci->cap + supported +
+ XHCI_SUPPORTED_NAME ) );
+ name.text[4] = '\0';
+ slot = readl ( xhci->cap + supported + XHCI_SUPPORTED_SLOT );
+ type = XHCI_SUPPORTED_SLOT_TYPE ( slot );
+ DBGC2 ( xhci, "XHCI %s-%d %sv%04x type %d",
+ xhci->name, port, name.text, protocol, type );
+ ports = readl ( xhci->cap + supported + XHCI_SUPPORTED_PORTS );
+ psic = XHCI_SUPPORTED_PORTS_PSIC ( ports );
+ if ( psic ) {
+ DBGC2 ( xhci, " speeds" );
+ for ( i = 0 ; i < psic ; i++ ) {
+ psi = readl ( xhci->cap + supported +
+ XHCI_SUPPORTED_PSI ( i ) );
+ psiv = XHCI_SUPPORTED_PSI_VALUE ( psi );
+ DBGC2 ( xhci, " %d:%s", psiv,
+ xhci_speed_name ( psi ) );
+ }
+ }
+ if ( xhci->quirks & XHCI_BAD_PSIV )
+ DBGC2 ( xhci, " (ignored)" );
+ DBGC2 ( xhci, "\n" );
+ }
+
+ return protocol;
+}
+
+/**
+ * Find port slot type
+ *
+ * @v xhci xHCI device
+ * @v port Port number
+ * @ret type Slot type, or negative error
+ */
+static int xhci_port_slot_type ( struct xhci_device *xhci, unsigned int port ) {
+ unsigned int supported = xhci_supported_protocol ( xhci, port );
+ unsigned int type;
+ uint32_t slot;
+
+ /* Fail if there is no supported protocol */
+ if ( ! supported )
+ return -ENOTSUP;
+
+ /* Get slot type */
+ slot = readl ( xhci->cap + supported + XHCI_SUPPORTED_SLOT );
+ type = XHCI_SUPPORTED_SLOT_TYPE ( slot );
+
+ return type;
+}
+
+/**
+ * Find port speed
+ *
+ * @v xhci xHCI device
+ * @v port Port number
+ * @v psiv Protocol speed ID value
+ * @ret speed Port speed, or negative error
+ */
+static int xhci_port_speed ( struct xhci_device *xhci, unsigned int port,
+ unsigned int psiv ) {
+ unsigned int supported = xhci_supported_protocol ( xhci, port );
+ unsigned int psic;
+ unsigned int mantissa;
+ unsigned int exponent;
+ unsigned int speed;
+ unsigned int i;
+ uint32_t ports;
+ uint32_t psi;
+
+ /* Fail if there is no supported protocol */
+ if ( ! supported )
+ return -ENOTSUP;
+
+ /* Get protocol speed ID count */
+ ports = readl ( xhci->cap + supported + XHCI_SUPPORTED_PORTS );
+ psic = XHCI_SUPPORTED_PORTS_PSIC ( ports );
+
+ /* Use the default mappings if applicable */
+ if ( ( psic == 0 ) || ( xhci->quirks & XHCI_BAD_PSIV ) ) {
+ switch ( psiv ) {
+ case XHCI_SPEED_LOW : return USB_SPEED_LOW;
+ case XHCI_SPEED_FULL : return USB_SPEED_FULL;
+ case XHCI_SPEED_HIGH : return USB_SPEED_HIGH;
+ case XHCI_SPEED_SUPER : return USB_SPEED_SUPER;
+ default:
+ DBGC ( xhci, "XHCI %s-%d non-standard PSI value %d\n",
+ xhci->name, port, psiv );
+ return -ENOTSUP;
+ }
+ }
+
+ /* Iterate over PSI dwords looking for a match */
+ for ( i = 0 ; i < psic ; i++ ) {
+ psi = readl ( xhci->cap + supported + XHCI_SUPPORTED_PSI ( i ));
+ if ( psiv == XHCI_SUPPORTED_PSI_VALUE ( psi ) ) {
+ mantissa = XHCI_SUPPORTED_PSI_MANTISSA ( psi );
+ exponent = XHCI_SUPPORTED_PSI_EXPONENT ( psi );
+ speed = USB_SPEED ( mantissa, exponent );
+ return speed;
+ }
+ }
+
+ DBGC ( xhci, "XHCI %s-%d spurious PSI value %d\n",
+ xhci->name, port, psiv );
+ return -ENOENT;
+}
+
+/**
+ * Find protocol speed ID value
+ *
+ * @v xhci xHCI device
+ * @v port Port number
+ * @v speed USB speed
+ * @ret psiv Protocol speed ID value, or negative error
+ */
+static int xhci_port_psiv ( struct xhci_device *xhci, unsigned int port,
+ unsigned int speed ) {
+ unsigned int supported = xhci_supported_protocol ( xhci, port );
+ unsigned int psic;
+ unsigned int mantissa;
+ unsigned int exponent;
+ unsigned int psiv;
+ unsigned int i;
+ uint32_t ports;
+ uint32_t psi;
+
+ /* Fail if there is no supported protocol */
+ if ( ! supported )
+ return -ENOTSUP;
+
+ /* Get protocol speed ID count */
+ ports = readl ( xhci->cap + supported + XHCI_SUPPORTED_PORTS );
+ psic = XHCI_SUPPORTED_PORTS_PSIC ( ports );
+
+ /* Use the default mappings if applicable */
+ if ( ( psic == 0 ) || ( xhci->quirks & XHCI_BAD_PSIV ) ) {
+ switch ( speed ) {
+ case USB_SPEED_LOW : return XHCI_SPEED_LOW;
+ case USB_SPEED_FULL : return XHCI_SPEED_FULL;
+ case USB_SPEED_HIGH : return XHCI_SPEED_HIGH;
+ case USB_SPEED_SUPER : return XHCI_SPEED_SUPER;
+ default:
+ DBGC ( xhci, "XHCI %s-%d non-standard speed %d\n",
+ xhci->name, port, speed );
+ return -ENOTSUP;
+ }
+ }
+
+ /* Iterate over PSI dwords looking for a match */
+ for ( i = 0 ; i < psic ; i++ ) {
+ psi = readl ( xhci->cap + supported + XHCI_SUPPORTED_PSI ( i ));
+ mantissa = XHCI_SUPPORTED_PSI_MANTISSA ( psi );
+ exponent = XHCI_SUPPORTED_PSI_EXPONENT ( psi );
+ if ( speed == USB_SPEED ( mantissa, exponent ) ) {
+ psiv = XHCI_SUPPORTED_PSI_VALUE ( psi );
+ return psiv;
+ }
+ }
+
+ DBGC ( xhci, "XHCI %s-%d unrepresentable speed %#x\n",
+ xhci->name, port, speed );
+ return -ENOENT;
+}
+
+/******************************************************************************
+ *
+ * Device context base address array
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Allocate device context base address array
+ *
+ * @v xhci xHCI device
+ * @ret rc Return status code
+ */
+static int xhci_dcbaa_alloc ( struct xhci_device *xhci ) {
+ size_t len;
+ physaddr_t dcbaap;
+ int rc;
+
+ /* Allocate and initialise structure. Must be at least
+ * 64-byte aligned and must not cross a page boundary, so
+ * align on its own size (rounded up to a power of two and
+ * with a minimum of 64 bytes).
+ */
+ len = ( ( xhci->slots + 1 ) * sizeof ( xhci->dcbaa[0] ) );
+ xhci->dcbaa = malloc_dma ( len, xhci_align ( len ) );
+ if ( ! xhci->dcbaa ) {
+ DBGC ( xhci, "XHCI %s could not allocate DCBAA\n", xhci->name );
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ memset ( xhci->dcbaa, 0, len );
+
+ /* Program DCBAA pointer */
+ dcbaap = virt_to_phys ( xhci->dcbaa );
+ if ( ( rc = xhci_writeq ( xhci, dcbaap,
+ xhci->op + XHCI_OP_DCBAAP ) ) != 0 )
+ goto err_writeq;
+
+ DBGC2 ( xhci, "XHCI %s DCBAA at [%08lx,%08lx)\n",
+ xhci->name, dcbaap, ( dcbaap + len ) );
+ return 0;
+
+ err_writeq:
+ free_dma ( xhci->dcbaa, len );
+ err_alloc:
+ return rc;
+}
+
+/**
+ * Free device context base address array
+ *
+ * @v xhci xHCI device
+ */
+static void xhci_dcbaa_free ( struct xhci_device *xhci ) {
+ size_t len;
+ unsigned int i;
+
+ /* Sanity check */
+ for ( i = 0 ; i <= xhci->slots ; i++ )
+ assert ( xhci->dcbaa[i] == 0 );
+
+ /* Clear DCBAA pointer */
+ xhci_writeq ( xhci, 0, xhci->op + XHCI_OP_DCBAAP );
+
+ /* Free DCBAA */
+ len = ( ( xhci->slots + 1 ) * sizeof ( xhci->dcbaa[0] ) );
+ free_dma ( xhci->dcbaa, len );
+}
+
+/******************************************************************************
+ *
+ * Scratchpad buffers
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Allocate scratchpad buffers
+ *
+ * @v xhci xHCI device
+ * @ret rc Return status code
+ */
+static int xhci_scratchpad_alloc ( struct xhci_device *xhci ) {
+ size_t array_len;
+ size_t len;
+ physaddr_t phys;
+ unsigned int i;
+ int rc;
+
+ /* Do nothing if no scratchpad buffers are used */
+ if ( ! xhci->scratchpads )
+ return 0;
+
+ /* Allocate scratchpads */
+ len = ( xhci->scratchpads * xhci->pagesize );
+ xhci->scratchpad = umalloc ( len );
+ if ( ! xhci->scratchpad ) {
+ DBGC ( xhci, "XHCI %s could not allocate scratchpad buffers\n",
+ xhci->name );
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ memset_user ( xhci->scratchpad, 0, 0, len );
+
+ /* Allocate scratchpad array */
+ array_len = ( xhci->scratchpads * sizeof ( xhci->scratchpad_array[0] ));
+ xhci->scratchpad_array =
+ malloc_dma ( array_len, xhci_align ( array_len ) );
+ if ( ! xhci->scratchpad_array ) {
+ DBGC ( xhci, "XHCI %s could not allocate scratchpad buffer "
+ "array\n", xhci->name );
+ rc = -ENOMEM;
+ goto err_alloc_array;
+ }
+
+ /* Populate scratchpad array */
+ for ( i = 0 ; i < xhci->scratchpads ; i++ ) {
+ phys = user_to_phys ( xhci->scratchpad, ( i * xhci->pagesize ));
+ xhci->scratchpad_array[i] = phys;
+ }
+
+ /* Set scratchpad array pointer */
+ assert ( xhci->dcbaa != NULL );
+ xhci->dcbaa[0] = cpu_to_le64 ( virt_to_phys ( xhci->scratchpad_array ));
+
+ DBGC2 ( xhci, "XHCI %s scratchpad [%08lx,%08lx) array [%08lx,%08lx)\n",
+ xhci->name, user_to_phys ( xhci->scratchpad, 0 ),
+ user_to_phys ( xhci->scratchpad, len ),
+ virt_to_phys ( xhci->scratchpad_array ),
+ ( virt_to_phys ( xhci->scratchpad_array ) + array_len ) );
+ return 0;
+
+ free_dma ( xhci->scratchpad_array, array_len );
+ err_alloc_array:
+ ufree ( xhci->scratchpad );
+ err_alloc:
+ return rc;
+}
+
+/**
+ * Free scratchpad buffers
+ *
+ * @v xhci xHCI device
+ */
+static void xhci_scratchpad_free ( struct xhci_device *xhci ) {
+ size_t array_len;
+
+ /* Do nothing if no scratchpad buffers are used */
+ if ( ! xhci->scratchpads )
+ return;
+
+ /* Clear scratchpad array pointer */
+ assert ( xhci->dcbaa != NULL );
+ xhci->dcbaa[0] = 0;
+
+ /* Free scratchpad array */
+ array_len = ( xhci->scratchpads * sizeof ( xhci->scratchpad_array[0] ));
+ free_dma ( xhci->scratchpad_array, array_len );
+
+ /* Free scratchpads */
+ ufree ( xhci->scratchpad );
+}
+
+/******************************************************************************
+ *
+ * Run / stop / reset
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Start xHCI device
+ *
+ * @v xhci xHCI device
+ */
+static void xhci_run ( struct xhci_device *xhci ) {
+ uint32_t config;
+ uint32_t usbcmd;
+
+ /* Configure number of device slots */
+ config = readl ( xhci->op + XHCI_OP_CONFIG );
+ config &= ~XHCI_CONFIG_MAX_SLOTS_EN_MASK;
+ config |= XHCI_CONFIG_MAX_SLOTS_EN ( xhci->slots );
+ writel ( config, xhci->op + XHCI_OP_CONFIG );
+
+ /* Set run/stop bit */
+ usbcmd = readl ( xhci->op + XHCI_OP_USBCMD );
+ usbcmd |= XHCI_USBCMD_RUN;
+ writel ( usbcmd, xhci->op + XHCI_OP_USBCMD );
+}
+
+/**
+ * Stop xHCI device
+ *
+ * @v xhci xHCI device
+ * @ret rc Return status code
+ */
+static int xhci_stop ( struct xhci_device *xhci ) {
+ uint32_t usbcmd;
+ uint32_t usbsts;
+ unsigned int i;
+
+ /* Clear run/stop bit */
+ usbcmd = readl ( xhci->op + XHCI_OP_USBCMD );
+ usbcmd &= ~XHCI_USBCMD_RUN;
+ writel ( usbcmd, xhci->op + XHCI_OP_USBCMD );
+
+ /* Wait for device to stop */
+ for ( i = 0 ; i < XHCI_STOP_MAX_WAIT_MS ; i++ ) {
+
+ /* Check if device is stopped */
+ usbsts = readl ( xhci->op + XHCI_OP_USBSTS );
+ if ( usbsts & XHCI_USBSTS_HCH )
+ return 0;
+
+ /* Delay */
+ mdelay ( 1 );
+ }
+
+ DBGC ( xhci, "XHCI %s timed out waiting for stop\n", xhci->name );
+ return -ETIMEDOUT;
+}
+
+/**
+ * Reset xHCI device
+ *
+ * @v xhci xHCI device
+ * @ret rc Return status code
+ */
+static int xhci_reset ( struct xhci_device *xhci ) {
+ uint32_t usbcmd;
+ unsigned int i;
+ int rc;
+
+ /* The xHCI specification states that resetting a running
+ * device may result in undefined behaviour, so try stopping
+ * it first.
+ */
+ if ( ( rc = xhci_stop ( xhci ) ) != 0 ) {
+ /* Ignore errors and attempt to reset the device anyway */
+ }
+
+ /* Reset device */
+ writel ( XHCI_USBCMD_HCRST, xhci->op + XHCI_OP_USBCMD );
+
+ /* Wait for reset to complete */
+ for ( i = 0 ; i < XHCI_RESET_MAX_WAIT_MS ; i++ ) {
+
+ /* Check if reset is complete */
+ usbcmd = readl ( xhci->op + XHCI_OP_USBCMD );
+ if ( ! ( usbcmd & XHCI_USBCMD_HCRST ) )
+ return 0;
+
+ /* Delay */
+ mdelay ( 1 );
+ }
+
+ DBGC ( xhci, "XHCI %s timed out waiting for reset\n", xhci->name );
+ return -ETIMEDOUT;
+}
+
+/******************************************************************************
+ *
+ * Transfer request blocks
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Allocate transfer request block ring
+ *
+ * @v xhci xHCI device
+ * @v ring TRB ring
+ * @v shift Ring size (log2)
+ * @v slot Device slot
+ * @v target Doorbell target
+ * @v stream Doorbell stream ID
+ * @ret rc Return status code
+ */
+static int xhci_ring_alloc ( struct xhci_device *xhci,
+ struct xhci_trb_ring *ring,
+ unsigned int shift, unsigned int slot,
+ unsigned int target, unsigned int stream ) {
+ struct xhci_trb_link *link;
+ unsigned int count;
+ int rc;
+
+ /* Sanity check */
+ assert ( shift > 0 );
+
+ /* Initialise structure */
+ memset ( ring, 0, sizeof ( *ring ) );
+ ring->shift = shift;
+ count = ( 1U << shift );
+ ring->mask = ( count - 1 );
+ ring->len = ( ( count + 1 /* Link TRB */ ) * sizeof ( ring->trb[0] ) );
+ ring->db = ( xhci->db + ( slot * sizeof ( ring->dbval ) ) );
+ ring->dbval = XHCI_DBVAL ( target, stream );
+
+ /* Allocate I/O buffers */
+ ring->iobuf = zalloc ( count * sizeof ( ring->iobuf[0] ) );
+ if ( ! ring->iobuf ) {
+ rc = -ENOMEM;
+ goto err_alloc_iobuf;
+ }
+
+ /* Allocate TRBs */
+ ring->trb = malloc_dma ( ring->len, xhci_align ( ring->len ) );
+ if ( ! ring->trb ) {
+ rc = -ENOMEM;
+ goto err_alloc_trb;
+ }
+ memset ( ring->trb, 0, ring->len );
+
+ /* Initialise Link TRB */
+ link = &ring->trb[count].link;
+ link->next = cpu_to_le64 ( virt_to_phys ( ring->trb ) );
+ link->flags = XHCI_TRB_TC;
+ link->type = XHCI_TRB_LINK;
+ ring->link = link;
+
+ return 0;
+
+ free_dma ( ring->trb, ring->len );
+ err_alloc_trb:
+ free ( ring->iobuf );
+ err_alloc_iobuf:
+ return rc;
+}
+
+/**
+ * Reset transfer request block ring
+ *
+ * @v ring TRB ring
+ */
+static void xhci_ring_reset ( struct xhci_trb_ring *ring ) {
+ unsigned int count = ( 1U << ring->shift );
+
+ /* Reset producer and consumer counters */
+ ring->prod = 0;
+ ring->cons = 0;
+
+ /* Reset TRBs (except Link TRB) */
+ memset ( ring->trb, 0, ( count * sizeof ( ring->trb[0] ) ) );
+}
+
+/**
+ * Free transfer request block ring
+ *
+ * @v ring TRB ring
+ */
+static void xhci_ring_free ( struct xhci_trb_ring *ring ) {
+ unsigned int count = ( 1U << ring->shift );
+ unsigned int i;
+
+ /* Sanity checks */
+ assert ( ring->cons == ring->prod );
+ for ( i = 0 ; i < count ; i++ )
+ assert ( ring->iobuf[i] == NULL );
+
+ /* Free TRBs */
+ free_dma ( ring->trb, ring->len );
+
+ /* Free I/O buffers */
+ free ( ring->iobuf );
+}
+
+/**
+ * Enqueue a transfer request block
+ *
+ * @v ring TRB ring
+ * @v iobuf I/O buffer (if any)
+ * @v trb Transfer request block (with empty Cycle flag)
+ * @ret rc Return status code
+ *
+ * This operation does not implicitly ring the doorbell register.
+ */
+static int xhci_enqueue ( struct xhci_trb_ring *ring, struct io_buffer *iobuf,
+ const union xhci_trb *trb ) {
+ union xhci_trb *dest;
+ unsigned int prod;
+ unsigned int mask;
+ unsigned int index;
+ unsigned int cycle;
+
+ /* Sanity check */
+ assert ( ! ( trb->common.flags & XHCI_TRB_C ) );
+
+ /* Fail if ring is full */
+ if ( ! xhci_ring_remaining ( ring ) )
+ return -ENOBUFS;
+
+ /* Update producer counter (and link TRB, if applicable) */
+ prod = ring->prod++;
+ mask = ring->mask;
+ cycle = ( ( ~( prod >> ring->shift ) ) & XHCI_TRB_C );
+ index = ( prod & mask );
+ if ( index == 0 )
+ ring->link->flags = ( XHCI_TRB_TC | ( cycle ^ XHCI_TRB_C ) );
+
+ /* Record I/O buffer */
+ ring->iobuf[index] = iobuf;
+
+ /* Enqueue TRB */
+ dest = &ring->trb[index];
+ dest->template.parameter = trb->template.parameter;
+ dest->template.status = trb->template.status;
+ wmb();
+ dest->template.control = ( trb->template.control |
+ cpu_to_le32 ( cycle ) );
+
+ return 0;
+}
+
+/**
+ * Dequeue a transfer request block
+ *
+ * @v ring TRB ring
+ * @ret iobuf I/O buffer
+ */
+static struct io_buffer * xhci_dequeue ( struct xhci_trb_ring *ring ) {
+ struct io_buffer *iobuf;
+ unsigned int cons;
+ unsigned int mask;
+ unsigned int index;
+
+ /* Sanity check */
+ assert ( xhci_ring_fill ( ring ) != 0 );
+
+ /* Update consumer counter */
+ cons = ring->cons++;
+ mask = ring->mask;
+ index = ( cons & mask );
+
+ /* Retrieve I/O buffer */
+ iobuf = ring->iobuf[index];
+ ring->iobuf[index] = NULL;
+
+ return iobuf;
+}
+
+/**
+ * Enqueue multiple transfer request blocks
+ *
+ * @v ring TRB ring
+ * @v iobuf I/O buffer
+ * @v trbs Transfer request blocks (with empty Cycle flag)
+ * @v count Number of transfer request blocks
+ * @ret rc Return status code
+ *
+ * This operation does not implicitly ring the doorbell register.
+ */
+static int xhci_enqueue_multi ( struct xhci_trb_ring *ring,
+ struct io_buffer *iobuf,
+ const union xhci_trb *trbs,
+ unsigned int count ) {
+ const union xhci_trb *trb = trbs;
+ int rc;
+
+ /* Sanity check */
+ assert ( iobuf != NULL );
+
+ /* Fail if ring does not have sufficient space */
+ if ( xhci_ring_remaining ( ring ) < count )
+ return -ENOBUFS;
+
+ /* Enqueue each TRB, recording the I/O buffer with the final TRB */
+ while ( count-- ) {
+ rc = xhci_enqueue ( ring, ( count ? NULL : iobuf ), trb++ );
+ assert ( rc == 0 ); /* Should never be able to fail */
+ }
+
+ return 0;
+}
+
+/**
+ * Dequeue multiple transfer request blocks
+ *
+ * @v ring TRB ring
+ * @ret iobuf I/O buffer
+ */
+static struct io_buffer * xhci_dequeue_multi ( struct xhci_trb_ring *ring ) {
+ struct io_buffer *iobuf;
+
+ /* Dequeue TRBs until we reach the final TRB for an I/O buffer */
+ do {
+ iobuf = xhci_dequeue ( ring );
+ } while ( iobuf == NULL );
+
+ return iobuf;
+}
+
+/**
+ * Ring doorbell register
+ *
+ * @v ring TRB ring
+ */
+static inline __attribute__ (( always_inline )) void
+xhci_doorbell ( struct xhci_trb_ring *ring ) {
+
+ wmb();
+ writel ( ring->dbval, ring->db );
+}
+
+/******************************************************************************
+ *
+ * Command and event rings
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Allocate command ring
+ *
+ * @v xhci xHCI device
+ * @ret rc Return status code
+ */
+static int xhci_command_alloc ( struct xhci_device *xhci ) {
+ physaddr_t crp;
+ int rc;
+
+ /* Allocate TRB ring */
+ if ( ( rc = xhci_ring_alloc ( xhci, &xhci->command, XHCI_CMD_TRBS_LOG2,
+ 0, 0, 0 ) ) != 0 )
+ goto err_ring_alloc;
+
+ /* Program command ring control register */
+ crp = virt_to_phys ( xhci->command.trb );
+ if ( ( rc = xhci_writeq ( xhci, ( crp | XHCI_CRCR_RCS ),
+ xhci->op + XHCI_OP_CRCR ) ) != 0 )
+ goto err_writeq;
+
+ DBGC2 ( xhci, "XHCI %s CRCR at [%08lx,%08lx)\n",
+ xhci->name, crp, ( crp + xhci->command.len ) );
+ return 0;
+
+ err_writeq:
+ xhci_ring_free ( &xhci->command );
+ err_ring_alloc:
+ return rc;
+}
+
+/**
+ * Free command ring
+ *
+ * @v xhci xHCI device
+ */
+static void xhci_command_free ( struct xhci_device *xhci ) {
+
+ /* Sanity check */
+ assert ( ( readl ( xhci->op + XHCI_OP_CRCR ) & XHCI_CRCR_CRR ) == 0 );
+
+ /* Clear command ring control register */
+ xhci_writeq ( xhci, 0, xhci->op + XHCI_OP_CRCR );
+
+ /* Free TRB ring */
+ xhci_ring_free ( &xhci->command );
+}
+
+/**
+ * Allocate event ring
+ *
+ * @v xhci xHCI device
+ * @ret rc Return status code
+ */
+static int xhci_event_alloc ( struct xhci_device *xhci ) {
+ struct xhci_event_ring *event = &xhci->event;
+ unsigned int count;
+ size_t len;
+ int rc;
+
+ /* Allocate event ring */
+ count = ( 1 << XHCI_EVENT_TRBS_LOG2 );
+ len = ( count * sizeof ( event->trb[0] ) );
+ event->trb = malloc_dma ( len, xhci_align ( len ) );
+ if ( ! event->trb ) {
+ rc = -ENOMEM;
+ goto err_alloc_trb;
+ }
+ memset ( event->trb, 0, len );
+
+ /* Allocate event ring segment table */
+ event->segment = malloc_dma ( sizeof ( event->segment[0] ),
+ xhci_align ( sizeof (event->segment[0])));
+ if ( ! event->segment ) {
+ rc = -ENOMEM;
+ goto err_alloc_segment;
+ }
+ memset ( event->segment, 0, sizeof ( event->segment[0] ) );
+ event->segment[0].base = cpu_to_le64 ( virt_to_phys ( event->trb ) );
+ event->segment[0].count = cpu_to_le32 ( count );
+
+ /* Program event ring registers */
+ writel ( 1, xhci->run + XHCI_RUN_ERSTSZ ( 0 ) );
+ if ( ( rc = xhci_writeq ( xhci, virt_to_phys ( event->trb ),
+ xhci->run + XHCI_RUN_ERDP ( 0 ) ) ) != 0 )
+ goto err_writeq_erdp;
+ if ( ( rc = xhci_writeq ( xhci, virt_to_phys ( event->segment ),
+ xhci->run + XHCI_RUN_ERSTBA ( 0 ) ) ) != 0 )
+ goto err_writeq_erstba;
+
+ DBGC2 ( xhci, "XHCI %s event ring [%08lx,%08lx) table [%08lx,%08lx)\n",
+ xhci->name, virt_to_phys ( event->trb ),
+ ( virt_to_phys ( event->trb ) + len ),
+ virt_to_phys ( event->segment ),
+ ( virt_to_phys ( event->segment ) +
+ sizeof (event->segment[0] ) ) );
+ return 0;
+
+ xhci_writeq ( xhci, 0, xhci->run + XHCI_RUN_ERSTBA ( 0 ) );
+ err_writeq_erstba:
+ xhci_writeq ( xhci, 0, xhci->run + XHCI_RUN_ERDP ( 0 ) );
+ err_writeq_erdp:
+ free_dma ( event->trb, len );
+ err_alloc_segment:
+ free_dma ( event->segment, sizeof ( event->segment[0] ) );
+ err_alloc_trb:
+ return rc;
+}
+
+/**
+ * Free event ring
+ *
+ * @v xhci xHCI device
+ */
+static void xhci_event_free ( struct xhci_device *xhci ) {
+ struct xhci_event_ring *event = &xhci->event;
+ unsigned int count;
+ size_t len;
+
+ /* Clear event ring registers */
+ writel ( 0, xhci->run + XHCI_RUN_ERSTSZ ( 0 ) );
+ xhci_writeq ( xhci, 0, xhci->run + XHCI_RUN_ERSTBA ( 0 ) );
+ xhci_writeq ( xhci, 0, xhci->run + XHCI_RUN_ERDP ( 0 ) );
+
+ /* Free event ring segment table */
+ free_dma ( event->segment, sizeof ( event->segment[0] ) );
+
+ /* Free event ring */
+ count = ( 1 << XHCI_EVENT_TRBS_LOG2 );
+ len = ( count * sizeof ( event->trb[0] ) );
+ free_dma ( event->trb, len );
+}
+
+/**
+ * Handle transfer event
+ *
+ * @v xhci xHCI device
+ * @v trb Transfer event TRB
+ */
+static void xhci_transfer ( struct xhci_device *xhci,
+ struct xhci_trb_transfer *trb ) {
+ struct xhci_slot *slot;
+ struct xhci_endpoint *endpoint;
+ struct io_buffer *iobuf;
+ int rc;
+
+ /* Profile transfer events */
+ profile_start ( &xhci_transfer_profiler );
+
+ /* Identify slot */
+ if ( ( trb->slot > xhci->slots ) ||
+ ( ( slot = xhci->slot[trb->slot] ) == NULL ) ) {
+ DBGC ( xhci, "XHCI %s transfer event invalid slot %d:\n",
+ xhci->name, trb->slot );
+ DBGC_HDA ( xhci, 0, trb, sizeof ( *trb ) );
+ return;
+ }
+
+ /* Identify endpoint */
+ if ( ( trb->endpoint > XHCI_CTX_END ) ||
+ ( ( endpoint = slot->endpoint[trb->endpoint] ) == NULL ) ) {
+ DBGC ( xhci, "XHCI %s slot %d transfer event invalid epid "
+ "%d:\n", xhci->name, slot->id, trb->endpoint );
+ DBGC_HDA ( xhci, 0, trb, sizeof ( *trb ) );
+ return;
+ }
+
+ /* Dequeue TRB(s) */
+ iobuf = xhci_dequeue_multi ( &endpoint->ring );
+ assert ( iobuf != NULL );
+
+ /* Check for errors */
+ if ( ! ( ( trb->code == XHCI_CMPLT_SUCCESS ) ||
+ ( trb->code == XHCI_CMPLT_SHORT ) ) ) {
+
+ /* Construct error */
+ rc = -ECODE ( trb->code );
+ DBGC ( xhci, "XHCI %s slot %d ctx %d failed (code %d): %s\n",
+ xhci->name, slot->id, endpoint->ctx, trb->code,
+ strerror ( rc ) );
+ DBGC_HDA ( xhci, 0, trb, sizeof ( *trb ) );
+
+ /* Sanity check */
+ assert ( ( endpoint->context->state & XHCI_ENDPOINT_STATE_MASK )
+ != XHCI_ENDPOINT_RUNNING );
+
+ /* Report failure to USB core */
+ usb_complete_err ( endpoint->ep, iobuf, rc );
+ return;
+ }
+
+ /* Record actual transfer size */
+ iob_unput ( iobuf, le16_to_cpu ( trb->residual ) );
+
+ /* Sanity check (for successful completions only) */
+ assert ( xhci_ring_consumed ( &endpoint->ring ) ==
+ le64_to_cpu ( trb->transfer ) );
+
+ /* Report completion to USB core */
+ usb_complete ( endpoint->ep, iobuf );
+ profile_stop ( &xhci_transfer_profiler );
+}
+
+/**
+ * Handle command completion event
+ *
+ * @v xhci xHCI device
+ * @v trb Command completion event
+ */
+static void xhci_complete ( struct xhci_device *xhci,
+ struct xhci_trb_complete *trb ) {
+ int rc;
+
+ /* Ignore "command ring stopped" notifications */
+ if ( trb->code == XHCI_CMPLT_CMD_STOPPED ) {
+ DBGC2 ( xhci, "XHCI %s command ring stopped\n", xhci->name );
+ return;
+ }
+
+ /* Ignore unexpected completions */
+ if ( ! xhci->pending ) {
+ rc = -ECODE ( trb->code );
+ DBGC ( xhci, "XHCI %s unexpected completion (code %d): %s\n",
+ xhci->name, trb->code, strerror ( rc ) );
+ DBGC_HDA ( xhci, 0, trb, sizeof ( *trb ) );
+ return;
+ }
+
+ /* Dequeue command TRB */
+ xhci_dequeue ( &xhci->command );
+
+ /* Sanity check */
+ assert ( xhci_ring_consumed ( &xhci->command ) ==
+ le64_to_cpu ( trb->command ) );
+
+ /* Record completion */
+ memcpy ( xhci->pending, trb, sizeof ( *xhci->pending ) );
+ xhci->pending = NULL;
+}
+
+/**
+ * Handle port status event
+ *
+ * @v xhci xHCI device
+ * @v trb Port status event
+ */
+static void xhci_port_status ( struct xhci_device *xhci,
+ struct xhci_trb_port_status *trb ) {
+ struct usb_port *port = usb_port ( xhci->bus->hub, trb->port );
+ uint32_t portsc;
+
+ /* Sanity check */
+ assert ( ( trb->port > 0 ) && ( trb->port <= xhci->ports ) );
+
+ /* Record disconnections and clear changes */
+ portsc = readl ( xhci->op + XHCI_OP_PORTSC ( trb->port ) );
+ port->disconnected |= ( portsc & XHCI_PORTSC_CSC );
+ portsc &= ( XHCI_PORTSC_PRESERVE | XHCI_PORTSC_CHANGE );
+ writel ( portsc, xhci->op + XHCI_OP_PORTSC ( trb->port ) );
+
+ /* Report port status change */
+ usb_port_changed ( port );
+}
+
+/**
+ * Handle host controller event
+ *
+ * @v xhci xHCI device
+ * @v trb Host controller event
+ */
+static void xhci_host_controller ( struct xhci_device *xhci,
+ struct xhci_trb_host_controller *trb ) {
+ int rc;
+
+ /* Construct error */
+ rc = -ECODE ( trb->code );
+ DBGC ( xhci, "XHCI %s host controller event (code %d): %s\n",
+ xhci->name, trb->code, strerror ( rc ) );
+}
+
+/**
+ * Poll event ring
+ *
+ * @v xhci xHCI device
+ */
+static void xhci_event_poll ( struct xhci_device *xhci ) {
+ struct xhci_event_ring *event = &xhci->event;
+ union xhci_trb *trb;
+ unsigned int shift = XHCI_EVENT_TRBS_LOG2;
+ unsigned int count = ( 1 << shift );
+ unsigned int mask = ( count - 1 );
+ unsigned int consumed;
+ unsigned int type;
+
+ /* Poll for events */
+ profile_start ( &xhci_event_profiler );
+ for ( consumed = 0 ; ; consumed++ ) {
+
+ /* Stop if we reach an empty TRB */
+ rmb();
+ trb = &event->trb[ event->cons & mask ];
+ if ( ! ( ( trb->common.flags ^
+ ( event->cons >> shift ) ) & XHCI_TRB_C ) )
+ break;
+
+ /* Handle TRB */
+ type = ( trb->common.type & XHCI_TRB_TYPE_MASK );
+ switch ( type ) {
+
+ case XHCI_TRB_TRANSFER :
+ xhci_transfer ( xhci, &trb->transfer );
+ break;
+
+ case XHCI_TRB_COMPLETE :
+ xhci_complete ( xhci, &trb->complete );
+ break;
+
+ case XHCI_TRB_PORT_STATUS:
+ xhci_port_status ( xhci, &trb->port );
+ break;
+
+ case XHCI_TRB_HOST_CONTROLLER:
+ xhci_host_controller ( xhci, &trb->host );
+ break;
+
+ default:
+ DBGC ( xhci, "XHCI %s unrecognised event %#x\n:",
+ xhci->name, event->cons );
+ DBGC_HDA ( xhci, virt_to_phys ( trb ),
+ trb, sizeof ( *trb ) );
+ break;
+ }
+
+ /* Consume this TRB */
+ event->cons++;
+ }
+
+ /* Update dequeue pointer if applicable */
+ if ( consumed ) {
+ xhci_writeq ( xhci, virt_to_phys ( trb ),
+ xhci->run + XHCI_RUN_ERDP ( 0 ) );
+ profile_stop ( &xhci_event_profiler );
+ }
+}
+
+/**
+ * Abort command
+ *
+ * @v xhci xHCI device
+ */
+static void xhci_abort ( struct xhci_device *xhci ) {
+ physaddr_t crp;
+
+ /* Abort the command */
+ DBGC2 ( xhci, "XHCI %s aborting command\n", xhci->name );
+ xhci_writeq ( xhci, XHCI_CRCR_CA, xhci->op + XHCI_OP_CRCR );
+
+ /* Allow time for command to abort */
+ mdelay ( XHCI_COMMAND_ABORT_DELAY_MS );
+
+ /* Sanity check */
+ assert ( ( readl ( xhci->op + XHCI_OP_CRCR ) & XHCI_CRCR_CRR ) == 0 );
+
+ /* Consume (and ignore) any final command status */
+ xhci_event_poll ( xhci );
+
+ /* Reset the command ring control register */
+ xhci_ring_reset ( &xhci->command );
+ crp = virt_to_phys ( xhci->command.trb );
+ xhci_writeq ( xhci, ( crp | XHCI_CRCR_RCS ), xhci->op + XHCI_OP_CRCR );
+}
+
+/**
+ * Issue command and wait for completion
+ *
+ * @v xhci xHCI device
+ * @v trb Transfer request block (with empty Cycle flag)
+ * @ret rc Return status code
+ *
+ * On a successful completion, the TRB will be overwritten with the
+ * completion.
+ */
+static int xhci_command ( struct xhci_device *xhci, union xhci_trb *trb ) {
+ struct xhci_trb_complete *complete = &trb->complete;
+ unsigned int i;
+ int rc;
+
+ /* Record the pending command */
+ xhci->pending = trb;
+
+ /* Enqueue the command */
+ if ( ( rc = xhci_enqueue ( &xhci->command, NULL, trb ) ) != 0 )
+ goto err_enqueue;
+
+ /* Ring the command doorbell */
+ xhci_doorbell ( &xhci->command );
+
+ /* Wait for the command to complete */
+ for ( i = 0 ; i < XHCI_COMMAND_MAX_WAIT_MS ; i++ ) {
+
+ /* Poll event ring */
+ xhci_event_poll ( xhci );
+
+ /* Check for completion */
+ if ( ! xhci->pending ) {
+ if ( complete->code != XHCI_CMPLT_SUCCESS ) {
+ rc = -ECODE ( complete->code );
+ DBGC ( xhci, "XHCI %s command failed (code "
+ "%d): %s\n", xhci->name, complete->code,
+ strerror ( rc ) );
+ DBGC_HDA ( xhci, 0, trb, sizeof ( *trb ) );
+ return rc;
+ }
+ return 0;
+ }
+
+ /* Delay */
+ mdelay ( 1 );
+ }
+
+ /* Timeout */
+ DBGC ( xhci, "XHCI %s timed out waiting for completion\n", xhci->name );
+ rc = -ETIMEDOUT;
+
+ /* Abort command */
+ xhci_abort ( xhci );
+
+ err_enqueue:
+ xhci->pending = NULL;
+ return rc;
+}
+
+/**
+ * Issue NOP and wait for completion
+ *
+ * @v xhci xHCI device
+ * @ret rc Return status code
+ */
+static inline int xhci_nop ( struct xhci_device *xhci ) {
+ union xhci_trb trb;
+ struct xhci_trb_common *nop = &trb.common;
+ int rc;
+
+ /* Construct command */
+ memset ( nop, 0, sizeof ( *nop ) );
+ nop->flags = XHCI_TRB_IOC;
+ nop->type = XHCI_TRB_NOP_CMD;
+
+ /* Issue command and wait for completion */
+ if ( ( rc = xhci_command ( xhci, &trb ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/**
+ * Enable slot
+ *
+ * @v xhci xHCI device
+ * @v type Slot type
+ * @ret slot Device slot ID, or negative error
+ */
+static inline int xhci_enable_slot ( struct xhci_device *xhci,
+ unsigned int type ) {
+ union xhci_trb trb;
+ struct xhci_trb_enable_slot *enable = &trb.enable;
+ struct xhci_trb_complete *enabled = &trb.complete;
+ unsigned int slot;
+ int rc;
+
+ /* Construct command */
+ memset ( enable, 0, sizeof ( *enable ) );
+ enable->slot = type;
+ enable->type = XHCI_TRB_ENABLE_SLOT;
+
+ /* Issue command and wait for completion */
+ if ( ( rc = xhci_command ( xhci, &trb ) ) != 0 ) {
+ DBGC ( xhci, "XHCI %s could not enable new slot: %s\n",
+ xhci->name, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Extract slot number */
+ slot = enabled->slot;
+
+ DBGC2 ( xhci, "XHCI %s slot %d enabled\n", xhci->name, slot );
+ return slot;
+}
+
+/**
+ * Disable slot
+ *
+ * @v xhci xHCI device
+ * @v slot Device slot
+ * @ret rc Return status code
+ */
+static inline int xhci_disable_slot ( struct xhci_device *xhci,
+ unsigned int slot ) {
+ union xhci_trb trb;
+ struct xhci_trb_disable_slot *disable = &trb.disable;
+ int rc;
+
+ /* Construct command */
+ memset ( disable, 0, sizeof ( *disable ) );
+ disable->type = XHCI_TRB_DISABLE_SLOT;
+ disable->slot = slot;
+
+ /* Issue command and wait for completion */
+ if ( ( rc = xhci_command ( xhci, &trb ) ) != 0 ) {
+ DBGC ( xhci, "XHCI %s could not disable slot %d: %s\n",
+ xhci->name, slot, strerror ( rc ) );
+ return rc;
+ }
+
+ DBGC2 ( xhci, "XHCI %s slot %d disabled\n", xhci->name, slot );
+ return 0;
+}
+
+/**
+ * Issue context-based command and wait for completion
+ *
+ * @v xhci xHCI device
+ * @v slot Device slot
+ * @v endpoint Endpoint
+ * @v type TRB type
+ * @v populate Input context populater
+ * @ret rc Return status code
+ */
+static int xhci_context ( struct xhci_device *xhci, struct xhci_slot *slot,
+ struct xhci_endpoint *endpoint, unsigned int type,
+ void ( * populate ) ( struct xhci_device *xhci,
+ struct xhci_slot *slot,
+ struct xhci_endpoint *endpoint,
+ void *input ) ) {
+ union xhci_trb trb;
+ struct xhci_trb_context *context = &trb.context;
+ size_t len;
+ void *input;
+ int rc;
+
+ /* Allocate an input context */
+ len = xhci_input_context_offset ( xhci, XHCI_CTX_END );
+ input = malloc_dma ( len, xhci_align ( len ) );
+ if ( ! input ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ memset ( input, 0, len );
+
+ /* Populate input context */
+ populate ( xhci, slot, endpoint, input );
+
+ /* Construct command */
+ memset ( context, 0, sizeof ( *context ) );
+ context->type = type;
+ context->input = cpu_to_le64 ( virt_to_phys ( input ) );
+ context->slot = slot->id;
+
+ /* Issue command and wait for completion */
+ if ( ( rc = xhci_command ( xhci, &trb ) ) != 0 )
+ goto err_command;
+
+ err_command:
+ free_dma ( input, len );
+ err_alloc:
+ return rc;
+}
+
+/**
+ * Populate address device input context
+ *
+ * @v xhci xHCI device
+ * @v slot Device slot
+ * @v endpoint Endpoint
+ * @v input Input context
+ */
+static void xhci_address_device_input ( struct xhci_device *xhci,
+ struct xhci_slot *slot,
+ struct xhci_endpoint *endpoint,
+ void *input ) {
+ struct xhci_control_context *control_ctx;
+ struct xhci_slot_context *slot_ctx;
+ struct xhci_endpoint_context *ep_ctx;
+
+ /* Sanity checks */
+ assert ( endpoint->ctx == XHCI_CTX_EP0 );
+
+ /* Populate control context */
+ control_ctx = input;
+ control_ctx->add = cpu_to_le32 ( ( 1 << XHCI_CTX_SLOT ) |
+ ( 1 << XHCI_CTX_EP0 ) );
+
+ /* Populate slot context */
+ slot_ctx = ( input + xhci_input_context_offset ( xhci, XHCI_CTX_SLOT ));
+ slot_ctx->info = cpu_to_le32 ( XHCI_SLOT_INFO ( 1, 0, slot->psiv,
+ slot->route ) );
+ slot_ctx->port = slot->port;
+ slot_ctx->tt_id = slot->tt_id;
+ slot_ctx->tt_port = slot->tt_port;
+
+ /* Populate control endpoint context */
+ ep_ctx = ( input + xhci_input_context_offset ( xhci, XHCI_CTX_EP0 ) );
+ ep_ctx->type = XHCI_EP_TYPE_CONTROL;
+ ep_ctx->burst = endpoint->ep->burst;
+ ep_ctx->mtu = cpu_to_le16 ( endpoint->ep->mtu );
+ ep_ctx->dequeue = cpu_to_le64 ( virt_to_phys ( endpoint->ring.trb ) |
+ XHCI_EP_DCS );
+ ep_ctx->trb_len = cpu_to_le16 ( XHCI_EP0_TRB_LEN );
+}
+
+/**
+ * Address device
+ *
+ * @v xhci xHCI device
+ * @v slot Device slot
+ * @ret rc Return status code
+ */
+static inline int xhci_address_device ( struct xhci_device *xhci,
+ struct xhci_slot *slot ) {
+ struct usb_device *usb = slot->usb;
+ struct xhci_slot_context *slot_ctx;
+ int rc;
+
+ /* Assign device address */
+ if ( ( rc = xhci_context ( xhci, slot, slot->endpoint[XHCI_CTX_EP0],
+ XHCI_TRB_ADDRESS_DEVICE,
+ xhci_address_device_input ) ) != 0 )
+ return rc;
+
+ /* Get assigned address */
+ slot_ctx = ( slot->context +
+ xhci_device_context_offset ( xhci, XHCI_CTX_SLOT ) );
+ usb->address = slot_ctx->address;
+ DBGC2 ( xhci, "XHCI %s assigned address %d to %s\n",
+ xhci->name, usb->address, usb->name );
+
+ return 0;
+}
+
+/**
+ * Populate configure endpoint input context
+ *
+ * @v xhci xHCI device
+ * @v slot Device slot
+ * @v endpoint Endpoint
+ * @v input Input context
+ */
+static void xhci_configure_endpoint_input ( struct xhci_device *xhci,
+ struct xhci_slot *slot,
+ struct xhci_endpoint *endpoint,
+ void *input ) {
+ struct xhci_control_context *control_ctx;
+ struct xhci_slot_context *slot_ctx;
+ struct xhci_endpoint_context *ep_ctx;
+
+ /* Populate control context */
+ control_ctx = input;
+ control_ctx->add = cpu_to_le32 ( ( 1 << XHCI_CTX_SLOT ) |
+ ( 1 << endpoint->ctx ) );
+
+ /* Populate slot context */
+ slot_ctx = ( input + xhci_input_context_offset ( xhci, XHCI_CTX_SLOT ));
+ slot_ctx->info = cpu_to_le32 ( XHCI_SLOT_INFO ( ( XHCI_CTX_END - 1 ),
+ ( slot->ports ? 1 : 0 ),
+ slot->psiv, 0 ) );
+ slot_ctx->ports = slot->ports;
+
+ /* Populate endpoint context */
+ ep_ctx = ( input + xhci_input_context_offset ( xhci, endpoint->ctx ) );
+ ep_ctx->interval = endpoint->interval;
+ ep_ctx->type = endpoint->type;
+ ep_ctx->burst = endpoint->ep->burst;
+ ep_ctx->mtu = cpu_to_le16 ( endpoint->ep->mtu );
+ ep_ctx->dequeue = cpu_to_le64 ( virt_to_phys ( endpoint->ring.trb ) |
+ XHCI_EP_DCS );
+ ep_ctx->trb_len = cpu_to_le16 ( endpoint->ep->mtu ); /* best guess */
+}
+
+/**
+ * Configure endpoint
+ *
+ * @v xhci xHCI device
+ * @v slot Device slot
+ * @v endpoint Endpoint
+ * @ret rc Return status code
+ */
+static inline int xhci_configure_endpoint ( struct xhci_device *xhci,
+ struct xhci_slot *slot,
+ struct xhci_endpoint *endpoint ) {
+ int rc;
+
+ /* Configure endpoint */
+ if ( ( rc = xhci_context ( xhci, slot, endpoint,
+ XHCI_TRB_CONFIGURE_ENDPOINT,
+ xhci_configure_endpoint_input ) ) != 0 )
+ return rc;
+
+ DBGC2 ( xhci, "XHCI %s slot %d ctx %d configured\n",
+ xhci->name, slot->id, endpoint->ctx );
+ return 0;
+}
+
+/**
+ * Populate deconfigure endpoint input context
+ *
+ * @v xhci xHCI device
+ * @v slot Device slot
+ * @v endpoint Endpoint
+ * @v input Input context
+ */
+static void
+xhci_deconfigure_endpoint_input ( struct xhci_device *xhci __unused,
+ struct xhci_slot *slot __unused,
+ struct xhci_endpoint *endpoint,
+ void *input ) {
+ struct xhci_control_context *control_ctx;
+ struct xhci_slot_context *slot_ctx;
+
+ /* Populate control context */
+ control_ctx = input;
+ control_ctx->add = cpu_to_le32 ( 1 << XHCI_CTX_SLOT );
+ control_ctx->drop = cpu_to_le32 ( 1 << endpoint->ctx );
+
+ /* Populate slot context */
+ slot_ctx = ( input + xhci_input_context_offset ( xhci, XHCI_CTX_SLOT ));
+ slot_ctx->info = cpu_to_le32 ( XHCI_SLOT_INFO ( ( XHCI_CTX_END - 1 ),
+ 0, 0, 0 ) );
+}
+
+/**
+ * Deconfigure endpoint
+ *
+ * @v xhci xHCI device
+ * @v slot Device slot
+ * @v endpoint Endpoint
+ * @ret rc Return status code
+ */
+static inline int xhci_deconfigure_endpoint ( struct xhci_device *xhci,
+ struct xhci_slot *slot,
+ struct xhci_endpoint *endpoint ) {
+ int rc;
+
+ /* Deconfigure endpoint */
+ if ( ( rc = xhci_context ( xhci, slot, endpoint,
+ XHCI_TRB_CONFIGURE_ENDPOINT,
+ xhci_deconfigure_endpoint_input ) ) != 0 )
+ return rc;
+
+ DBGC2 ( xhci, "XHCI %s slot %d ctx %d deconfigured\n",
+ xhci->name, slot->id, endpoint->ctx );
+ return 0;
+}
+
+/**
+ * Populate evaluate context input context
+ *
+ * @v xhci xHCI device
+ * @v slot Device slot
+ * @v endpoint Endpoint
+ * @v input Input context
+ */
+static void xhci_evaluate_context_input ( struct xhci_device *xhci,
+ struct xhci_slot *slot __unused,
+ struct xhci_endpoint *endpoint,
+ void *input ) {
+ struct xhci_control_context *control_ctx;
+ struct xhci_slot_context *slot_ctx;
+ struct xhci_endpoint_context *ep_ctx;
+
+ /* Populate control context */
+ control_ctx = input;
+ control_ctx->add = cpu_to_le32 ( ( 1 << XHCI_CTX_SLOT ) |
+ ( 1 << endpoint->ctx ) );
+
+ /* Populate slot context */
+ slot_ctx = ( input + xhci_input_context_offset ( xhci, XHCI_CTX_SLOT ));
+ slot_ctx->info = cpu_to_le32 ( XHCI_SLOT_INFO ( ( XHCI_CTX_END - 1 ),
+ 0, 0, 0 ) );
+
+ /* Populate endpoint context */
+ ep_ctx = ( input + xhci_input_context_offset ( xhci, endpoint->ctx ) );
+ ep_ctx->mtu = cpu_to_le16 ( endpoint->ep->mtu );
+}
+
+/**
+ * Evaluate context
+ *
+ * @v xhci xHCI device
+ * @v slot Device slot
+ * @v endpoint Endpoint
+ * @ret rc Return status code
+ */
+static inline int xhci_evaluate_context ( struct xhci_device *xhci,
+ struct xhci_slot *slot,
+ struct xhci_endpoint *endpoint ) {
+ int rc;
+
+ /* Configure endpoint */
+ if ( ( rc = xhci_context ( xhci, slot, endpoint,
+ XHCI_TRB_EVALUATE_CONTEXT,
+ xhci_evaluate_context_input ) ) != 0 )
+ return rc;
+
+ DBGC2 ( xhci, "XHCI %s slot %d ctx %d (re-)evaluated\n",
+ xhci->name, slot->id, endpoint->ctx );
+ return 0;
+}
+
+/**
+ * Reset endpoint
+ *
+ * @v xhci xHCI device
+ * @v slot Device slot
+ * @v endpoint Endpoint
+ * @ret rc Return status code
+ */
+static inline int xhci_reset_endpoint ( struct xhci_device *xhci,
+ struct xhci_slot *slot,
+ struct xhci_endpoint *endpoint ) {
+ union xhci_trb trb;
+ struct xhci_trb_reset_endpoint *reset = &trb.reset;
+ int rc;
+
+ /* Construct command */
+ memset ( reset, 0, sizeof ( *reset ) );
+ reset->slot = slot->id;
+ reset->endpoint = endpoint->ctx;
+ reset->type = XHCI_TRB_RESET_ENDPOINT;
+
+ /* Issue command and wait for completion */
+ if ( ( rc = xhci_command ( xhci, &trb ) ) != 0 ) {
+ DBGC ( xhci, "XHCI %s slot %d ctx %d could not reset endpoint "
+ "in state %d: %s\n", xhci->name, slot->id, endpoint->ctx,
+ endpoint->context->state, strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Stop endpoint
+ *
+ * @v xhci xHCI device
+ * @v slot Device slot
+ * @v endpoint Endpoint
+ * @ret rc Return status code
+ */
+static inline int xhci_stop_endpoint ( struct xhci_device *xhci,
+ struct xhci_slot *slot,
+ struct xhci_endpoint *endpoint ) {
+ union xhci_trb trb;
+ struct xhci_trb_stop_endpoint *stop = &trb.stop;
+ int rc;
+
+ /* Construct command */
+ memset ( stop, 0, sizeof ( *stop ) );
+ stop->slot = slot->id;
+ stop->endpoint = endpoint->ctx;
+ stop->type = XHCI_TRB_STOP_ENDPOINT;
+
+ /* Issue command and wait for completion */
+ if ( ( rc = xhci_command ( xhci, &trb ) ) != 0 ) {
+ DBGC ( xhci, "XHCI %s slot %d ctx %d could not stop endpoint "
+ "in state %d: %s\n", xhci->name, slot->id, endpoint->ctx,
+ endpoint->context->state, strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Set transfer ring dequeue pointer
+ *
+ * @v xhci xHCI device
+ * @v slot Device slot
+ * @v endpoint Endpoint
+ * @ret rc Return status code
+ */
+static inline int
+xhci_set_tr_dequeue_pointer ( struct xhci_device *xhci,
+ struct xhci_slot *slot,
+ struct xhci_endpoint *endpoint ) {
+ union xhci_trb trb;
+ struct xhci_trb_set_tr_dequeue_pointer *dequeue = &trb.dequeue;
+ struct xhci_trb_ring *ring = &endpoint->ring;
+ unsigned int cons;
+ unsigned int mask;
+ unsigned int index;
+ unsigned int dcs;
+ int rc;
+
+ /* Construct command */
+ memset ( dequeue, 0, sizeof ( *dequeue ) );
+ cons = ring->cons;
+ mask = ring->mask;
+ dcs = ( ( ~( cons >> ring->shift ) ) & XHCI_EP_DCS );
+ index = ( cons & mask );
+ dequeue->dequeue =
+ cpu_to_le64 ( virt_to_phys ( &ring->trb[index] ) | dcs );
+ dequeue->slot = slot->id;
+ dequeue->endpoint = endpoint->ctx;
+ dequeue->type = XHCI_TRB_SET_TR_DEQUEUE_POINTER;
+
+ /* Issue command and wait for completion */
+ if ( ( rc = xhci_command ( xhci, &trb ) ) != 0 ) {
+ DBGC ( xhci, "XHCI %s slot %d ctx %d could not set TR dequeue "
+ "pointer in state %d: %s\n", xhci->name, slot->id,
+ endpoint->ctx, endpoint->context->state, strerror ( rc));
+ return rc;
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * Endpoint operations
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Open endpoint
+ *
+ * @v ep USB endpoint
+ * @ret rc Return status code
+ */
+static int xhci_endpoint_open ( struct usb_endpoint *ep ) {
+ struct usb_device *usb = ep->usb;
+ struct xhci_slot *slot = usb_get_hostdata ( usb );
+ struct xhci_device *xhci = slot->xhci;
+ struct xhci_endpoint *endpoint;
+ unsigned int ctx;
+ unsigned int type;
+ unsigned int interval;
+ int rc;
+
+ /* Calculate context index */
+ ctx = XHCI_CTX ( ep->address );
+ assert ( slot->endpoint[ctx] == NULL );
+
+ /* Calculate endpoint type */
+ type = XHCI_EP_TYPE ( ep->attributes & USB_ENDPOINT_ATTR_TYPE_MASK );
+ if ( type == XHCI_EP_TYPE ( USB_ENDPOINT_ATTR_CONTROL ) )
+ type = XHCI_EP_TYPE_CONTROL;
+ if ( ep->address & USB_DIR_IN )
+ type |= XHCI_EP_TYPE_IN;
+
+ /* Calculate interval */
+ if ( type & XHCI_EP_TYPE_PERIODIC ) {
+ interval = ( fls ( ep->interval ) - 1 );
+ } else {
+ interval = ep->interval;
+ }
+
+ /* Allocate and initialise structure */
+ endpoint = zalloc ( sizeof ( *endpoint ) );
+ if ( ! endpoint ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ usb_endpoint_set_hostdata ( ep, endpoint );
+ slot->endpoint[ctx] = endpoint;
+ endpoint->xhci = xhci;
+ endpoint->slot = slot;
+ endpoint->ep = ep;
+ endpoint->ctx = ctx;
+ endpoint->type = type;
+ endpoint->interval = interval;
+ endpoint->context = ( ( ( void * ) slot->context ) +
+ xhci_device_context_offset ( xhci, ctx ) );
+
+ /* Allocate transfer ring */
+ if ( ( rc = xhci_ring_alloc ( xhci, &endpoint->ring,
+ XHCI_TRANSFER_TRBS_LOG2,
+ slot->id, ctx, 0 ) ) != 0 )
+ goto err_ring_alloc;
+
+ /* Configure endpoint, if applicable */
+ if ( ( ctx != XHCI_CTX_EP0 ) &&
+ ( ( rc = xhci_configure_endpoint ( xhci, slot, endpoint ) ) != 0 ))
+ goto err_configure_endpoint;
+
+ DBGC2 ( xhci, "XHCI %s slot %d ctx %d ring [%08lx,%08lx)\n",
+ xhci->name, slot->id, ctx, virt_to_phys ( endpoint->ring.trb ),
+ ( virt_to_phys ( endpoint->ring.trb ) + endpoint->ring.len ) );
+ return 0;
+
+ xhci_deconfigure_endpoint ( xhci, slot, endpoint );
+ err_configure_endpoint:
+ xhci_ring_free ( &endpoint->ring );
+ err_ring_alloc:
+ slot->endpoint[ctx] = NULL;
+ free ( endpoint );
+ err_alloc:
+ return rc;
+}
+
+/**
+ * Close endpoint
+ *
+ * @v ep USB endpoint
+ */
+static void xhci_endpoint_close ( struct usb_endpoint *ep ) {
+ struct xhci_endpoint *endpoint = usb_endpoint_get_hostdata ( ep );
+ struct xhci_slot *slot = endpoint->slot;
+ struct xhci_device *xhci = slot->xhci;
+ struct io_buffer *iobuf;
+ unsigned int ctx = endpoint->ctx;
+
+ /* Deconfigure endpoint, if applicable */
+ if ( ctx != XHCI_CTX_EP0 )
+ xhci_deconfigure_endpoint ( xhci, slot, endpoint );
+
+ /* Cancel any incomplete transfers */
+ while ( xhci_ring_fill ( &endpoint->ring ) ) {
+ iobuf = xhci_dequeue_multi ( &endpoint->ring );
+ usb_complete_err ( ep, iobuf, -ECANCELED );
+ }
+
+ /* Free endpoint */
+ xhci_ring_free ( &endpoint->ring );
+ slot->endpoint[ctx] = NULL;
+ free ( endpoint );
+}
+
+/**
+ * Reset endpoint
+ *
+ * @v ep USB endpoint
+ * @ret rc Return status code
+ */
+static int xhci_endpoint_reset ( struct usb_endpoint *ep ) {
+ struct xhci_endpoint *endpoint = usb_endpoint_get_hostdata ( ep );
+ struct xhci_slot *slot = endpoint->slot;
+ struct xhci_device *xhci = slot->xhci;
+ int rc;
+
+ /* Reset endpoint context */
+ if ( ( rc = xhci_reset_endpoint ( xhci, slot, endpoint ) ) != 0 )
+ return rc;
+
+ /* Set transfer ring dequeue pointer */
+ if ( ( rc = xhci_set_tr_dequeue_pointer ( xhci, slot, endpoint ) ) != 0)
+ return rc;
+
+ /* Ring doorbell to resume processing */
+ xhci_doorbell ( &endpoint->ring );
+
+ DBGC ( xhci, "XHCI %s slot %d ctx %d reset\n",
+ xhci->name, slot->id, endpoint->ctx );
+ return 0;
+}
+
+/**
+ * Update MTU
+ *
+ * @v ep USB endpoint
+ * @ret rc Return status code
+ */
+static int xhci_endpoint_mtu ( struct usb_endpoint *ep ) {
+ struct xhci_endpoint *endpoint = usb_endpoint_get_hostdata ( ep );
+ struct xhci_slot *slot = endpoint->slot;
+ struct xhci_device *xhci = slot->xhci;
+ int rc;
+
+ /* Evalulate context */
+ if ( ( rc = xhci_evaluate_context ( xhci, slot, endpoint ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/**
+ * Enqueue message transfer
+ *
+ * @v ep USB endpoint
+ * @v iobuf I/O buffer
+ * @ret rc Return status code
+ */
+static int xhci_endpoint_message ( struct usb_endpoint *ep,
+ struct io_buffer *iobuf ) {
+ struct xhci_endpoint *endpoint = usb_endpoint_get_hostdata ( ep );
+ struct usb_setup_packet *packet;
+ unsigned int input;
+ size_t len;
+ union xhci_trb trbs[ 1 /* setup */ + 1 /* possible data */ +
+ 1 /* status */ ];
+ union xhci_trb *trb = trbs;
+ struct xhci_trb_setup *setup;
+ struct xhci_trb_data *data;
+ struct xhci_trb_status *status;
+ int rc;
+
+ /* Profile message transfers */
+ profile_start ( &xhci_message_profiler );
+
+ /* Construct setup stage TRB */
+ memset ( trbs, 0, sizeof ( trbs ) );
+ assert ( iob_len ( iobuf ) >= sizeof ( *packet ) );
+ packet = iobuf->data;
+ iob_pull ( iobuf, sizeof ( *packet ) );
+ setup = &(trb++)->setup;
+ memcpy ( &setup->packet, packet, sizeof ( setup->packet ) );
+ setup->len = cpu_to_le32 ( sizeof ( *packet ) );
+ setup->flags = XHCI_TRB_IDT;
+ setup->type = XHCI_TRB_SETUP;
+ len = iob_len ( iobuf );
+ input = ( packet->request & cpu_to_le16 ( USB_DIR_IN ) );
+ if ( len )
+ setup->direction = ( input ? XHCI_SETUP_IN : XHCI_SETUP_OUT );
+
+ /* Construct data stage TRB, if applicable */
+ if ( len ) {
+ data = &(trb++)->data;
+ data->data = cpu_to_le64 ( virt_to_phys ( iobuf->data ) );
+ data->len = cpu_to_le32 ( len );
+ data->type = XHCI_TRB_DATA;
+ data->direction = ( input ? XHCI_DATA_IN : XHCI_DATA_OUT );
+ }
+
+ /* Construct status stage TRB */
+ status = &(trb++)->status;
+ status->flags = XHCI_TRB_IOC;
+ status->type = XHCI_TRB_STATUS;
+ status->direction =
+ ( ( len && input ) ? XHCI_STATUS_OUT : XHCI_STATUS_IN );
+
+ /* Enqueue TRBs */
+ if ( ( rc = xhci_enqueue_multi ( &endpoint->ring, iobuf, trbs,
+ ( trb - trbs ) ) ) != 0 )
+ return rc;
+
+ /* Ring the doorbell */
+ xhci_doorbell ( &endpoint->ring );
+
+ profile_stop ( &xhci_message_profiler );
+ return 0;
+}
+
+/**
+ * Enqueue stream transfer
+ *
+ * @v ep USB endpoint
+ * @v iobuf I/O buffer
+ * @v terminate Terminate using a short packet
+ * @ret rc Return status code
+ */
+static int xhci_endpoint_stream ( struct usb_endpoint *ep,
+ struct io_buffer *iobuf, int terminate ) {
+ struct xhci_endpoint *endpoint = usb_endpoint_get_hostdata ( ep );
+ union xhci_trb trbs[ 1 /* Normal */ + 1 /* Possible zero-length */ ];
+ union xhci_trb *trb = trbs;
+ struct xhci_trb_normal *normal;
+ size_t len = iob_len ( iobuf );
+ int rc;
+
+ /* Profile stream transfers */
+ profile_start ( &xhci_stream_profiler );
+
+ /* Construct normal TRBs */
+ memset ( &trbs, 0, sizeof ( trbs ) );
+ normal = &(trb++)->normal;
+ normal->data = cpu_to_le64 ( virt_to_phys ( iobuf->data ) );
+ normal->len = cpu_to_le32 ( len );
+ normal->type = XHCI_TRB_NORMAL;
+ if ( terminate && ( ( len & ( ep->mtu - 1 ) ) == 0 ) ) {
+ normal->flags = XHCI_TRB_CH;
+ normal = &(trb++)->normal;
+ normal->type = XHCI_TRB_NORMAL;
+ }
+ normal->flags = XHCI_TRB_IOC;
+
+ /* Enqueue TRBs */
+ if ( ( rc = xhci_enqueue_multi ( &endpoint->ring, iobuf, trbs,
+ ( trb - trbs ) ) ) != 0 )
+ return rc;
+
+ /* Ring the doorbell */
+ xhci_doorbell ( &endpoint->ring );
+
+ profile_stop ( &xhci_stream_profiler );
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * Device operations
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Open device
+ *
+ * @v usb USB device
+ * @ret rc Return status code
+ */
+static int xhci_device_open ( struct usb_device *usb ) {
+ struct xhci_device *xhci = usb_bus_get_hostdata ( usb->port->hub->bus );
+ struct usb_port *tt = usb_transaction_translator ( usb );
+ struct xhci_slot *slot;
+ struct xhci_slot *tt_slot;
+ size_t len;
+ int type;
+ int id;
+ int rc;
+
+ /* Determine applicable slot type */
+ type = xhci_port_slot_type ( xhci, usb->port->address );
+ if ( type < 0 ) {
+ rc = type;
+ DBGC ( xhci, "XHCI %s-%d has no slot type\n",
+ xhci->name, usb->port->address );
+ goto err_type;
+ }
+
+ /* Allocate a device slot number */
+ id = xhci_enable_slot ( xhci, type );
+ if ( id < 0 ) {
+ rc = id;
+ goto err_enable_slot;
+ }
+ assert ( ( id > 0 ) && ( ( unsigned int ) id <= xhci->slots ) );
+ assert ( xhci->slot[id] == NULL );
+
+ /* Allocate and initialise structure */
+ slot = zalloc ( sizeof ( *slot ) );
+ if ( ! slot ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ usb_set_hostdata ( usb, slot );
+ xhci->slot[id] = slot;
+ slot->xhci = xhci;
+ slot->usb = usb;
+ slot->id = id;
+ if ( tt ) {
+ tt_slot = usb_get_hostdata ( tt->hub->usb );
+ slot->tt_id = tt_slot->id;
+ slot->tt_port = tt->address;
+ }
+
+ /* Allocate a device context */
+ len = xhci_device_context_offset ( xhci, XHCI_CTX_END );
+ slot->context = malloc_dma ( len, xhci_align ( len ) );
+ if ( ! slot->context ) {
+ rc = -ENOMEM;
+ goto err_alloc_context;
+ }
+ memset ( slot->context, 0, len );
+
+ /* Set device context base address */
+ assert ( xhci->dcbaa[id] == 0 );
+ xhci->dcbaa[id] = cpu_to_le64 ( virt_to_phys ( slot->context ) );
+
+ DBGC2 ( xhci, "XHCI %s slot %d device context [%08lx,%08lx) for %s\n",
+ xhci->name, slot->id, virt_to_phys ( slot->context ),
+ ( virt_to_phys ( slot->context ) + len ), usb->name );
+ return 0;
+
+ xhci->dcbaa[id] = 0;
+ free_dma ( slot->context, len );
+ err_alloc_context:
+ xhci->slot[id] = NULL;
+ free ( slot );
+ err_alloc:
+ xhci_disable_slot ( xhci, id );
+ err_enable_slot:
+ err_type:
+ return rc;
+}
+
+/**
+ * Close device
+ *
+ * @v usb USB device
+ */
+static void xhci_device_close ( struct usb_device *usb ) {
+ struct xhci_slot *slot = usb_get_hostdata ( usb );
+ struct xhci_device *xhci = slot->xhci;
+ size_t len = xhci_device_context_offset ( xhci, XHCI_CTX_END );
+ unsigned int id = slot->id;
+ int rc;
+
+ /* Disable slot */
+ if ( ( rc = xhci_disable_slot ( xhci, id ) ) != 0 ) {
+ /* Slot is still enabled. Leak the slot context,
+ * since the controller may still write to this
+ * memory, and leave the DCBAA entry intact.
+ *
+ * If the controller later reports that this same slot
+ * has been re-enabled, then some assertions will be
+ * triggered.
+ */
+ DBGC ( xhci, "XHCI %s slot %d leaking context memory\n",
+ xhci->name, slot->id );
+ slot->context = NULL;
+ }
+
+ /* Free slot */
+ if ( slot->context ) {
+ free_dma ( slot->context, len );
+ xhci->dcbaa[id] = 0;
+ }
+ xhci->slot[id] = NULL;
+ free ( slot );
+}
+
+/**
+ * Assign device address
+ *
+ * @v usb USB device
+ * @ret rc Return status code
+ */
+static int xhci_device_address ( struct usb_device *usb ) {
+ struct xhci_slot *slot = usb_get_hostdata ( usb );
+ struct xhci_device *xhci = slot->xhci;
+ struct usb_port *port = usb->port;
+ struct usb_port *root_port;
+ int psiv;
+ int rc;
+
+ /* Calculate route string */
+ slot->route = usb_route_string ( usb );
+
+ /* Calculate root hub port number */
+ root_port = usb_root_hub_port ( usb );
+ slot->port = root_port->address;
+
+ /* Calculate protocol speed ID */
+ psiv = xhci_port_psiv ( xhci, slot->port, port->speed );
+ if ( psiv < 0 ) {
+ rc = psiv;
+ return rc;
+ }
+ slot->psiv = psiv;
+
+ /* Address device */
+ if ( ( rc = xhci_address_device ( xhci, slot ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * Bus operations
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Open USB bus
+ *
+ * @v bus USB bus
+ * @ret rc Return status code
+ */
+static int xhci_bus_open ( struct usb_bus *bus ) {
+ struct xhci_device *xhci = usb_bus_get_hostdata ( bus );
+ int rc;
+
+ /* Allocate device slot array */
+ xhci->slot = zalloc ( ( xhci->slots + 1 ) * sizeof ( xhci->slot[0] ) );
+ if ( ! xhci->slot ) {
+ rc = -ENOMEM;
+ goto err_slot_alloc;
+ }
+
+ /* Allocate device context base address array */
+ if ( ( rc = xhci_dcbaa_alloc ( xhci ) ) != 0 )
+ goto err_dcbaa_alloc;
+
+ /* Allocate scratchpad buffers */
+ if ( ( rc = xhci_scratchpad_alloc ( xhci ) ) != 0 )
+ goto err_scratchpad_alloc;
+
+ /* Allocate command ring */
+ if ( ( rc = xhci_command_alloc ( xhci ) ) != 0 )
+ goto err_command_alloc;
+
+ /* Allocate event ring */
+ if ( ( rc = xhci_event_alloc ( xhci ) ) != 0 )
+ goto err_event_alloc;
+
+ /* Start controller */
+ xhci_run ( xhci );
+
+ return 0;
+
+ xhci_stop ( xhci );
+ xhci_event_free ( xhci );
+ err_event_alloc:
+ xhci_command_free ( xhci );
+ err_command_alloc:
+ xhci_scratchpad_free ( xhci );
+ err_scratchpad_alloc:
+ xhci_dcbaa_free ( xhci );
+ err_dcbaa_alloc:
+ free ( xhci->slot );
+ err_slot_alloc:
+ return rc;
+}
+
+/**
+ * Close USB bus
+ *
+ * @v bus USB bus
+ */
+static void xhci_bus_close ( struct usb_bus *bus ) {
+ struct xhci_device *xhci = usb_bus_get_hostdata ( bus );
+ unsigned int i;
+
+ /* Sanity checks */
+ assert ( xhci->slot != NULL );
+ for ( i = 0 ; i <= xhci->slots ; i++ )
+ assert ( xhci->slot[i] == NULL );
+
+ xhci_stop ( xhci );
+ xhci_event_free ( xhci );
+ xhci_command_free ( xhci );
+ xhci_scratchpad_free ( xhci );
+ xhci_dcbaa_free ( xhci );
+ free ( xhci->slot );
+}
+
+/**
+ * Poll USB bus
+ *
+ * @v bus USB bus
+ */
+static void xhci_bus_poll ( struct usb_bus *bus ) {
+ struct xhci_device *xhci = usb_bus_get_hostdata ( bus );
+
+ /* Poll event ring */
+ xhci_event_poll ( xhci );
+}
+
+/******************************************************************************
+ *
+ * Hub operations
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Open hub
+ *
+ * @v hub USB hub
+ * @ret rc Return status code
+ */
+static int xhci_hub_open ( struct usb_hub *hub ) {
+ struct xhci_slot *slot;
+
+ /* Do nothing if this is the root hub */
+ if ( ! hub->usb )
+ return 0;
+
+ /* Get device slot */
+ slot = usb_get_hostdata ( hub->usb );
+
+ /* Update device slot hub parameters. We don't inform the
+ * hardware of this information until the hub's interrupt
+ * endpoint is opened, since the only mechanism for so doing
+ * provided by the xHCI specification is a Configure Endpoint
+ * command, and we can't issue that command until we have a
+ * non-EP0 endpoint to configure.
+ */
+ slot->ports = hub->ports;
+
+ return 0;
+}
+
+/**
+ * Close hub
+ *
+ * @v hub USB hub
+ */
+static void xhci_hub_close ( struct usb_hub *hub __unused ) {
+
+ /* Nothing to do */
+}
+
+/******************************************************************************
+ *
+ * Root hub operations
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Open root hub
+ *
+ * @v hub USB hub
+ * @ret rc Return status code
+ */
+static int xhci_root_open ( struct usb_hub *hub ) {
+ struct usb_bus *bus = hub->bus;
+ struct xhci_device *xhci = usb_bus_get_hostdata ( bus );
+ struct usb_port *port;
+ uint32_t portsc;
+ unsigned int i;
+
+ /* Enable power to all ports */
+ for ( i = 1 ; i <= xhci->ports ; i++ ) {
+ portsc = readl ( xhci->op + XHCI_OP_PORTSC ( i ) );
+ portsc &= XHCI_PORTSC_PRESERVE;
+ portsc |= XHCI_PORTSC_PP;
+ writel ( portsc, xhci->op + XHCI_OP_PORTSC ( i ) );
+ }
+
+ /* xHCI spec requires us to potentially wait 20ms after
+ * enabling power to a port.
+ */
+ mdelay ( XHCI_PORT_POWER_DELAY_MS );
+
+ /* USB3 ports may power up as Disabled */
+ for ( i = 1 ; i <= xhci->ports ; i++ ) {
+ portsc = readl ( xhci->op + XHCI_OP_PORTSC ( i ) );
+ port = usb_port ( hub, i );
+ if ( ( port->protocol >= USB_PROTO_3_0 ) &&
+ ( ( portsc & XHCI_PORTSC_PLS_MASK ) ==
+ XHCI_PORTSC_PLS_DISABLED ) ) {
+ /* Force link state to RxDetect */
+ portsc &= XHCI_PORTSC_PRESERVE;
+ portsc |= ( XHCI_PORTSC_PLS_RXDETECT | XHCI_PORTSC_LWS);
+ writel ( portsc, xhci->op + XHCI_OP_PORTSC ( i ) );
+ }
+ }
+
+ /* Some xHCI cards seem to require an additional delay after
+ * setting the link state to RxDetect.
+ */
+ mdelay ( XHCI_LINK_STATE_DELAY_MS );
+
+ /* Record hub driver private data */
+ usb_hub_set_drvdata ( hub, xhci );
+
+ return 0;
+}
+
+/**
+ * Close root hub
+ *
+ * @v hub USB hub
+ */
+static void xhci_root_close ( struct usb_hub *hub ) {
+
+ /* Clear hub driver private data */
+ usb_hub_set_drvdata ( hub, NULL );
+}
+
+/**
+ * Enable port
+ *
+ * @v hub USB hub
+ * @v port USB port
+ * @ret rc Return status code
+ */
+static int xhci_root_enable ( struct usb_hub *hub, struct usb_port *port ) {
+ struct xhci_device *xhci = usb_hub_get_drvdata ( hub );
+ uint32_t portsc;
+ unsigned int i;
+
+ /* Reset port */
+ portsc = readl ( xhci->op + XHCI_OP_PORTSC ( port->address ) );
+ portsc &= XHCI_PORTSC_PRESERVE;
+ portsc |= XHCI_PORTSC_PR;
+ writel ( portsc, xhci->op + XHCI_OP_PORTSC ( port->address ) );
+
+ /* Wait for port to become enabled */
+ for ( i = 0 ; i < XHCI_PORT_RESET_MAX_WAIT_MS ; i++ ) {
+
+ /* Check port status */
+ portsc = readl ( xhci->op + XHCI_OP_PORTSC ( port->address ) );
+ if ( portsc & XHCI_PORTSC_PED )
+ return 0;
+
+ /* Delay */
+ mdelay ( 1 );
+ }
+
+ DBGC ( xhci, "XHCI %s-%d timed out waiting for port to enable\n",
+ xhci->name, port->address );
+ return -ETIMEDOUT;
+}
+
+/**
+ * Disable port
+ *
+ * @v hub USB hub
+ * @v port USB port
+ * @ret rc Return status code
+ */
+static int xhci_root_disable ( struct usb_hub *hub, struct usb_port *port ) {
+ struct xhci_device *xhci = usb_hub_get_drvdata ( hub );
+ uint32_t portsc;
+
+ /* Disable port */
+ portsc = readl ( xhci->op + XHCI_OP_PORTSC ( port->address ) );
+ portsc &= XHCI_PORTSC_PRESERVE;
+ portsc |= XHCI_PORTSC_PED;
+ writel ( portsc, xhci->op + XHCI_OP_PORTSC ( port->address ) );
+
+ return 0;
+}
+
+/**
+ * Update root hub port speed
+ *
+ * @v hub USB hub
+ * @v port USB port
+ * @ret rc Return status code
+ */
+static int xhci_root_speed ( struct usb_hub *hub, struct usb_port *port ) {
+ struct xhci_device *xhci = usb_hub_get_drvdata ( hub );
+ uint32_t portsc;
+ unsigned int psiv;
+ int ccs;
+ int ped;
+ int csc;
+ int speed;
+ int rc;
+
+ /* Read port status */
+ portsc = readl ( xhci->op + XHCI_OP_PORTSC ( port->address ) );
+ DBGC2 ( xhci, "XHCI %s-%d status is %08x\n",
+ xhci->name, port->address, portsc );
+ ccs = ( portsc & XHCI_PORTSC_CCS );
+ ped = ( portsc & XHCI_PORTSC_PED );
+ csc = ( portsc & XHCI_PORTSC_CSC );
+ psiv = XHCI_PORTSC_PSIV ( portsc );
+
+ /* Record disconnections and clear changes */
+ port->disconnected |= csc;
+ portsc &= ( XHCI_PORTSC_PRESERVE | XHCI_PORTSC_CHANGE );
+ writel ( portsc, xhci->op + XHCI_OP_PORTSC ( port->address ) );
+
+ /* Port speed is not valid unless port is connected */
+ if ( ! ccs ) {
+ port->speed = USB_SPEED_NONE;
+ return 0;
+ }
+
+ /* For USB2 ports, the PSIV field is not valid until the port
+ * completes reset and becomes enabled.
+ */
+ if ( ( port->protocol < USB_PROTO_3_0 ) && ! ped ) {
+ port->speed = USB_SPEED_FULL;
+ return 0;
+ }
+
+ /* Get port speed and map to generic USB speed */
+ speed = xhci_port_speed ( xhci, port->address, psiv );
+ if ( speed < 0 ) {
+ rc = speed;
+ return rc;
+ }
+
+ port->speed = speed;
+ return 0;
+}
+
+/**
+ * Clear transaction translator buffer
+ *
+ * @v hub USB hub
+ * @v port USB port
+ * @v ep USB endpoint
+ * @ret rc Return status code
+ */
+static int xhci_root_clear_tt ( struct usb_hub *hub, struct usb_port *port,
+ struct usb_endpoint *ep ) {
+ struct xhci_device *xhci = usb_hub_get_drvdata ( hub );
+
+ /* Should never be called; this is a root hub */
+ DBGC ( xhci, "XHCI %s-%d nonsensical CLEAR_TT for %s %s\n", xhci->name,
+ port->address, ep->usb->name, usb_endpoint_name ( ep ) );
+
+ return -ENOTSUP;
+}
+
+/******************************************************************************
+ *
+ * PCI interface
+ *
+ ******************************************************************************
+ */
+
+/** USB host controller operations */
+static struct usb_host_operations xhci_operations = {
+ .endpoint = {
+ .open = xhci_endpoint_open,
+ .close = xhci_endpoint_close,
+ .reset = xhci_endpoint_reset,
+ .mtu = xhci_endpoint_mtu,
+ .message = xhci_endpoint_message,
+ .stream = xhci_endpoint_stream,
+ },
+ .device = {
+ .open = xhci_device_open,
+ .close = xhci_device_close,
+ .address = xhci_device_address,
+ },
+ .bus = {
+ .open = xhci_bus_open,
+ .close = xhci_bus_close,
+ .poll = xhci_bus_poll,
+ },
+ .hub = {
+ .open = xhci_hub_open,
+ .close = xhci_hub_close,
+ },
+ .root = {
+ .open = xhci_root_open,
+ .close = xhci_root_close,
+ .enable = xhci_root_enable,
+ .disable = xhci_root_disable,
+ .speed = xhci_root_speed,
+ .clear_tt = xhci_root_clear_tt,
+ },
+};
+
+/**
+ * Fix Intel PCH-specific quirks
+ *
+ * @v xhci xHCI device
+ * @v pci PCI device
+ */
+static void xhci_pch_fix ( struct xhci_device *xhci, struct pci_device *pci ) {
+ struct xhci_pch *pch = &xhci->pch;
+ uint32_t xusb2pr;
+ uint32_t xusb2prm;
+ uint32_t usb3pssen;
+ uint32_t usb3prm;
+
+ /* Enable SuperSpeed capability. Do this before rerouting
+ * USB2 ports, so that USB3 devices connect at SuperSpeed.
+ */
+ pci_read_config_dword ( pci, XHCI_PCH_USB3PSSEN, &usb3pssen );
+ pci_read_config_dword ( pci, XHCI_PCH_USB3PRM, &usb3prm );
+ if ( usb3prm & ~usb3pssen ) {
+ DBGC ( xhci, "XHCI %s enabling SuperSpeed on ports %08x\n",
+ xhci->name, ( usb3prm & ~usb3pssen ) );
+ }
+ pch->usb3pssen = usb3pssen;
+ usb3pssen |= usb3prm;
+ pci_write_config_dword ( pci, XHCI_PCH_USB3PSSEN, usb3pssen );
+
+ /* Route USB2 ports from EHCI to xHCI */
+ pci_read_config_dword ( pci, XHCI_PCH_XUSB2PR, &xusb2pr );
+ pci_read_config_dword ( pci, XHCI_PCH_XUSB2PRM, &xusb2prm );
+ if ( xusb2prm & ~xusb2pr ) {
+ DBGC ( xhci, "XHCI %s routing ports %08x from EHCI to xHCI\n",
+ xhci->name, ( xusb2prm & ~xusb2pr ) );
+ }
+ pch->xusb2pr = xusb2pr;
+ xusb2pr |= xusb2prm;
+ pci_write_config_dword ( pci, XHCI_PCH_XUSB2PR, xusb2pr );
+}
+
+/**
+ * Undo Intel PCH-specific quirk fixes
+ *
+ * @v xhci xHCI device
+ * @v pci PCI device
+ */
+static void xhci_pch_undo ( struct xhci_device *xhci, struct pci_device *pci ) {
+ struct xhci_pch *pch = &xhci->pch;
+
+ /* Restore USB2 port routing to original state */
+ pci_write_config_dword ( pci, XHCI_PCH_XUSB2PR, pch->xusb2pr );
+
+ /* Restore SuperSpeed capability to original state */
+ pci_write_config_dword ( pci, XHCI_PCH_USB3PSSEN, pch->usb3pssen );
+}
+
+/**
+ * Probe PCI device
+ *
+ * @v pci PCI device
+ * @ret rc Return status code
+ */
+static int xhci_probe ( struct pci_device *pci ) {
+ struct xhci_device *xhci;
+ struct usb_port *port;
+ unsigned long bar_start;
+ size_t bar_size;
+ unsigned int i;
+ int rc;
+
+ /* Allocate and initialise structure */
+ xhci = zalloc ( sizeof ( *xhci ) );
+ if ( ! xhci ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ xhci->name = pci->dev.name;
+ xhci->quirks = pci->id->driver_data;
+
+ /* Fix up PCI device */
+ adjust_pci_device ( pci );
+
+ /* Map registers */
+ bar_start = pci_bar_start ( pci, XHCI_BAR );
+ bar_size = pci_bar_size ( pci, XHCI_BAR );
+ xhci->regs = ioremap ( bar_start, bar_size );
+ if ( ! xhci->regs ) {
+ rc = -ENODEV;
+ goto err_ioremap;
+ }
+
+ /* Initialise xHCI device */
+ xhci_init ( xhci, xhci->regs );
+
+ /* Initialise USB legacy support and claim ownership */
+ xhci_legacy_init ( xhci );
+ xhci_legacy_claim ( xhci );
+
+ /* Fix Intel PCH-specific quirks, if applicable */
+ if ( xhci->quirks & XHCI_PCH )
+ xhci_pch_fix ( xhci, pci );
+
+ /* Reset device */
+ if ( ( rc = xhci_reset ( xhci ) ) != 0 )
+ goto err_reset;
+
+ /* Allocate USB bus */
+ xhci->bus = alloc_usb_bus ( &pci->dev, xhci->ports, XHCI_MTU,
+ &xhci_operations );
+ if ( ! xhci->bus ) {
+ rc = -ENOMEM;
+ goto err_alloc_bus;
+ }
+ usb_bus_set_hostdata ( xhci->bus, xhci );
+ usb_hub_set_drvdata ( xhci->bus->hub, xhci );
+
+ /* Set port protocols */
+ for ( i = 1 ; i <= xhci->ports ; i++ ) {
+ port = usb_port ( xhci->bus->hub, i );
+ port->protocol = xhci_port_protocol ( xhci, i );
+ }
+
+ /* Register USB bus */
+ if ( ( rc = register_usb_bus ( xhci->bus ) ) != 0 )
+ goto err_register;
+
+ pci_set_drvdata ( pci, xhci );
+ return 0;
+
+ unregister_usb_bus ( xhci->bus );
+ err_register:
+ free_usb_bus ( xhci->bus );
+ err_alloc_bus:
+ xhci_reset ( xhci );
+ err_reset:
+ if ( xhci->quirks & XHCI_PCH )
+ xhci_pch_undo ( xhci, pci );
+ xhci_legacy_release ( xhci );
+ iounmap ( xhci->regs );
+ err_ioremap:
+ free ( xhci );
+ err_alloc:
+ return rc;
+}
+
+/**
+ * Remove PCI device
+ *
+ * @v pci PCI device
+ */
+static void xhci_remove ( struct pci_device *pci ) {
+ struct xhci_device *xhci = pci_get_drvdata ( pci );
+ struct usb_bus *bus = xhci->bus;
+
+ unregister_usb_bus ( bus );
+ free_usb_bus ( bus );
+ xhci_reset ( xhci );
+ if ( xhci->quirks & XHCI_PCH )
+ xhci_pch_undo ( xhci, pci );
+ xhci_legacy_release ( xhci );
+ iounmap ( xhci->regs );
+ free ( xhci );
+}
+
+/** XHCI PCI device IDs */
+static struct pci_device_id xhci_ids[] = {
+ PCI_ROM ( 0x8086, 0x9d2f, "xhci-skylake", "xHCI (Skylake)", ( XHCI_PCH | XHCI_BAD_PSIV ) ),
+ PCI_ROM ( 0x8086, 0xffff, "xhci-pch", "xHCI (Intel PCH)", XHCI_PCH ),
+ PCI_ROM ( 0xffff, 0xffff, "xhci", "xHCI", 0 ),
+};
+
+/** XHCI PCI driver */
+struct pci_driver xhci_driver __pci_driver = {
+ .ids = xhci_ids,
+ .id_count = ( sizeof ( xhci_ids ) / sizeof ( xhci_ids[0] ) ),
+ .class = PCI_CLASS_ID ( PCI_CLASS_SERIAL, PCI_CLASS_SERIAL_USB,
+ PCI_CLASS_SERIAL_USB_XHCI ),
+ .probe = xhci_probe,
+ .remove = xhci_remove,
+};
+
+/**
+ * Prepare for exit
+ *
+ * @v booting System is shutting down for OS boot
+ */
+static void xhci_shutdown ( int booting ) {
+ /* If we are shutting down to boot an OS, then prevent the
+ * release of ownership back to BIOS.
+ */
+ xhci_legacy_prevent_release = booting;
+}
+
+/** Startup/shutdown function */
+struct startup_fn xhci_startup __startup_fn ( STARTUP_LATE ) = {
+ .shutdown = xhci_shutdown,
+};
diff --git a/roms/ipxe/src/drivers/usb/xhci.h b/roms/ipxe/src/drivers/usb/xhci.h
new file mode 100644
index 000000000..83bf71e7e
--- /dev/null
+++ b/roms/ipxe/src/drivers/usb/xhci.h
@@ -0,0 +1,1150 @@
+#ifndef _IPXE_XHCI_H
+#define _IPXE_XHCI_H
+
+/** @file
+ *
+ * USB eXtensible Host Controller Interface (xHCI) driver
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <assert.h>
+#include <ipxe/pci.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/usb.h>
+
+/** Minimum alignment required for data structures
+ *
+ * With the exception of the scratchpad buffer pages (which are
+ * page-aligned), data structures used by xHCI generally require from
+ * 16 to 64 byte alignment and must not cross an (xHCI) page boundary.
+ * We simplify this requirement by aligning each structure on its own
+ * size, with a minimum of a 64 byte alignment.
+ */
+#define XHCI_MIN_ALIGN 64
+
+/** Maximum transfer size */
+#define XHCI_MTU 65536
+
+/** xHCI PCI BAR */
+#define XHCI_BAR PCI_BASE_ADDRESS_0
+
+/** Capability register length */
+#define XHCI_CAP_CAPLENGTH 0x00
+
+/** Host controller interface version number */
+#define XHCI_CAP_HCIVERSION 0x02
+
+/** Structural parameters 1 */
+#define XHCI_CAP_HCSPARAMS1 0x04
+
+/** Number of device slots */
+#define XHCI_HCSPARAMS1_SLOTS(params) ( ( (params) >> 0 ) & 0xff )
+
+/** Number of interrupters */
+#define XHCI_HCSPARAMS1_INTRS(params) ( ( (params) >> 8 ) & 0x3ff )
+
+/** Number of ports */
+#define XHCI_HCSPARAMS1_PORTS(params) ( ( (params) >> 24 ) & 0xff )
+
+/** Structural parameters 2 */
+#define XHCI_CAP_HCSPARAMS2 0x08
+
+/** Number of page-sized scratchpad buffers */
+#define XHCI_HCSPARAMS2_SCRATCHPADS(params) \
+ ( ( ( (params) >> 16 ) & 0x3e0 ) | ( ( (params) >> 27 ) & 0x1f ) )
+
+/** Capability parameters */
+#define XHCI_CAP_HCCPARAMS1 0x10
+
+/** 64-bit addressing capability */
+#define XHCI_HCCPARAMS1_ADDR64(params) ( ( (params) >> 0 ) & 0x1 )
+
+/** Context size shift */
+#define XHCI_HCCPARAMS1_CSZ_SHIFT(params) ( 5 + ( ( (params) >> 2 ) & 0x1 ) )
+
+/** xHCI extended capabilities pointer */
+#define XHCI_HCCPARAMS1_XECP(params) ( ( ( (params) >> 16 ) & 0xffff ) << 2 )
+
+/** Doorbell offset */
+#define XHCI_CAP_DBOFF 0x14
+
+/** Runtime register space offset */
+#define XHCI_CAP_RTSOFF 0x18
+
+/** xHCI extended capability ID */
+#define XHCI_XECP_ID(xecp) ( ( (xecp) >> 0 ) & 0xff )
+
+/** Next xHCI extended capability pointer */
+#define XHCI_XECP_NEXT(xecp) ( ( ( (xecp) >> 8 ) & 0xff ) << 2 )
+
+/** USB legacy support extended capability */
+#define XHCI_XECP_ID_LEGACY 1
+
+/** USB legacy support BIOS owned semaphore */
+#define XHCI_USBLEGSUP_BIOS 0x02
+
+/** USB legacy support BIOS ownership flag */
+#define XHCI_USBLEGSUP_BIOS_OWNED 0x01
+
+/** USB legacy support OS owned semaphore */
+#define XHCI_USBLEGSUP_OS 0x03
+
+/** USB legacy support OS ownership flag */
+#define XHCI_USBLEGSUP_OS_OWNED 0x01
+
+/** USB legacy support control/status */
+#define XHCI_USBLEGSUP_CTLSTS 0x04
+
+/** Supported protocol extended capability */
+#define XHCI_XECP_ID_SUPPORTED 2
+
+/** Supported protocol revision */
+#define XHCI_SUPPORTED_REVISION 0x00
+
+/** Supported protocol minor revision */
+#define XHCI_SUPPORTED_REVISION_VER(revision) ( ( (revision) >> 16 ) & 0xffff )
+
+/** Supported protocol name */
+#define XHCI_SUPPORTED_NAME 0x04
+
+/** Supported protocol ports */
+#define XHCI_SUPPORTED_PORTS 0x08
+
+/** Supported protocol port offset */
+#define XHCI_SUPPORTED_PORTS_OFFSET(ports) ( ( (ports) >> 0 ) & 0xff )
+
+/** Supported protocol port count */
+#define XHCI_SUPPORTED_PORTS_COUNT(ports) ( ( (ports) >> 8 ) & 0xff )
+
+/** Supported protocol PSI count */
+#define XHCI_SUPPORTED_PORTS_PSIC(ports) ( ( (ports) >> 28 ) & 0x0f )
+
+/** Supported protocol slot */
+#define XHCI_SUPPORTED_SLOT 0x0c
+
+/** Supported protocol slot type */
+#define XHCI_SUPPORTED_SLOT_TYPE(slot) ( ( (slot) >> 0 ) & 0x1f )
+
+/** Supported protocol PSI */
+#define XHCI_SUPPORTED_PSI(index) ( 0x10 + ( (index) * 4 ) )
+
+/** Supported protocol PSI value */
+#define XHCI_SUPPORTED_PSI_VALUE(psi) ( ( (psi) >> 0 ) & 0x0f )
+
+/** Supported protocol PSI mantissa */
+#define XHCI_SUPPORTED_PSI_MANTISSA(psi) ( ( (psi) >> 16 ) & 0xffff )
+
+/** Supported protocol PSI exponent */
+#define XHCI_SUPPORTED_PSI_EXPONENT(psi) ( ( (psi) >> 4 ) & 0x03 )
+
+/** Default PSI values */
+enum xhci_default_psi_value {
+ /** Full speed (12Mbps) */
+ XHCI_SPEED_FULL = 1,
+ /** Low speed (1.5Mbps) */
+ XHCI_SPEED_LOW = 2,
+ /** High speed (480Mbps) */
+ XHCI_SPEED_HIGH = 3,
+ /** Super speed */
+ XHCI_SPEED_SUPER = 4,
+};
+
+/** USB command register */
+#define XHCI_OP_USBCMD 0x00
+
+/** Run/stop */
+#define XHCI_USBCMD_RUN 0x00000001UL
+
+/** Host controller reset */
+#define XHCI_USBCMD_HCRST 0x00000002UL
+
+/** USB status register */
+#define XHCI_OP_USBSTS 0x04
+
+/** Host controller halted */
+#define XHCI_USBSTS_HCH 0x00000001UL
+
+/** Page size register */
+#define XHCI_OP_PAGESIZE 0x08
+
+/** Page size */
+#define XHCI_PAGESIZE(pagesize) ( (pagesize) << 12 )
+
+/** Device notifcation control register */
+#define XHCI_OP_DNCTRL 0x14
+
+/** Command ring control register */
+#define XHCI_OP_CRCR 0x18
+
+/** Command ring cycle state */
+#define XHCI_CRCR_RCS 0x00000001UL
+
+/** Command abort */
+#define XHCI_CRCR_CA 0x00000004UL
+
+/** Command ring running */
+#define XHCI_CRCR_CRR 0x00000008UL
+
+/** Device context base address array pointer */
+#define XHCI_OP_DCBAAP 0x30
+
+/** Configure register */
+#define XHCI_OP_CONFIG 0x38
+
+/** Maximum device slots enabled */
+#define XHCI_CONFIG_MAX_SLOTS_EN(slots) ( (slots) << 0 )
+
+/** Maximum device slots enabled mask */
+#define XHCI_CONFIG_MAX_SLOTS_EN_MASK \
+ XHCI_CONFIG_MAX_SLOTS_EN ( 0xff )
+
+/** Port status and control register */
+#define XHCI_OP_PORTSC(port) ( 0x400 - 0x10 + ( (port) << 4 ) )
+
+/** Current connect status */
+#define XHCI_PORTSC_CCS 0x00000001UL
+
+/** Port enabled */
+#define XHCI_PORTSC_PED 0x00000002UL
+
+/** Port reset */
+#define XHCI_PORTSC_PR 0x00000010UL
+
+/** Port link state */
+#define XHCI_PORTSC_PLS(pls) ( (pls) << 5 )
+
+/** Disabled port link state */
+#define XHCI_PORTSC_PLS_DISABLED XHCI_PORTSC_PLS ( 4 )
+
+/** RxDetect port link state */
+#define XHCI_PORTSC_PLS_RXDETECT XHCI_PORTSC_PLS ( 5 )
+
+/** Port link state mask */
+#define XHCI_PORTSC_PLS_MASK XHCI_PORTSC_PLS ( 0xf )
+
+/** Port power */
+#define XHCI_PORTSC_PP 0x00000200UL
+
+/** Time to delay after enabling power to a port */
+#define XHCI_PORT_POWER_DELAY_MS 20
+
+/** Port speed ID value */
+#define XHCI_PORTSC_PSIV(portsc) ( ( (portsc) >> 10 ) & 0xf )
+
+/** Port indicator control */
+#define XHCI_PORTSC_PIC(indicators) ( (indicators) << 14 )
+
+/** Port indicator control mask */
+#define XHCI_PORTSC_PIC_MASK XHCI_PORTSC_PIC ( 3 )
+
+/** Port link state write strobe */
+#define XHCI_PORTSC_LWS 0x00010000UL
+
+/** Time to delay after writing the port link state */
+#define XHCI_LINK_STATE_DELAY_MS 20
+
+/** Connect status change */
+#define XHCI_PORTSC_CSC 0x00020000UL
+
+/** Port enabled/disabled change */
+#define XHCI_PORTSC_PEC 0x00040000UL
+
+/** Warm port reset change */
+#define XHCI_PORTSC_WRC 0x00080000UL
+
+/** Over-current change */
+#define XHCI_PORTSC_OCC 0x00100000UL
+
+/** Port reset change */
+#define XHCI_PORTSC_PRC 0x00200000UL
+
+/** Port link state change */
+#define XHCI_PORTSC_PLC 0x00400000UL
+
+/** Port config error change */
+#define XHCI_PORTSC_CEC 0x00800000UL
+
+/** Port status change mask */
+#define XHCI_PORTSC_CHANGE \
+ ( XHCI_PORTSC_CSC | XHCI_PORTSC_PEC | XHCI_PORTSC_WRC | \
+ XHCI_PORTSC_OCC | XHCI_PORTSC_PRC | XHCI_PORTSC_PLC | \
+ XHCI_PORTSC_CEC )
+
+/** Port status and control bits which should be preserved
+ *
+ * The port status and control register is a horrendous mix of
+ * differing semantics. Some bits are written to only when a separate
+ * write strobe bit is set. Some bits should be preserved when
+ * modifying other bits. Some bits will be cleared if written back as
+ * a one. Most excitingly, the "port enabled" bit has the semantics
+ * that 1=enabled, 0=disabled, yet writing a 1 will disable the port.
+ */
+#define XHCI_PORTSC_PRESERVE ( XHCI_PORTSC_PP | XHCI_PORTSC_PIC_MASK )
+
+/** Port power management status and control register */
+#define XHCI_OP_PORTPMSC(port) ( 0x404 - 0x10 + ( (port) << 4 ) )
+
+/** Port link info register */
+#define XHCI_OP_PORTLI(port) ( 0x408 - 0x10 + ( (port) << 4 ) )
+
+/** Port hardware link power management control register */
+#define XHCI_OP_PORTHLPMC(port) ( 0x40c - 0x10 + ( (port) << 4 ) )
+
+/** Event ring segment table size register */
+#define XHCI_RUN_ERSTSZ(intr) ( 0x28 + ( (intr) << 5 ) )
+
+/** Event ring segment table base address register */
+#define XHCI_RUN_ERSTBA(intr) ( 0x30 + ( (intr) << 5 ) )
+
+/** Event ring dequeue pointer register */
+#define XHCI_RUN_ERDP(intr) ( 0x38 + ( (intr) << 5 ) )
+
+/** A transfer request block template */
+struct xhci_trb_template {
+ /** Parameter */
+ uint64_t parameter;
+ /** Status */
+ uint32_t status;
+ /** Control */
+ uint32_t control;
+};
+
+/** A transfer request block */
+struct xhci_trb_common {
+ /** Reserved */
+ uint64_t reserved_a;
+ /** Reserved */
+ uint32_t reserved_b;
+ /** Flags */
+ uint8_t flags;
+ /** Type */
+ uint8_t type;
+ /** Reserved */
+ uint16_t reserved_c;
+} __attribute__ (( packed ));
+
+/** Transfer request block cycle bit flag */
+#define XHCI_TRB_C 0x01
+
+/** Transfer request block toggle cycle bit flag */
+#define XHCI_TRB_TC 0x02
+
+/** Transfer request block chain flag */
+#define XHCI_TRB_CH 0x10
+
+/** Transfer request block interrupt on completion flag */
+#define XHCI_TRB_IOC 0x20
+
+/** Transfer request block immediate data flag */
+#define XHCI_TRB_IDT 0x40
+
+/** Transfer request block type */
+#define XHCI_TRB_TYPE(type) ( (type) << 2 )
+
+/** Transfer request block type mask */
+#define XHCI_TRB_TYPE_MASK XHCI_TRB_TYPE ( 0x3f )
+
+/** A normal transfer request block */
+struct xhci_trb_normal {
+ /** Data buffer */
+ uint64_t data;
+ /** Length */
+ uint32_t len;
+ /** Flags */
+ uint8_t flags;
+ /** Type */
+ uint8_t type;
+ /** Reserved */
+ uint16_t reserved;
+} __attribute__ (( packed ));
+
+/** A normal transfer request block */
+#define XHCI_TRB_NORMAL XHCI_TRB_TYPE ( 1 )
+
+/** Construct TD size field */
+#define XHCI_TD_SIZE(remaining) \
+ ( ( ( (remaining) <= 0xf ) ? remaining : 0xf ) << 17 )
+
+/** A setup stage transfer request block */
+struct xhci_trb_setup {
+ /** Setup packet */
+ struct usb_setup_packet packet;
+ /** Length */
+ uint32_t len;
+ /** Flags */
+ uint8_t flags;
+ /** Type */
+ uint8_t type;
+ /** Transfer direction */
+ uint8_t direction;
+ /** Reserved */
+ uint8_t reserved;
+} __attribute__ (( packed ));
+
+/** A setup stage transfer request block */
+#define XHCI_TRB_SETUP XHCI_TRB_TYPE ( 2 )
+
+/** Setup stage input data direction */
+#define XHCI_SETUP_IN 3
+
+/** Setup stage output data direction */
+#define XHCI_SETUP_OUT 2
+
+/** A data stage transfer request block */
+struct xhci_trb_data {
+ /** Data buffer */
+ uint64_t data;
+ /** Length */
+ uint32_t len;
+ /** Flags */
+ uint8_t flags;
+ /** Type */
+ uint8_t type;
+ /** Transfer direction */
+ uint8_t direction;
+ /** Reserved */
+ uint8_t reserved;
+} __attribute__ (( packed ));
+
+/** A data stage transfer request block */
+#define XHCI_TRB_DATA XHCI_TRB_TYPE ( 3 )
+
+/** Input data direction */
+#define XHCI_DATA_IN 0x01
+
+/** Output data direction */
+#define XHCI_DATA_OUT 0x00
+
+/** A status stage transfer request block */
+struct xhci_trb_status {
+ /** Reserved */
+ uint64_t reserved_a;
+ /** Reserved */
+ uint32_t reserved_b;
+ /** Flags */
+ uint8_t flags;
+ /** Type */
+ uint8_t type;
+ /** Direction */
+ uint8_t direction;
+ /** Reserved */
+ uint8_t reserved_c;
+} __attribute__ (( packed ));
+
+/** A status stage transfer request block */
+#define XHCI_TRB_STATUS XHCI_TRB_TYPE ( 4 )
+
+/** Input status direction */
+#define XHCI_STATUS_IN 0x01
+
+/** Output status direction */
+#define XHCI_STATUS_OUT 0x00
+
+/** A link transfer request block */
+struct xhci_trb_link {
+ /** Next ring segment */
+ uint64_t next;
+ /** Reserved */
+ uint32_t reserved_a;
+ /** Flags */
+ uint8_t flags;
+ /** Type */
+ uint8_t type;
+ /** Reserved */
+ uint16_t reserved_c;
+} __attribute__ (( packed ));
+
+/** A link transfer request block */
+#define XHCI_TRB_LINK XHCI_TRB_TYPE ( 6 )
+
+/** A no-op transfer request block */
+#define XHCI_TRB_NOP XHCI_TRB_TYPE ( 8 )
+
+/** An enable slot transfer request block */
+struct xhci_trb_enable_slot {
+ /** Reserved */
+ uint64_t reserved_a;
+ /** Reserved */
+ uint32_t reserved_b;
+ /** Flags */
+ uint8_t flags;
+ /** Type */
+ uint8_t type;
+ /** Slot type */
+ uint8_t slot;
+ /** Reserved */
+ uint8_t reserved_c;
+} __attribute__ (( packed ));
+
+/** An enable slot transfer request block */
+#define XHCI_TRB_ENABLE_SLOT XHCI_TRB_TYPE ( 9 )
+
+/** A disable slot transfer request block */
+struct xhci_trb_disable_slot {
+ /** Reserved */
+ uint64_t reserved_a;
+ /** Reserved */
+ uint32_t reserved_b;
+ /** Flags */
+ uint8_t flags;
+ /** Type */
+ uint8_t type;
+ /** Reserved */
+ uint8_t reserved_c;
+ /** Slot ID */
+ uint8_t slot;
+} __attribute__ (( packed ));
+
+/** A disable slot transfer request block */
+#define XHCI_TRB_DISABLE_SLOT XHCI_TRB_TYPE ( 10 )
+
+/** A context transfer request block */
+struct xhci_trb_context {
+ /** Input context */
+ uint64_t input;
+ /** Reserved */
+ uint32_t reserved_a;
+ /** Flags */
+ uint8_t flags;
+ /** Type */
+ uint8_t type;
+ /** Reserved */
+ uint8_t reserved_b;
+ /** Slot ID */
+ uint8_t slot;
+} __attribute__ (( packed ));
+
+/** An address device transfer request block */
+#define XHCI_TRB_ADDRESS_DEVICE XHCI_TRB_TYPE ( 11 )
+
+/** A configure endpoint transfer request block */
+#define XHCI_TRB_CONFIGURE_ENDPOINT XHCI_TRB_TYPE ( 12 )
+
+/** An evaluate context transfer request block */
+#define XHCI_TRB_EVALUATE_CONTEXT XHCI_TRB_TYPE ( 13 )
+
+/** A reset endpoint transfer request block */
+struct xhci_trb_reset_endpoint {
+ /** Reserved */
+ uint64_t reserved_a;
+ /** Reserved */
+ uint32_t reserved_b;
+ /** Flags */
+ uint8_t flags;
+ /** Type */
+ uint8_t type;
+ /** Endpoint ID */
+ uint8_t endpoint;
+ /** Slot ID */
+ uint8_t slot;
+} __attribute__ (( packed ));
+
+/** A reset endpoint transfer request block */
+#define XHCI_TRB_RESET_ENDPOINT XHCI_TRB_TYPE ( 14 )
+
+/** A stop endpoint transfer request block */
+struct xhci_trb_stop_endpoint {
+ /** Reserved */
+ uint64_t reserved_a;
+ /** Reserved */
+ uint32_t reserved_b;
+ /** Flags */
+ uint8_t flags;
+ /** Type */
+ uint8_t type;
+ /** Endpoint ID */
+ uint8_t endpoint;
+ /** Slot ID */
+ uint8_t slot;
+} __attribute__ (( packed ));
+
+/** A stop endpoint transfer request block */
+#define XHCI_TRB_STOP_ENDPOINT XHCI_TRB_TYPE ( 15 )
+
+/** A set transfer ring dequeue pointer transfer request block */
+struct xhci_trb_set_tr_dequeue_pointer {
+ /** Dequeue pointer */
+ uint64_t dequeue;
+ /** Reserved */
+ uint32_t reserved;
+ /** Flags */
+ uint8_t flags;
+ /** Type */
+ uint8_t type;
+ /** Endpoint ID */
+ uint8_t endpoint;
+ /** Slot ID */
+ uint8_t slot;
+} __attribute__ (( packed ));
+
+/** A set transfer ring dequeue pointer transfer request block */
+#define XHCI_TRB_SET_TR_DEQUEUE_POINTER XHCI_TRB_TYPE ( 16 )
+
+/** A no-op command transfer request block */
+#define XHCI_TRB_NOP_CMD XHCI_TRB_TYPE ( 23 )
+
+/** A transfer event transfer request block */
+struct xhci_trb_transfer {
+ /** Transfer TRB pointer */
+ uint64_t transfer;
+ /** Residual transfer length */
+ uint16_t residual;
+ /** Reserved */
+ uint8_t reserved;
+ /** Completion code */
+ uint8_t code;
+ /** Flags */
+ uint8_t flags;
+ /** Type */
+ uint8_t type;
+ /** Endpoint ID */
+ uint8_t endpoint;
+ /** Slot ID */
+ uint8_t slot;
+} __attribute__ (( packed ));
+
+/** A transfer event transfer request block */
+#define XHCI_TRB_TRANSFER XHCI_TRB_TYPE ( 32 )
+
+/** A command completion event transfer request block */
+struct xhci_trb_complete {
+ /** Command TRB pointer */
+ uint64_t command;
+ /** Parameter */
+ uint8_t parameter[3];
+ /** Completion code */
+ uint8_t code;
+ /** Flags */
+ uint8_t flags;
+ /** Type */
+ uint8_t type;
+ /** Virtual function ID */
+ uint8_t vf;
+ /** Slot ID */
+ uint8_t slot;
+} __attribute__ (( packed ));
+
+/** A command completion event transfer request block */
+#define XHCI_TRB_COMPLETE XHCI_TRB_TYPE ( 33 )
+
+/** xHCI completion codes */
+enum xhci_completion_code {
+ /** Success */
+ XHCI_CMPLT_SUCCESS = 1,
+ /** Short packet */
+ XHCI_CMPLT_SHORT = 13,
+ /** Command ring stopped */
+ XHCI_CMPLT_CMD_STOPPED = 24,
+};
+
+/** A port status change transfer request block */
+struct xhci_trb_port_status {
+ /** Reserved */
+ uint8_t reserved_a[3];
+ /** Port ID */
+ uint8_t port;
+ /** Reserved */
+ uint8_t reserved_b[7];
+ /** Completion code */
+ uint8_t code;
+ /** Flags */
+ uint8_t flags;
+ /** Type */
+ uint8_t type;
+ /** Reserved */
+ uint16_t reserved_c;
+} __attribute__ (( packed ));
+
+/** A port status change transfer request block */
+#define XHCI_TRB_PORT_STATUS XHCI_TRB_TYPE ( 34 )
+
+/** A port status change transfer request block */
+struct xhci_trb_host_controller {
+ /** Reserved */
+ uint64_t reserved_a;
+ /** Reserved */
+ uint8_t reserved_b[3];
+ /** Completion code */
+ uint8_t code;
+ /** Flags */
+ uint8_t flags;
+ /** Type */
+ uint8_t type;
+ /** Reserved */
+ uint16_t reserved_c;
+} __attribute__ (( packed ));
+
+/** A port status change transfer request block */
+#define XHCI_TRB_HOST_CONTROLLER XHCI_TRB_TYPE ( 37 )
+
+/** A transfer request block */
+union xhci_trb {
+ /** Template */
+ struct xhci_trb_template template;
+ /** Common fields */
+ struct xhci_trb_common common;
+ /** Normal TRB */
+ struct xhci_trb_normal normal;
+ /** Setup stage TRB */
+ struct xhci_trb_setup setup;
+ /** Data stage TRB */
+ struct xhci_trb_data data;
+ /** Status stage TRB */
+ struct xhci_trb_status status;
+ /** Link TRB */
+ struct xhci_trb_link link;
+ /** Enable slot TRB */
+ struct xhci_trb_enable_slot enable;
+ /** Disable slot TRB */
+ struct xhci_trb_disable_slot disable;
+ /** Input context TRB */
+ struct xhci_trb_context context;
+ /** Reset endpoint TRB */
+ struct xhci_trb_reset_endpoint reset;
+ /** Stop endpoint TRB */
+ struct xhci_trb_stop_endpoint stop;
+ /** Set transfer ring dequeue pointer TRB */
+ struct xhci_trb_set_tr_dequeue_pointer dequeue;
+ /** Transfer event */
+ struct xhci_trb_transfer transfer;
+ /** Command completion event */
+ struct xhci_trb_complete complete;
+ /** Port status changed event */
+ struct xhci_trb_port_status port;
+ /** Host controller event */
+ struct xhci_trb_host_controller host;
+} __attribute__ (( packed ));
+
+/** An input control context */
+struct xhci_control_context {
+ /** Drop context flags */
+ uint32_t drop;
+ /** Add context flags */
+ uint32_t add;
+ /** Reserved */
+ uint32_t reserved_a[5];
+ /** Configuration value */
+ uint8_t config;
+ /** Interface number */
+ uint8_t intf;
+ /** Alternate setting */
+ uint8_t alt;
+ /** Reserved */
+ uint8_t reserved_b;
+} __attribute__ (( packed ));
+
+/** A slot context */
+struct xhci_slot_context {
+ /** Device info */
+ uint32_t info;
+ /** Maximum exit latency */
+ uint16_t latency;
+ /** Root hub port number */
+ uint8_t port;
+ /** Number of downstream ports */
+ uint8_t ports;
+ /** TT hub slot ID */
+ uint8_t tt_id;
+ /** TT port number */
+ uint8_t tt_port;
+ /** Interrupter target */
+ uint16_t intr;
+ /** USB address */
+ uint8_t address;
+ /** Reserved */
+ uint16_t reserved_a;
+ /** Slot state */
+ uint8_t state;
+ /** Reserved */
+ uint32_t reserved_b[4];
+} __attribute__ (( packed ));
+
+/** Construct slot context device info */
+#define XHCI_SLOT_INFO( entries, hub, speed, route ) \
+ ( ( (entries) << 27 ) | ( (hub) << 26 ) | ( (speed) << 20 ) | (route) )
+
+/** An endpoint context */
+struct xhci_endpoint_context {
+ /** Endpoint state */
+ uint8_t state;
+ /** Stream configuration */
+ uint8_t stream;
+ /** Polling interval */
+ uint8_t interval;
+ /** Max ESIT payload high */
+ uint8_t esit_high;
+ /** Endpoint type */
+ uint8_t type;
+ /** Maximum burst size */
+ uint8_t burst;
+ /** Maximum packet size */
+ uint16_t mtu;
+ /** Transfer ring dequeue pointer */
+ uint64_t dequeue;
+ /** Average TRB length */
+ uint16_t trb_len;
+ /** Max ESIT payload low */
+ uint16_t esit_low;
+ /** Reserved */
+ uint32_t reserved[3];
+} __attribute__ (( packed ));
+
+/** Endpoint states */
+enum xhci_endpoint_state {
+ /** Endpoint is disabled */
+ XHCI_ENDPOINT_DISABLED = 0,
+ /** Endpoint is running */
+ XHCI_ENDPOINT_RUNNING = 1,
+ /** Endpoint is halted due to a USB Halt condition */
+ XHCI_ENDPOINT_HALTED = 2,
+ /** Endpoint is stopped */
+ XHCI_ENDPOINT_STOPPED = 3,
+ /** Endpoint is halted due to a TRB error */
+ XHCI_ENDPOINT_ERROR = 4,
+};
+
+/** Endpoint state mask */
+#define XHCI_ENDPOINT_STATE_MASK 0x07
+
+/** Endpoint type */
+#define XHCI_EP_TYPE(type) ( (type) << 3 )
+
+/** Control endpoint type */
+#define XHCI_EP_TYPE_CONTROL XHCI_EP_TYPE ( 4 )
+
+/** Input endpoint type */
+#define XHCI_EP_TYPE_IN XHCI_EP_TYPE ( 4 )
+
+/** Periodic endpoint type */
+#define XHCI_EP_TYPE_PERIODIC XHCI_EP_TYPE ( 1 )
+
+/** Endpoint dequeue cycle state */
+#define XHCI_EP_DCS 0x00000001UL
+
+/** Control endpoint average TRB length */
+#define XHCI_EP0_TRB_LEN 8
+
+/** An event ring segment */
+struct xhci_event_ring_segment {
+ /** Base address */
+ uint64_t base;
+ /** Number of TRBs */
+ uint32_t count;
+ /** Reserved */
+ uint32_t reserved;
+} __attribute__ (( packed ));
+
+/** A transfer request block command/transfer ring */
+struct xhci_trb_ring {
+ /** Producer counter */
+ unsigned int prod;
+ /** Consumer counter */
+ unsigned int cons;
+ /** Ring size (log2) */
+ unsigned int shift;
+ /** Ring counter mask */
+ unsigned int mask;
+
+ /** I/O buffers */
+ struct io_buffer **iobuf;
+
+ /** Transfer request blocks */
+ union xhci_trb *trb;
+ /** Length of transfer request blocks */
+ size_t len;
+ /** Link TRB (if applicable) */
+ struct xhci_trb_link *link;
+
+ /** Doorbell register */
+ void *db;
+ /** Doorbell register value */
+ uint32_t dbval;
+};
+
+/** An event ring */
+struct xhci_event_ring {
+ /** Consumer counter */
+ unsigned int cons;
+ /** Event ring segment table */
+ struct xhci_event_ring_segment *segment;
+ /** Transfer request blocks */
+ union xhci_trb *trb;
+};
+
+/**
+ * Calculate doorbell register value
+ *
+ * @v target Doorbell target
+ * @v stream Doorbell stream ID
+ * @ret dbval Doorbell register value
+ */
+#define XHCI_DBVAL( target, stream ) ( (target) | ( (stream) << 16 ) )
+
+/**
+ * Calculate space used in TRB ring
+ *
+ * @v ring TRB ring
+ * @ret fill Number of entries used
+ */
+static inline __attribute__ (( always_inline )) unsigned int
+xhci_ring_fill ( struct xhci_trb_ring *ring ) {
+
+ return ( ring->prod - ring->cons );
+}
+
+/**
+ * Calculate space remaining in TRB ring
+ *
+ * @v ring TRB ring
+ * @ret remaining Number of entries remaining
+ *
+ * xHCI does not allow us to completely fill a ring; there must be at
+ * least one free entry (excluding the Link TRB).
+ */
+static inline __attribute__ (( always_inline )) unsigned int
+xhci_ring_remaining ( struct xhci_trb_ring *ring ) {
+ unsigned int fill = xhci_ring_fill ( ring );
+
+ /* We choose to utilise rings with ( 2^n + 1 ) entries, with
+ * the final entry being a Link TRB. The maximum fill level
+ * is therefore
+ *
+ * ( ( 2^n + 1 ) - 1 (Link TRB) - 1 (one slot always empty)
+ * == ( 2^n - 1 )
+ *
+ * which is therefore equal to the ring mask.
+ */
+ assert ( fill <= ring->mask );
+ return ( ring->mask - fill );
+}
+
+/**
+ * Calculate physical address of most recently consumed TRB
+ *
+ * @v ring TRB ring
+ * @ret trb TRB physical address
+ */
+static inline __attribute__ (( always_inline )) physaddr_t
+xhci_ring_consumed ( struct xhci_trb_ring *ring ) {
+ unsigned int index = ( ( ring->cons - 1 ) & ring->mask );
+
+ return virt_to_phys ( &ring->trb[index] );
+}
+
+/** Slot context index */
+#define XHCI_CTX_SLOT 0
+
+/** Calculate context index from USB endpoint address */
+#define XHCI_CTX(address) \
+ ( (address) ? ( ( ( (address) & 0x0f ) << 1 ) | \
+ ( ( (address) & 0x80 ) >> 7 ) ) : 1 )
+
+/** Endpoint zero context index */
+#define XHCI_CTX_EP0 XHCI_CTX ( 0x00 )
+
+/** End of contexts */
+#define XHCI_CTX_END 32
+
+/** Device context index */
+#define XHCI_DCI(ctx) ( (ctx) + 0 )
+
+/** Input context index */
+#define XHCI_ICI(ctx) ( (ctx) + 1 )
+
+/** Number of TRBs (excluding Link TRB) in the command ring
+ *
+ * This is a policy decision.
+ */
+#define XHCI_CMD_TRBS_LOG2 2
+
+/** Number of TRBs in the event ring
+ *
+ * This is a policy decision.
+ */
+#define XHCI_EVENT_TRBS_LOG2 6
+
+/** Number of TRBs in a transfer ring
+ *
+ * This is a policy decision.
+ */
+#define XHCI_TRANSFER_TRBS_LOG2 6
+
+/** Maximum time to wait for BIOS to release ownership
+ *
+ * This is a policy decision.
+ */
+#define XHCI_USBLEGSUP_MAX_WAIT_MS 100
+
+/** Maximum time to wait for host controller to stop
+ *
+ * This is a policy decision.
+ */
+#define XHCI_STOP_MAX_WAIT_MS 100
+
+/** Maximum time to wait for reset to complete
+ *
+ * This is a policy decision.
+ */
+#define XHCI_RESET_MAX_WAIT_MS 500
+
+/** Maximum time to wait for a command to complete
+ *
+ * The "address device" command involves waiting for a response to a
+ * USB control transaction, and so we must wait for up to the 5000ms
+ * that USB allows for devices to respond to control transactions.
+ */
+#define XHCI_COMMAND_MAX_WAIT_MS USB_CONTROL_MAX_WAIT_MS
+
+/** Time to delay after aborting a command
+ *
+ * This is a policy decision
+ */
+#define XHCI_COMMAND_ABORT_DELAY_MS 500
+
+/** Maximum time to wait for a port reset to complete
+ *
+ * This is a policy decision.
+ */
+#define XHCI_PORT_RESET_MAX_WAIT_MS 500
+
+/** Intel PCH quirk */
+struct xhci_pch {
+ /** USB2 port routing register original value */
+ uint32_t xusb2pr;
+ /** USB3 port SuperSpeed enable register original value */
+ uint32_t usb3pssen;
+};
+
+/** Intel PCH quirk flag */
+#define XHCI_PCH 0x0001
+
+/** Intel PCH USB2 port routing register */
+#define XHCI_PCH_XUSB2PR 0xd0
+
+/** Intel PCH USB2 port routing mask register */
+#define XHCI_PCH_XUSB2PRM 0xd4
+
+/** Intel PCH SuperSpeed enable register */
+#define XHCI_PCH_USB3PSSEN 0xd8
+
+/** Intel PCH USB3 port routing mask register */
+#define XHCI_PCH_USB3PRM 0xdc
+
+/** Invalid protocol speed ID values quirk */
+#define XHCI_BAD_PSIV 0x0002
+
+/** An xHCI device */
+struct xhci_device {
+ /** Registers */
+ void *regs;
+ /** Name */
+ const char *name;
+ /** Quirks */
+ unsigned int quirks;
+
+ /** Capability registers */
+ void *cap;
+ /** Operational registers */
+ void *op;
+ /** Runtime registers */
+ void *run;
+ /** Doorbell registers */
+ void *db;
+
+ /** Number of device slots */
+ unsigned int slots;
+ /** Number of interrupters */
+ unsigned int intrs;
+ /** Number of ports */
+ unsigned int ports;
+
+ /** Number of page-sized scratchpad buffers */
+ unsigned int scratchpads;
+
+ /** 64-bit addressing capability */
+ int addr64;
+ /** Context size shift */
+ unsigned int csz_shift;
+ /** xHCI extended capabilities offset */
+ unsigned int xecp;
+
+ /** Page size */
+ size_t pagesize;
+
+ /** USB legacy support capability (if present and enabled) */
+ unsigned int legacy;
+
+ /** Device context base address array */
+ uint64_t *dcbaa;
+
+ /** Scratchpad buffer area */
+ userptr_t scratchpad;
+ /** Scratchpad buffer array */
+ uint64_t *scratchpad_array;
+
+ /** Command ring */
+ struct xhci_trb_ring command;
+ /** Event ring */
+ struct xhci_event_ring event;
+ /** Current command (if any) */
+ union xhci_trb *pending;
+
+ /** Device slots, indexed by slot ID */
+ struct xhci_slot **slot;
+
+ /** USB bus */
+ struct usb_bus *bus;
+
+ /** Intel PCH quirk */
+ struct xhci_pch pch;
+};
+
+/** An xHCI device slot */
+struct xhci_slot {
+ /** xHCI device */
+ struct xhci_device *xhci;
+ /** USB device */
+ struct usb_device *usb;
+ /** Slot ID */
+ unsigned int id;
+ /** Slot context */
+ struct xhci_slot_context *context;
+ /** Route string */
+ unsigned int route;
+ /** Root hub port number */
+ unsigned int port;
+ /** Protocol speed ID */
+ unsigned int psiv;
+ /** Number of ports (if this device is a hub) */
+ unsigned int ports;
+ /** Transaction translator slot ID */
+ unsigned int tt_id;
+ /** Transaction translator port */
+ unsigned int tt_port;
+ /** Endpoints, indexed by context ID */
+ struct xhci_endpoint *endpoint[XHCI_CTX_END];
+};
+
+/** An xHCI endpoint */
+struct xhci_endpoint {
+ /** xHCI device */
+ struct xhci_device *xhci;
+ /** xHCI slot */
+ struct xhci_slot *slot;
+ /** USB endpoint */
+ struct usb_endpoint *ep;
+ /** Context index */
+ unsigned int ctx;
+ /** Endpoint type */
+ unsigned int type;
+ /** Endpoint interval */
+ unsigned int interval;
+ /** Endpoint context */
+ struct xhci_endpoint_context *context;
+ /** Transfer ring */
+ struct xhci_trb_ring ring;
+};
+
+#endif /* _IPXE_XHCI_H */
diff --git a/roms/ipxe/src/hci/commands/autoboot_cmd.c b/roms/ipxe/src/hci/commands/autoboot_cmd.c
index 62235a278..56f39a1ce 100644
--- a/roms/ipxe/src/hci/commands/autoboot_cmd.c
+++ b/roms/ipxe/src/hci/commands/autoboot_cmd.c
@@ -15,6 +15,10 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
#include <stdio.h>
@@ -25,7 +29,7 @@
#include <hci/ifmgmt_cmd.h>
#include <usr/autoboot.h>
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/hci/commands/config_cmd.c b/roms/ipxe/src/hci/commands/config_cmd.c
index b81c866ff..ad415e045 100644
--- a/roms/ipxe/src/hci/commands/config_cmd.c
+++ b/roms/ipxe/src/hci/commands/config_cmd.c
@@ -15,6 +15,10 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
#include <string.h>
@@ -26,7 +30,7 @@
#include <ipxe/settings.h>
#include <ipxe/settings_ui.h>
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/hci/commands/console_cmd.c b/roms/ipxe/src/hci/commands/console_cmd.c
index d2eae59f0..ba472b9f6 100644
--- a/roms/ipxe/src/hci/commands/console_cmd.c
+++ b/roms/ipxe/src/hci/commands/console_cmd.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/hci/commands/dhcp_cmd.c b/roms/ipxe/src/hci/commands/dhcp_cmd.c
index feeb55ee5..45a922b51 100644
--- a/roms/ipxe/src/hci/commands/dhcp_cmd.c
+++ b/roms/ipxe/src/hci/commands/dhcp_cmd.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdio.h>
#include <stdint.h>
diff --git a/roms/ipxe/src/hci/commands/fcmgmt_cmd.c b/roms/ipxe/src/hci/commands/fcmgmt_cmd.c
index 1c199b5dc..97f10f4dd 100644
--- a/roms/ipxe/src/hci/commands/fcmgmt_cmd.c
+++ b/roms/ipxe/src/hci/commands/fcmgmt_cmd.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdio.h>
#include <errno.h>
diff --git a/roms/ipxe/src/hci/commands/gdbstub_cmd.c b/roms/ipxe/src/hci/commands/gdbstub_cmd.c
index 33890aebc..c4a831e7a 100644
--- a/roms/ipxe/src/hci/commands/gdbstub_cmd.c
+++ b/roms/ipxe/src/hci/commands/gdbstub_cmd.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdio.h>
#include <errno.h>
diff --git a/roms/ipxe/src/hci/commands/ifmgmt_cmd.c b/roms/ipxe/src/hci/commands/ifmgmt_cmd.c
index 5307c9423..c89af2e81 100644
--- a/roms/ipxe/src/hci/commands/ifmgmt_cmd.c
+++ b/roms/ipxe/src/hci/commands/ifmgmt_cmd.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdio.h>
#include <errno.h>
diff --git a/roms/ipxe/src/hci/commands/image_cmd.c b/roms/ipxe/src/hci/commands/image_cmd.c
index a9e831bf5..4a7c500a4 100644
--- a/roms/ipxe/src/hci/commands/image_cmd.c
+++ b/roms/ipxe/src/hci/commands/image_cmd.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/hci/commands/image_trust_cmd.c b/roms/ipxe/src/hci/commands/image_trust_cmd.c
index ca59a858a..f9d6b5b3e 100644
--- a/roms/ipxe/src/hci/commands/image_trust_cmd.c
+++ b/roms/ipxe/src/hci/commands/image_trust_cmd.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdio.h>
@@ -169,6 +173,9 @@ struct command image_trust_commands[] __command = {
},
};
+/* Drag in objects via command list */
+REQUIRING_SYMBOL ( image_trust_commands );
+
/* Drag in objects typically required for signature verification */
REQUIRE_OBJECT ( rsa );
REQUIRE_OBJECT ( md5 );
diff --git a/roms/ipxe/src/hci/commands/ipstat_cmd.c b/roms/ipxe/src/hci/commands/ipstat_cmd.c
index d565dc0ae..763e4dfd6 100644
--- a/roms/ipxe/src/hci/commands/ipstat_cmd.c
+++ b/roms/ipxe/src/hci/commands/ipstat_cmd.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdio.h>
#include <getopt.h>
diff --git a/roms/ipxe/src/hci/commands/login_cmd.c b/roms/ipxe/src/hci/commands/login_cmd.c
index f5db427d5..c9e196437 100644
--- a/roms/ipxe/src/hci/commands/login_cmd.c
+++ b/roms/ipxe/src/hci/commands/login_cmd.c
@@ -15,6 +15,10 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
#include <string.h>
@@ -23,7 +27,7 @@
#include <ipxe/parseopt.h>
#include <ipxe/login_ui.h>
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/hci/commands/lotest_cmd.c b/roms/ipxe/src/hci/commands/lotest_cmd.c
index 0fa031bcb..a989932d4 100644
--- a/roms/ipxe/src/hci/commands/lotest_cmd.c
+++ b/roms/ipxe/src/hci/commands/lotest_cmd.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdio.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/hci/commands/menu_cmd.c b/roms/ipxe/src/hci/commands/menu_cmd.c
index 66a6262e6..76bce8695 100644
--- a/roms/ipxe/src/hci/commands/menu_cmd.c
+++ b/roms/ipxe/src/hci/commands/menu_cmd.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/hci/commands/neighbour_cmd.c b/roms/ipxe/src/hci/commands/neighbour_cmd.c
index a1e052439..816e87357 100644
--- a/roms/ipxe/src/hci/commands/neighbour_cmd.c
+++ b/roms/ipxe/src/hci/commands/neighbour_cmd.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/hci/commands/nvo_cmd.c b/roms/ipxe/src/hci/commands/nvo_cmd.c
index e63dab08e..ac0d60651 100644
--- a/roms/ipxe/src/hci/commands/nvo_cmd.c
+++ b/roms/ipxe/src/hci/commands/nvo_cmd.c
@@ -15,6 +15,10 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
#include <stdint.h>
@@ -29,7 +33,7 @@
#include <ipxe/parseopt.h>
#include <readline/readline.h>
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/hci/commands/param_cmd.c b/roms/ipxe/src/hci/commands/param_cmd.c
index 6cf096d00..bff04f2ff 100644
--- a/roms/ipxe/src/hci/commands/param_cmd.c
+++ b/roms/ipxe/src/hci/commands/param_cmd.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/hci/commands/pci_cmd.c b/roms/ipxe/src/hci/commands/pci_cmd.c
index f5145fb35..a2a811aa0 100644
--- a/roms/ipxe/src/hci/commands/pci_cmd.c
+++ b/roms/ipxe/src/hci/commands/pci_cmd.c
@@ -15,6 +15,10 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
#include <stdio.h>
@@ -23,7 +27,7 @@
#include <ipxe/command.h>
#include <ipxe/parseopt.h>
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/hci/commands/ping_cmd.c b/roms/ipxe/src/hci/commands/ping_cmd.c
index 34807696f..ab271e75a 100644
--- a/roms/ipxe/src/hci/commands/ping_cmd.c
+++ b/roms/ipxe/src/hci/commands/ping_cmd.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/hci/commands/poweroff_cmd.c b/roms/ipxe/src/hci/commands/poweroff_cmd.c
index 9d487d330..afdf12dde 100644
--- a/roms/ipxe/src/hci/commands/poweroff_cmd.c
+++ b/roms/ipxe/src/hci/commands/poweroff_cmd.c
@@ -15,6 +15,10 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
#include <stdio.h>
@@ -24,7 +28,7 @@
#include <ipxe/parseopt.h>
#include <ipxe/reboot.h>
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/hci/commands/profstat_cmd.c b/roms/ipxe/src/hci/commands/profstat_cmd.c
index e4c9e5a24..dc6f649e3 100644
--- a/roms/ipxe/src/hci/commands/profstat_cmd.c
+++ b/roms/ipxe/src/hci/commands/profstat_cmd.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdio.h>
#include <getopt.h>
diff --git a/roms/ipxe/src/hci/commands/reboot_cmd.c b/roms/ipxe/src/hci/commands/reboot_cmd.c
index 485939e42..45d54cc2c 100644
--- a/roms/ipxe/src/hci/commands/reboot_cmd.c
+++ b/roms/ipxe/src/hci/commands/reboot_cmd.c
@@ -15,6 +15,10 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
#include <getopt.h>
@@ -22,7 +26,7 @@
#include <ipxe/parseopt.h>
#include <ipxe/reboot.h>
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/hci/commands/route_cmd.c b/roms/ipxe/src/hci/commands/route_cmd.c
index cc5ffc2f2..8aa535363 100644
--- a/roms/ipxe/src/hci/commands/route_cmd.c
+++ b/roms/ipxe/src/hci/commands/route_cmd.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdio.h>
#include <getopt.h>
diff --git a/roms/ipxe/src/hci/commands/sanboot_cmd.c b/roms/ipxe/src/hci/commands/sanboot_cmd.c
index 5954b6326..24ec8bc4e 100644
--- a/roms/ipxe/src/hci/commands/sanboot_cmd.c
+++ b/roms/ipxe/src/hci/commands/sanboot_cmd.c
@@ -15,6 +15,10 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
#include <stdio.h>
@@ -27,7 +31,7 @@
#include <ipxe/sanboot.h>
#include <usr/autoboot.h>
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/hci/commands/sync_cmd.c b/roms/ipxe/src/hci/commands/sync_cmd.c
index adf7e3cc6..54799d422 100644
--- a/roms/ipxe/src/hci/commands/sync_cmd.c
+++ b/roms/ipxe/src/hci/commands/sync_cmd.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <stdio.h>
diff --git a/roms/ipxe/src/hci/commands/vlan_cmd.c b/roms/ipxe/src/hci/commands/vlan_cmd.c
index 5d7298220..8a2f0c749 100644
--- a/roms/ipxe/src/hci/commands/vlan_cmd.c
+++ b/roms/ipxe/src/hci/commands/vlan_cmd.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdio.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/hci/editstring.c b/roms/ipxe/src/hci/editstring.c
index 5f6f04d51..8cbce0767 100644
--- a/roms/ipxe/src/hci/editstring.c
+++ b/roms/ipxe/src/hci/editstring.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <assert.h>
#include <string.h>
diff --git a/roms/ipxe/src/hci/jumpscroll.c b/roms/ipxe/src/hci/jumpscroll.c
new file mode 100644
index 000000000..dd6bcac2b
--- /dev/null
+++ b/roms/ipxe/src/hci/jumpscroll.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2015 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/**
+ * Jump scrolling
+ *
+ */
+
+#include <assert.h>
+#include <ipxe/keys.h>
+#include <ipxe/jumpscroll.h>
+
+/**
+ * Handle keypress
+ *
+ * @v scroll Jump scroller
+ * @v key Key pressed by user
+ * @ret move Scroller movement, or zero
+ */
+int jump_scroll_key ( struct jump_scroller *scroll, int key ) {
+
+ /* Sanity checks */
+ assert ( scroll->rows != 0 );
+ assert ( scroll->count != 0 );
+ assert ( scroll->current < scroll->count );
+ assert ( scroll->first < scroll->count );
+ assert ( scroll->first <= scroll->current );
+ assert ( scroll->current < ( scroll->first + scroll->rows ) );
+
+ /* Handle key, if applicable */
+ switch ( key ) {
+ case KEY_UP:
+ return -1;
+ case KEY_DOWN:
+ return +1;
+ case KEY_PPAGE:
+ return ( scroll->first - scroll->current - 1 );
+ case KEY_NPAGE:
+ return ( scroll->first - scroll->current + scroll->rows );
+ case KEY_HOME:
+ return -( scroll->count );
+ case KEY_END:
+ return +( scroll->count );
+ default:
+ return 0;
+ }
+}
+
+/**
+ * Move scroller
+ *
+ * @v scroll Jump scroller
+ * @v move Scroller movement
+ * @ret move Continuing scroller movement (if applicable)
+ */
+int jump_scroll_move ( struct jump_scroller *scroll, int move ) {
+ int current = scroll->current;
+ int last = ( scroll->count - 1 );
+
+ /* Sanity checks */
+ assert ( move != 0 );
+ assert ( scroll->count != 0 );
+
+ /* Move to the new current item */
+ current += move;
+
+ /* Check for start/end of list */
+ if ( current < 0 ) {
+ /* We have attempted to move before the start of the
+ * list. Move to the start of the list and continue
+ * moving forwards (if applicable).
+ */
+ scroll->current = 0;
+ return +1;
+ } else if ( current > last ) {
+ /* We have attempted to move after the end of the
+ * list. Move to the end of the list and continue
+ * moving backwards (if applicable).
+ */
+ scroll->current = last;
+ return -1;
+ } else {
+ /* Update the current item and continue moving in the
+ * same direction (if applicable).
+ */
+ scroll->current = current;
+ return ( ( move > 0 ) ? +1 : -1 );
+ }
+}
+
+/**
+ * Jump scroll to new page (if applicable)
+ *
+ * @v scroll Jump scroller
+ * @ret jumped Jumped to a new page
+ */
+int jump_scroll ( struct jump_scroller *scroll ) {
+ unsigned int index;
+
+ /* Sanity checks */
+ assert ( scroll->rows != 0 );
+ assert ( scroll->count != 0 );
+ assert ( scroll->current < scroll->count );
+ assert ( scroll->first < scroll->count );
+
+ /* Do nothing if we are already on the correct page */
+ index = ( scroll->current - scroll->first );
+ if ( index < scroll->rows )
+ return 0;
+
+ /* Move to required page */
+ while ( scroll->first < scroll->current )
+ scroll->first += scroll->rows;
+ while ( scroll->first > scroll->current )
+ scroll->first -= scroll->rows;
+
+ return 1;
+}
diff --git a/roms/ipxe/src/hci/mucurses/alert.c b/roms/ipxe/src/hci/mucurses/alert.c
index 00e959a89..7dc61c222 100644
--- a/roms/ipxe/src/hci/mucurses/alert.c
+++ b/roms/ipxe/src/hci/mucurses/alert.c
@@ -7,6 +7,8 @@
*
*/
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
/**
* Audible signal
*
diff --git a/roms/ipxe/src/hci/mucurses/ansi_screen.c b/roms/ipxe/src/hci/mucurses/ansi_screen.c
index 1d3143f89..1cf3309dd 100644
--- a/roms/ipxe/src/hci/mucurses/ansi_screen.c
+++ b/roms/ipxe/src/hci/mucurses/ansi_screen.c
@@ -3,7 +3,7 @@
#include <ipxe/ansicol.h>
#include <ipxe/console.h>
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
static void ansiscr_reset(struct _curses_screen *scr) __nonnull;
static void ansiscr_movetoyx(struct _curses_screen *scr,
diff --git a/roms/ipxe/src/hci/mucurses/clear.c b/roms/ipxe/src/hci/mucurses/clear.c
index f5e52ca20..2054f72cc 100644
--- a/roms/ipxe/src/hci/mucurses/clear.c
+++ b/roms/ipxe/src/hci/mucurses/clear.c
@@ -8,7 +8,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* Clear a window to the bottom from current cursor position
diff --git a/roms/ipxe/src/hci/mucurses/colour.c b/roms/ipxe/src/hci/mucurses/colour.c
index c1359c868..b0c480b1f 100644
--- a/roms/ipxe/src/hci/mucurses/colour.c
+++ b/roms/ipxe/src/hci/mucurses/colour.c
@@ -1,6 +1,6 @@
#include <curses.h>
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
struct colour_pair {
short fcol;
diff --git a/roms/ipxe/src/hci/mucurses/cursor.h b/roms/ipxe/src/hci/mucurses/cursor.h
index 16b7d27c2..2e0c896a6 100644
--- a/roms/ipxe/src/hci/mucurses/cursor.h
+++ b/roms/ipxe/src/hci/mucurses/cursor.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
struct cursor_pos {
unsigned int y, x;
diff --git a/roms/ipxe/src/hci/mucurses/edging.c b/roms/ipxe/src/hci/mucurses/edging.c
index eccd32422..e938d338b 100644
--- a/roms/ipxe/src/hci/mucurses/edging.c
+++ b/roms/ipxe/src/hci/mucurses/edging.c
@@ -8,6 +8,8 @@
*
*/
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
/**
* Draw borders from single-byte characters and renditions around a
* window
diff --git a/roms/ipxe/src/hci/mucurses/kb.c b/roms/ipxe/src/hci/mucurses/kb.c
index b38c8c146..8face14d8 100644
--- a/roms/ipxe/src/hci/mucurses/kb.c
+++ b/roms/ipxe/src/hci/mucurses/kb.c
@@ -8,6 +8,8 @@
* MuCurses keyboard input handling functions
*/
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
#define INPUT_DELAY 200 // half-blocking delay timer resolution (ms)
#define INPUT_DELAY_TIMEOUT 1000 // half-blocking delay timeout
diff --git a/roms/ipxe/src/hci/mucurses/mucurses.c b/roms/ipxe/src/hci/mucurses/mucurses.c
index b67445baf..98a8a2c59 100644
--- a/roms/ipxe/src/hci/mucurses/mucurses.c
+++ b/roms/ipxe/src/hci/mucurses/mucurses.c
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
static void _wupdcurs ( WINDOW *win ) __nonnull;
void _wputch ( WINDOW *win, chtype ch, int wrap ) __nonnull;
diff --git a/roms/ipxe/src/hci/mucurses/mucurses.h b/roms/ipxe/src/hci/mucurses/mucurses.h
index 7ac1086ac..270394787 100644
--- a/roms/ipxe/src/hci/mucurses/mucurses.h
+++ b/roms/ipxe/src/hci/mucurses/mucurses.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define WRAP 0
#define NOWRAP 1
diff --git a/roms/ipxe/src/hci/mucurses/print.c b/roms/ipxe/src/hci/mucurses/print.c
index 9c682588b..e8831c58f 100644
--- a/roms/ipxe/src/hci/mucurses/print.c
+++ b/roms/ipxe/src/hci/mucurses/print.c
@@ -10,7 +10,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* Add a single-byte character and rendition to a window and advance
diff --git a/roms/ipxe/src/hci/mucurses/print_nadv.c b/roms/ipxe/src/hci/mucurses/print_nadv.c
index ee472e685..3a44e5bd2 100644
--- a/roms/ipxe/src/hci/mucurses/print_nadv.c
+++ b/roms/ipxe/src/hci/mucurses/print_nadv.c
@@ -8,6 +8,8 @@
*
*/
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
/**
* Add string of single-byte characters and renditions to a window
*
diff --git a/roms/ipxe/src/hci/mucurses/slk.c b/roms/ipxe/src/hci/mucurses/slk.c
index 600658e75..660eb65c0 100644
--- a/roms/ipxe/src/hci/mucurses/slk.c
+++ b/roms/ipxe/src/hci/mucurses/slk.c
@@ -11,6 +11,8 @@
* Soft label key functions
*/
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
#define MIN_SPACE_SIZE 2
#define SLK_MAX_LABEL_LEN 8
diff --git a/roms/ipxe/src/hci/mucurses/widgets/editbox.c b/roms/ipxe/src/hci/mucurses/widgets/editbox.c
index 630a66e0b..210de4481 100644
--- a/roms/ipxe/src/hci/mucurses/widgets/editbox.c
+++ b/roms/ipxe/src/hci/mucurses/widgets/editbox.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <assert.h>
diff --git a/roms/ipxe/src/hci/mucurses/winattrs.c b/roms/ipxe/src/hci/mucurses/winattrs.c
index f549d7519..97a5a18b3 100644
--- a/roms/ipxe/src/hci/mucurses/winattrs.c
+++ b/roms/ipxe/src/hci/mucurses/winattrs.c
@@ -6,7 +6,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* Get the background rendition attributes for a window
diff --git a/roms/ipxe/src/hci/mucurses/windows.c b/roms/ipxe/src/hci/mucurses/windows.c
index 63d0af08c..7f39bdea2 100644
--- a/roms/ipxe/src/hci/mucurses/windows.c
+++ b/roms/ipxe/src/hci/mucurses/windows.c
@@ -9,6 +9,8 @@
*
*/
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
/**
* Delete a window
*
diff --git a/roms/ipxe/src/hci/mucurses/wininit.c b/roms/ipxe/src/hci/mucurses/wininit.c
index b75abba44..dd84d2f1d 100644
--- a/roms/ipxe/src/hci/mucurses/wininit.c
+++ b/roms/ipxe/src/hci/mucurses/wininit.c
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* Initialise console environment
diff --git a/roms/ipxe/src/hci/readline.c b/roms/ipxe/src/hci/readline.c
index 40aa59787..83a2e0b90 100644
--- a/roms/ipxe/src/hci/readline.c
+++ b/roms/ipxe/src/hci/readline.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdio.h>
#include <string.h>
diff --git a/roms/ipxe/src/hci/shell.c b/roms/ipxe/src/hci/shell.c
index c1a543849..276eb3527 100644
--- a/roms/ipxe/src/hci/shell.c
+++ b/roms/ipxe/src/hci/shell.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
@@ -28,6 +32,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/command.h>
#include <ipxe/parseopt.h>
#include <ipxe/shell.h>
+#include <config/branding.h>
/** @file
*
@@ -36,7 +41,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
*/
/** The shell prompt string */
-static const char shell_prompt[] = "iPXE> ";
+static const char shell_prompt[] = PRODUCT_SHORT_NAME "> ";
/**
* "help" command
diff --git a/roms/ipxe/src/hci/strerror.c b/roms/ipxe/src/hci/strerror.c
index 9356e9e0a..1bba8c620 100644
--- a/roms/ipxe/src/hci/strerror.c
+++ b/roms/ipxe/src/hci/strerror.c
@@ -2,6 +2,7 @@
#include <string.h>
#include <stdio.h>
#include <ipxe/errortab.h>
+#include <config/branding.h>
/** @file
*
@@ -18,7 +19,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* Find error description
@@ -74,7 +75,7 @@ static struct errortab * find_closest_error ( int errno ) {
* call to strerror().
*
*/
-const char * strerror ( int errno ) {
+char * strerror ( int errno ) {
static char errbuf[64];
struct errortab *errortab;
@@ -88,11 +89,11 @@ const char * strerror ( int errno ) {
/* Construct the error message */
if ( errortab ) {
snprintf ( errbuf, sizeof ( errbuf ),
- "%s (http://ipxe.org/%08x)",
+ "%s (" PRODUCT_ERROR_URI ")",
errortab->text, errno );
} else {
snprintf ( errbuf, sizeof ( errbuf ),
- "Error %#08x (http://ipxe.org/%08x)",
+ "Error %#08x (" PRODUCT_ERROR_URI ")",
errno, errno );
}
diff --git a/roms/ipxe/src/hci/tui/login_ui.c b/roms/ipxe/src/hci/tui/login_ui.c
index 996b68a0a..3c55325d5 100644
--- a/roms/ipxe/src/hci/tui/login_ui.c
+++ b/roms/ipxe/src/hci/tui/login_ui.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/hci/tui/menu_ui.c b/roms/ipxe/src/hci/tui/menu_ui.c
index 0a9566def..f9dd9d100 100644
--- a/roms/ipxe/src/hci/tui/menu_ui.c
+++ b/roms/ipxe/src/hci/tui/menu_ui.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
@@ -32,6 +36,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/timer.h>
#include <ipxe/console.h>
#include <ipxe/ansicol.h>
+#include <ipxe/jumpscroll.h>
#include <ipxe/menu.h>
/* Screen layout */
@@ -46,12 +51,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
struct menu_ui {
/** Menu */
struct menu *menu;
- /** Number of menu items */
- unsigned int count;
- /** Currently selected item */
- int selected;
- /** First visible item */
- int first_visible;
+ /** Jump scroller */
+ struct jump_scroller scroll;
/** Timeout (0=indefinite) */
unsigned long timeout;
};
@@ -80,7 +81,7 @@ static struct menu_item * menu_item ( struct menu *menu, unsigned int index ) {
* @v ui Menu user interface
* @v index Index
*/
-static void draw_menu_item ( struct menu_ui *ui, int index ) {
+static void draw_menu_item ( struct menu_ui *ui, unsigned int index ) {
struct menu_item *item;
unsigned int row_offset;
char buf[ MENU_COLS + 1 /* NUL */ ];
@@ -90,7 +91,7 @@ static void draw_menu_item ( struct menu_ui *ui, int index ) {
size_t len;
/* Move to start of row */
- row_offset = ( index - ui->first_visible );
+ row_offset = ( index - ui->scroll.first );
move ( ( MENU_ROW + row_offset ), MENU_COL );
/* Get menu item */
@@ -102,7 +103,7 @@ static void draw_menu_item ( struct menu_ui *ui, int index ) {
color_set ( CPAIR_SEPARATOR, NULL );
/* Highlight if this is the selected item */
- if ( index == ui->selected ) {
+ if ( index == ui->scroll.current ) {
color_set ( CPAIR_SELECT, NULL );
attron ( A_BOLD );
}
@@ -121,7 +122,7 @@ static void draw_menu_item ( struct menu_ui *ui, int index ) {
snprintf ( timeout_buf, sizeof ( timeout_buf ), "(%ld)",
( ( ui->timeout + TICKS_PER_SEC - 1 ) /
TICKS_PER_SEC ) );
- if ( ( index == ui->selected ) && ( ui->timeout != 0 ) ) {
+ if ( ( index == ui->scroll.current ) && ( ui->timeout != 0 ) ) {
memcpy ( ( buf + MENU_COLS - MENU_PAD - timeout_len ),
timeout_buf, timeout_len );
}
@@ -150,24 +151,17 @@ static void draw_menu_item ( struct menu_ui *ui, int index ) {
static void draw_menu_items ( struct menu_ui *ui ) {
unsigned int i;
- /* Jump scroll to correct point in list */
- while ( ui->first_visible < ui->selected )
- ui->first_visible += MENU_ROWS;
- while ( ui->first_visible > ui->selected )
- ui->first_visible -= MENU_ROWS;
-
/* Draw ellipses before and/or after the list as necessary */
color_set ( CPAIR_SEPARATOR, NULL );
mvaddstr ( ( MENU_ROW - 1 ), ( MENU_COL + MENU_PAD ),
- ( ( ui->first_visible > 0 ) ? "..." : " " ) );
+ ( jump_scroll_is_first ( &ui->scroll ) ? " " : "..." ) );
mvaddstr ( ( MENU_ROW + MENU_ROWS ), ( MENU_COL + MENU_PAD ),
- ( ( ( ui->first_visible + MENU_ROWS ) < ui->count ) ?
- "..." : " " ) );
+ ( jump_scroll_is_last ( &ui->scroll ) ? " " : "..." ) );
color_set ( CPAIR_NORMAL, NULL );
/* Draw visible items */
for ( i = 0 ; i < MENU_ROWS ; i++ )
- draw_menu_item ( ui, ( ui->first_visible + i ) );
+ draw_menu_item ( ui, ( ui->scroll.first + i ) );
}
/**
@@ -180,8 +174,7 @@ static void draw_menu_items ( struct menu_ui *ui ) {
static int menu_loop ( struct menu_ui *ui, struct menu_item **selected ) {
struct menu_item *item;
unsigned long timeout;
- unsigned int delta;
- int current;
+ unsigned int previous;
int key;
int i;
int move;
@@ -190,7 +183,7 @@ static int menu_loop ( struct menu_ui *ui, struct menu_item **selected ) {
do {
/* Record current selection */
- current = ui->selected;
+ previous = ui->scroll.current;
/* Calculate timeout as remainder of current second */
timeout = ( ui->timeout % TICKS_PER_SEC );
@@ -209,27 +202,11 @@ static int menu_loop ( struct menu_ui *ui, struct menu_item **selected ) {
/* Cancel any timeout */
ui->timeout = 0;
- /* Handle key */
+ /* Handle scroll keys */
+ move = jump_scroll_key ( &ui->scroll, key );
+
+ /* Handle other keys */
switch ( key ) {
- case KEY_UP:
- move = -1;
- break;
- case KEY_DOWN:
- move = +1;
- break;
- case KEY_PPAGE:
- move = ( ui->first_visible - ui->selected - 1 );
- break;
- case KEY_NPAGE:
- move = ( ui->first_visible - ui->selected
- + MENU_ROWS );
- break;
- case KEY_HOME:
- move = -ui->count;
- break;
- case KEY_END:
- move = +ui->count;
- break;
case ESC:
case CTRL_C:
rc = -ECANCELED;
@@ -247,7 +224,7 @@ static int menu_loop ( struct menu_ui *ui, struct menu_item **selected ) {
i++;
continue;
}
- ui->selected = i;
+ ui->scroll.current = i;
if ( item->label ) {
chosen = 1;
} else {
@@ -260,31 +237,22 @@ static int menu_loop ( struct menu_ui *ui, struct menu_item **selected ) {
/* Move selection, if applicable */
while ( move ) {
- ui->selected += move;
- if ( ui->selected < 0 ) {
- ui->selected = 0;
- move = +1;
- } else if ( ui->selected >= ( int ) ui->count ) {
- ui->selected = ( ui->count - 1 );
- move = -1;
- }
- item = menu_item ( ui->menu, ui->selected );
+ move = jump_scroll_move ( &ui->scroll, move );
+ item = menu_item ( ui->menu, ui->scroll.current );
if ( item->label )
break;
- move = ( ( move > 0 ) ? +1 : -1 );
}
/* Redraw selection if necessary */
- if ( ( ui->selected != current ) || ( timeout != 0 ) ) {
- draw_menu_item ( ui, current );
- delta = ( ui->selected - ui->first_visible );
- if ( delta >= MENU_ROWS )
+ if ( ( ui->scroll.current != previous ) || ( timeout != 0 ) ) {
+ draw_menu_item ( ui, previous );
+ if ( jump_scroll ( &ui->scroll ) )
draw_menu_items ( ui );
- draw_menu_item ( ui, ui->selected );
+ draw_menu_item ( ui, ui->scroll.current );
}
/* Record selection */
- item = menu_item ( ui->menu, ui->selected );
+ item = menu_item ( ui->menu, ui->scroll.current );
assert ( item != NULL );
assert ( item->label != NULL );
*selected = item;
@@ -313,21 +281,22 @@ int show_menu ( struct menu *menu, unsigned long timeout,
/* Initialise UI */
memset ( &ui, 0, sizeof ( ui ) );
ui.menu = menu;
+ ui.scroll.rows = MENU_ROWS;
ui.timeout = timeout;
list_for_each_entry ( item, &menu->items, list ) {
if ( item->label ) {
if ( ! labelled_count )
- ui.selected = ui.count;
+ ui.scroll.current = ui.scroll.count;
labelled_count++;
if ( select ) {
if ( strcmp ( select, item->label ) == 0 )
- ui.selected = ui.count;
+ ui.scroll.current = ui.scroll.count;
} else {
if ( item->is_default )
- ui.selected = ui.count;
+ ui.scroll.current = ui.scroll.count;
}
}
- ui.count++;
+ ui.scroll.count++;
}
if ( ! labelled_count ) {
/* Menus with no labelled items cannot be selected
@@ -349,8 +318,9 @@ int show_menu ( struct menu *menu, unsigned long timeout,
snprintf ( buf, sizeof ( buf ), "%s", ui.menu->title );
mvprintw ( TITLE_ROW, ( ( COLS - strlen ( buf ) ) / 2 ), "%s", buf );
attroff ( A_BOLD );
+ jump_scroll ( &ui.scroll );
draw_menu_items ( &ui );
- draw_menu_item ( &ui, ui.selected );
+ draw_menu_item ( &ui, ui.scroll.current );
/* Enter main loop */
rc = menu_loop ( &ui, selected );
diff --git a/roms/ipxe/src/hci/tui/settings_ui.c b/roms/ipxe/src/hci/tui/settings_ui.c
index 221839730..be421cc0a 100644
--- a/roms/ipxe/src/hci/tui/settings_ui.c
+++ b/roms/ipxe/src/hci/tui/settings_ui.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdio.h>
#include <stdarg.h>
@@ -29,7 +33,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/editbox.h>
#include <ipxe/keys.h>
#include <ipxe/ansicol.h>
+#include <ipxe/jumpscroll.h>
#include <ipxe/settings_ui.h>
+#include <config/branding.h>
/** @file
*
@@ -47,7 +53,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define INSTRUCTION_ROW ( LINES - 2U )
#define INSTRUCTION_PAD " "
-/** Layout of text within a setting widget */
+/** Layout of text within a setting row */
#define SETTING_ROW_TEXT( cols ) struct { \
char start[0]; \
char pad1[1]; \
@@ -63,8 +69,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
char nul; \
} __attribute__ (( packed ))
-/** A setting row widget */
-struct setting_row_widget {
+/** A settings user interface row */
+struct settings_ui_row {
/** Target configuration settings block
*
* Valid only for rows that lead to new settings blocks.
@@ -82,8 +88,6 @@ struct setting_row_widget {
struct setting setting;
/** Screen row */
unsigned int row;
- /** Screen column */
- unsigned int col;
/** Edit box widget used for editing setting */
struct edit_box editbox;
/** Editing in progress flag */
@@ -92,28 +96,24 @@ struct setting_row_widget {
char value[256]; /* enough size for a DHCP string */
};
-/** A settings widget */
-struct setting_widget {
+/** A settings user interface */
+struct settings_ui {
/** Settings block */
struct settings *settings;
- /** Number of rows */
- unsigned int num_rows;
- /** Current row index */
- unsigned int current;
- /** Index of the first visible row, for scrolling. */
- unsigned int first_visible;
- /** Active row */
- struct setting_row_widget row;
+ /** Jump scroller */
+ struct jump_scroller scroll;
+ /** Current row */
+ struct settings_ui_row row;
};
/**
- * Select a setting row
+ * Select a setting
*
- * @v widget Setting widget
+ * @v ui Settings user interface
* @v index Index of setting row
- * @ret count Number of settings rows
+ * @ret count Number of setting rows
*/
-static unsigned int select_setting_row ( struct setting_widget *widget,
+static unsigned int select_setting_row ( struct settings_ui *ui,
unsigned int index ) {
SETTING_ROW_TEXT ( COLS ) *text;
struct settings *settings;
@@ -122,25 +122,22 @@ static unsigned int select_setting_row ( struct setting_widget *widget,
unsigned int count = 0;
/* Initialise structure */
- memset ( &widget->row, 0, sizeof ( widget->row ) );
- widget->current = index;
- widget->row.row = ( SETTINGS_LIST_ROW + index - widget->first_visible );
- widget->row.col = SETTINGS_LIST_COL;
+ memset ( &ui->row, 0, sizeof ( ui->row ) );
+ ui->row.row = ( SETTINGS_LIST_ROW + index - ui->scroll.first );
/* Include parent settings block, if applicable */
- if ( widget->settings->parent && ( count++ == index ) ) {
- widget->row.settings = widget->settings->parent;
- snprintf ( widget->row.value, sizeof ( widget->row.value ),
+ if ( ui->settings->parent && ( count++ == index ) ) {
+ ui->row.settings = ui->settings->parent;
+ snprintf ( ui->row.value, sizeof ( ui->row.value ),
"../" );
}
/* Include any child settings blocks, if applicable */
- list_for_each_entry ( settings, &widget->settings->children, siblings ){
+ list_for_each_entry ( settings, &ui->settings->children, siblings ) {
if ( count++ == index ) {
- widget->row.settings = settings;
- snprintf ( widget->row.value,
- sizeof ( widget->row.value ), "%s/",
- settings->name );
+ ui->row.settings = settings;
+ snprintf ( ui->row.value, sizeof ( ui->row.value ),
+ "%s/", settings->name );
}
}
@@ -148,7 +145,7 @@ static unsigned int select_setting_row ( struct setting_widget *widget,
for_each_table_entry ( setting, SETTINGS ) {
/* Skip inapplicable settings */
- if ( ! setting_applies ( widget->settings, setting ) )
+ if ( ! setting_applies ( ui->settings, setting ) )
continue;
/* Skip duplicate settings */
@@ -158,18 +155,16 @@ static unsigned int select_setting_row ( struct setting_widget *widget,
/* Read current setting value and origin */
if ( count++ == index ) {
- fetchf_setting ( widget->settings, setting,
- &widget->row.origin,
- &widget->row.setting,
- widget->row.value,
- sizeof ( widget->row.value ) );
+ fetchf_setting ( ui->settings, setting, &ui->row.origin,
+ &ui->row.setting, ui->row.value,
+ sizeof ( ui->row.value ) );
}
}
/* Initialise edit box */
- init_editbox ( &widget->row.editbox, widget->row.value,
- sizeof ( widget->row.value ), NULL, widget->row.row,
- ( widget->row.col +
+ init_editbox ( &ui->row.editbox, ui->row.value,
+ sizeof ( ui->row.value ), NULL, ui->row.row,
+ ( SETTINGS_LIST_COL +
offsetof ( typeof ( *text ), u.setting.value ) ),
sizeof ( text->u.setting.value ), 0 );
@@ -197,9 +192,9 @@ static size_t string_copy ( char *dest, const char *src, size_t len ) {
/**
* Draw setting row
*
- * @v widget Setting widget
+ * @v ui Settings UI
*/
-static void draw_setting_row ( struct setting_widget *widget ) {
+static void draw_setting_row ( struct settings_ui *ui ) {
SETTING_ROW_TEXT ( COLS ) text;
unsigned int curs_offset;
char *value;
@@ -209,12 +204,12 @@ static void draw_setting_row ( struct setting_widget *widget ) {
text.nul = '\0';
/* Construct row content */
- if ( widget->row.settings ) {
+ if ( ui->row.settings ) {
/* Construct space-padded name */
curs_offset = ( offsetof ( typeof ( text ), u.settings ) +
string_copy ( text.u.settings,
- widget->row.value,
+ ui->row.value,
sizeof ( text.u.settings ) ) );
} else {
@@ -222,11 +217,11 @@ static void draw_setting_row ( struct setting_widget *widget ) {
/* Construct dot-padded name */
memset ( text.u.setting.name, '.',
sizeof ( text.u.setting.name ) );
- string_copy ( text.u.setting.name, widget->row.setting.name,
+ string_copy ( text.u.setting.name, ui->row.setting.name,
sizeof ( text.u.setting.name ) );
/* Construct space-padded value */
- value = widget->row.value;
+ value = ui->row.value;
if ( ! *value )
value = "<not specified>";
curs_offset = ( offsetof ( typeof ( text ), u.setting.value ) +
@@ -235,37 +230,34 @@ static void draw_setting_row ( struct setting_widget *widget ) {
}
/* Print row */
- if ( ( widget->row.origin == widget->settings ) ||
- ( widget->row.settings != NULL ) ) {
+ if ( ( ui->row.origin == ui->settings ) || ( ui->row.settings != NULL ))
attron ( A_BOLD );
- }
- mvprintw ( widget->row.row, widget->row.col, "%s", text.start );
+ mvprintw ( ui->row.row, SETTINGS_LIST_COL, "%s", text.start );
attroff ( A_BOLD );
- move ( widget->row.row, widget->row.col + curs_offset );
+ move ( ui->row.row, ( SETTINGS_LIST_COL + curs_offset ) );
}
/**
- * Edit setting widget
+ * Edit setting ui
*
- * @v widget Setting widget
+ * @v ui Settings UI
* @v key Key pressed by user
* @ret key Key returned to application, or zero
*/
-static int edit_setting ( struct setting_widget *widget, int key ) {
- assert ( widget->row.setting.name != NULL );
- widget->row.editing = 1;
- return edit_editbox ( &widget->row.editbox, key );
+static int edit_setting ( struct settings_ui *ui, int key ) {
+ assert ( ui->row.setting.name != NULL );
+ ui->row.editing = 1;
+ return edit_editbox ( &ui->row.editbox, key );
}
/**
- * Save setting widget value back to configuration settings
+ * Save setting ui value back to configuration settings
*
- * @v widget Setting widget
+ * @v ui Settings UI
*/
-static int save_setting ( struct setting_widget *widget ) {
- assert ( widget->row.setting.name != NULL );
- return storef_setting ( widget->settings, &widget->row.setting,
- widget->row.value );
+static int save_setting ( struct settings_ui *ui ) {
+ assert ( ui->row.setting.name != NULL );
+ return storef_setting ( ui->settings, &ui->row.setting, ui->row.value );
}
/**
@@ -340,15 +332,15 @@ static void alert ( const char *fmt, ... ) {
/**
* Draw title row
*
- * @v widget Setting widget
+ * @v ui Settings UI
*/
-static void draw_title_row ( struct setting_widget *widget ) {
+static void draw_title_row ( struct settings_ui *ui ) {
const char *name;
clearmsg ( TITLE_ROW );
- name = settings_name ( widget->settings );
+ name = settings_name ( ui->settings );
attron ( A_BOLD );
- msg ( TITLE_ROW, "iPXE configuration settings%s%s",
+ msg ( TITLE_ROW, PRODUCT_SHORT_NAME " configuration settings%s%s",
( name[0] ? " - " : "" ), name );
attroff ( A_BOLD );
}
@@ -356,89 +348,73 @@ static void draw_title_row ( struct setting_widget *widget ) {
/**
* Draw information row
*
- * @v widget Setting widget
+ * @v ui Settings UI
*/
-static void draw_info_row ( struct setting_widget *widget ) {
+static void draw_info_row ( struct settings_ui *ui ) {
char buf[32];
/* Draw nothing unless this row represents a setting */
clearmsg ( INFO_ROW );
clearmsg ( INFO_ROW + 1 );
- if ( ! widget->row.setting.name )
+ if ( ! ui->row.setting.name )
return;
/* Determine a suitable setting name */
- setting_name ( ( widget->row.origin ?
- widget->row.origin : widget->settings ),
- &widget->row.setting, buf, sizeof ( buf ) );
+ setting_name ( ( ui->row.origin ?
+ ui->row.origin : ui->settings ),
+ &ui->row.setting, buf, sizeof ( buf ) );
/* Draw row */
attron ( A_BOLD );
- msg ( INFO_ROW, "%s - %s", buf, widget->row.setting.description );
+ msg ( INFO_ROW, "%s - %s", buf, ui->row.setting.description );
attroff ( A_BOLD );
color_set ( CPAIR_URL, NULL );
- msg ( ( INFO_ROW + 1 ), "http://ipxe.org/cfg/%s",
- widget->row.setting.name );
+ msg ( ( INFO_ROW + 1 ), PRODUCT_SETTING_URI, ui->row.setting.name );
color_set ( CPAIR_NORMAL, NULL );
}
/**
* Draw instruction row
*
- * @v widget Setting widget
+ * @v ui Settings UI
*/
-static void draw_instruction_row ( struct setting_widget *widget ) {
+static void draw_instruction_row ( struct settings_ui *ui ) {
clearmsg ( INSTRUCTION_ROW );
- if ( widget->row.editing ) {
+ if ( ui->row.editing ) {
msg ( INSTRUCTION_ROW,
"Enter - accept changes" INSTRUCTION_PAD
"Ctrl-C - discard changes" );
} else {
msg ( INSTRUCTION_ROW,
"%sCtrl-X - exit configuration utility",
- ( ( widget->row.origin == widget->settings ) ?
+ ( ( ui->row.origin == ui->settings ) ?
"Ctrl-D - delete setting" INSTRUCTION_PAD : "" ) );
}
}
/**
- * Reveal setting row
+ * Draw the current block of setting rows
*
- * @v widget Setting widget
- * @v index Index of setting row
+ * @v ui Settings UI
*/
-static void reveal_setting_row ( struct setting_widget *widget,
- unsigned int index ) {
+static void draw_setting_rows ( struct settings_ui *ui ) {
unsigned int i;
- /* Simply return if setting N is already on-screen. */
- if ( index - widget->first_visible < SETTINGS_LIST_ROWS )
- return;
-
- /* Jump scroll to make the specified setting row visible. */
- while ( widget->first_visible < index )
- widget->first_visible += SETTINGS_LIST_ROWS;
- while ( widget->first_visible > index )
- widget->first_visible -= SETTINGS_LIST_ROWS;
-
- /* Draw ellipses before and/or after the settings list to
- * represent any invisible settings.
- */
- mvaddstr ( SETTINGS_LIST_ROW - 1,
- SETTINGS_LIST_COL + 1,
- widget->first_visible > 0 ? "..." : " " );
- mvaddstr ( SETTINGS_LIST_ROW + SETTINGS_LIST_ROWS,
- SETTINGS_LIST_COL + 1,
- ( ( widget->first_visible + SETTINGS_LIST_ROWS )
- < widget->num_rows ? "..." : " " ) );
+ /* Draw ellipses before and/or after the list as necessary */
+ color_set ( CPAIR_SEPARATOR, NULL );
+ mvaddstr ( ( SETTINGS_LIST_ROW - 1 ), ( SETTINGS_LIST_COL + 1 ),
+ jump_scroll_is_first ( &ui->scroll ) ? " " : "..." );
+ mvaddstr ( ( SETTINGS_LIST_ROW + SETTINGS_LIST_ROWS ),
+ ( SETTINGS_LIST_COL + 1 ),
+ jump_scroll_is_last ( &ui->scroll ) ? " " : "..." );
+ color_set ( CPAIR_NORMAL, NULL );
/* Draw visible settings. */
- for ( i = 0; i < SETTINGS_LIST_ROWS; i++ ) {
- if ( ( widget->first_visible + i ) < widget->num_rows ) {
- select_setting_row ( widget,
- widget->first_visible + i );
- draw_setting_row ( widget );
+ for ( i = 0 ; i < SETTINGS_LIST_ROWS ; i++ ) {
+ if ( ( ui->scroll.first + i ) < ui->scroll.count ) {
+ select_setting_row ( ui, ( ui->scroll.first + i ) );
+ draw_setting_row ( ui );
} else {
clearmsg ( SETTINGS_LIST_ROW + i );
}
@@ -446,69 +422,72 @@ static void reveal_setting_row ( struct setting_widget *widget,
}
/**
- * Reveal setting row
+ * Select settings block
*
- * @v widget Setting widget
+ * @v ui Settings UI
* @v settings Settings block
*/
-static void init_widget ( struct setting_widget *widget,
- struct settings *settings ) {
-
- widget->settings = settings_target ( settings );
- widget->num_rows = select_setting_row ( widget, 0 );
- widget->first_visible = SETTINGS_LIST_ROWS;
- draw_title_row ( widget );
- reveal_setting_row ( widget, 0 );
- select_setting_row ( widget, 0 );
+static void select_settings ( struct settings_ui *ui,
+ struct settings *settings ) {
+
+ ui->settings = settings_target ( settings );
+ ui->scroll.count = select_setting_row ( ui, 0 );
+ ui->scroll.rows = SETTINGS_LIST_ROWS;
+ ui->scroll.current = 0;
+ ui->scroll.first = 0;
+ draw_title_row ( ui );
+ draw_setting_rows ( ui );
+ select_setting_row ( ui, 0 );
}
static int main_loop ( struct settings *settings ) {
- struct setting_widget widget;
+ struct settings_ui ui;
+ unsigned int previous;
int redraw = 1;
int move;
- unsigned int next;
int key;
int rc;
/* Print initial screen content */
color_set ( CPAIR_NORMAL, NULL );
- memset ( &widget, 0, sizeof ( widget ) );
- init_widget ( &widget, settings );
+ memset ( &ui, 0, sizeof ( ui ) );
+ select_settings ( &ui, settings );
while ( 1 ) {
/* Redraw rows if necessary */
if ( redraw ) {
- draw_info_row ( &widget );
- draw_instruction_row ( &widget );
- color_set ( ( widget.row.editing ?
+ draw_info_row ( &ui );
+ draw_instruction_row ( &ui );
+ color_set ( ( ui.row.editing ?
CPAIR_EDIT : CPAIR_SELECT ), NULL );
- draw_setting_row ( &widget );
+ draw_setting_row ( &ui );
color_set ( CPAIR_NORMAL, NULL );
- curs_set ( widget.row.editing );
+ curs_set ( ui.row.editing );
redraw = 0;
}
- if ( widget.row.editing ) {
+ /* Edit setting, if we are currently editing */
+ if ( ui.row.editing ) {
/* Sanity check */
- assert ( widget.row.setting.name != NULL );
+ assert ( ui.row.setting.name != NULL );
/* Redraw edit box */
color_set ( CPAIR_EDIT, NULL );
- draw_editbox ( &widget.row.editbox );
+ draw_editbox ( &ui.row.editbox );
color_set ( CPAIR_NORMAL, NULL );
/* Process keypress */
- key = edit_setting ( &widget, getkey ( 0 ) );
+ key = edit_setting ( &ui, getkey ( 0 ) );
switch ( key ) {
case CR:
case LF:
- if ( ( rc = save_setting ( &widget ) ) != 0 )
+ if ( ( rc = save_setting ( &ui ) ) != 0 )
alert ( " %s ", strerror ( rc ) );
/* Fall through */
case CTRL_C:
- select_setting_row ( &widget, widget.current );
+ select_setting_row ( &ui, ui.scroll.current );
redraw = 1;
break;
default:
@@ -516,72 +495,52 @@ static int main_loop ( struct settings *settings ) {
break;
}
- } else {
+ continue;
+ }
- /* Process keypress */
- key = getkey ( 0 );
- move = 0;
- switch ( key ) {
- case KEY_UP:
- move = -1;
- break;
- case KEY_DOWN:
- move = +1;
- break;
- case KEY_PPAGE:
- move = ( widget.first_visible -
- widget.current - 1 );
- break;
- case KEY_NPAGE:
- move = ( widget.first_visible - widget.current
- + SETTINGS_LIST_ROWS );
- break;
- case KEY_HOME:
- move = -widget.num_rows;
- break;
- case KEY_END:
- move = +widget.num_rows;
- break;
- case CTRL_D:
- if ( ! widget.row.setting.name )
- break;
- if ( ( rc = delete_setting ( widget.settings,
- &widget.row.setting ) ) != 0 ) {
- alert ( " %s ", strerror ( rc ) );
- }
- select_setting_row ( &widget, widget.current );
+ /* Otherwise, navigate through settings */
+ key = getkey ( 0 );
+ move = jump_scroll_key ( &ui.scroll, key );
+ if ( move ) {
+ previous = ui.scroll.current;
+ jump_scroll_move ( &ui.scroll, move );
+ if ( ui.scroll.current != previous ) {
+ draw_setting_row ( &ui );
redraw = 1;
+ if ( jump_scroll ( &ui.scroll ) )
+ draw_setting_rows ( &ui );
+ select_setting_row ( &ui, ui.scroll.current );
+ }
+ continue;
+ }
+
+ /* Handle non-navigation keys */
+ switch ( key ) {
+ case CTRL_D:
+ if ( ! ui.row.setting.name )
break;
- case CTRL_X:
- return 0;
- case CR:
- case LF:
- if ( widget.row.settings ) {
- init_widget ( &widget,
- widget.row.settings );
- redraw = 1;
- }
- /* Fall through */
- default:
- if ( widget.row.setting.name ) {
- edit_setting ( &widget, key );
- redraw = 1;
- }
- break;
+ if ( ( rc = delete_setting ( ui.settings,
+ &ui.row.setting ) ) != 0 ){
+ alert ( " %s ", strerror ( rc ) );
+ }
+ select_setting_row ( &ui, ui.scroll.current );
+ redraw = 1;
+ break;
+ case CTRL_X:
+ return 0;
+ case CR:
+ case LF:
+ if ( ui.row.settings ) {
+ select_settings ( &ui, ui.row.settings );
+ redraw = 1;
}
- if ( move ) {
- next = ( widget.current + move );
- if ( ( int ) next < 0 )
- next = 0;
- if ( next >= widget.num_rows )
- next = ( widget.num_rows - 1 );
- if ( next != widget.current ) {
- draw_setting_row ( &widget );
- redraw = 1;
- reveal_setting_row ( &widget, next );
- select_setting_row ( &widget, next );
- }
+ /* Fall through */
+ default:
+ if ( ui.row.setting.name ) {
+ edit_setting ( &ui, key );
+ redraw = 1;
}
+ break;
}
}
}
diff --git a/roms/ipxe/src/image/elf.c b/roms/ipxe/src/image/elf.c
index 51636a8e9..5c2f9db25 100644
--- a/roms/ipxe/src/image/elf.c
+++ b/roms/ipxe/src/image/elf.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @file
@@ -36,27 +40,54 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/image.h>
#include <ipxe/elf.h>
-typedef Elf32_Ehdr Elf_Ehdr;
-typedef Elf32_Phdr Elf_Phdr;
-typedef Elf32_Off Elf_Off;
-#define ELFCLASS ELFCLASS32
-
/**
* Load ELF segment into memory
*
* @v image ELF file
* @v phdr ELF program header
+ * @v dest Destination address
+ * @ret rc Return status code
+ */
+static int elf_load_segment ( struct image *image, Elf_Phdr *phdr,
+ physaddr_t dest ) {
+ userptr_t buffer = phys_to_user ( dest );
+ int rc;
+
+ DBGC ( image, "ELF %p loading segment [%x,%x) to [%lx,%lx,%lx)\n",
+ image, phdr->p_offset, ( phdr->p_offset + phdr->p_filesz ),
+ dest, ( dest + phdr->p_filesz ), ( dest + phdr->p_memsz ) );
+
+ /* Verify and prepare segment */
+ if ( ( rc = prep_segment ( buffer, phdr->p_filesz,
+ phdr->p_memsz ) ) != 0 ) {
+ DBGC ( image, "ELF %p could not prepare segment: %s\n",
+ image, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Copy image to segment */
+ memcpy_user ( buffer, 0, image->data, phdr->p_offset, phdr->p_filesz );
+
+ return 0;
+}
+
+/**
+ * Process ELF segment
+ *
+ * @v image ELF file
* @v ehdr ELF executable header
+ * @v phdr ELF program header
+ * @v process Segment processor
* @ret entry Entry point, if found
* @ret max Maximum used address
* @ret rc Return status code
*/
-static int elf_load_segment ( struct image *image, Elf_Phdr *phdr,
- Elf_Ehdr *ehdr, physaddr_t *entry,
- physaddr_t *max ) {
+static int elf_segment ( struct image *image, Elf_Ehdr *ehdr, Elf_Phdr *phdr,
+ int ( * process ) ( struct image *image,
+ Elf_Phdr *phdr, physaddr_t dest ),
+ physaddr_t *entry, physaddr_t *max ) {
physaddr_t dest;
physaddr_t end;
- userptr_t buffer;
unsigned long e_offset;
int rc;
@@ -82,28 +113,15 @@ static int elf_load_segment ( struct image *image, Elf_Phdr *phdr,
image );
return -ENOEXEC;
}
- buffer = phys_to_user ( dest );
end = ( dest + phdr->p_memsz );
- DBGC ( image, "ELF %p loading segment [%x,%x) to [%x,%x,%x)\n", image,
- phdr->p_offset, ( phdr->p_offset + phdr->p_filesz ),
- phdr->p_paddr, ( phdr->p_paddr + phdr->p_filesz ),
- ( phdr->p_paddr + phdr->p_memsz ) );
-
- /* Verify and prepare segment */
- if ( ( rc = prep_segment ( buffer, phdr->p_filesz,
- phdr->p_memsz ) ) != 0 ) {
- DBGC ( image, "ELF %p could not prepare segment: %s\n",
- image, strerror ( rc ) );
- return rc;
- }
-
/* Update maximum used address, if applicable */
if ( end > *max )
*max = end;
- /* Copy image to segment */
- memcpy_user ( buffer, 0, image->data, phdr->p_offset, phdr->p_filesz );
+ /* Process segment */
+ if ( ( rc = process ( image, phdr, dest ) ) != 0 )
+ return rc;
/* Set execution address, if it lies within this segment */
if ( ( e_offset = ( ehdr->e_entry - dest ) ) < phdr->p_filesz ) {
@@ -124,62 +142,85 @@ static int elf_load_segment ( struct image *image, Elf_Phdr *phdr,
}
/**
- * Load ELF image into memory
+ * Process ELF segments
*
* @v image ELF file
- * @ret entry Entry point
+ * @v ehdr ELF executable header
+ * @v process Segment processor
+ * @ret entry Entry point, if found
* @ret max Maximum used address
* @ret rc Return status code
*/
-int elf_load ( struct image *image, physaddr_t *entry, physaddr_t *max ) {
- static const uint8_t e_ident[] = {
- [EI_MAG0] = ELFMAG0,
- [EI_MAG1] = ELFMAG1,
- [EI_MAG2] = ELFMAG2,
- [EI_MAG3] = ELFMAG3,
- [EI_CLASS] = ELFCLASS,
- };
- Elf_Ehdr ehdr;
+int elf_segments ( struct image *image, Elf_Ehdr *ehdr,
+ int ( * process ) ( struct image *image, Elf_Phdr *phdr,
+ physaddr_t dest ),
+ physaddr_t *entry, physaddr_t *max ) {
Elf_Phdr phdr;
Elf_Off phoff;
unsigned int phnum;
int rc;
- /* Read ELF header */
- copy_from_user ( &ehdr, image->data, 0, sizeof ( ehdr ) );
- if ( memcmp ( &ehdr.e_ident[EI_MAG0], e_ident,
- sizeof ( e_ident ) ) != 0 ) {
- DBGC ( image, "ELF %p has invalid signature\n", image );
- return -ENOEXEC;
- }
-
/* Initialise maximum used address */
*max = 0;
/* Invalidate entry point */
*entry = 0;
- /* Read ELF program headers */
- for ( phoff = ehdr.e_phoff , phnum = ehdr.e_phnum ; phnum ;
- phoff += ehdr.e_phentsize, phnum-- ) {
+ /* Read and process ELF program headers */
+ for ( phoff = ehdr->e_phoff , phnum = ehdr->e_phnum ; phnum ;
+ phoff += ehdr->e_phentsize, phnum-- ) {
if ( phoff > image->len ) {
DBGC ( image, "ELF %p program header %d outside "
"image\n", image, phnum );
return -ENOEXEC;
}
copy_from_user ( &phdr, image->data, phoff, sizeof ( phdr ) );
- if ( ( rc = elf_load_segment ( image, &phdr, &ehdr,
- entry, max ) ) != 0 ) {
+ if ( ( rc = elf_segment ( image, ehdr, &phdr, process,
+ entry, max ) ) != 0 )
return rc;
- }
}
/* Check for a valid execution address */
if ( ! *entry ) {
DBGC ( image, "ELF %p entry point %lx outside image\n",
- image, ( ( unsigned long ) ehdr.e_entry ) );
+ image, ( ( unsigned long ) ehdr->e_entry ) );
+ return -ENOEXEC;
+ }
+
+ return 0;
+}
+
+/**
+ * Load ELF image into memory
+ *
+ * @v image ELF file
+ * @ret entry Entry point
+ * @ret max Maximum used address
+ * @ret rc Return status code
+ */
+int elf_load ( struct image *image, physaddr_t *entry, physaddr_t *max ) {
+ static const uint8_t e_ident[] = {
+ [EI_MAG0] = ELFMAG0,
+ [EI_MAG1] = ELFMAG1,
+ [EI_MAG2] = ELFMAG2,
+ [EI_MAG3] = ELFMAG3,
+ [EI_CLASS] = ELFCLASS,
+ };
+ Elf_Ehdr ehdr;
+ int rc;
+
+ /* Read ELF header */
+ copy_from_user ( &ehdr, image->data, 0, sizeof ( ehdr ) );
+ if ( memcmp ( &ehdr.e_ident[EI_MAG0], e_ident,
+ sizeof ( e_ident ) ) != 0 ) {
+ DBGC ( image, "ELF %p has invalid signature\n", image );
return -ENOEXEC;
}
+ /* Load ELF segments into memory */
+ if ( ( rc = elf_segments ( image, &ehdr, elf_load_segment,
+ entry, max ) ) != 0 )
+ return rc;
+
return 0;
}
diff --git a/roms/ipxe/src/image/embedded.c b/roms/ipxe/src/image/embedded.c
index 6358378fb..48dd86851 100644
--- a/roms/ipxe/src/image/embedded.c
+++ b/roms/ipxe/src/image/embedded.c
@@ -6,7 +6,7 @@
* fetching over the network.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <ipxe/image.h>
diff --git a/roms/ipxe/src/image/png.c b/roms/ipxe/src/image/png.c
index c14608553..5c4bcb3a0 100644
--- a/roms/ipxe/src/image/png.c
+++ b/roms/ipxe/src/image/png.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/image/pnm.c b/roms/ipxe/src/image/pnm.c
index af9e571a2..f24b28841 100644
--- a/roms/ipxe/src/image/pnm.c
+++ b/roms/ipxe/src/image/pnm.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/image/script.c b/roms/ipxe/src/image/script.c
index 5328da8b4..28050868a 100644
--- a/roms/ipxe/src/image/script.c
+++ b/roms/ipxe/src/image/script.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @file
diff --git a/roms/ipxe/src/image/segment.c b/roms/ipxe/src/image/segment.c
index 86fe42662..2d0f2f0fc 100644
--- a/roms/ipxe/src/image/segment.c
+++ b/roms/ipxe/src/image/segment.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @file
diff --git a/roms/ipxe/src/include/.gitignore b/roms/ipxe/src/include/.gitignore
deleted file mode 100644
index de1598ef3..000000000
--- a/roms/ipxe/src/include/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-.buildserial.h
diff --git a/roms/ipxe/src/include/assert.h b/roms/ipxe/src/include/assert.h
index a33f6017c..07f3ecb8c 100644
--- a/roms/ipxe/src/include/assert.h
+++ b/roms/ipxe/src/include/assert.h
@@ -10,7 +10,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifdef NDEBUG
#define ASSERTING 0
diff --git a/roms/ipxe/src/include/big_bswap.h b/roms/ipxe/src/include/big_bswap.h
deleted file mode 100644
index 6c375a573..000000000
--- a/roms/ipxe/src/include/big_bswap.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef ETHERBOOT_BIG_BSWAP_H
-#define ETHERBOOT_BIG_BSWAP_H
-
-#define htonll(x) (x)
-#define ntohll(x) (x)
-#define ntohl(x) (x)
-#define htonl(x) (x)
-#define ntohs(x) (x)
-#define htons(x) (x)
-#define cpu_to_le64(x) __bswap_64(x)
-#define cpu_to_le32(x) __bswap_32(x)
-#define cpu_to_le16(x) __bswap_16(x)
-#define cpu_to_be64(x) (x)
-#define cpu_to_be32(x) (x)
-#define cpu_to_be16(x) (x)
-#define le64_to_cpu(x) __bswap_64(x)
-#define le32_to_cpu(x) __bswap_32(x)
-#define le16_to_cpu(x) __bswap_16(x)
-#define be64_to_cpu(x) (x)
-#define be32_to_cpu(x) (x)
-#define be16_to_cpu(x) (x)
-#define cpu_to_le64s(x) __bswap_64s(x)
-#define cpu_to_le32s(x) __bswap_32s(x)
-#define cpu_to_le16s(x) __bswap_16s(x)
-#define cpu_to_be64s(x) do {} while (0)
-#define cpu_to_be32s(x) do {} while (0)
-#define cpu_to_be16s(x) do {} while (0)
-#define le64_to_cpus(x) __bswap_64s(x)
-#define le32_to_cpus(x) __bswap_32s(x)
-#define le16_to_cpus(x) __bswap_16s(x)
-#define be64_to_cpus(x) do {} while (0)
-#define be32_to_cpus(x) do {} while (0)
-#define be16_to_cpus(x) do {} while (0)
-
-#endif /* ETHERBOOT_BIG_BSWAP_H */
diff --git a/roms/ipxe/src/include/byteswap.h b/roms/ipxe/src/include/byteswap.h
index 466759cf8..d1028c579 100644
--- a/roms/ipxe/src/include/byteswap.h
+++ b/roms/ipxe/src/include/byteswap.h
@@ -1,59 +1,138 @@
-#ifndef ETHERBOOT_BYTESWAP_H
-#define ETHERBOOT_BYTESWAP_H
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#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)))
+#ifndef BYTESWAP_H
+#define BYTESWAP_H
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
+#include <endian.h>
+#include <bits/byteswap.h>
+
+/**
+ * Byte-swap a 16-bit constant
+ *
+ * @v value Constant value
+ * @ret swapped Byte-swapped value
+ */
+#define __bswap_constant_16( value ) \
+ ( ( ( (value) & 0x00ff ) << 8 ) | \
+ ( ( (value) & 0xff00 ) >> 8 ) )
+
+/**
+ * Byte-swap a 32-bit constant
+ *
+ * @v value Constant value
+ * @ret swapped Byte-swapped value
+ */
+#define __bswap_constant_32( value ) \
+ ( ( ( (value) & 0x000000ffUL ) << 24 ) | \
+ ( ( (value) & 0x0000ff00UL ) << 8 ) | \
+ ( ( (value) & 0x00ff0000UL ) >> 8 ) | \
+ ( ( (value) & 0xff000000UL ) >> 24 ) )
+
+/**
+ * Byte-swap a 64-bit constant
+ *
+ * @v value Constant value
+ * @ret swapped Byte-swapped value
+ */
+#define __bswap_constant_64( value ) \
+ ( ( ( (value) & 0x00000000000000ffULL ) << 56 ) | \
+ ( ( (value) & 0x000000000000ff00ULL ) << 40 ) | \
+ ( ( (value) & 0x0000000000ff0000ULL ) << 24 ) | \
+ ( ( (value) & 0x00000000ff000000ULL ) << 8 ) | \
+ ( ( (value) & 0x000000ff00000000ULL ) >> 8 ) | \
+ ( ( (value) & 0x0000ff0000000000ULL ) >> 24 ) | \
+ ( ( (value) & 0x00ff000000000000ULL ) >> 40 ) | \
+ ( ( (value) & 0xff00000000000000ULL ) >> 56 ) )
+
+/**
+ * Byte-swap a 16-bit value
+ *
+ * @v value Value
+ * @ret swapped Byte-swapped value
+ */
+#define __bswap_16( value ) \
+ ( __builtin_constant_p (value) ? \
+ ( ( uint16_t ) __bswap_constant_16 ( ( uint16_t ) (value) ) ) \
+ : __bswap_variable_16 (value) )
+#define bswap_16( value ) __bswap_16 (value)
+
+/**
+ * Byte-swap a 32-bit value
+ *
+ * @v value Value
+ * @ret swapped Byte-swapped value
+ */
+#define __bswap_32( value ) \
+ ( __builtin_constant_p (value) ? \
+ ( ( uint32_t ) __bswap_constant_32 ( ( uint32_t ) (value) ) ) \
+ : __bswap_variable_32 (value) )
+#define bswap_32( value ) __bswap_32 (value)
+
+/**
+ * Byte-swap a 64-bit value
+ *
+ * @v value Value
+ * @ret swapped Byte-swapped value
+ */
+#define __bswap_64( value ) \
+ ( __builtin_constant_p (value) ? \
+ ( ( uint64_t ) __bswap_constant_64 ( ( uint64_t ) (value) ) ) \
+ : __bswap_variable_64 (value) )
+#define bswap_64( value ) __bswap_64 (value)
#if __BYTE_ORDER == __LITTLE_ENDIAN
-#include "little_bswap.h"
+#define __cpu_to_leNN( bits, value ) (value)
+#define __cpu_to_beNN( bits, value ) __bswap_ ## bits (value)
+#define __leNN_to_cpu( bits, value ) (value)
+#define __beNN_to_cpu( bits, value ) __bswap_ ## bits (value)
+#define __cpu_to_leNNs( bits, ptr ) do { } while ( 0 )
+#define __cpu_to_beNNs( bits, ptr ) __bswap_ ## bits ## s (ptr)
+#define __leNN_to_cpus( bits, ptr ) do { } while ( 0 )
+#define __beNN_to_cpus( bits, ptr ) __bswap_ ## bits ## s (ptr)
#endif
+
#if __BYTE_ORDER == __BIG_ENDIAN
-#include "big_bswap.h"
+#define __cpu_to_leNN( bits, value ) __bswap_ ## bits (value)
+#define __cpu_to_beNN( bits, value ) (value)
+#define __leNN_to_cpu( bits, value ) __bswap_ ## bits (value)
+#define __beNN_to_cpu( bits, value ) (value)
+#define __cpu_to_leNNs( bits, ptr ) __bswap_ ## bits ## s (ptr)
+#define __cpu_to_beNNs( bits, ptr ) do { } while ( 0 )
+#define __leNN_to_cpus( bits, ptr ) __bswap_ ## bits ## s (ptr)
+#define __beNN_to_cpus( bits, ptr ) do { } while ( 0 )
#endif
-/* Make routines available to all */
-#define swap64(x) __bswap_64(x)
-#define swap32(x) __bswap_32(x)
-#define swap16(x) __bswap_16(x)
-#define bswap_64(x) __bswap_64(x)
-#define bswap_32(x) __bswap_32(x)
-#define bswap_16(x) __bswap_16(x)
-
-#endif /* ETHERBOOT_BYTESWAP_H */
+#define cpu_to_le16( value ) __cpu_to_leNN ( 16, value )
+#define cpu_to_le32( value ) __cpu_to_leNN ( 32, value )
+#define cpu_to_le64( value ) __cpu_to_leNN ( 64, value )
+#define cpu_to_be16( value ) __cpu_to_beNN ( 16, value )
+#define cpu_to_be32( value ) __cpu_to_beNN ( 32, value )
+#define cpu_to_be64( value ) __cpu_to_beNN ( 64, value )
+#define le16_to_cpu( value ) __leNN_to_cpu ( 16, value )
+#define le32_to_cpu( value ) __leNN_to_cpu ( 32, value )
+#define le64_to_cpu( value ) __leNN_to_cpu ( 64, value )
+#define be16_to_cpu( value ) __beNN_to_cpu ( 16, value )
+#define be32_to_cpu( value ) __beNN_to_cpu ( 32, value )
+#define be64_to_cpu( value ) __beNN_to_cpu ( 64, value )
+#define cpu_to_le16s( ptr ) __cpu_to_leNNs ( 16, ptr )
+#define cpu_to_le32s( ptr ) __cpu_to_leNNs ( 32, ptr )
+#define cpu_to_le64s( ptr ) __cpu_to_leNNs ( 64, ptr )
+#define cpu_to_be16s( ptr ) __cpu_to_beNNs ( 16, ptr )
+#define cpu_to_be32s( ptr ) __cpu_to_beNNs ( 32, ptr )
+#define cpu_to_be64s( ptr ) __cpu_to_beNNs ( 64, ptr )
+#define le16_to_cpus( ptr ) __leNN_to_cpus ( 16, ptr )
+#define le32_to_cpus( ptr ) __leNN_to_cpus ( 32, ptr )
+#define le64_to_cpus( ptr ) __leNN_to_cpus ( 64, ptr )
+#define be16_to_cpus( ptr ) __beNN_to_cpus ( 16, ptr )
+#define be32_to_cpus( ptr ) __beNN_to_cpus ( 32, ptr )
+#define be64_to_cpus( ptr ) __beNN_to_cpus ( 64, ptr )
+
+#define htonll( value ) cpu_to_be64 (value)
+#define ntohll( value ) be64_to_cpu (value)
+#define htonl( value ) cpu_to_be32 (value)
+#define ntohl( value ) be32_to_cpu (value)
+#define htons( value ) cpu_to_be16 (value)
+#define ntohs( value ) be16_to_cpu (value)
+
+#endif /* BYTESWAP_H */
diff --git a/roms/ipxe/src/include/compiler.h b/roms/ipxe/src/include/compiler.h
index 3f5c913a0..ca82f9523 100644
--- a/roms/ipxe/src/include/compiler.h
+++ b/roms/ipxe/src/include/compiler.h
@@ -57,101 +57,100 @@
* @{
*/
-/** Provide a symbol within this object file */
+/**
+ * Provide a symbol within this object file
+ *
+ * @v symbol Symbol name
+ */
#ifdef ASSEMBLY
-#define PROVIDE_SYMBOL( _sym ) \
- .section ".provided", "a", @nobits ; \
- .hidden _sym ; \
- .globl _sym ; \
- _sym: ; \
+#define PROVIDE_SYMBOL( symbol ) \
+ .section ".provided", "a", @nobits ; \
+ .hidden symbol ; \
+ .globl symbol ; \
+ symbol: ; \
.previous
-#else /* ASSEMBLY */
-#define PROVIDE_SYMBOL( _sym ) \
- char _sym[0] \
+#else
+#define PROVIDE_SYMBOL( symbol ) \
+ char symbol[0] \
__attribute__ (( section ( ".provided" ) ))
-#endif /* ASSEMBLY */
+#endif
-/** Require a symbol within this object file
+/**
+ * Request a symbol
+ *
+ * @v symbol Symbol name
*
- * The symbol is referenced by a relocation in a discarded section, so
- * if it is not available at link time the link will fail.
+ * Request a symbol to be included within the link. If the symbol
+ * cannot be found, the link will succeed anyway.
*/
#ifdef ASSEMBLY
-#define REQUIRE_SYMBOL( _sym ) \
- .section ".discard", "a", @progbits ; \
- .extern _sym ; \
- .long _sym ; \
- .previous
-#else /* ASSEMBLY */
-#define REQUIRE_SYMBOL( _sym ) \
- extern char _sym; \
- static char * _C2 ( _C2 ( __require_, _sym ), _C2 ( _, __LINE__ ) ) \
- __attribute__ (( section ( ".discard" ), used )) \
- = &_sym
+#define REQUEST_SYMBOL( symbol ) \
+ .equ __request_ ## symbol, symbol
+#else
+#define REQUEST_SYMBOL( symbol ) \
+ __asm__ ( ".equ __request_" #symbol ", " #symbol )
#endif
-/** Request that a symbol be available at runtime
+/**
+ * Require a symbol
+ *
+ * @v symbol Symbol name
*
- * The requested symbol is entered as undefined into the symbol table
- * for this object, so the linker will pull in other object files as
- * necessary to satisfy the reference. However, the undefined symbol
- * is not referenced in any relocations, so the link can still succeed
- * if no file contains it.
+ * Require a symbol to be included within the link. If the symbol
+ * cannot be found, the link will fail.
*
- * A symbol passed to this macro may not be referenced anywhere
- * else in the file. If you want to do that, see IMPORT_SYMBOL().
+ * To use this macro within a file, you must also specify the file's
+ * "requiring symbol" using the REQUIRING_SYMBOL() or
+ * PROVIDE_REQUIRING_SYMBOL() macros.
*/
#ifdef ASSEMBLY
-#define REQUEST_SYMBOL( _sym ) \
- .equ __need_ ## _sym, _sym
-#else /* ASSEMBLY */
-#define REQUEST_SYMBOL( _sym ) \
- __asm__ ( ".equ\t__need_" #_sym ", " #_sym )
-#endif /* ASSEMBLY */
+#define REQUIRE_SYMBOL( symbol ) \
+ .reloc __requiring_symbol__, RELOC_TYPE_NONE, symbol
+#else
+#define REQUIRE_SYMBOL( symbol ) \
+ __asm__ ( ".reloc __requiring_symbol__, " \
+ _S2 ( RELOC_TYPE_NONE ) ", " #symbol )
+#endif
-/** Set up a symbol to be usable in another file by IMPORT_SYMBOL()
+/**
+ * Specify the file's requiring symbol
+ *
+ * @v symbol Symbol name
*
- * The symbol must already be marked as global.
+ * REQUIRE_SYMBOL() works by defining a dummy relocation record
+ * against a nominated "requiring symbol". The presence of the
+ * nominated requiring symbol will drag in all of the symbols
+ * specified using REQUIRE_SYMBOL().
*/
-#define EXPORT_SYMBOL( _sym ) PROVIDE_SYMBOL ( __export_ ## _sym )
+#ifdef ASSEMBLY
+#define REQUIRING_SYMBOL( symbol ) \
+ .equ __requiring_symbol__, symbol
+#else
+#define REQUIRING_SYMBOL( symbol ) \
+ __asm__ ( ".equ __requiring_symbol__, " #symbol )
+#endif
-/** Make a symbol usable to this file if available at link time
- *
- * If no file passed to the linker contains the symbol, it will have
- * @c NULL value to future uses. Keep in mind that the symbol value is
- * really the @e address of a variable or function; see the code
- * snippet below.
- *
- * In C using IMPORT_SYMBOL, you must specify the declaration as the
- * second argument, for instance
- *
- * @code
- * IMPORT_SYMBOL ( my_func, int my_func ( int arg ) );
- * IMPORT_SYMBOL ( my_var, int my_var );
- *
- * void use_imports ( void ) {
- * if ( my_func && &my_var )
- * my_var = my_func ( my_var );
- * }
- * @endcode
- *
- * GCC considers a weak declaration to override a strong one no matter
- * which comes first, so it is safe to include a header file declaring
- * the imported symbol normally, but providing the declaration to
- * IMPORT_SYMBOL is still required.
+/**
+ * Provide a file's requiring symbol
*
- * If no EXPORT_SYMBOL declaration exists for the imported symbol in
- * another file, the behavior will be most likely be identical to that
- * for an unavailable symbol.
+ * If the file contains no symbols that can be used as the requiring
+ * symbol, you can provide a dummy one-byte-long symbol using
+ * PROVIDE_REQUIRING_SYMBOL().
*/
#ifdef ASSEMBLY
-#define IMPORT_SYMBOL( _sym ) \
- REQUEST_SYMBOL ( __export_ ## _sym ) ; \
- .weak _sym
-#else /* ASSEMBLY */
-#define IMPORT_SYMBOL( _sym, _decl ) \
- REQUEST_SYMBOL ( __export_ ## _sym ) ; \
- extern _decl __attribute__ (( weak ))
+#define PROVIDE_REQUIRING_SYMBOL() \
+ .section ".tbl.requiring_symbols", "a", @progbits ; \
+ __requiring_symbol__: .byte 0 ; \
+ .size __requiring_symbol__, . - __requiring_symbol__ ; \
+ .previous
+#else
+#define PROVIDE_REQUIRING_SYMBOL() \
+ __asm__ ( ".section \".tbl.requiring_symbols\", " \
+ " \"a\", @progbits\n" \
+ "__requiring_symbol__:\t.byte 0\n" \
+ ".size __requiring_symbol__, " \
+ " . - __requiring_symbol__\n" \
+ ".previous" )
#endif
/** @} */
@@ -163,20 +162,33 @@
#define PREFIX_OBJECT( _prefix ) _C2 ( _prefix, OBJECT )
#define OBJECT_SYMBOL PREFIX_OBJECT ( obj_ )
-#define REQUEST_EXPANDED( _sym ) REQUEST_SYMBOL ( _sym )
-#define CONFIG_SYMBOL PREFIX_OBJECT ( obj_config_ )
/** Always provide the symbol for the current object (defined by -DOBJECT) */
PROVIDE_SYMBOL ( OBJECT_SYMBOL );
-/** Pull in an object-specific configuration file if available */
-REQUEST_EXPANDED ( CONFIG_SYMBOL );
-
-/** Explicitly require another object */
-#define REQUIRE_OBJECT( _obj ) REQUIRE_SYMBOL ( obj_ ## _obj )
+/**
+ * Request an object
+ *
+ * @v object Object name
+ *
+ * Request an object to be included within the link. If the object
+ * cannot be found, the link will succeed anyway.
+ */
+#define REQUEST_OBJECT( object ) REQUEST_SYMBOL ( obj_ ## object )
-/** Pull in another object if it exists */
-#define REQUEST_OBJECT( _obj ) REQUEST_SYMBOL ( obj_ ## _obj )
+/**
+ * Require an object
+ *
+ * @v object Object name
+ *
+ * Require an object to be included within the link. If the object
+ * cannot be found, the link will fail.
+ *
+ * To use this macro within a file, you must also specify the file's
+ * "requiring symbol" using the REQUIRING_SYMBOL() or
+ * PROVIDE_REQUIRING_SYMBOL() macros.
+ */
+#define REQUIRE_OBJECT( object ) REQUIRE_SYMBOL ( obj_ ## object )
/** @} */
@@ -195,14 +207,6 @@ REQUEST_EXPANDED ( CONFIG_SYMBOL );
*/
#define __weak __attribute__ (( weak, noinline ))
-/** Prevent a function from being optimized away without inlining
- *
- * Calls to functions with void return type that contain no code in their body
- * may be removed by gcc's optimizer even when inlining is inhibited. Placing
- * this macro in the body of the function prevents that from occurring.
- */
-#define __keepme asm("");
-
#endif
/** @defgroup dbg Debugging infrastructure
@@ -730,13 +734,24 @@ int __debug_disable;
#define FILE_LICENCE_MIT \
PROVIDE_SYMBOL ( PREFIX_OBJECT ( __licence__mit__ ) )
+/** Declare a file as being under GPLv2+ or UBDL
+ *
+ * This licence declaration is applicable when a file states itself to
+ * be licensed under the GNU GPL; "either version 2 of the License, or
+ * (at your option) any later version" and also states that it may be
+ * distributed under the terms of the Unmodified Binary Distribution
+ * Licence (as given in the file COPYING.UBDL).
+ */
+#define FILE_LICENCE_GPL2_OR_LATER_OR_UBDL \
+ PROVIDE_SYMBOL ( PREFIX_OBJECT ( __licence__gpl2_or_later_or_ubdl__ ) )
+
/** Declare a particular licence as applying to a file */
#define FILE_LICENCE( _licence ) FILE_LICENCE_ ## _licence
/** @} */
-/* This file itself is under GPLv2-or-later */
-FILE_LICENCE ( GPL2_OR_LATER );
+/* This file itself is under GPLv2+/UBDL */
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <bits/compiler.h>
diff --git a/roms/ipxe/src/include/ctype.h b/roms/ipxe/src/include/ctype.h
index e92ecb1c0..0d79ecd19 100644
--- a/roms/ipxe/src/include/ctype.h
+++ b/roms/ipxe/src/include/ctype.h
@@ -4,30 +4,114 @@
/** @file
*
* Character types
+ *
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
-#define isdigit(c) ((c) >= '0' && (c) <= '9')
-#define islower(c) ((c) >= 'a' && (c) <= 'z')
-#define isupper(c) ((c) >= 'A' && (c) <= 'Z')
-#define isxdigit(c) (isdigit(c) || ((c) >= 'A' && (c) <= 'F') || ((c) >= 'a' && (c) <= 'f'))
-#define isprint(c) ((c) >= ' ' && (c) <= '~' )
+/**
+ * Check if character is a decimal digit
+ *
+ * @v character ASCII character
+ * @ret is_digit Character is a decimal digit
+ */
+static inline int isdigit ( int character ) {
-static inline unsigned char tolower(unsigned char c)
-{
- if (isupper(c))
- c -= 'A'-'a';
- return c;
+ return ( ( character >= '0' ) && ( character <= '9' ) );
}
-static inline unsigned char toupper(unsigned char c)
-{
- if (islower(c))
- c -= 'a'-'A';
- return c;
+/**
+ * Check if character is a hexadecimal digit
+ *
+ * @v character ASCII character
+ * @ret is_xdigit Character is a hexadecimal digit
+ */
+static inline int isxdigit ( int character ) {
+
+ return ( ( ( character >= '0' ) && ( character <= '9' ) ) ||
+ ( ( character >= 'A' ) && ( character <= 'F' ) ) ||
+ ( ( character >= 'a' ) && ( character <= 'f' ) ) );
+}
+
+/**
+ * Check if character is an upper-case letter
+ *
+ * @v character ASCII character
+ * @ret is_upper Character is an upper-case letter
+ */
+static inline int isupper ( int character ) {
+
+ return ( ( character >= 'A' ) && ( character <= 'Z' ) );
+}
+
+/**
+ * Check if character is a lower-case letter
+ *
+ * @v character ASCII character
+ * @ret is_lower Character is a lower-case letter
+ */
+static inline int islower ( int character ) {
+
+ return ( ( character >= 'a' ) && ( character <= 'z' ) );
+}
+
+/**
+ * Check if character is alphabetic
+ *
+ * @v character ASCII character
+ * @ret is_alpha Character is alphabetic
+ */
+static inline int isalpha ( int character ) {
+
+ return ( isupper ( character ) || islower ( character ) );
+}
+
+/**
+ * Check if character is alphanumeric
+ *
+ * @v character ASCII character
+ * @ret is_alnum Character is alphanumeric
+ */
+static inline int isalnum ( int character ) {
+
+ return ( isalpha ( character ) || isdigit ( character ) );
+}
+
+/**
+ * Check if character is printable
+ *
+ * @v character ASCII character
+ * @ret is_print Character is printable
+ */
+static inline int isprint ( int character ) {
+
+ return ( ( character >= ' ' ) && ( character <= '~' ) );
+}
+
+/**
+ * Convert character to lower case
+ *
+ * @v character Character
+ * @v character Lower-case character
+ */
+static inline int tolower ( int character ) {
+
+ return ( isupper ( character ) ?
+ ( character - 'A' + 'a' ) : character );
+}
+
+/**
+ * Convert character to upper case
+ *
+ * @v character Character
+ * @v character Upper-case character
+ */
+static inline int toupper ( int character ) {
+
+ return ( islower ( character ) ?
+ ( character - 'a' + 'A' ) : character );
}
-extern int isspace ( int c );
+extern int isspace ( int character );
#endif /* _CTYPE_H */
diff --git a/roms/ipxe/src/include/curses.h b/roms/ipxe/src/include/curses.h
index f16f9d7d0..04060fe27 100644
--- a/roms/ipxe/src/include/curses.h
+++ b/roms/ipxe/src/include/curses.h
@@ -11,7 +11,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#undef ERR
#define ERR (-1)
diff --git a/roms/ipxe/src/include/elf.h b/roms/ipxe/src/include/elf.h
index 04022b687..18f755a21 100644
--- a/roms/ipxe/src/include/elf.h
+++ b/roms/ipxe/src/include/elf.h
@@ -1,234 +1,81 @@
#ifndef ELF_H
#define ELF_H
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#define EI_NIDENT 16 /* Size of e_ident array. */
-
-/* Values for e_type. */
-#define ET_NONE 0 /* No file type */
-#define ET_REL 1 /* Relocatable file */
-#define ET_EXEC 2 /* Executable file */
-#define ET_DYN 3 /* Shared object file */
-#define ET_CORE 4 /* Core file */
-
-/* Values for e_machine (architecute). */
-#define EM_NONE 0 /* No machine */
-#define EM_M32 1 /* AT&T WE 32100 */
-#define EM_SPARC 2 /* SUN SPARC */
-#define EM_386 3 /* Intel 80386+ */
-#define EM_68K 4 /* Motorola m68k family */
-#define EM_88K 5 /* Motorola m88k family */
-#define EM_486 6 /* Perhaps disused */
-#define EM_860 7 /* Intel 80860 */
-#define EM_MIPS 8 /* MIPS R3000 big-endian */
-#define EM_S370 9 /* IBM System/370 */
-#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */
-
-#define EM_PARISC 15 /* HPPA */
-#define EM_VPP500 17 /* Fujitsu VPP500 */
-#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */
-#define EM_960 19 /* Intel 80960 */
-#define EM_PPC 20 /* PowerPC */
-#define EM_PPC64 21 /* PowerPC 64-bit */
-#define EM_S390 22 /* IBM S390 */
-
-#define EM_V800 36 /* NEC V800 series */
-#define EM_FR20 37 /* Fujitsu FR20 */
-#define EM_RH32 38 /* TRW RH-32 */
-#define EM_RCE 39 /* Motorola RCE */
-#define EM_ARM 40 /* ARM */
-#define EM_FAKE_ALPHA 41 /* Digital Alpha */
-#define EM_SH 42 /* Hitachi SH */
-#define EM_SPARCV9 43 /* SPARC v9 64-bit */
-#define EM_TRICORE 44 /* Siemens Tricore */
-#define EM_ARC 45 /* Argonaut RISC Core */
-#define EM_H8_300 46 /* Hitachi H8/300 */
-#define EM_H8_300H 47 /* Hitachi H8/300H */
-#define EM_H8S 48 /* Hitachi H8S */
-#define EM_H8_500 49 /* Hitachi H8/500 */
-#define EM_IA_64 50 /* Intel Merced */
-#define EM_MIPS_X 51 /* Stanford MIPS-X */
-#define EM_COLDFIRE 52 /* Motorola Coldfire */
-#define EM_68HC12 53 /* Motorola M68HC12 */
-#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/
-#define EM_PCP 55 /* Siemens PCP */
-#define EM_NCPU 56 /* Sony nCPU embeeded RISC */
-#define EM_NDR1 57 /* Denso NDR1 microprocessor */
-#define EM_STARCORE 58 /* Motorola Start*Core processor */
-#define EM_ME16 59 /* Toyota ME16 processor */
-#define EM_ST100 60 /* STMicroelectronic ST100 processor */
-#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/
-#define EM_X86_64 62 /* AMD x86-64 architecture */
-#define EM_PDSP 63 /* Sony DSP Processor */
-
-#define EM_FX66 66 /* Siemens FX66 microcontroller */
-#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */
-#define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */
-#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */
-#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */
-#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */
-#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */
-#define EM_SVX 73 /* Silicon Graphics SVx */
-#define EM_AT19 74 /* STMicroelectronics ST19 8 bit mc */
-#define EM_VAX 75 /* Digital VAX */
-#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */
-#define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded processor */
-#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */
-#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */
-#define EM_MMIX 80 /* Donald Knuth's educational 64-bit processor */
-#define EM_HUANY 81 /* Harvard University machine-independent object files */
-#define EM_PRISM 82 /* SiTera Prism */
-#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */
-#define EM_FR30 84 /* Fujitsu FR30 */
-#define EM_D10V 85 /* Mitsubishi D10V */
-#define EM_D30V 86 /* Mitsubishi D30V */
-#define EM_V850 87 /* NEC v850 */
-#define EM_M32R 88 /* Mitsubishi M32R */
-#define EM_MN10300 89 /* Matsushita MN10300 */
-#define EM_MN10200 90 /* Matsushita MN10200 */
-#define EM_PJ 91 /* picoJava */
-#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */
-#define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */
-#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */
-#define EM_NUM 95
-
-/* Values for p_type. */
-#define PT_NULL 0 /* Unused entry. */
-#define PT_LOAD 1 /* Loadable segment. */
-#define PT_DYNAMIC 2 /* Dynamic linking information segment. */
-#define PT_INTERP 3 /* Pathname of interpreter. */
-#define PT_NOTE 4 /* Auxiliary information. */
-#define PT_SHLIB 5 /* Reserved (not used). */
-#define PT_PHDR 6 /* Location of program header itself. */
-
-/* Values for p_flags. */
-#define PF_X 0x1 /* Executable. */
-#define PF_W 0x2 /* Writable. */
-#define PF_R 0x4 /* Readable. */
-
-
-#define ELF_PROGRAM_RETURNS_BIT 0x8000000 /* e_flags bit 31 */
-
-#define EI_MAG0 0
-#define ELFMAG0 0x7f
-
-#define EI_MAG1 1
-#define ELFMAG1 'E'
-
-#define EI_MAG2 2
-#define ELFMAG2 'L'
-
-#define EI_MAG3 3
-#define ELFMAG3 'F'
-
-#define ELFMAG "\177ELF"
-#define SELFMAG 4
-
-#define EI_CLASS 4 /* File class byte index */
-#define ELFCLASSNONE 0 /* Invalid class */
-#define ELFCLASS32 1 /* 32-bit objects */
-#define ELFCLASS64 2 /* 64-bit objects */
+/**
+ * @file
+ *
+ * ELF headers
+ *
+ */
-#define EI_DATA 5 /* Data encodeing byte index */
-#define ELFDATANONE 0 /* Invalid data encoding */
-#define ELFDATA2LSB 1 /* 2's complement little endian */
-#define ELFDATA2MSB 2 /* 2's complement big endian */
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
-#define EI_VERSION 6 /* File version byte index */
- /* Value must be EV_CURRENT */
+#include <stdint.h>
-#define EV_NONE 0 /* Invalid ELF Version */
-#define EV_CURRENT 1 /* Current version */
+typedef uint32_t Elf32_Addr;
+typedef uint16_t Elf32_Half;
+typedef uint32_t Elf32_Off;
+typedef int32_t Elf32_Sword;
+typedef uint32_t Elf32_Word;
-#define ELF32_PHDR_SIZE (8*4) /* Size of an elf program header */
+/** Length of ELF identifier */
+#define EI_NIDENT 16
-#ifndef ASSEMBLY
+/** ELF header */
+typedef struct {
+ unsigned char e_ident[EI_NIDENT];
+ Elf32_Half e_type;
+ Elf32_Half e_machine;
+ Elf32_Word e_version;
+ Elf32_Addr e_entry;
+ Elf32_Off e_phoff;
+ Elf32_Off e_shoff;
+ Elf32_Word e_flags;
+ Elf32_Half e_ehsize;
+ Elf32_Half e_phentsize;
+ Elf32_Half e_phnum;
+ Elf32_Half e_shentsize;
+ Elf32_Half e_shnum;
+ Elf32_Half e_shstrndx;
+} Elf32_Ehdr;
-#include <stdint.h>
+/* ELF identifier indexes */
+#define EI_MAG0 0
+#define EI_MAG1 1
+#define EI_MAG2 2
+#define EI_MAG3 3
+#define EI_CLASS 4
+#define EI_DATA 5
+#define EI_VERSION 6
-/*
- * ELF definitions common to all 32-bit architectures.
- */
+/* ELF magic signature bytes */
+#define ELFMAG0 0x7f
+#define ELFMAG1 'E'
+#define ELFMAG2 'L'
+#define ELFMAG3 'F'
-typedef uint32_t Elf32_Addr;
-typedef uint16_t Elf32_Half;
-typedef uint32_t Elf32_Off;
-typedef int32_t Elf32_Sword;
-typedef uint32_t Elf32_Word;
-typedef uint32_t Elf32_Size;
+/* ELF classes */
+#define ELFCLASS32 1
-typedef uint64_t Elf64_Addr;
-typedef uint16_t Elf64_Half;
-typedef uint64_t Elf64_Off;
-typedef int32_t Elf64_Sword;
-typedef uint32_t Elf64_Word;
-typedef uint64_t Elf64_Size;
+/* ELF data encodings */
+#define ELFDATA2LSB 1
-/*
- * ELF header.
- */
-typedef struct {
- unsigned char e_ident[EI_NIDENT]; /* File identification. */
- Elf32_Half e_type; /* File type. */
- Elf32_Half e_machine; /* Machine architecture. */
- Elf32_Word e_version; /* ELF format version. */
- Elf32_Addr e_entry; /* Entry point. */
- Elf32_Off e_phoff; /* Program header file offset. */
- Elf32_Off e_shoff; /* Section header file offset. */
- Elf32_Word e_flags; /* Architecture-specific flags. */
- Elf32_Half e_ehsize; /* Size of ELF header in bytes. */
- Elf32_Half e_phentsize; /* Size of program header entry. */
- Elf32_Half e_phnum; /* Number of program header entries. */
- Elf32_Half e_shentsize; /* Size of section header entry. */
- Elf32_Half e_shnum; /* Number of section header entries. */
- Elf32_Half e_shstrndx; /* Section name strings section. */
-} Elf32_Ehdr;
-
-typedef struct {
- unsigned char e_ident[EI_NIDENT]; /* File identification. */
- Elf64_Half e_type; /* File type. */
- Elf64_Half e_machine; /* Machine architecture. */
- Elf64_Word e_version; /* ELF format version. */
- Elf64_Addr e_entry; /* Entry point. */
- Elf64_Off e_phoff; /* Program header file offset. */
- Elf64_Off e_shoff; /* Section header file offset. */
- Elf64_Word e_flags; /* Architecture-specific flags. */
- Elf64_Half e_ehsize; /* Size of ELF header in bytes. */
- Elf64_Half e_phentsize; /* Size of program header entry. */
- Elf64_Half e_phnum; /* Number of program header entries. */
- Elf64_Half e_shentsize; /* Size of section header entry. */
- Elf64_Half e_shnum; /* Number of section header entries. */
- Elf64_Half e_shstrndx; /* Section name strings section. */
-} Elf64_Ehdr;
+/* ELF versions */
+#define EV_CURRENT 1
-/*
- * Program header.
- */
+/** ELF program header */
typedef struct {
- Elf32_Word p_type; /* Entry type. */
- Elf32_Off p_offset; /* File offset of contents. */
- Elf32_Addr p_vaddr; /* Virtual address (not used). */
- Elf32_Addr p_paddr; /* Physical address. */
- Elf32_Size p_filesz; /* Size of contents in file. */
- Elf32_Size p_memsz; /* Size of contents in memory. */
- Elf32_Word p_flags; /* Access permission flags. */
- Elf32_Size p_align; /* Alignment in memory and file. */
+ Elf32_Word p_type;
+ Elf32_Off p_offset;
+ Elf32_Addr p_vaddr;
+ Elf32_Addr p_paddr;
+ Elf32_Word p_filesz;
+ Elf32_Word p_memsz;
+ Elf32_Word p_flags;
+ Elf32_Word p_align;
} Elf32_Phdr;
-typedef struct {
- Elf64_Word p_type; /* Entry type. */
- Elf64_Word p_flags; /* Access permission flags. */
- Elf64_Off p_offset; /* File offset of contents. */
- Elf64_Addr p_vaddr; /* Virtual address (not used). */
- Elf64_Addr p_paddr; /* Physical address. */
- Elf64_Size p_filesz; /* Size of contents in file. */
- Elf64_Size p_memsz; /* Size of contents in memory. */
- Elf64_Size p_align; /* Alignment in memory and file. */
-} Elf64_Phdr;
-
-/* Standardized Elf image notes for booting... The name for all of these is ELFBoot */
-
-#endif /* ASSEMBLY */
+/* ELF segment types */
+#define PT_LOAD 1
#endif /* ELF_H */
diff --git a/roms/ipxe/src/include/endian.h b/roms/ipxe/src/include/endian.h
index 9682cf9b4..79c3163ee 100644
--- a/roms/ipxe/src/include/endian.h
+++ b/roms/ipxe/src/include/endian.h
@@ -1,21 +1,22 @@
-#ifndef ETHERBOOT_ENDIAN_H
-#define ETHERBOOT_ENDIAN_H
+#ifndef _ENDIAN_H
+#define _ENDIAN_H
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
-/* Definitions for byte order, according to significance of bytes,
- from low addresses to high addresses. The value is what you get by
- putting '4' in the most significant byte, '3' in the second most
- significant byte, '2' in the second least significant byte, and '1'
- in the least significant byte, and then writing down one digit for
- each byte, starting with the byte at the lowest address at the left,
- and proceeding to the byte with the highest address at the right. */
+/** Constant representing little-endian byte order
+ *
+ * Little-endian systems should define BYTE_ORDER as LITTLE_ENDIAN.
+ * This constant is intended to be used only at compile time.
+ */
+#define __LITTLE_ENDIAN 0x44332211UL
-#define __LITTLE_ENDIAN 1234
-#define __BIG_ENDIAN 4321
-#define __PDP_ENDIAN 3412
+/** Constant representing big-endian byte order
+ *
+ * Big-endian systems should define BYTE_ORDER as BIG_ENDIAN.
+ * This constant is intended to be used only at compile time.
+ */
+#define __BIG_ENDIAN 0x11223344UL
#include "bits/endian.h"
-
-#endif /* ETHERBOOT_ENDIAN_H */
+#endif /* _ENDIAN_H */
diff --git a/roms/ipxe/src/include/errno.h b/roms/ipxe/src/include/errno.h
index bcc4a8816..036479aff 100644
--- a/roms/ipxe/src/include/errno.h
+++ b/roms/ipxe/src/include/errno.h
@@ -15,12 +15,16 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
#ifndef ERRNO_H
#define ERRNO_H
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/include/getopt.h b/roms/ipxe/src/include/getopt.h
index 0fe43567e..db3de1786 100644
--- a/roms/ipxe/src/include/getopt.h
+++ b/roms/ipxe/src/include/getopt.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
diff --git a/roms/ipxe/src/include/hci/ifmgmt_cmd.h b/roms/ipxe/src/include/hci/ifmgmt_cmd.h
index 913b911d8..5debf85c2 100644
--- a/roms/ipxe/src/include/hci/ifmgmt_cmd.h
+++ b/roms/ipxe/src/include/hci/ifmgmt_cmd.h
@@ -15,12 +15,16 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
#ifndef _IFMGMT_CMD_H
#define _IFMGMT_CMD_H
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/parseopt.h>
diff --git a/roms/ipxe/src/include/ipxe/acpi.h b/roms/ipxe/src/include/ipxe/acpi.h
index 282b6d92d..2ccd691ed 100644
--- a/roms/ipxe/src/include/ipxe/acpi.h
+++ b/roms/ipxe/src/include/ipxe/acpi.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/interface.h>
diff --git a/roms/ipxe/src/include/ipxe/aes.h b/roms/ipxe/src/include/ipxe/aes.h
index 4e44f9853..0432e43ee 100644
--- a/roms/ipxe/src/include/ipxe/aes.h
+++ b/roms/ipxe/src/include/ipxe/aes.h
@@ -1,31 +1,51 @@
#ifndef _IPXE_AES_H
#define _IPXE_AES_H
-FILE_LICENCE ( GPL2_OR_LATER );
+/** @file
+ *
+ * AES algorithm
+ *
+ */
-struct cipher_algorithm;
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
-/** Basic AES blocksize */
+#include <ipxe/crypto.h>
+
+/** AES blocksize */
#define AES_BLOCKSIZE 16
-#include "crypto/axtls/crypto.h"
+/** Maximum number of AES rounds */
+#define AES_MAX_ROUNDS 15
+
+/** AES matrix */
+union aes_matrix {
+ /** Viewed as an array of bytes */
+ uint8_t byte[16];
+ /** Viewed as an array of four-byte columns */
+ uint32_t column[4];
+} __attribute__ (( packed ));
+
+/** AES round keys */
+struct aes_round_keys {
+ /** Round keys */
+ union aes_matrix key[AES_MAX_ROUNDS];
+};
/** AES context */
struct aes_context {
- /** AES context for AXTLS */
- AES_CTX axtls_ctx;
- /** Cipher is being used for decrypting */
- int decrypting;
+ /** Encryption keys */
+ struct aes_round_keys encrypt;
+ /** Decryption keys */
+ struct aes_round_keys decrypt;
+ /** Number of rounds */
+ unsigned int rounds;
};
/** AES context size */
#define AES_CTX_SIZE sizeof ( struct aes_context )
-/* AXTLS functions */
-extern void axtls_aes_encrypt ( const AES_CTX *ctx, uint32_t *data );
-extern void axtls_aes_decrypt ( const AES_CTX *ctx, uint32_t *data );
-
extern struct cipher_algorithm aes_algorithm;
+extern struct cipher_algorithm aes_ecb_algorithm;
extern struct cipher_algorithm aes_cbc_algorithm;
int aes_wrap ( const void *kek, const void *src, void *dest, int nblk );
diff --git a/roms/ipxe/src/include/ipxe/ansicol.h b/roms/ipxe/src/include/ipxe/ansicol.h
index 707d1599d..2b54ecaca 100644
--- a/roms/ipxe/src/include/ipxe/ansicol.h
+++ b/roms/ipxe/src/include/ipxe/ansicol.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <curses.h> /* For COLOR_RED etc. */
diff --git a/roms/ipxe/src/include/ipxe/ansiesc.h b/roms/ipxe/src/include/ipxe/ansiesc.h
index c1c74481d..80bc83308 100644
--- a/roms/ipxe/src/include/ipxe/ansiesc.h
+++ b/roms/ipxe/src/include/ipxe/ansiesc.h
@@ -26,7 +26,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
struct ansiesc_context;
diff --git a/roms/ipxe/src/include/ipxe/aoe.h b/roms/ipxe/src/include/ipxe/aoe.h
index 60f3bd959..0c656e7c2 100644
--- a/roms/ipxe/src/include/ipxe/aoe.h
+++ b/roms/ipxe/src/include/ipxe/aoe.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/list.h>
diff --git a/roms/ipxe/src/include/ipxe/api.h b/roms/ipxe/src/include/ipxe/api.h
index 838b8936e..d05d3b07a 100644
--- a/roms/ipxe/src/include/ipxe/api.h
+++ b/roms/ipxe/src/include/ipxe/api.h
@@ -11,7 +11,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @defgroup Single-implementation APIs
*
diff --git a/roms/ipxe/src/include/ipxe/arp.h b/roms/ipxe/src/include/ipxe/arp.h
index e30ae6b76..5822fa095 100644
--- a/roms/ipxe/src/include/ipxe/arp.h
+++ b/roms/ipxe/src/include/ipxe/arp.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/tables.h>
#include <ipxe/netdevice.h>
@@ -57,4 +57,8 @@ static inline int arp_tx ( struct io_buffer *iobuf, struct net_device *netdev,
&arp_discovery, net_source, ll_source );
}
+extern int arp_tx_request ( struct net_device *netdev,
+ struct net_protocol *net_protocol,
+ const void *net_dest, const void *net_source );
+
#endif /* _IPXE_ARP_H */
diff --git a/roms/ipxe/src/include/ipxe/asn1.h b/roms/ipxe/src/include/ipxe/asn1.h
index d12524ddb..5fbd58281 100644
--- a/roms/ipxe/src/include/ipxe/asn1.h
+++ b/roms/ipxe/src/include/ipxe/asn1.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <time.h>
@@ -141,6 +141,24 @@ struct asn1_builder_header {
ASN1_OID_TRIPLE ( 113549 ), ASN1_OID_SINGLE ( 1 ), \
ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 11 )
+/** ASN.1 OID for sha384WithRSAEncryption (1.2.840.113549.1.1.12) */
+#define ASN1_OID_SHA384WITHRSAENCRYPTION \
+ ASN1_OID_INITIAL ( 1, 2 ), ASN1_OID_DOUBLE ( 840 ), \
+ ASN1_OID_TRIPLE ( 113549 ), ASN1_OID_SINGLE ( 1 ), \
+ ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 12 )
+
+/** ASN.1 OID for sha512WithRSAEncryption (1.2.840.113549.1.1.13) */
+#define ASN1_OID_SHA512WITHRSAENCRYPTION \
+ ASN1_OID_INITIAL ( 1, 2 ), ASN1_OID_DOUBLE ( 840 ), \
+ ASN1_OID_TRIPLE ( 113549 ), ASN1_OID_SINGLE ( 1 ), \
+ ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 13 )
+
+/** ASN.1 OID for sha224WithRSAEncryption (1.2.840.113549.1.1.14) */
+#define ASN1_OID_SHA224WITHRSAENCRYPTION \
+ ASN1_OID_INITIAL ( 1, 2 ), ASN1_OID_DOUBLE ( 840 ), \
+ ASN1_OID_TRIPLE ( 113549 ), ASN1_OID_SINGLE ( 1 ), \
+ ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 14 )
+
/** ASN.1 OID for id-md5 (1.2.840.113549.2.5) */
#define ASN1_OID_MD5 \
ASN1_OID_INITIAL ( 1, 2 ), ASN1_OID_DOUBLE ( 840 ), \
@@ -160,6 +178,41 @@ struct asn1_builder_header {
ASN1_OID_SINGLE ( 3 ), ASN1_OID_SINGLE ( 4 ), \
ASN1_OID_SINGLE ( 2 ), ASN1_OID_SINGLE ( 1 )
+/** ASN.1 OID for id-sha384 (2.16.840.1.101.3.4.2.2) */
+#define ASN1_OID_SHA384 \
+ ASN1_OID_INITIAL ( 2, 16 ), ASN1_OID_DOUBLE ( 840 ), \
+ ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 101 ), \
+ ASN1_OID_SINGLE ( 3 ), ASN1_OID_SINGLE ( 4 ), \
+ ASN1_OID_SINGLE ( 2 ), ASN1_OID_SINGLE ( 2 )
+
+/** ASN.1 OID for id-sha512 (2.16.840.1.101.3.4.2.3) */
+#define ASN1_OID_SHA512 \
+ ASN1_OID_INITIAL ( 2, 16 ), ASN1_OID_DOUBLE ( 840 ), \
+ ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 101 ), \
+ ASN1_OID_SINGLE ( 3 ), ASN1_OID_SINGLE ( 4 ), \
+ ASN1_OID_SINGLE ( 2 ), ASN1_OID_SINGLE ( 3 )
+
+/** ASN.1 OID for id-sha224 (2.16.840.1.101.3.4.2.4) */
+#define ASN1_OID_SHA224 \
+ ASN1_OID_INITIAL ( 2, 16 ), ASN1_OID_DOUBLE ( 840 ), \
+ ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 101 ), \
+ ASN1_OID_SINGLE ( 3 ), ASN1_OID_SINGLE ( 4 ), \
+ ASN1_OID_SINGLE ( 2 ), ASN1_OID_SINGLE ( 4 )
+
+/** ASN.1 OID for id-sha512-224 (2.16.840.1.101.3.4.2.5) */
+#define ASN1_OID_SHA512_224 \
+ ASN1_OID_INITIAL ( 2, 16 ), ASN1_OID_DOUBLE ( 840 ), \
+ ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 101 ), \
+ ASN1_OID_SINGLE ( 3 ), ASN1_OID_SINGLE ( 4 ), \
+ ASN1_OID_SINGLE ( 2 ), ASN1_OID_SINGLE ( 5 )
+
+/** ASN.1 OID for id-sha512-256 (2.16.840.1.101.3.4.2.6) */
+#define ASN1_OID_SHA512_256 \
+ ASN1_OID_INITIAL ( 2, 16 ), ASN1_OID_DOUBLE ( 840 ), \
+ ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 101 ), \
+ ASN1_OID_SINGLE ( 3 ), ASN1_OID_SINGLE ( 4 ), \
+ ASN1_OID_SINGLE ( 2 ), ASN1_OID_SINGLE ( 6 )
+
/** ASN.1 OID for commonName (2.5.4.3) */
#define ASN1_OID_COMMON_NAME \
ASN1_OID_INITIAL ( 2, 5 ), ASN1_OID_SINGLE ( 4 ), \
diff --git a/roms/ipxe/src/include/ipxe/ata.h b/roms/ipxe/src/include/ipxe/ata.h
index b7f02d655..a10cfafcc 100644
--- a/roms/ipxe/src/include/ipxe/ata.h
+++ b/roms/ipxe/src/include/ipxe/ata.h
@@ -11,7 +11,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* An ATA Logical Block Address
diff --git a/roms/ipxe/src/include/ipxe/base16.h b/roms/ipxe/src/include/ipxe/base16.h
index 60e3f2315..8c44da17e 100644
--- a/roms/ipxe/src/include/ipxe/base16.h
+++ b/roms/ipxe/src/include/ipxe/base16.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <string.h>
@@ -32,9 +32,36 @@ static inline size_t base16_decoded_max_len ( const char *encoded ) {
return ( ( strlen ( encoded ) + 1 ) / 2 );
}
-extern void base16_encode ( const uint8_t *raw, size_t len, char *encoded );
-extern int hex_decode ( const char *string, char separator, void *data,
+extern size_t hex_encode ( char separator, const void *raw, size_t raw_len,
+ char *data, size_t len );
+extern int hex_decode ( char separator, const char *encoded, void *data,
size_t len );
-extern int base16_decode ( const char *encoded, uint8_t *raw );
+
+/**
+ * Base16-encode data
+ *
+ * @v raw Raw data
+ * @v raw_len Length of raw data
+ * @v data Buffer
+ * @v len Length of buffer
+ * @ret len Encoded length
+ */
+static inline __attribute__ (( always_inline )) size_t
+base16_encode ( const void *raw, size_t raw_len, char *data, size_t len ) {
+ return hex_encode ( 0, raw, raw_len, data, len );
+}
+
+/**
+ * Base16-decode data
+ *
+ * @v encoded Encoded string
+ * @v data Buffer
+ * @v len Length of buffer
+ * @ret len Length of data, or negative error
+ */
+static inline __attribute__ (( always_inline )) int
+base16_decode ( const char *encoded, void *data, size_t len ) {
+ return hex_decode ( 0, encoded, data, len );
+}
#endif /* _IPXE_BASE16_H */
diff --git a/roms/ipxe/src/include/ipxe/base64.h b/roms/ipxe/src/include/ipxe/base64.h
index 5fe134dc8..0c70d8382 100644
--- a/roms/ipxe/src/include/ipxe/base64.h
+++ b/roms/ipxe/src/include/ipxe/base64.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <string.h>
@@ -35,7 +35,8 @@ static inline size_t base64_decoded_max_len ( const char *encoded ) {
return ( ( ( strlen ( encoded ) + 4 - 1 ) / 4 ) * 3 );
}
-extern void base64_encode ( const uint8_t *raw, size_t len, char *encoded );
-extern int base64_decode ( const char *encoded, uint8_t *raw );
+extern size_t base64_encode ( const void *raw, size_t raw_len, char *data,
+ size_t len );
+extern int base64_decode ( const char *encoded, void *data, size_t len );
#endif /* _IPXE_BASE64_H */
diff --git a/roms/ipxe/src/include/ipxe/bigint.h b/roms/ipxe/src/include/ipxe/bigint.h
index 97fbce245..2f99f8445 100644
--- a/roms/ipxe/src/include/ipxe/bigint.h
+++ b/roms/ipxe/src/include/ipxe/bigint.h
@@ -6,7 +6,7 @@
* Big integer support
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* Define a big-integer type
diff --git a/roms/ipxe/src/include/ipxe/bitbash.h b/roms/ipxe/src/include/ipxe/bitbash.h
index 69d5d9e3e..2a2e475d0 100644
--- a/roms/ipxe/src/include/ipxe/bitbash.h
+++ b/roms/ipxe/src/include/ipxe/bitbash.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
struct bit_basher;
diff --git a/roms/ipxe/src/include/ipxe/bitmap.h b/roms/ipxe/src/include/ipxe/bitmap.h
index b18584c1f..38aca694b 100644
--- a/roms/ipxe/src/include/ipxe/bitmap.h
+++ b/roms/ipxe/src/include/ipxe/bitmap.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stddef.h>
diff --git a/roms/ipxe/src/include/ipxe/bitops.h b/roms/ipxe/src/include/ipxe/bitops.h
index 73e859f41..220ab0fe7 100644
--- a/roms/ipxe/src/include/ipxe/bitops.h
+++ b/roms/ipxe/src/include/ipxe/bitops.h
@@ -18,9 +18,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @file
diff --git a/roms/ipxe/src/include/ipxe/blockdev.h b/roms/ipxe/src/include/ipxe/blockdev.h
index 9f0a9f787..418c43004 100644
--- a/roms/ipxe/src/include/ipxe/blockdev.h
+++ b/roms/ipxe/src/include/ipxe/blockdev.h
@@ -8,7 +8,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/uaccess.h>
diff --git a/roms/ipxe/src/include/ipxe/blocktrans.h b/roms/ipxe/src/include/ipxe/blocktrans.h
new file mode 100644
index 000000000..fee71b96c
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/blocktrans.h
@@ -0,0 +1,38 @@
+#ifndef _IPXE_BLOCKTRANS_H
+#define _IPXE_BLOCKTRANS_H
+
+/** @file
+ *
+ * Block device translator
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
+#include <ipxe/refcnt.h>
+#include <ipxe/interface.h>
+#include <ipxe/xferbuf.h>
+#include <ipxe/uaccess.h>
+
+/** A block device translator */
+struct block_translator {
+ /** Reference count */
+ struct refcnt refcnt;
+ /** Block device interface */
+ struct interface block;
+ /** Data transfer interface */
+ struct interface xfer;
+
+ /** Data transfer buffer */
+ struct xfer_buffer xferbuf;
+ /** Data buffer */
+ userptr_t buffer;
+ /** Block size */
+ size_t blksize;
+};
+
+extern int block_translate ( struct interface *block,
+ userptr_t buffer, size_t size );
+
+#endif /* _IPXE_BLOCKTRANS_H */
diff --git a/roms/ipxe/src/include/ipxe/bofm.h b/roms/ipxe/src/include/ipxe/bofm.h
index 1da47f651..bc994ea8b 100644
--- a/roms/ipxe/src/include/ipxe/bofm.h
+++ b/roms/ipxe/src/include/ipxe/bofm.h
@@ -8,7 +8,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/list.h>
diff --git a/roms/ipxe/src/include/ipxe/cbc.h b/roms/ipxe/src/include/ipxe/cbc.h
index fae376577..18a94e144 100644
--- a/roms/ipxe/src/include/ipxe/cbc.h
+++ b/roms/ipxe/src/include/ipxe/cbc.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/crypto.h>
diff --git a/roms/ipxe/src/include/ipxe/cdc.h b/roms/ipxe/src/include/ipxe/cdc.h
new file mode 100644
index 000000000..f1799cd9a
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/cdc.h
@@ -0,0 +1,55 @@
+#ifndef _IPXE_CDC_H
+#define _IPXE_CDC_H
+
+/** @file
+ *
+ * USB Communications Device Class (CDC)
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <ipxe/usb.h>
+
+/** Class code for communications devices */
+#define USB_CLASS_CDC 2
+
+/** Union functional descriptor */
+struct cdc_union_descriptor {
+ /** Descriptor header */
+ struct usb_descriptor_header header;
+ /** Descriptor subtype */
+ uint8_t subtype;
+ /** Interfaces (variable-length) */
+ uint8_t interface[1];
+} __attribute__ (( packed ));
+
+/** Union functional descriptor subtype */
+#define CDC_SUBTYPE_UNION 6
+
+/** Ethernet descriptor subtype */
+#define CDC_SUBTYPE_ETHERNET 15
+
+/** Network connection notification */
+#define CDC_NETWORK_CONNECTION \
+ ( USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE | \
+ USB_REQUEST_TYPE ( 0x00 ) )
+
+/** Connection speed change notification */
+#define CDC_CONNECTION_SPEED_CHANGE \
+ ( USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE | \
+ USB_REQUEST_TYPE ( 0x2a ) )
+
+/** Connection speed change notification */
+struct cdc_connection_speed_change {
+ /** Downlink bit rate, in bits per second */
+ uint32_t down;
+ /** Uplink bit rate, in bits per second */
+ uint32_t up;
+} __attribute__ (( packed ));
+
+extern struct cdc_union_descriptor *
+cdc_union_descriptor ( struct usb_configuration_descriptor *config,
+ struct usb_interface_descriptor *interface );
+
+#endif /* _IPXE_CDC_H */
diff --git a/roms/ipxe/src/include/ipxe/certstore.h b/roms/ipxe/src/include/ipxe/certstore.h
index 7456db621..49b3b512c 100644
--- a/roms/ipxe/src/include/ipxe/certstore.h
+++ b/roms/ipxe/src/include/ipxe/certstore.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/asn1.h>
#include <ipxe/x509.h>
diff --git a/roms/ipxe/src/include/ipxe/chap.h b/roms/ipxe/src/include/ipxe/chap.h
index fce48f3ea..7c693e29d 100644
--- a/roms/ipxe/src/include/ipxe/chap.h
+++ b/roms/ipxe/src/include/ipxe/chap.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/md5.h>
diff --git a/roms/ipxe/src/include/ipxe/cms.h b/roms/ipxe/src/include/ipxe/cms.h
index e026ebd2f..7adf724b2 100644
--- a/roms/ipxe/src/include/ipxe/cms.h
+++ b/roms/ipxe/src/include/ipxe/cms.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <time.h>
#include <ipxe/asn1.h>
diff --git a/roms/ipxe/src/include/ipxe/command.h b/roms/ipxe/src/include/ipxe/command.h
index 432da1abb..a208e7d8f 100644
--- a/roms/ipxe/src/include/ipxe/command.h
+++ b/roms/ipxe/src/include/ipxe/command.h
@@ -1,7 +1,7 @@
#ifndef _IPXE_COMMAND_H
#define _IPXE_COMMAND_H
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/tables.h>
diff --git a/roms/ipxe/src/include/ipxe/console.h b/roms/ipxe/src/include/ipxe/console.h
index 4b90c9cec..1b764aaca 100644
--- a/roms/ipxe/src/include/ipxe/console.h
+++ b/roms/ipxe/src/include/ipxe/console.h
@@ -16,7 +16,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
struct pixel_buffer;
diff --git a/roms/ipxe/src/include/ipxe/cpio.h b/roms/ipxe/src/include/ipxe/cpio.h
index 277232808..0637c531d 100644
--- a/roms/ipxe/src/include/ipxe/cpio.h
+++ b/roms/ipxe/src/include/ipxe/cpio.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** A CPIO archive header
*
diff --git a/roms/ipxe/src/include/ipxe/crc32.h b/roms/ipxe/src/include/ipxe/crc32.h
index 38ac1b31f..30d2fe66c 100644
--- a/roms/ipxe/src/include/ipxe/crc32.h
+++ b/roms/ipxe/src/include/ipxe/crc32.h
@@ -1,7 +1,7 @@
#ifndef _IPXE_CRC32_H
#define _IPXE_CRC32_H
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
diff --git a/roms/ipxe/src/include/ipxe/crypto.h b/roms/ipxe/src/include/ipxe/crypto.h
index 3eda5ec6e..fc0d8b22b 100644
--- a/roms/ipxe/src/include/ipxe/crypto.h
+++ b/roms/ipxe/src/include/ipxe/crypto.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stddef.h>
diff --git a/roms/ipxe/src/include/ipxe/deflate.h b/roms/ipxe/src/include/ipxe/deflate.h
index 19c5125eb..b751aa9a3 100644
--- a/roms/ipxe/src/include/ipxe/deflate.h
+++ b/roms/ipxe/src/include/ipxe/deflate.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <string.h>
diff --git a/roms/ipxe/src/include/ipxe/device.h b/roms/ipxe/src/include/ipxe/device.h
index 7202a6966..d81417e8e 100644
--- a/roms/ipxe/src/include/ipxe/device.h
+++ b/roms/ipxe/src/include/ipxe/device.h
@@ -8,7 +8,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/list.h>
#include <ipxe/tables.h>
@@ -63,10 +63,16 @@ struct device_description {
/** Xen bus type */
#define BUS_TYPE_XEN 8
+/** Hyper-V bus type */
+#define BUS_TYPE_HV 9
+
+/** USB bus type */
+#define BUS_TYPE_USB 10
+
/** A hardware device */
struct device {
/** Name */
- char name[16];
+ char name[32];
/** Driver name */
const char *driver_name;
/** Device description */
@@ -93,6 +99,8 @@ struct root_device {
struct device dev;
/** Root device driver */
struct root_driver *driver;
+ /** Driver-private data */
+ void *priv;
};
/** A root device driver */
@@ -123,6 +131,27 @@ struct root_driver {
/** Declare a root device */
#define __root_device __table_entry ( ROOT_DEVICES, 01 )
+/**
+ * Set root device driver-private data
+ *
+ * @v rootdev Root device
+ * @v priv Private data
+ */
+static inline void rootdev_set_drvdata ( struct root_device *rootdev,
+ void *priv ){
+ rootdev->priv = priv;
+}
+
+/**
+ * Get root device driver-private data
+ *
+ * @v rootdev Root device
+ * @ret priv Private data
+ */
+static inline void * rootdev_get_drvdata ( struct root_device *rootdev ) {
+ return rootdev->priv;
+}
+
extern int device_keep_count;
/**
diff --git a/roms/ipxe/src/include/ipxe/dhcp.h b/roms/ipxe/src/include/ipxe/dhcp.h
index bcfb85cc1..a11db3497 100644
--- a/roms/ipxe/src/include/ipxe/dhcp.h
+++ b/roms/ipxe/src/include/ipxe/dhcp.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdarg.h>
@@ -639,16 +639,6 @@ struct dhcphdr {
*/
#define DHCP_MIN_LEN 552
-/** 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"
diff --git a/roms/ipxe/src/include/ipxe/dhcpopts.h b/roms/ipxe/src/include/ipxe/dhcpopts.h
index c5af5d749..707fda4a8 100644
--- a/roms/ipxe/src/include/ipxe/dhcpopts.h
+++ b/roms/ipxe/src/include/ipxe/dhcpopts.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
diff --git a/roms/ipxe/src/include/ipxe/dhcppkt.h b/roms/ipxe/src/include/ipxe/dhcppkt.h
index 3179a6bb0..f13dfc93d 100644
--- a/roms/ipxe/src/include/ipxe/dhcppkt.h
+++ b/roms/ipxe/src/include/ipxe/dhcppkt.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/dhcp.h>
#include <ipxe/dhcpopts.h>
diff --git a/roms/ipxe/src/include/ipxe/dhcpv6.h b/roms/ipxe/src/include/ipxe/dhcpv6.h
index 2636b8ab2..9307b6cae 100644
--- a/roms/ipxe/src/include/ipxe/dhcpv6.h
+++ b/roms/ipxe/src/include/ipxe/dhcpv6.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/in.h>
diff --git a/roms/ipxe/src/include/ipxe/dns.h b/roms/ipxe/src/include/ipxe/dns.h
index 4f6cab3a4..738dea6e4 100644
--- a/roms/ipxe/src/include/ipxe/dns.h
+++ b/roms/ipxe/src/include/ipxe/dns.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/in.h>
diff --git a/roms/ipxe/src/include/ipxe/downloader.h b/roms/ipxe/src/include/ipxe/downloader.h
index de1a2e75e..ccb1abfef 100644
--- a/roms/ipxe/src/include/ipxe/downloader.h
+++ b/roms/ipxe/src/include/ipxe/downloader.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
struct interface;
struct image;
diff --git a/roms/ipxe/src/include/ipxe/drbg.h b/roms/ipxe/src/include/ipxe/drbg.h
index 6374e7787..ed2b3757a 100644
--- a/roms/ipxe/src/include/ipxe/drbg.h
+++ b/roms/ipxe/src/include/ipxe/drbg.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/sha256.h>
diff --git a/roms/ipxe/src/include/ipxe/ecb.h b/roms/ipxe/src/include/ipxe/ecb.h
new file mode 100644
index 000000000..4e6aa3c81
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/ecb.h
@@ -0,0 +1,55 @@
+#ifndef _IPXE_ECB_H
+#define _IPXE_ECB_H
+
+/** @file
+ *
+ * Electronic codebook (ECB)
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <ipxe/crypto.h>
+
+extern void ecb_encrypt ( void *ctx, const void *src, void *dst,
+ size_t len, struct cipher_algorithm *raw_cipher );
+extern void ecb_decrypt ( void *ctx, const void *src, void *dst,
+ size_t len, struct cipher_algorithm *raw_cipher );
+
+/**
+ * Create a cipher-block chaining mode of behaviour of an existing cipher
+ *
+ * @v _ecb_name Name for the new ECB cipher
+ * @v _ecb_cipher New cipher algorithm
+ * @v _raw_cipher Underlying cipher algorithm
+ * @v _raw_context Context structure for the underlying cipher
+ * @v _blocksize Cipher block size
+ */
+#define ECB_CIPHER( _ecb_name, _ecb_cipher, _raw_cipher, _raw_context, \
+ _blocksize ) \
+static int _ecb_name ## _setkey ( void *ctx, const void *key, \
+ size_t keylen ) { \
+ return cipher_setkey ( &_raw_cipher, ctx, key, keylen ); \
+} \
+static void _ecb_name ## _setiv ( void *ctx, const void *iv ) { \
+ cipher_setiv ( &_raw_cipher, ctx, iv ); \
+} \
+static void _ecb_name ## _encrypt ( void *ctx, const void *src, \
+ void *dst, size_t len ) { \
+ ecb_encrypt ( ctx, src, dst, len, &_raw_cipher ); \
+} \
+static void _ecb_name ## _decrypt ( void *ctx, const void *src, \
+ void *dst, size_t len ) { \
+ ecb_decrypt ( ctx, src, dst, len, &_raw_cipher ); \
+} \
+struct cipher_algorithm _ecb_cipher = { \
+ .name = #_ecb_name, \
+ .ctxsize = sizeof ( _raw_context ), \
+ .blocksize = _blocksize, \
+ .setkey = _ecb_name ## _setkey, \
+ .setiv = _ecb_name ## _setiv, \
+ .encrypt = _ecb_name ## _encrypt, \
+ .decrypt = _ecb_name ## _decrypt, \
+};
+
+#endif /* _IPXE_ECB_H */
diff --git a/roms/ipxe/src/include/ipxe/edd.h b/roms/ipxe/src/include/ipxe/edd.h
index 0c25593d5..1914fd0b0 100644
--- a/roms/ipxe/src/include/ipxe/edd.h
+++ b/roms/ipxe/src/include/ipxe/edd.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/interface.h>
diff --git a/roms/ipxe/src/include/ipxe/editbox.h b/roms/ipxe/src/include/ipxe/editbox.h
index 9122dbbf3..2c70e0b6b 100644
--- a/roms/ipxe/src/include/ipxe/editbox.h
+++ b/roms/ipxe/src/include/ipxe/editbox.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <curses.h>
#include <ipxe/editstring.h>
diff --git a/roms/ipxe/src/include/ipxe/editstring.h b/roms/ipxe/src/include/ipxe/editstring.h
index 2ef546a63..a00a8adaa 100644
--- a/roms/ipxe/src/include/ipxe/editstring.h
+++ b/roms/ipxe/src/include/ipxe/editstring.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** An editable string */
struct edit_string {
diff --git a/roms/ipxe/src/include/ipxe/efi/ProcessorBind.h b/roms/ipxe/src/include/ipxe/efi/ProcessorBind.h
index 1294459f9..7466814fa 100644
--- a/roms/ipxe/src/include/ipxe/efi/ProcessorBind.h
+++ b/roms/ipxe/src/include/ipxe/efi/ProcessorBind.h
@@ -1,7 +1,7 @@
#ifndef _IPXE_EFI_PROCESSOR_BIND_H
#define _IPXE_EFI_PROCESSOR_BIND_H
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/*
* EFI header files rely on having the CPU architecture directory
diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/Rng.h b/roms/ipxe/src/include/ipxe/efi/Protocol/Rng.h
new file mode 100644
index 000000000..f04efbb03
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/efi/Protocol/Rng.h
@@ -0,0 +1,158 @@
+/** @file
+ EFI_RNG_PROTOCOL as defined in UEFI 2.4.
+ The UEFI Random Number Generator Protocol is used to provide random bits for use
+ in applications, or entropy for seeding other random number generators.
+
+Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that 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_RNG_PROTOCOL_H__
+#define __EFI_RNG_PROTOCOL_H__
+
+FILE_LICENCE ( BSD3 );
+
+///
+/// Global ID for the Random Number Generator Protocol
+///
+#define EFI_RNG_PROTOCOL_GUID \
+ { \
+ 0x3152bca5, 0xeade, 0x433d, {0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44 } \
+ }
+
+typedef struct _EFI_RNG_PROTOCOL EFI_RNG_PROTOCOL;
+
+///
+/// A selection of EFI_RNG_PROTOCOL algorithms.
+/// The algorithms listed are optional, not meant to be exhaustive and be argmented by
+/// vendors or other industry standards.
+///
+
+typedef EFI_GUID EFI_RNG_ALGORITHM;
+
+///
+/// The algorithms corresponds to SP800-90 as defined in
+/// NIST SP 800-90, "Recommendation for Random Number Generation Using Deterministic Random
+/// Bit Generators", March 2007.
+///
+#define EFI_RNG_ALGORITHM_SP800_90_HASH_256_GUID \
+ { \
+ 0xa7af67cb, 0x603b, 0x4d42, {0xba, 0x21, 0x70, 0xbf, 0xb6, 0x29, 0x3f, 0x96 } \
+ }
+#define EFI_RNG_ALGORITHM_SP800_90_HMAC_256_GUID \
+ { \
+ 0xc5149b43, 0xae85, 0x4f53, {0x99, 0x82, 0xb9, 0x43, 0x35, 0xd3, 0xa9, 0xe7 } \
+ }
+#define EFI_RNG_ALGORITHM_SP800_90_CTR_256_GUID \
+ { \
+ 0x44f0de6e, 0x4d8c, 0x4045, {0xa8, 0xc7, 0x4d, 0xd1, 0x68, 0x85, 0x6b, 0x9e } \
+ }
+///
+/// The algorithms correspond to X9.31 as defined in
+/// NIST, "Recommended Random Number Generator Based on ANSI X9.31 Appendix A.2.4 Using
+/// the 3-Key Triple DES and AES Algorithm", January 2005.
+///
+#define EFI_RNG_ALGORITHM_X9_31_3DES_GUID \
+ { \
+ 0x63c4785a, 0xca34, 0x4012, {0xa3, 0xc8, 0x0b, 0x6a, 0x32, 0x4f, 0x55, 0x46 } \
+ }
+#define EFI_RNG_ALGORITHM_X9_31_AES_GUID \
+ { \
+ 0xacd03321, 0x777e, 0x4d3d, {0xb1, 0xc8, 0x20, 0xcf, 0xd8, 0x88, 0x20, 0xc9 } \
+ }
+///
+/// The "raw" algorithm, when supported, is intended to provide entropy directly from
+/// the source, without it going through some deterministic random bit generator.
+///
+#define EFI_RNG_ALGORITHM_RAW \
+ { \
+ 0xe43176d7, 0xb6e8, 0x4827, {0xb7, 0x84, 0x7f, 0xfd, 0xc4, 0xb6, 0x85, 0x61 } \
+ }
+
+/**
+ Returns information about the random number generation implementation.
+
+ @param[in] This A pointer to the EFI_RNG_PROTOCOL instance.
+ @param[in,out] RNGAlgorithmListSize On input, the size in bytes of RNGAlgorithmList.
+ On output with a return code of EFI_SUCCESS, the size
+ in bytes of the data returned in RNGAlgorithmList. On output
+ with a return code of EFI_BUFFER_TOO_SMALL,
+ the size of RNGAlgorithmList required to obtain the list.
+ @param[out] RNGAlgorithmList A caller-allocated memory buffer filled by the driver
+ with one EFI_RNG_ALGORITHM element for each supported
+ RNG algorithm. The list must not change across multiple
+ calls to the same driver. The first algorithm in the list
+ is the default algorithm for the driver.
+
+ @retval EFI_SUCCESS The RNG algorithm list was returned successfully.
+ @retval EFI_UNSUPPORTED The services is not supported by this driver.
+ @retval EFI_DEVICE_ERROR The list of algorithms could not be retrieved due to a
+ hardware or firmware error.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect.
+ @retval EFI_BUFFER_TOO_SMALL The buffer RNGAlgorithmList is too small to hold the result.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_RNG_GET_INFO) (
+ IN EFI_RNG_PROTOCOL *This,
+ IN OUT UINTN *RNGAlgorithmListSize,
+ OUT EFI_RNG_ALGORITHM *RNGAlgorithmList
+ );
+
+/**
+ Produces and returns an RNG value using either the default or specified RNG algorithm.
+
+ @param[in] This A pointer to the EFI_RNG_PROTOCOL instance.
+ @param[in] RNGAlgorithm A pointer to the EFI_RNG_ALGORITHM that identifies the RNG
+ algorithm to use. May be NULL in which case the function will
+ use its default RNG algorithm.
+ @param[in] RNGValueLength The length in bytes of the memory buffer pointed to by
+ RNGValue. The driver shall return exactly this numbers of bytes.
+ @param[out] RNGValue A caller-allocated memory buffer filled by the driver with the
+ resulting RNG value.
+
+ @retval EFI_SUCCESS The RNG value was returned successfully.
+ @retval EFI_UNSUPPORTED The algorithm specified by RNGAlgorithm is not supported by
+ this driver.
+ @retval EFI_DEVICE_ERROR An RNG value could not be retrieved due to a hardware or
+ firmware error.
+ @retval EFI_NOT_READY There is not enough random data available to satisfy the length
+ requested by RNGValueLength.
+ @retval EFI_INVALID_PARAMETER RNGValue is NULL or RNGValueLength is zero.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_RNG_GET_RNG) (
+ IN EFI_RNG_PROTOCOL *This,
+ IN EFI_RNG_ALGORITHM *RNGAlgorithm, OPTIONAL
+ IN UINTN RNGValueLength,
+ OUT UINT8 *RNGValue
+ );
+
+///
+/// The Random Number Generator (RNG) protocol provides random bits for use in
+/// applications, or entropy for seeding other random number generators.
+///
+struct _EFI_RNG_PROTOCOL {
+ EFI_RNG_GET_INFO GetInfo;
+ EFI_RNG_GET_RNG GetRNG;
+};
+
+extern EFI_GUID gEfiRngProtocolGuid;
+extern EFI_GUID gEfiRngAlgorithmSp80090Hash256Guid;
+extern EFI_GUID gEfiRngAlgorithmSp80090Hmac256Guid;
+extern EFI_GUID gEfiRngAlgorithmSp80090Ctr256Guid;
+extern EFI_GUID gEfiRngAlgorithmX9313DesGuid;
+extern EFI_GUID gEfiRngAlgorithmX931AesGuid;
+extern EFI_GUID gEfiRngAlgorithmRaw;
+
+#endif
diff --git a/roms/ipxe/src/include/ipxe/efi/efi_autoboot.h b/roms/ipxe/src/include/ipxe/efi/efi_autoboot.h
index d4a26850c..1d5ddc8c3 100644
--- a/roms/ipxe/src/include/ipxe/efi/efi_autoboot.h
+++ b/roms/ipxe/src/include/ipxe/efi/efi_autoboot.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
extern void efi_set_autoboot ( void );
diff --git a/roms/ipxe/src/include/ipxe/efi/efi_driver.h b/roms/ipxe/src/include/ipxe/efi/efi_driver.h
index e16a24daa..f497df3e3 100644
--- a/roms/ipxe/src/include/ipxe/efi/efi_driver.h
+++ b/roms/ipxe/src/include/ipxe/efi/efi_driver.h
@@ -6,7 +6,7 @@
* EFI driver interface
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/device.h>
#include <ipxe/tables.h>
diff --git a/roms/ipxe/src/include/ipxe/efi/efi_entropy.h b/roms/ipxe/src/include/ipxe/efi/efi_entropy.h
new file mode 100644
index 000000000..39a667355
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/efi/efi_entropy.h
@@ -0,0 +1,35 @@
+#ifndef _IPXE_EFI_ENTROPY_H
+#define _IPXE_EFI_ENTROPY_H
+
+/** @file
+ *
+ * EFI entropy source
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
+
+#ifdef ENTROPY_EFI
+#define ENTROPY_PREFIX_efi
+#else
+#define ENTROPY_PREFIX_efi __efi_
+#endif
+
+/**
+ * min-entropy per sample
+ *
+ * @ret min_entropy min-entropy of each sample
+ */
+static inline __always_inline double
+ENTROPY_INLINE ( efi, min_entropy_per_sample ) ( void ) {
+
+ /* We use essentially the same mechanism as for the BIOS
+ * RTC-based entropy source, and so assume the same
+ * min-entropy per sample.
+ */
+ return 1.3;
+}
+
+#endif /* _IPXE_EFI_ENTROPY_H */
diff --git a/roms/ipxe/src/include/ipxe/efi/efi_hii.h b/roms/ipxe/src/include/ipxe/efi/efi_hii.h
index 8e94bbe7e..bbec31194 100644
--- a/roms/ipxe/src/include/ipxe/efi/efi_hii.h
+++ b/roms/ipxe/src/include/ipxe/efi/efi_hii.h
@@ -6,7 +6,7 @@
* EFI human interface infrastructure
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <ipxe/efi/Uefi/UefiInternalFormRepresentation.h>
diff --git a/roms/ipxe/src/include/ipxe/efi/efi_pci.h b/roms/ipxe/src/include/ipxe/efi/efi_pci.h
index af36613d9..6dd945f05 100644
--- a/roms/ipxe/src/include/ipxe/efi/efi_pci.h
+++ b/roms/ipxe/src/include/ipxe/efi/efi_pci.h
@@ -6,7 +6,7 @@
* EFI driver interface
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/pci.h>
#include <ipxe/efi/efi.h>
diff --git a/roms/ipxe/src/include/ipxe/efi/efi_pci_api.h b/roms/ipxe/src/include/ipxe/efi/efi_pci_api.h
index 498a0388b..887d5ee14 100644
--- a/roms/ipxe/src/include/ipxe/efi/efi_pci_api.h
+++ b/roms/ipxe/src/include/ipxe/efi/efi_pci_api.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifdef PCIAPI_EFI
#define PCIAPI_PREFIX_efi
diff --git a/roms/ipxe/src/include/ipxe/efi/efi_reboot.h b/roms/ipxe/src/include/ipxe/efi/efi_reboot.h
index 33921b913..249cae8c5 100644
--- a/roms/ipxe/src/include/ipxe/efi/efi_reboot.h
+++ b/roms/ipxe/src/include/ipxe/efi/efi_reboot.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifdef REBOOT_EFI
#define REBOOT_PREFIX_efi
diff --git a/roms/ipxe/src/include/ipxe/efi/efi_smbios.h b/roms/ipxe/src/include/ipxe/efi/efi_smbios.h
index 7642e5bc5..d890d5460 100644
--- a/roms/ipxe/src/include/ipxe/efi/efi_smbios.h
+++ b/roms/ipxe/src/include/ipxe/efi/efi_smbios.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifdef SMBIOS_EFI
#define SMBIOS_PREFIX_efi
diff --git a/roms/ipxe/src/include/ipxe/efi/efi_snp.h b/roms/ipxe/src/include/ipxe/efi/efi_snp.h
index a18bced5f..1e5c66626 100644
--- a/roms/ipxe/src/include/ipxe/efi/efi_snp.h
+++ b/roms/ipxe/src/include/ipxe/efi/efi_snp.h
@@ -18,6 +18,9 @@
#include <ipxe/efi/Protocol/HiiDatabase.h>
#include <ipxe/efi/Protocol/LoadFile.h>
+/** SNP transmit completion ring size */
+#define EFI_SNP_NUM_TX 32
+
/** An SNP device */
struct efi_snp_device {
/** List of SNP devices */
@@ -34,20 +37,16 @@ struct efi_snp_device {
EFI_SIMPLE_NETWORK_MODE mode;
/** Started flag */
int started;
- /** 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;
+ /** Pending interrupt status */
+ unsigned int interrupts;
+ /** Transmit completion ring */
+ VOID *tx[EFI_SNP_NUM_TX];
+ /** Transmit completion ring producer counter */
+ unsigned int tx_prod;
+ /** Transmit completion ring consumer counter */
+ unsigned int tx_cons;
+ /** Receive queue */
+ struct list_head rx;
/** The network interface identifier */
EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL nii;
/** Component name protocol */
diff --git a/roms/ipxe/src/include/ipxe/efi/efi_strings.h b/roms/ipxe/src/include/ipxe/efi/efi_strings.h
index 023ccda07..2f241537e 100644
--- a/roms/ipxe/src/include/ipxe/efi/efi_strings.h
+++ b/roms/ipxe/src/include/ipxe/efi/efi_strings.h
@@ -6,7 +6,7 @@
* EFI strings
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <stdint.h>
diff --git a/roms/ipxe/src/include/ipxe/efi/efi_time.h b/roms/ipxe/src/include/ipxe/efi/efi_time.h
new file mode 100644
index 000000000..099994b57
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/efi/efi_time.h
@@ -0,0 +1,20 @@
+#ifndef _IPXE_EFI_TIME_H
+#define _IPXE_EFI_TIME_H
+
+/** @file
+ *
+ * EFI time source
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
+
+#ifdef TIME_EFI
+#define TIME_PREFIX_efi
+#else
+#define TIME_PREFIX_efi __efi_
+#endif
+
+#endif /* _IPXE_EFI_TIME_H */
diff --git a/roms/ipxe/src/include/ipxe/efi/efi_timer.h b/roms/ipxe/src/include/ipxe/efi/efi_timer.h
index b10543d6c..c03765393 100644
--- a/roms/ipxe/src/include/ipxe/efi/efi_timer.h
+++ b/roms/ipxe/src/include/ipxe/efi/efi_timer.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifdef TIMER_EFI
#define TIMER_PREFIX_efi
diff --git a/roms/ipxe/src/include/ipxe/efi/efi_uaccess.h b/roms/ipxe/src/include/ipxe/efi/efi_uaccess.h
index 870a089b2..3cc750405 100644
--- a/roms/ipxe/src/include/ipxe/efi/efi_uaccess.h
+++ b/roms/ipxe/src/include/ipxe/efi/efi_uaccess.h
@@ -10,7 +10,7 @@
* no-ops.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifdef UACCESS_EFI
#define UACCESS_PREFIX_efi
diff --git a/roms/ipxe/src/include/ipxe/efi/efi_umalloc.h b/roms/ipxe/src/include/ipxe/efi/efi_umalloc.h
index 911e69a96..4eb2a5f9b 100644
--- a/roms/ipxe/src/include/ipxe/efi/efi_umalloc.h
+++ b/roms/ipxe/src/include/ipxe/efi/efi_umalloc.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifdef UMALLOC_EFI
#define UMALLOC_PREFIX_efi
diff --git a/roms/ipxe/src/include/ipxe/efi/efi_utils.h b/roms/ipxe/src/include/ipxe/efi/efi_utils.h
index 9164be190..57268daf7 100644
--- a/roms/ipxe/src/include/ipxe/efi/efi_utils.h
+++ b/roms/ipxe/src/include/ipxe/efi/efi_utils.h
@@ -6,7 +6,7 @@
* EFI utilities
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/efi/efi.h>
#include <ipxe/efi/Protocol/DevicePath.h>
diff --git a/roms/ipxe/src/include/ipxe/efi/efi_watchdog.h b/roms/ipxe/src/include/ipxe/efi/efi_watchdog.h
new file mode 100644
index 000000000..4a56b9a29
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/efi/efi_watchdog.h
@@ -0,0 +1,31 @@
+#ifndef _IPXE_EFI_WATCHDOG_H
+#define _IPXE_EFI_WATCHDOG_H
+
+/** @file
+ *
+ * EFI watchdog holdoff timer
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+extern struct retry_timer efi_watchdog;
+
+/**
+ * Start EFI watchdog holdoff timer
+ *
+ */
+static inline void efi_watchdog_start ( void ) {
+
+ start_timer_nodelay ( &efi_watchdog );
+}
+
+/**
+ * Stop EFI watchdog holdoff timer
+ *
+ */
+static inline void efi_watchdog_stop ( void ) {
+
+ stop_timer ( &efi_watchdog );
+}
+
+#endif /* _IPXE_EFI_WATCHDOG_H */
diff --git a/roms/ipxe/src/include/ipxe/efi/efi_wrap.h b/roms/ipxe/src/include/ipxe/efi/efi_wrap.h
index 7579e0fe9..d8ed1a5cc 100644
--- a/roms/ipxe/src/include/ipxe/efi/efi_wrap.h
+++ b/roms/ipxe/src/include/ipxe/efi/efi_wrap.h
@@ -6,7 +6,7 @@
* EFI driver interface
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/efi/efi.h>
diff --git a/roms/ipxe/src/include/ipxe/eisa.h b/roms/ipxe/src/include/ipxe/eisa.h
index 22a1ed94e..e7dac1f39 100644
--- a/roms/ipxe/src/include/ipxe/eisa.h
+++ b/roms/ipxe/src/include/ipxe/eisa.h
@@ -1,7 +1,7 @@
#ifndef EISA_H
#define EISA_H
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/isa_ids.h>
diff --git a/roms/ipxe/src/include/ipxe/elf.h b/roms/ipxe/src/include/ipxe/elf.h
index ec675c047..033c3f7a8 100644
--- a/roms/ipxe/src/include/ipxe/elf.h
+++ b/roms/ipxe/src/include/ipxe/elf.h
@@ -8,10 +8,21 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+#include <stdint.h>
+#include <ipxe/image.h>
#include <elf.h>
+typedef Elf32_Ehdr Elf_Ehdr;
+typedef Elf32_Phdr Elf_Phdr;
+typedef Elf32_Off Elf_Off;
+#define ELFCLASS ELFCLASS32
+
+extern int elf_segments ( struct image *image, Elf_Ehdr *ehdr,
+ int ( * process ) ( struct image *image,
+ Elf_Phdr *phdr, physaddr_t dest ),
+ physaddr_t *entry, physaddr_t *max );
extern int elf_load ( struct image *image, physaddr_t *entry, physaddr_t *max );
#endif /* _IPXE_ELF_H */
diff --git a/roms/ipxe/src/include/ipxe/eltorito.h b/roms/ipxe/src/include/ipxe/eltorito.h
index 3302b38b6..27e361b16 100644
--- a/roms/ipxe/src/include/ipxe/eltorito.h
+++ b/roms/ipxe/src/include/ipxe/eltorito.h
@@ -8,7 +8,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/iso9660.h>
diff --git a/roms/ipxe/src/include/ipxe/entropy.h b/roms/ipxe/src/include/ipxe/entropy.h
index adf325e79..beeb3abfa 100644
--- a/roms/ipxe/src/include/ipxe/entropy.h
+++ b/roms/ipxe/src/include/ipxe/entropy.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <string.h>
@@ -54,6 +54,7 @@ typedef uint8_t entropy_sample_t;
/* Include all architecture-independent entropy API headers */
#include <ipxe/null_entropy.h>
+#include <ipxe/efi/efi_entropy.h>
#include <ipxe/linux/linux_entropy.h>
/* Include all architecture-dependent entropy API headers */
diff --git a/roms/ipxe/src/include/ipxe/errfile.h b/roms/ipxe/src/include/ipxe/errfile.h
index f809337ff..e21c95938 100644
--- a/roms/ipxe/src/include/ipxe/errfile.h
+++ b/roms/ipxe/src/include/ipxe/errfile.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <bits/errfile.h>
@@ -68,6 +68,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define ERRFILE_fbcon ( ERRFILE_CORE | 0x001c0000 )
#define ERRFILE_ansicol ( ERRFILE_CORE | 0x001d0000 )
#define ERRFILE_ansicoldef ( ERRFILE_CORE | 0x001e0000 )
+#define ERRFILE_fault ( ERRFILE_CORE | 0x001f0000 )
+#define ERRFILE_blocktrans ( ERRFILE_CORE | 0x00200000 )
#define ERRFILE_eisa ( ERRFILE_DRIVER | 0x00000000 )
#define ERRFILE_isa ( ERRFILE_DRIVER | 0x00010000 )
@@ -76,12 +78,20 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define ERRFILE_pci ( ERRFILE_DRIVER | 0x00040000 )
#define ERRFILE_linux ( ERRFILE_DRIVER | 0x00050000 )
#define ERRFILE_pcivpd ( ERRFILE_DRIVER | 0x00060000 )
+#define ERRFILE_usb ( ERRFILE_DRIVER | 0x00070000 )
+#define ERRFILE_usbhub ( ERRFILE_DRIVER | 0x00080000 )
+#define ERRFILE_xhci ( ERRFILE_DRIVER | 0x00090000 )
+#define ERRFILE_ehci ( ERRFILE_DRIVER | 0x000a0000 )
+#define ERRFILE_uhci ( ERRFILE_DRIVER | 0x000b0000 )
+#define ERRFILE_usbhid ( ERRFILE_DRIVER | 0x000c0000 )
+#define ERRFILE_usbkbd ( ERRFILE_DRIVER | 0x000d0000 )
#define ERRFILE_nvs ( ERRFILE_DRIVER | 0x00100000 )
#define ERRFILE_spi ( ERRFILE_DRIVER | 0x00110000 )
#define ERRFILE_i2c_bit ( ERRFILE_DRIVER | 0x00120000 )
#define ERRFILE_spi_bit ( ERRFILE_DRIVER | 0x00130000 )
#define ERRFILE_nvsvpd ( ERRFILE_DRIVER | 0x00140000 )
+#define ERRFILE_uart ( ERRFILE_DRIVER | 0x00150000 )
#define ERRFILE_3c509 ( ERRFILE_DRIVER | 0x00200000 )
#define ERRFILE_bnx2 ( ERRFILE_DRIVER | 0x00210000 )
@@ -157,7 +167,11 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define ERRFILE_snp ( ERRFILE_DRIVER | 0x00680000 )
#define ERRFILE_netfront ( ERRFILE_DRIVER | 0x00690000 )
#define ERRFILE_nii ( ERRFILE_DRIVER | 0x006a0000 )
-
+#define ERRFILE_netvsc ( ERRFILE_DRIVER | 0x006b0000 )
+#define ERRFILE_ecm ( ERRFILE_DRIVER | 0x006c0000 )
+#define ERRFILE_ncm ( ERRFILE_DRIVER | 0x006d0000 )
+#define ERRFILE_usbnet ( ERRFILE_DRIVER | 0x006e0000 )
+#define ERRFILE_dm96xx ( ERRFILE_DRIVER | 0x006f0000 )
#define ERRFILE_scsi ( ERRFILE_DRIVER | 0x00700000 )
#define ERRFILE_arbel ( ERRFILE_DRIVER | 0x00710000 )
#define ERRFILE_hermon ( ERRFILE_DRIVER | 0x00720000 )
@@ -165,6 +179,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define ERRFILE_ata ( ERRFILE_DRIVER | 0x00740000 )
#define ERRFILE_srp ( ERRFILE_DRIVER | 0x00750000 )
#define ERRFILE_qib7322 ( ERRFILE_DRIVER | 0x00760000 )
+#define ERRFILE_smsc75xx ( ERRFILE_DRIVER | 0x00770000 )
+#define ERRFILE_intelvf ( ERRFILE_DRIVER | 0x00780000 )
+#define ERRFILE_intelxvf ( ERRFILE_DRIVER | 0x00790000 )
#define ERRFILE_aoe ( ERRFILE_NET | 0x00000000 )
#define ERRFILE_arp ( ERRFILE_NET | 0x00010000 )
@@ -227,6 +244,17 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define ERRFILE_ping ( ERRFILE_NET | 0x003a0000 )
#define ERRFILE_dhcpv6 ( ERRFILE_NET | 0x003b0000 )
#define ERRFILE_nfs_uri ( ERRFILE_NET | 0x003c0000 )
+#define ERRFILE_rndis ( ERRFILE_NET | 0x003d0000 )
+#define ERRFILE_pccrc ( ERRFILE_NET | 0x003e0000 )
+#define ERRFILE_stp ( ERRFILE_NET | 0x003f0000 )
+#define ERRFILE_pccrd ( ERRFILE_NET | 0x00400000 )
+#define ERRFILE_httpconn ( ERRFILE_NET | 0x00410000 )
+#define ERRFILE_httpauth ( ERRFILE_NET | 0x00420000 )
+#define ERRFILE_httpbasic ( ERRFILE_NET | 0x00430000 )
+#define ERRFILE_httpdigest ( ERRFILE_NET | 0x00440000 )
+#define ERRFILE_peerdisc ( ERRFILE_NET | 0x00450000 )
+#define ERRFILE_peerblk ( ERRFILE_NET | 0x00460000 )
+#define ERRFILE_peermux ( ERRFILE_NET | 0x00470000 )
#define ERRFILE_image ( ERRFILE_IMAGE | 0x00000000 )
#define ERRFILE_elf ( ERRFILE_IMAGE | 0x00010000 )
@@ -245,7 +273,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define ERRFILE_imgmgmt ( ERRFILE_OTHER | 0x00050000 )
#define ERRFILE_pxe_tftp ( ERRFILE_OTHER | 0x00060000 )
#define ERRFILE_pxe_udp ( ERRFILE_OTHER | 0x00070000 )
-#define ERRFILE_axtls_aes ( ERRFILE_OTHER | 0x00080000 )
+#define ERRFILE_aes ( ERRFILE_OTHER | 0x00080000 )
#define ERRFILE_cipher ( ERRFILE_OTHER | 0x00090000 )
#define ERRFILE_image_cmd ( ERRFILE_OTHER | 0x000a0000 )
#define ERRFILE_uri_test ( ERRFILE_OTHER | 0x000b0000 )
@@ -308,6 +336,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define ERRFILE_xengrant ( ERRFILE_OTHER | 0x00440000 )
#define ERRFILE_efi_utils ( ERRFILE_OTHER | 0x00450000 )
#define ERRFILE_efi_wrap ( ERRFILE_OTHER | 0x00460000 )
+#define ERRFILE_vmbus ( ERRFILE_OTHER | 0x00470000 )
+#define ERRFILE_efi_time ( ERRFILE_OTHER | 0x00480000 )
+#define ERRFILE_efi_watchdog ( ERRFILE_OTHER | 0x00490000 )
/** @} */
diff --git a/roms/ipxe/src/include/ipxe/errno/efi.h b/roms/ipxe/src/include/ipxe/errno/efi.h
index 2d2c50176..9f010f5fb 100644
--- a/roms/ipxe/src/include/ipxe/errno/efi.h
+++ b/roms/ipxe/src/include/ipxe/errno/efi.h
@@ -21,7 +21,7 @@
* as-is.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/efi/efi.h>
#include <ipxe/efi/Uefi/UefiBaseType.h>
diff --git a/roms/ipxe/src/include/ipxe/errno/linux.h b/roms/ipxe/src/include/ipxe/errno/linux.h
index 11309b4ad..99133c816 100644
--- a/roms/ipxe/src/include/ipxe/errno/linux.h
+++ b/roms/ipxe/src/include/ipxe/errno/linux.h
@@ -10,7 +10,7 @@
* directly as our platform error codes.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* Convert platform error code to platform component of iPXE error code
diff --git a/roms/ipxe/src/include/ipxe/errortab.h b/roms/ipxe/src/include/ipxe/errortab.h
index a2f6a70f5..4fe81a6be 100644
--- a/roms/ipxe/src/include/ipxe/errortab.h
+++ b/roms/ipxe/src/include/ipxe/errortab.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/tables.h>
diff --git a/roms/ipxe/src/include/ipxe/eth_slow.h b/roms/ipxe/src/include/ipxe/eth_slow.h
index 00509197d..f6d731b3b 100644
--- a/roms/ipxe/src/include/ipxe/eth_slow.h
+++ b/roms/ipxe/src/include/ipxe/eth_slow.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** Slow protocols header */
struct eth_slow_header {
diff --git a/roms/ipxe/src/include/ipxe/ethernet.h b/roms/ipxe/src/include/ipxe/ethernet.h
index d1263d7c3..dd04e00ce 100644
--- a/roms/ipxe/src/include/ipxe/ethernet.h
+++ b/roms/ipxe/src/include/ipxe/ethernet.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/netdevice.h>
diff --git a/roms/ipxe/src/include/ipxe/fakedhcp.h b/roms/ipxe/src/include/ipxe/fakedhcp.h
index ea06b06dc..d016b5237 100644
--- a/roms/ipxe/src/include/ipxe/fakedhcp.h
+++ b/roms/ipxe/src/include/ipxe/fakedhcp.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
diff --git a/roms/ipxe/src/include/ipxe/fault.h b/roms/ipxe/src/include/ipxe/fault.h
new file mode 100644
index 000000000..356296c35
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/fault.h
@@ -0,0 +1,53 @@
+#ifndef _IPXE_FAULT_H
+#define _IPXE_FAULT_H
+
+/** @file
+ *
+ * Fault injection
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
+#include <config/fault.h>
+
+extern int inject_fault_nonzero ( unsigned int rate );
+extern void inject_corruption_nonzero ( unsigned int rate, const void *data,
+ size_t len );
+
+/**
+ * Inject fault with a specified probability
+ *
+ * @v rate Reciprocal of fault probability (zero for no faults)
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+inject_fault ( unsigned int rate ) {
+
+ /* Force dead code elimination in non-fault-injecting builds */
+ if ( rate == 0 )
+ return 0;
+
+ return inject_fault_nonzero ( rate );
+}
+
+/**
+ * Corrupt data with a specified probability
+ *
+ * @v rate Reciprocal of fault probability (zero for no faults)
+ * @v data Data
+ * @v len Length of data
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) void
+inject_corruption ( unsigned int rate, const void *data, size_t len ) {
+
+ /* Force dead code elimination in non-fault-injecting builds */
+ if ( rate == 0 )
+ return;
+
+ return inject_corruption_nonzero ( rate, data, len );
+}
+
+#endif /* _IPXE_FAULT_H */
diff --git a/roms/ipxe/src/include/ipxe/fbcon.h b/roms/ipxe/src/include/ipxe/fbcon.h
index 0538449ac..d442bb918 100644
--- a/roms/ipxe/src/include/ipxe/fbcon.h
+++ b/roms/ipxe/src/include/ipxe/fbcon.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/ansiesc.h>
diff --git a/roms/ipxe/src/include/ipxe/fc.h b/roms/ipxe/src/include/ipxe/fc.h
index 6fdef092d..840d11f62 100644
--- a/roms/ipxe/src/include/ipxe/fc.h
+++ b/roms/ipxe/src/include/ipxe/fc.h
@@ -8,7 +8,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/refcnt.h>
diff --git a/roms/ipxe/src/include/ipxe/fcels.h b/roms/ipxe/src/include/ipxe/fcels.h
index 45fa69a4a..02f755115 100644
--- a/roms/ipxe/src/include/ipxe/fcels.h
+++ b/roms/ipxe/src/include/ipxe/fcels.h
@@ -8,7 +8,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/fc.h>
diff --git a/roms/ipxe/src/include/ipxe/fcns.h b/roms/ipxe/src/include/ipxe/fcns.h
index e25d9b9d5..9011a7be7 100644
--- a/roms/ipxe/src/include/ipxe/fcns.h
+++ b/roms/ipxe/src/include/ipxe/fcns.h
@@ -8,7 +8,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/fc.h>
diff --git a/roms/ipxe/src/include/ipxe/fcoe.h b/roms/ipxe/src/include/ipxe/fcoe.h
index 6ba5b406a..b61e82fea 100644
--- a/roms/ipxe/src/include/ipxe/fcoe.h
+++ b/roms/ipxe/src/include/ipxe/fcoe.h
@@ -8,7 +8,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/fc.h>
diff --git a/roms/ipxe/src/include/ipxe/fcp.h b/roms/ipxe/src/include/ipxe/fcp.h
index f6922bc7c..853ca13f6 100644
--- a/roms/ipxe/src/include/ipxe/fcp.h
+++ b/roms/ipxe/src/include/ipxe/fcp.h
@@ -8,7 +8,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/fc.h>
diff --git a/roms/ipxe/src/include/ipxe/features.h b/roms/ipxe/src/include/ipxe/features.h
index d8b8b2184..e86a2d226 100644
--- a/roms/ipxe/src/include/ipxe/features.h
+++ b/roms/ipxe/src/include/ipxe/features.h
@@ -11,7 +11,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @defgroup featurecat Feature categories
diff --git a/roms/ipxe/src/include/ipxe/fragment.h b/roms/ipxe/src/include/ipxe/fragment.h
index e311ad1e4..0069e5e08 100644
--- a/roms/ipxe/src/include/ipxe/fragment.h
+++ b/roms/ipxe/src/include/ipxe/fragment.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/list.h>
diff --git a/roms/ipxe/src/include/ipxe/ftp.h b/roms/ipxe/src/include/ipxe/ftp.h
index cbab12d2c..3180f1631 100644
--- a/roms/ipxe/src/include/ipxe/ftp.h
+++ b/roms/ipxe/src/include/ipxe/ftp.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** FTP default port */
#define FTP_PORT 21
diff --git a/roms/ipxe/src/include/ipxe/gdbserial.h b/roms/ipxe/src/include/ipxe/gdbserial.h
index a3b56173c..e1040c94e 100644
--- a/roms/ipxe/src/include/ipxe/gdbserial.h
+++ b/roms/ipxe/src/include/ipxe/gdbserial.h
@@ -7,15 +7,14 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
struct gdb_transport;
-/**
- * Set up the serial transport
- *
- * @ret transport suitable for starting the GDB stub or NULL on error
- */
-struct gdb_transport *gdbserial_configure ( void );
+extern struct gdb_transport * gdbserial_configure ( unsigned int port,
+ unsigned int baud,
+ uint8_t lcr );
#endif /* _IPXE_GDBSERIAL_H */
diff --git a/roms/ipxe/src/include/ipxe/gdbstub.h b/roms/ipxe/src/include/ipxe/gdbstub.h
index 319606747..13ca33ddb 100644
--- a/roms/ipxe/src/include/ipxe/gdbstub.h
+++ b/roms/ipxe/src/include/ipxe/gdbstub.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/tables.h>
diff --git a/roms/ipxe/src/include/ipxe/gdbudp.h b/roms/ipxe/src/include/ipxe/gdbudp.h
index db7a451c9..a1c091522 100644
--- a/roms/ipxe/src/include/ipxe/gdbudp.h
+++ b/roms/ipxe/src/include/ipxe/gdbudp.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
struct sockaddr_in;
struct gdb_transport;
diff --git a/roms/ipxe/src/include/ipxe/hash_df.h b/roms/ipxe/src/include/ipxe/hash_df.h
index 607a4a610..e57682446 100644
--- a/roms/ipxe/src/include/ipxe/hash_df.h
+++ b/roms/ipxe/src/include/ipxe/hash_df.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/crypto.h>
diff --git a/roms/ipxe/src/include/ipxe/hidemem.h b/roms/ipxe/src/include/ipxe/hidemem.h
index ddc9cd8b3..cc8d5ee37 100644
--- a/roms/ipxe/src/include/ipxe/hidemem.h
+++ b/roms/ipxe/src/include/ipxe/hidemem.h
@@ -8,7 +8,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
diff --git a/roms/ipxe/src/include/ipxe/hmac.h b/roms/ipxe/src/include/ipxe/hmac.h
index d5ec0868d..09d3e273d 100644
--- a/roms/ipxe/src/include/ipxe/hmac.h
+++ b/roms/ipxe/src/include/ipxe/hmac.h
@@ -6,7 +6,7 @@
* Keyed-Hashing for Message Authentication
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/crypto.h>
diff --git a/roms/ipxe/src/include/ipxe/hmac_drbg.h b/roms/ipxe/src/include/ipxe/hmac_drbg.h
index 8dfd2924f..a0f22da75 100644
--- a/roms/ipxe/src/include/ipxe/hmac_drbg.h
+++ b/roms/ipxe/src/include/ipxe/hmac_drbg.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/crypto.h>
diff --git a/roms/ipxe/src/include/ipxe/http.h b/roms/ipxe/src/include/ipxe/http.h
index cf8c0c7fa..a0dff7d00 100644
--- a/roms/ipxe/src/include/ipxe/http.h
+++ b/roms/ipxe/src/include/ipxe/http.h
@@ -7,7 +7,26 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
+#include <ipxe/refcnt.h>
+#include <ipxe/interface.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/process.h>
+#include <ipxe/retry.h>
+#include <ipxe/linebuf.h>
+#include <ipxe/pool.h>
+#include <ipxe/tables.h>
+
+struct http_transaction;
+
+/******************************************************************************
+ *
+ * HTTP URI schemes
+ *
+ ******************************************************************************
+ */
/** HTTP default port */
#define HTTP_PORT 80
@@ -15,10 +34,469 @@ FILE_LICENCE ( GPL2_OR_LATER );
/** HTTPS default port */
#define HTTPS_PORT 443
-extern int http_open_filter ( struct interface *xfer, struct uri *uri,
- unsigned int default_port,
- int ( * filter ) ( struct interface *,
- const char *,
- struct interface ** ) );
+/** An HTTP URI scheme */
+struct http_scheme {
+ /** Scheme name (e.g. "http" or "https") */
+ const char *name;
+ /** Default port */
+ unsigned int port;
+ /** Transport-layer filter (if any)
+ *
+ * @v xfer Data transfer interface
+ * @v name Host name
+ * @v next Next interface
+ * @ret rc Return status code
+ */
+ int ( * filter ) ( struct interface *xfer, const char *name,
+ struct interface **next );
+};
+
+/** HTTP scheme table */
+#define HTTP_SCHEMES __table ( struct http_scheme, "http_schemes" )
+
+/** Declare an HTTP scheme */
+#define __http_scheme __table_entry ( HTTP_SCHEMES, 01 )
+
+/******************************************************************************
+ *
+ * Connections
+ *
+ ******************************************************************************
+ */
+
+/** An HTTP connection
+ *
+ * This represents a potentially reusable connection to an HTTP
+ * server.
+ */
+struct http_connection {
+ /** Reference count */
+ struct refcnt refcnt;
+ /** Connection URI
+ *
+ * This encapsulates the server (and protocol) used for the
+ * connection. This may be the origin server or a proxy
+ * server.
+ */
+ struct uri *uri;
+ /** HTTP scheme */
+ struct http_scheme *scheme;
+ /** Transport layer interface */
+ struct interface socket;
+ /** Data transfer interface */
+ struct interface xfer;
+ /** Pooled connection */
+ struct pooled_connection pool;
+};
+
+/******************************************************************************
+ *
+ * HTTP methods
+ *
+ ******************************************************************************
+ */
+
+/** An HTTP method */
+struct http_method {
+ /** Method name (e.g. "GET" or "POST") */
+ const char *name;
+};
+
+extern struct http_method http_head;
+extern struct http_method http_get;
+extern struct http_method http_post;
+
+/******************************************************************************
+ *
+ * Requests
+ *
+ ******************************************************************************
+ */
+
+/** HTTP Digest authentication client nonce count
+ *
+ * We choose to generate a new client nonce each time.
+ */
+#define HTTP_DIGEST_NC "00000001"
+
+/** HTTP Digest authentication client nonce length
+ *
+ * We choose to use a 32-bit hex client nonce.
+ */
+#define HTTP_DIGEST_CNONCE_LEN 8
+
+/** HTTP Digest authentication response length
+ *
+ * The Digest authentication response is a Base16-encoded 16-byte MD5
+ * checksum.
+ */
+#define HTTP_DIGEST_RESPONSE_LEN 32
+
+/** HTTP request range descriptor */
+struct http_request_range {
+ /** Range start */
+ size_t start;
+ /** Range length, or zero for no range request */
+ size_t len;
+};
+
+/** HTTP request content descriptor */
+struct http_request_content {
+ /** Content type (if any) */
+ const char *type;
+ /** Content data (if any) */
+ const void *data;
+ /** Content length */
+ size_t len;
+};
+
+/** HTTP request authentication descriptor */
+struct http_request_auth {
+ /** Authentication scheme (if any) */
+ struct http_authentication *auth;
+ /** Username */
+ const char *username;
+ /** Password */
+ const char *password;
+ /** Quality of protection */
+ const char *qop;
+ /** Algorithm */
+ const char *algorithm;
+ /** Client nonce */
+ char cnonce[ HTTP_DIGEST_CNONCE_LEN + 1 /* NUL */ ];
+ /** Response */
+ char response[ HTTP_DIGEST_RESPONSE_LEN + 1 /* NUL */ ];
+};
+
+/** An HTTP request
+ *
+ * This represents a single request to be sent to a server, including
+ * the values required to construct all headers.
+ *
+ * Pointers within this structure must point to storage which is
+ * guaranteed to remain valid for the lifetime of the containing HTTP
+ * transaction.
+ */
+struct http_request {
+ /** Method */
+ struct http_method *method;
+ /** Request URI string */
+ const char *uri;
+ /** Server host name */
+ const char *host;
+ /** Range descriptor */
+ struct http_request_range range;
+ /** Content descriptor */
+ struct http_request_content content;
+ /** Authentication descriptor */
+ struct http_request_auth auth;
+};
+
+/** An HTTP request header */
+struct http_request_header {
+ /** Header name (e.g. "User-Agent") */
+ const char *name;
+ /** Construct remaining header line
+ *
+ * @v http HTTP transaction
+ * @v buf Buffer
+ * @v len Length of buffer
+ * @ret len Header length if present, or negative error
+ */
+ int ( * format ) ( struct http_transaction *http, char *buf,
+ size_t len );
+};
+
+/** HTTP request header table */
+#define HTTP_REQUEST_HEADERS \
+ __table ( struct http_request_header, "http_request_headers" )
+
+/** Declare an HTTP request header */
+#define __http_request_header __table_entry ( HTTP_REQUEST_HEADERS, 01 )
+
+/******************************************************************************
+ *
+ * Responses
+ *
+ ******************************************************************************
+ */
+
+/** HTTP response transfer descriptor */
+struct http_response_transfer {
+ /** Transfer encoding */
+ struct http_transfer_encoding *encoding;
+};
+
+/** HTTP response content descriptor */
+struct http_response_content {
+ /** Content length (may be zero) */
+ size_t len;
+ /** Content encoding */
+ struct http_content_encoding *encoding;
+};
+
+/** HTTP response authorization descriptor */
+struct http_response_auth {
+ /** Authentication scheme (if any) */
+ struct http_authentication *auth;
+ /** Realm */
+ const char *realm;
+ /** Quality of protection */
+ const char *qop;
+ /** Algorithm */
+ const char *algorithm;
+ /** Nonce */
+ const char *nonce;
+ /** Opaque */
+ const char *opaque;
+};
+
+/** An HTTP response
+ *
+ * This represents a single response received from the server,
+ * including all values parsed from headers.
+ *
+ * Pointers within this structure may point into the raw response
+ * buffer, and so should be invalidated when the response buffer is
+ * modified or discarded.
+ */
+struct http_response {
+ /** Raw response header lines
+ *
+ * This is the raw response data received from the server, up
+ * to and including the terminating empty line. String
+ * pointers within the response may point into this data
+ * buffer; NUL terminators will be added (overwriting the
+ * original terminating characters) as needed.
+ */
+ struct line_buffer headers;
+ /** Status code
+ *
+ * This is the raw HTTP numeric status code (e.g. 404).
+ */
+ unsigned int status;
+ /** Return status code
+ *
+ * This is the iPXE return status code corresponding to the
+ * HTTP status code (e.g. -ENOENT).
+ */
+ int rc;
+ /** Redirection location */
+ const char *location;
+ /** Transfer descriptor */
+ struct http_response_transfer transfer;
+ /** Content descriptor */
+ struct http_response_content content;
+ /** Authorization descriptor */
+ struct http_response_auth auth;
+ /** Retry delay (in seconds) */
+ unsigned int retry_after;
+ /** Flags */
+ unsigned int flags;
+};
+
+/** HTTP response flags */
+enum http_response_flags {
+ /** Keep connection alive after close */
+ HTTP_RESPONSE_KEEPALIVE = 0x0001,
+ /** Content length specified */
+ HTTP_RESPONSE_CONTENT_LEN = 0x0002,
+ /** Transaction may be retried on failure */
+ HTTP_RESPONSE_RETRY = 0x0004,
+};
+
+/** An HTTP response header */
+struct http_response_header {
+ /** Header name (e.g. "Transfer-Encoding") */
+ const char *name;
+ /** Parse header line
+ *
+ * @v http HTTP transaction
+ * @v line Remaining header line
+ * @ret rc Return status code
+ */
+ int ( * parse ) ( struct http_transaction *http, char *line );
+};
+
+/** HTTP response header table */
+#define HTTP_RESPONSE_HEADERS \
+ __table ( struct http_response_header, "http_response_headers" )
+
+/** Declare an HTTP response header */
+#define __http_response_header __table_entry ( HTTP_RESPONSE_HEADERS, 01 )
+
+/******************************************************************************
+ *
+ * Transactions
+ *
+ ******************************************************************************
+ */
+
+/** HTTP transaction state */
+struct http_state {
+ /** Transmit data
+ *
+ * @v http HTTP transaction
+ * @ret rc Return status code
+ */
+ int ( * tx ) ( struct http_transaction *http );
+ /** Receive data
+ *
+ * @v http HTTP transaction
+ * @v iobuf I/O buffer (may be claimed)
+ * @ret rc Return status code
+ */
+ int ( * rx ) ( struct http_transaction *http,
+ struct io_buffer **iobuf );
+ /** Server connection closed
+ *
+ * @v http HTTP transaction
+ * @v rc Reason for close
+ */
+ void ( * close ) ( struct http_transaction *http, int rc );
+};
+
+/** An HTTP transaction */
+struct http_transaction {
+ /** Reference count */
+ struct refcnt refcnt;
+ /** Data transfer interface */
+ struct interface xfer;
+ /** Content-decoded interface */
+ struct interface content;
+ /** Transfer-decoded interface */
+ struct interface transfer;
+ /** Server connection */
+ struct interface conn;
+ /** Transmit process */
+ struct process process;
+ /** Reconnection timer */
+ struct retry_timer timer;
+
+ /** Request URI */
+ struct uri *uri;
+ /** Request */
+ struct http_request request;
+ /** Response */
+ struct http_response response;
+ /** Temporary line buffer */
+ struct line_buffer linebuf;
+
+ /** Transaction state */
+ struct http_state *state;
+ /** Accumulated transfer-decoded length */
+ size_t len;
+ /** Chunk length remaining */
+ size_t remaining;
+};
+
+/******************************************************************************
+ *
+ * Transfer encoding
+ *
+ ******************************************************************************
+ */
+
+/** An HTTP transfer encoding */
+struct http_transfer_encoding {
+ /** Name */
+ const char *name;
+ /** Initialise transfer encoding
+ *
+ * @v http HTTP transaction
+ * @ret rc Return status code
+ */
+ int ( * init ) ( struct http_transaction *http );
+ /** Receive data state */
+ struct http_state state;
+};
+
+/** HTTP transfer encoding table */
+#define HTTP_TRANSFER_ENCODINGS \
+ __table ( struct http_transfer_encoding, "http_transfer_encodings" )
+
+/** Declare an HTTP transfer encoding */
+#define __http_transfer_encoding __table_entry ( HTTP_TRANSFER_ENCODINGS, 01 )
+
+/******************************************************************************
+ *
+ * Content encoding
+ *
+ ******************************************************************************
+ */
+
+/** An HTTP content encoding */
+struct http_content_encoding {
+ /** Name */
+ const char *name;
+ /** Check if content encoding is supported for this request
+ *
+ * @v http HTTP transaction
+ * @ret supported Content encoding is supported for this request
+ */
+ int ( * supported ) ( struct http_transaction *http );
+ /** Initialise content encoding
+ *
+ * @v http HTTP transaction
+ * @ret rc Return status code
+ */
+ int ( * init ) ( struct http_transaction *http );
+};
+
+/** HTTP content encoding table */
+#define HTTP_CONTENT_ENCODINGS \
+ __table ( struct http_content_encoding, "http_content_encodings" )
+
+/** Declare an HTTP content encoding */
+#define __http_content_encoding __table_entry ( HTTP_CONTENT_ENCODINGS, 01 )
+
+/******************************************************************************
+ *
+ * Authentication
+ *
+ ******************************************************************************
+ */
+
+/** An HTTP authentication scheme */
+struct http_authentication {
+ /** Name (e.g. "Digest") */
+ const char *name;
+ /** Perform authentication
+ *
+ * @v http HTTP transaction
+ * @ret rc Return status code
+ */
+ int ( * authenticate ) ( struct http_transaction *http );
+ /** Construct remaining "Authorization" header line
+ *
+ * @v http HTTP transaction
+ * @v buf Buffer
+ * @v len Length of buffer
+ * @ret len Header length if present, or negative error
+ */
+ int ( * format ) ( struct http_transaction *http, char *buf,
+ size_t len );
+};
+
+/** HTTP authentication scheme table */
+#define HTTP_AUTHENTICATIONS \
+ __table ( struct http_authentication, "http_authentications" )
+
+/** Declare an HTTP authentication scheme */
+#define __http_authentication __table_entry ( HTTP_AUTHENTICATIONS, 01 )
+
+/******************************************************************************
+ *
+ * General
+ *
+ ******************************************************************************
+ */
+
+extern char * http_token ( char **line, char **value );
+extern int http_connect ( struct interface *xfer, struct uri *uri );
+extern int http_open ( struct interface *xfer, struct http_method *method,
+ struct uri *uri, struct http_request_range *range,
+ struct http_request_content *content );
+extern int http_open_uri ( struct interface *xfer, struct uri *uri );
#endif /* _IPXE_HTTP_H */
diff --git a/roms/ipxe/src/include/ipxe/hyperv.h b/roms/ipxe/src/include/ipxe/hyperv.h
new file mode 100644
index 000000000..c61e2a083
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/hyperv.h
@@ -0,0 +1,232 @@
+#ifndef _IPXE_HYPERV_H
+#define _IPXE_HYPERV_H
+
+/** @file
+ *
+ * Hyper-V interface
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
+#include <ipxe/io.h>
+
+/** Hyper-V interface identification */
+#define HV_INTERFACE_ID 0x31237648 /* "Hv#1" */
+
+/** Guest OS identity for iPXE
+ *
+ * This field comprises:
+ *
+ * Bit 63 : set to 1 to indicate an open source OS
+ * Bits 62:56 : OS Type
+ * Bits 55:48 : OS ID
+ * Bits 47:16 : Version
+ * Bits 15:0 : Build number
+ *
+ * There appears to be no central registry for the "OS Type". The
+ * specification states that "Linux is 0x100", and the FreeBSD source
+ * states that "FreeBSD is 0x200". Both of these statements are
+ * actually referring to the combined "OS Type" and "OS ID" field.
+ *
+ * We choose to use 0x98ae: this is generated by setting bit 63 (to
+ * indicate an open source OS) and setting the OS Type+ID equal to the
+ * PnP vendor ID used in romprefix.S. No version information or build
+ * number is included.
+ */
+#define HV_GUEST_OS_ID_IPXE ( ( 1ULL << 63 ) | ( 0x18aeULL << 48 ) )
+
+/** Enable hypercall page */
+#define HV_HYPERCALL_ENABLE 0x00000001UL
+
+/** Enable SynIC */
+#define HV_SCONTROL_ENABLE 0x00000001UL
+
+/** Enable SynIC event flags */
+#define HV_SIEFP_ENABLE 0x00000001UL
+
+/** Enable SynIC messages */
+#define HV_SIMP_ENABLE 0x00000001UL
+
+/** Perform implicit EOI upon synthetic interrupt delivery */
+#define HV_SINT_AUTO_EOI 0x00020000UL
+
+/** Mask synthetic interrupt */
+#define HV_SINT_MASKED 0x00010000UL
+
+/** Synthetic interrupt vector */
+#define HV_SINT_VECTOR(x) ( (x) << 0 )
+
+/** Synthetic interrupt vector mask */
+#define HV_SINT_VECTOR_MASK HV_SINT_VECTOR ( 0xff )
+
+/** Post message */
+#define HV_POST_MESSAGE 0x005c
+
+/** A posted message
+ *
+ * This is the input parameter list for the HvPostMessage hypercall.
+ */
+struct hv_post_message {
+ /** Connection ID */
+ uint32_t id;
+ /** Padding */
+ uint32_t reserved;
+ /** Type */
+ uint32_t type;
+ /** Length of message */
+ uint32_t len;
+ /** Message */
+ uint8_t data[240];
+} __attribute__ (( packed ));
+
+/** A received message
+ *
+ * This is the HV_MESSAGE structure from the Hypervisor Top-Level
+ * Functional Specification. The field order given in the
+ * documentation is incorrect.
+ */
+struct hv_message {
+ /** Type */
+ uint32_t type;
+ /** Length of message */
+ uint8_t len;
+ /** Flags */
+ uint8_t flags;
+ /** Padding */
+ uint16_t reserved;
+ /** Origin */
+ uint64_t origin;
+ /** Message */
+ uint8_t data[240];
+} __attribute__ (( packed ));
+
+/** Signal event */
+#define HV_SIGNAL_EVENT 0x005d
+
+/** A signalled event */
+struct hv_signal_event {
+ /** Connection ID */
+ uint32_t id;
+ /** Flag number */
+ uint16_t flag;
+ /** Reserved */
+ uint16_t reserved;
+} __attribute__ (( packed ));
+
+/** A received event */
+struct hv_event {
+ /** Event flags */
+ uint8_t flags[256];
+} __attribute__ (( packed ));
+
+/** A monitor trigger group
+ *
+ * This is the HV_MONITOR_TRIGGER_GROUP structure from the Hypervisor
+ * Top-Level Functional Specification.
+ */
+struct hv_monitor_trigger {
+ /** Pending events */
+ uint32_t pending;
+ /** Armed events */
+ uint32_t armed;
+} __attribute__ (( packed ));
+
+/** A monitor parameter set
+ *
+ * This is the HV_MONITOR_PARAMETER structure from the Hypervisor
+ * Top-Level Functional Specification.
+ */
+struct hv_monitor_parameter {
+ /** Connection ID */
+ uint32_t id;
+ /** Flag number */
+ uint16_t flag;
+ /** Reserved */
+ uint16_t reserved;
+} __attribute__ (( packed ));
+
+/** A monitor page
+ *
+ * This is the HV_MONITOR_PAGE structure from the Hypervisor Top-Level
+ * Functional Specification.
+ */
+struct hv_monitor {
+ /** Flags */
+ uint32_t flags;
+ /** Reserved */
+ uint8_t reserved_a[4];
+ /** Trigger groups */
+ struct hv_monitor_trigger trigger[4];
+ /** Reserved */
+ uint8_t reserved_b[536];
+ /** Latencies */
+ uint16 latency[4][32];
+ /** Reserved */
+ uint8_t reserved_c[256];
+ /** Parameters */
+ struct hv_monitor_parameter param[4][32];
+ /** Reserved */
+ uint8_t reserved_d[1984];
+} __attribute__ (( packed ));
+
+/** A synthetic interrupt controller */
+struct hv_synic {
+ /** Message page */
+ struct hv_message *message;
+ /** Event flag page */
+ struct hv_event *event;
+};
+
+/** A message buffer */
+union hv_message_buffer {
+ /** Posted message */
+ struct hv_post_message posted;
+ /** Received message */
+ struct hv_message received;
+ /** Signalled event */
+ struct hv_signal_event signalled;
+};
+
+/** A Hyper-V hypervisor */
+struct hv_hypervisor {
+ /** Hypercall page */
+ void *hypercall;
+ /** Synthetic interrupt controller (SynIC) */
+ struct hv_synic synic;
+ /** Message buffer */
+ union hv_message_buffer *message;
+ /** Virtual machine bus */
+ struct vmbus *vmbus;
+};
+
+#include <bits/hyperv.h>
+
+/**
+ * Calculate the number of pages covering an address range
+ *
+ * @v data Start of data
+ * @v len Length of data (must be non-zero)
+ * @ret pfn_count Number of pages covered
+ */
+static inline unsigned int hv_pfn_count ( physaddr_t data, size_t len ) {
+ unsigned int first_pfn = ( data / PAGE_SIZE );
+ unsigned int last_pfn = ( ( data + len - 1 ) / PAGE_SIZE );
+
+ return ( last_pfn - first_pfn + 1 );
+}
+
+extern __attribute__ (( sentinel )) int
+hv_alloc_pages ( struct hv_hypervisor *hv, ... );
+extern __attribute__ (( sentinel )) void
+hv_free_pages ( struct hv_hypervisor *hv, ... );
+extern void hv_enable_sint ( struct hv_hypervisor *hv, unsigned int sintx );
+extern void hv_disable_sint ( struct hv_hypervisor *hv, unsigned int sintx );
+extern int hv_post_message ( struct hv_hypervisor *hv, unsigned int id,
+ unsigned int type, const void *data, size_t len );
+extern int hv_wait_for_message ( struct hv_hypervisor *hv, unsigned int sintx );
+extern int hv_signal_event ( struct hv_hypervisor *hv, unsigned int id,
+ unsigned int flag );
+
+#endif /* _IPXE_HYPERV_H */
diff --git a/roms/ipxe/src/include/ipxe/i2c.h b/roms/ipxe/src/include/ipxe/i2c.h
index c1f5a9bbd..46970515c 100644
--- a/roms/ipxe/src/include/ipxe/i2c.h
+++ b/roms/ipxe/src/include/ipxe/i2c.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/bitbash.h>
diff --git a/roms/ipxe/src/include/ipxe/ib_cm.h b/roms/ipxe/src/include/ipxe/ib_cm.h
index 7d08cd9b1..4913eebae 100644
--- a/roms/ipxe/src/include/ipxe/ib_cm.h
+++ b/roms/ipxe/src/include/ipxe/ib_cm.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/infiniband.h>
#include <ipxe/retry.h>
diff --git a/roms/ipxe/src/include/ipxe/ib_mad.h b/roms/ipxe/src/include/ipxe/ib_mad.h
index b8694833e..ae1eea7e4 100644
--- a/roms/ipxe/src/include/ipxe/ib_mad.h
+++ b/roms/ipxe/src/include/ipxe/ib_mad.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/ib_packet.h>
diff --git a/roms/ipxe/src/include/ipxe/ib_mcast.h b/roms/ipxe/src/include/ipxe/ib_mcast.h
index a5c22a03e..564066975 100644
--- a/roms/ipxe/src/include/ipxe/ib_mcast.h
+++ b/roms/ipxe/src/include/ipxe/ib_mcast.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/infiniband.h>
diff --git a/roms/ipxe/src/include/ipxe/ib_mi.h b/roms/ipxe/src/include/ipxe/ib_mi.h
index 5c5415b71..c7c8143ba 100644
--- a/roms/ipxe/src/include/ipxe/ib_mi.h
+++ b/roms/ipxe/src/include/ipxe/ib_mi.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/list.h>
#include <ipxe/retry.h>
diff --git a/roms/ipxe/src/include/ipxe/ib_packet.h b/roms/ipxe/src/include/ipxe/ib_packet.h
index a959967cb..f275fcb09 100644
--- a/roms/ipxe/src/include/ipxe/ib_packet.h
+++ b/roms/ipxe/src/include/ipxe/ib_packet.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
struct ib_device;
struct ib_queue_pair;
diff --git a/roms/ipxe/src/include/ipxe/ib_pathrec.h b/roms/ipxe/src/include/ipxe/ib_pathrec.h
index 1fe67f87d..a4e11ebe3 100644
--- a/roms/ipxe/src/include/ipxe/ib_pathrec.h
+++ b/roms/ipxe/src/include/ipxe/ib_pathrec.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/infiniband.h>
diff --git a/roms/ipxe/src/include/ipxe/ib_sma.h b/roms/ipxe/src/include/ipxe/ib_sma.h
index fa355c652..74003d045 100644
--- a/roms/ipxe/src/include/ipxe/ib_sma.h
+++ b/roms/ipxe/src/include/ipxe/ib_sma.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
struct ib_device;
struct ib_mad_interface;
diff --git a/roms/ipxe/src/include/ipxe/ib_smc.h b/roms/ipxe/src/include/ipxe/ib_smc.h
index 259d2cde1..f9b96b1bd 100644
--- a/roms/ipxe/src/include/ipxe/ib_smc.h
+++ b/roms/ipxe/src/include/ipxe/ib_smc.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/infiniband.h>
diff --git a/roms/ipxe/src/include/ipxe/icmp.h b/roms/ipxe/src/include/ipxe/icmp.h
index 0480ddfaf..803f8e019 100644
--- a/roms/ipxe/src/include/ipxe/icmp.h
+++ b/roms/ipxe/src/include/ipxe/icmp.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/iobuf.h>
diff --git a/roms/ipxe/src/include/ipxe/icmpv6.h b/roms/ipxe/src/include/ipxe/icmpv6.h
index b5ea54eab..0474ddca8 100644
--- a/roms/ipxe/src/include/ipxe/icmpv6.h
+++ b/roms/ipxe/src/include/ipxe/icmpv6.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/tables.h>
@@ -40,6 +40,18 @@ struct icmpv6_handler {
/** Declare an ICMPv6 handler */
#define __icmpv6_handler __table_entry ( ICMPV6_HANDLERS, 01 )
+/** ICMPv6 destination unreachable */
+#define ICMPV6_DESTINATION_UNREACHABLE 1
+
+/** ICMPv6 packet too big */
+#define ICMPV6_PACKET_TOO_BIG 2
+
+/** ICMPv6 time exceeded */
+#define ICMPV6_TIME_EXCEEDED 3
+
+/** ICMPv6 parameter problem */
+#define ICMPV6_PARAMETER_PROBLEM 4
+
/** ICMPv6 echo request */
#define ICMPV6_ECHO_REQUEST 128
diff --git a/roms/ipxe/src/include/ipxe/if_arp.h b/roms/ipxe/src/include/ipxe/if_arp.h
index fd36e9c67..4eb1f80b7 100644
--- a/roms/ipxe/src/include/ipxe/if_arp.h
+++ b/roms/ipxe/src/include/ipxe/if_arp.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
diff --git a/roms/ipxe/src/include/ipxe/if_ether.h b/roms/ipxe/src/include/ipxe/if_ether.h
index a7e237349..58d91b976 100644
--- a/roms/ipxe/src/include/ipxe/if_ether.h
+++ b/roms/ipxe/src/include/ipxe/if_ether.h
@@ -1,7 +1,7 @@
#ifndef _IPXE_IF_ETHER_H
#define _IPXE_IF_ETHER_H
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
diff --git a/roms/ipxe/src/include/ipxe/image.h b/roms/ipxe/src/include/ipxe/image.h
index 5d7080a75..6abd7a2d2 100644
--- a/roms/ipxe/src/include/ipxe/image.h
+++ b/roms/ipxe/src/include/ipxe/image.h
@@ -8,7 +8,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/tables.h>
#include <ipxe/list.h>
@@ -163,7 +163,6 @@ extern int image_set_cmdline ( struct image *image, const char *cmdline );
extern int register_image ( struct image *image );
extern void unregister_image ( struct image *image );
struct image * find_image ( const char *name );
-extern int image_probe ( struct image *image );
extern int image_exec ( struct image *image );
extern int image_replace ( struct image *replacement );
extern int image_select ( struct image *image );
diff --git a/roms/ipxe/src/include/ipxe/in.h b/roms/ipxe/src/include/ipxe/in.h
index de96ca22a..0ebf441c2 100644
--- a/roms/ipxe/src/include/ipxe/in.h
+++ b/roms/ipxe/src/include/ipxe/in.h
@@ -1,9 +1,10 @@
#ifndef _IPXE_IN_H
#define _IPXE_IN_H
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
+#include <byteswap.h>
#include <ipxe/socket.h>
/* Protocol numbers */
@@ -15,17 +16,22 @@ FILE_LICENCE ( GPL2_OR_LATER );
/* IP address constants */
-#define INADDR_NONE 0xffffffff
+#define INADDR_NONE htonl ( 0xffffffff )
-#define INADDR_BROADCAST 0xffffffff
+#define INADDR_BROADCAST htonl ( 0xffffffff )
-#define IN_CLASSA(addr) ( ( (addr) & 0x80000000 ) == 0x00000000 )
-#define IN_CLASSA_NET 0xff000000
-#define IN_CLASSB(addr) ( ( (addr) & 0xc0000000 ) == 0x80000000 )
-#define IN_CLASSB_NET 0xffff0000
-#define IN_CLASSC(addr) ( ( (addr) & 0xe0000000 ) == 0xc0000000 )
-#define IN_CLASSC_NET 0xffffff00
-#define IN_MULTICAST(addr) ( ( (addr) & 0xf0000000 ) == 0xe0000000 )
+#define INADDR_NET_CLASSA htonl ( 0xff000000 )
+#define INADDR_NET_CLASSB htonl ( 0xffff0000 )
+#define INADDR_NET_CLASSC htonl ( 0xffffff00 )
+
+#define IN_IS_CLASSA( addr ) \
+ ( ( (addr) & htonl ( 0x80000000 ) ) == htonl ( 0x00000000 ) )
+#define IN_IS_CLASSB( addr ) \
+ ( ( (addr) & htonl ( 0xc0000000 ) ) == htonl ( 0x80000000 ) )
+#define IN_IS_CLASSC( addr ) \
+ ( ( (addr) & htonl ( 0xe0000000 ) ) == htonl ( 0xc0000000 ) )
+#define IN_IS_MULTICAST( addr ) \
+ ( ( (addr) & htonl ( 0xf0000000 ) ) == htonl ( 0xe0000000 ) )
/**
* IP address structure
@@ -63,6 +69,9 @@ struct in6_addr {
( ( *( ( const uint16_t * ) (addr) ) & htons ( 0xffc0 ) ) == \
htons ( 0xfe80 ) )
+#define IN6_IS_ADDR_NONGLOBAL( addr ) \
+ ( IN6_IS_ADDR_LINKLOCAL (addr) || IN6_IS_ADDR_MULTICAST (addr) )
+
/**
* IPv4 socket address
*/
@@ -76,6 +85,11 @@ struct sockaddr_in {
uint16_t sin_flags;
/** TCP/IP port (part of struct @c sockaddr_tcpip) */
uint16_t sin_port;
+ /** Scope ID (part of struct @c sockaddr_tcpip)
+ *
+ * For multicast addresses, this is the network device index.
+ */
+ uint16_t sin_scope_id;
/** IPv4 address */
struct in_addr sin_addr;
/** Padding
@@ -87,6 +101,7 @@ struct sockaddr_in {
( sizeof ( sa_family_t ) /* sin_family */ +
sizeof ( uint16_t ) /* sin_flags */ +
sizeof ( uint16_t ) /* sin_port */ +
+ sizeof ( uint16_t ) /* sin_scope_id */ +
sizeof ( struct in_addr ) /* sin_addr */ ) ];
} __attribute__ (( packed, may_alias ));
@@ -103,9 +118,10 @@ struct sockaddr_in6 {
uint16_t sin6_flags;
/** TCP/IP port (part of struct @c sockaddr_tcpip) */
uint16_t sin6_port;
- /** Scope ID
+ /** Scope ID (part of struct @c sockaddr_tcpip)
*
- * For link-local addresses, this is the network device index.
+ * For link-local or multicast addresses, this is the network
+ * device index.
*/
uint16_t sin6_scope_id;
/** IPv6 address */
diff --git a/roms/ipxe/src/include/ipxe/infiniband.h b/roms/ipxe/src/include/ipxe/infiniband.h
index f546ea61b..87cfe5082 100644
--- a/roms/ipxe/src/include/ipxe/infiniband.h
+++ b/roms/ipxe/src/include/ipxe/infiniband.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/refcnt.h>
diff --git a/roms/ipxe/src/include/ipxe/init.h b/roms/ipxe/src/include/ipxe/init.h
index 19c5925bf..025cfaf37 100644
--- a/roms/ipxe/src/include/ipxe/init.h
+++ b/roms/ipxe/src/include/ipxe/init.h
@@ -1,7 +1,7 @@
#ifndef _IPXE_INIT_H
#define _IPXE_INIT_H
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/tables.h>
@@ -26,10 +26,9 @@ struct init_fn {
*/
#define INIT_EARLY 01 /**< Early initialisation */
-#define INIT_SERIAL 02 /**< Serial driver initialisation */
-#define INIT_CONSOLE 03 /**< Console initialisation */
-#define INIT_NORMAL 04 /**< Normal initialisation */
-#define INIT_LATE 05 /**< Late initialisation */
+#define INIT_CONSOLE 02 /**< Console initialisation */
+#define INIT_NORMAL 03 /**< Normal initialisation */
+#define INIT_LATE 04 /**< Late initialisation */
/** @} */
diff --git a/roms/ipxe/src/include/ipxe/interface.h b/roms/ipxe/src/include/ipxe/interface.h
index a474aaad0..a8d823775 100644
--- a/roms/ipxe/src/include/ipxe/interface.h
+++ b/roms/ipxe/src/include/ipxe/interface.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <ipxe/refcnt.h>
@@ -145,6 +145,11 @@ extern void intf_close ( struct interface *intf, int rc );
extern void intf_shutdown ( struct interface *intf, int rc );
extern void intf_restart ( struct interface *intf, int rc );
+extern void intf_poke ( struct interface *intf,
+ void ( type ) ( struct interface *intf ) );
+#define intf_poke_TYPE( object_type ) \
+ typeof ( void ( object_type ) )
+
extern struct interface_descriptor null_intf_desc;
extern struct interface null_intf;
diff --git a/roms/ipxe/src/include/ipxe/io.h b/roms/ipxe/src/include/ipxe/io.h
index 29ccfd1fa..af767915d 100644
--- a/roms/ipxe/src/include/ipxe/io.h
+++ b/roms/ipxe/src/include/ipxe/io.h
@@ -16,7 +16,7 @@
* the address parameter.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/api.h>
diff --git a/roms/ipxe/src/include/ipxe/iobuf.h b/roms/ipxe/src/include/ipxe/iobuf.h
index b2b0cb440..27d285d44 100644
--- a/roms/ipxe/src/include/ipxe/iobuf.h
+++ b/roms/ipxe/src/include/ipxe/iobuf.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <assert.h>
@@ -217,5 +217,6 @@ extern void free_iob ( struct io_buffer *iobuf );
extern void iob_pad ( struct io_buffer *iobuf, size_t min_len );
extern int iob_ensure_headroom ( struct io_buffer *iobuf, size_t len );
extern struct io_buffer * iob_concatenate ( struct list_head *list );
+extern struct io_buffer * iob_split ( struct io_buffer *iobuf, size_t len );
#endif /* _IPXE_IOBUF_H */
diff --git a/roms/ipxe/src/include/ipxe/ip.h b/roms/ipxe/src/include/ipxe/ip.h
index 1a93a552e..285be6dcd 100644
--- a/roms/ipxe/src/include/ipxe/ip.h
+++ b/roms/ipxe/src/include/ipxe/ip.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/in.h>
diff --git a/roms/ipxe/src/include/ipxe/ipoib.h b/roms/ipxe/src/include/ipxe/ipoib.h
index 68ff8df49..b34dd32d0 100644
--- a/roms/ipxe/src/include/ipxe/ipoib.h
+++ b/roms/ipxe/src/include/ipxe/ipoib.h
@@ -6,7 +6,7 @@
* IP over Infiniband
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/if_arp.h>
#include <ipxe/infiniband.h>
diff --git a/roms/ipxe/src/include/ipxe/ipstat.h b/roms/ipxe/src/include/ipxe/ipstat.h
index c554c1859..b34ed5fcf 100644
--- a/roms/ipxe/src/include/ipxe/ipstat.h
+++ b/roms/ipxe/src/include/ipxe/ipstat.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/tables.h>
diff --git a/roms/ipxe/src/include/ipxe/ipv6.h b/roms/ipxe/src/include/ipxe/ipv6.h
index 48aaf677e..b500382c1 100644
--- a/roms/ipxe/src/include/ipxe/ipv6.h
+++ b/roms/ipxe/src/include/ipxe/ipv6.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <string.h>
diff --git a/roms/ipxe/src/include/ipxe/isa_ids.h b/roms/ipxe/src/include/ipxe/isa_ids.h
index 1faf1148d..d815bda34 100644
--- a/roms/ipxe/src/include/ipxe/isa_ids.h
+++ b/roms/ipxe/src/include/ipxe/isa_ids.h
@@ -19,7 +19,7 @@
* the underlying "meaning" is big-endian.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <byteswap.h>
diff --git a/roms/ipxe/src/include/ipxe/isapnp.h b/roms/ipxe/src/include/ipxe/isapnp.h
index b0b0e98d6..59beac986 100644
--- a/roms/ipxe/src/include/ipxe/isapnp.h
+++ b/roms/ipxe/src/include/ipxe/isapnp.h
@@ -17,6 +17,10 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*
* Portions of this code:
* Copyright (C) 2001 P.J.H.Fox (fox@roestock.demon.co.uk)
@@ -34,7 +38,7 @@
*
***************************************************************************/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifndef ISAPNP_H
#define ISAPNP_H
diff --git a/roms/ipxe/src/include/ipxe/iscsi.h b/roms/ipxe/src/include/ipxe/iscsi.h
index be71360a0..c75ff4188 100644
--- a/roms/ipxe/src/include/ipxe/iscsi.h
+++ b/roms/ipxe/src/include/ipxe/iscsi.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/socket.h>
diff --git a/roms/ipxe/src/include/ipxe/iso9660.h b/roms/ipxe/src/include/ipxe/iso9660.h
index 02c2ae377..34cb8f0a1 100644
--- a/roms/ipxe/src/include/ipxe/iso9660.h
+++ b/roms/ipxe/src/include/ipxe/iso9660.h
@@ -8,7 +8,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
diff --git a/roms/ipxe/src/include/ipxe/isqrt.h b/roms/ipxe/src/include/ipxe/isqrt.h
index 58ed42f0c..68255d1bc 100644
--- a/roms/ipxe/src/include/ipxe/isqrt.h
+++ b/roms/ipxe/src/include/ipxe/isqrt.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
extern unsigned long isqrt ( unsigned long value );
diff --git a/roms/ipxe/src/include/ipxe/job.h b/roms/ipxe/src/include/ipxe/job.h
index a2369f7c2..7e1bd8109 100644
--- a/roms/ipxe/src/include/ipxe/job.h
+++ b/roms/ipxe/src/include/ipxe/job.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/interface.h>
diff --git a/roms/ipxe/src/include/ipxe/jumpscroll.h b/roms/ipxe/src/include/ipxe/jumpscroll.h
new file mode 100644
index 000000000..7a5b111c1
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/jumpscroll.h
@@ -0,0 +1,50 @@
+#ifndef _IPXE_JUMPSCROLL_H
+#define _IPXE_JUMPSCROLL_H
+
+/** @file
+ *
+ * Jump scrolling
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/** A jump scroller */
+struct jump_scroller {
+ /** Maximum number of visible rows */
+ unsigned int rows;
+ /** Total number of items */
+ unsigned int count;
+ /** Currently selected item */
+ unsigned int current;
+ /** First visible item */
+ unsigned int first;
+};
+
+/**
+ * Check if jump scroller is currently on first page
+ *
+ * @v scroll Jump scroller
+ * @ret is_first Scroller is currently on first page
+ */
+static inline int jump_scroll_is_first ( struct jump_scroller *scroll ) {
+
+ return ( scroll->first == 0 );
+}
+
+/**
+ * Check if jump scroller is currently on last page
+ *
+ * @v scroll Jump scroller
+ * @ret is_last Scroller is currently on last page
+ */
+static inline int jump_scroll_is_last ( struct jump_scroller *scroll ) {
+
+ return ( ( scroll->first + scroll->rows ) >= scroll->count );
+}
+
+extern int jump_scroll_key ( struct jump_scroller *scroll, int key );
+extern int jump_scroll_move ( struct jump_scroller *scroll, int move );
+extern int jump_scroll ( struct jump_scroller *scroll );
+
+#endif /* _IPXE_JUMPSCROLL_H */
diff --git a/roms/ipxe/src/include/ipxe/keymap.h b/roms/ipxe/src/include/ipxe/keymap.h
index 9ac42a6b1..0f1b0c656 100644
--- a/roms/ipxe/src/include/ipxe/keymap.h
+++ b/roms/ipxe/src/include/ipxe/keymap.h
@@ -8,7 +8,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/tables.h>
diff --git a/roms/ipxe/src/include/ipxe/keys.h b/roms/ipxe/src/include/ipxe/keys.h
index 8b13550b9..d15267a1f 100644
--- a/roms/ipxe/src/include/ipxe/keys.h
+++ b/roms/ipxe/src/include/ipxe/keys.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/*
* Symbolic names for some standard ASCII characters
@@ -58,6 +58,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
*/
#define KEY_ANSI( n, terminator ) ( 0x100 * ( (n) + 1 ) + (terminator) )
+#define KEY_ANSI_N( key ) ( ( (key) / 0x100 ) - 1 )
+#define KEY_ANSI_TERMINATOR( key ) ( (key) & 0xff )
#define KEY_MIN 0x101
#define KEY_UP KEY_ANSI ( 0, 'A' ) /**< Up arrow */
diff --git a/roms/ipxe/src/include/ipxe/linebuf.h b/roms/ipxe/src/include/ipxe/linebuf.h
index 706ef2554..630278a04 100644
--- a/roms/ipxe/src/include/ipxe/linebuf.h
+++ b/roms/ipxe/src/include/ipxe/linebuf.h
@@ -7,24 +7,24 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stddef.h>
/** A line buffer */
struct line_buffer {
- /** Current string in the buffer */
+ /** Data buffer */
char *data;
- /** Length of current string, excluding the terminating NUL */
+ /** Length of buffered data */
size_t len;
- /** String is ready to read */
- int ready;
+ /** Most recently consumed length */
+ size_t consumed;
};
extern char * buffered_line ( struct line_buffer *linebuf );
-extern ssize_t line_buffer ( struct line_buffer *linebuf,
- const char *data, size_t len );
+extern int line_buffer ( struct line_buffer *linebuf,
+ const char *data, size_t len );
extern void empty_line_buffer ( struct line_buffer *linebuf );
#endif /* _IPXE_LINEBUF_H */
diff --git a/roms/ipxe/src/include/ipxe/lineconsole.h b/roms/ipxe/src/include/ipxe/lineconsole.h
index 925c0accc..31117e73c 100644
--- a/roms/ipxe/src/include/ipxe/lineconsole.h
+++ b/roms/ipxe/src/include/ipxe/lineconsole.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/ansiesc.h>
diff --git a/roms/ipxe/src/include/ipxe/linux/linux_entropy.h b/roms/ipxe/src/include/ipxe/linux/linux_entropy.h
index bd89bd52f..afef6fe19 100644
--- a/roms/ipxe/src/include/ipxe/linux/linux_entropy.h
+++ b/roms/ipxe/src/include/ipxe/linux/linux_entropy.h
@@ -3,11 +3,11 @@
/** @file
*
- * iPXE entropy API for linux
+ * /dev/random-based entropy source
*
*/
-FILE_LICENCE(GPL2_OR_LATER);
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifdef ENTROPY_LINUX
#define ENTROPY_PREFIX_linux
@@ -23,10 +23,12 @@ FILE_LICENCE(GPL2_OR_LATER);
static inline __always_inline double
ENTROPY_INLINE ( linux, min_entropy_per_sample ) ( void ) {
- /* We read single bytes from /dev/random and assume that each
- * contains full entropy.
+ /* linux_get_noise() reads a single byte from /dev/random,
+ * which is supposed to block until a sufficient amount of
+ * entropy is available. We therefore assume that each sample
+ * contains exactly 8 bits of entropy.
*/
- return 8;
+ return 8.0;
}
#endif /* _IPXE_LINUX_ENTROPY_H */
diff --git a/roms/ipxe/src/include/ipxe/linux/linux_nap.h b/roms/ipxe/src/include/ipxe/linux/linux_nap.h
index 5bac7242f..d072886c7 100644
--- a/roms/ipxe/src/include/ipxe/linux/linux_nap.h
+++ b/roms/ipxe/src/include/ipxe/linux/linux_nap.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE(GPL2_OR_LATER);
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifdef NAP_LINUX
#define NAP_PREFIX_linux
diff --git a/roms/ipxe/src/include/ipxe/linux/linux_pci.h b/roms/ipxe/src/include/ipxe/linux/linux_pci.h
index 439166733..22ae7f1bc 100644
--- a/roms/ipxe/src/include/ipxe/linux/linux_pci.h
+++ b/roms/ipxe/src/include/ipxe/linux/linux_pci.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifdef PCIAPI_LINUX
#define PCIAPI_PREFIX_linux
diff --git a/roms/ipxe/src/include/ipxe/linux/linux_smbios.h b/roms/ipxe/src/include/ipxe/linux/linux_smbios.h
index 6d51e13ba..16c6d8acd 100644
--- a/roms/ipxe/src/include/ipxe/linux/linux_smbios.h
+++ b/roms/ipxe/src/include/ipxe/linux/linux_smbios.h
@@ -3,11 +3,11 @@
/** @file
*
- * iPXE SMBIOS API for linux
+ * iPXE SMBIOS API for Linux
*
*/
-FILE_LICENCE(GPL2_OR_LATER);
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifdef SMBIOS_LINUX
#define SMBIOS_PREFIX_linux
diff --git a/roms/ipxe/src/include/ipxe/linux/linux_time.h b/roms/ipxe/src/include/ipxe/linux/linux_time.h
index 93a257730..872ef5ade 100644
--- a/roms/ipxe/src/include/ipxe/linux/linux_time.h
+++ b/roms/ipxe/src/include/ipxe/linux/linux_time.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifdef TIME_LINUX
#define TIME_PREFIX_linux
diff --git a/roms/ipxe/src/include/ipxe/linux/linux_timer.h b/roms/ipxe/src/include/ipxe/linux/linux_timer.h
index 379507417..7f46e36b2 100644
--- a/roms/ipxe/src/include/ipxe/linux/linux_timer.h
+++ b/roms/ipxe/src/include/ipxe/linux/linux_timer.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifdef TIMER_LINUX
#define TIMER_PREFIX_linux
diff --git a/roms/ipxe/src/include/ipxe/linux/linux_uaccess.h b/roms/ipxe/src/include/ipxe/linux/linux_uaccess.h
index e4d16d9e0..acd919a85 100644
--- a/roms/ipxe/src/include/ipxe/linux/linux_uaccess.h
+++ b/roms/ipxe/src/include/ipxe/linux/linux_uaccess.h
@@ -1,116 +1,108 @@
-/*
- * Copyright (C) 2010 Piotr Jaroszyński <p.jaroszynski@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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
#ifndef _IPXE_LINUX_UACCESS_H
#define _IPXE_LINUX_UACCESS_H
-FILE_LICENCE(GPL2_OR_LATER);
-
/** @file
*
- * iPXE user access API for linux
+ * iPXE user access API for Linux
+ *
+ * We run with no distinction between internal and external addresses,
+ * so can use trivial_virt_to_user() et al.
*
- * In linux userspace virtual == user == phys addresses.
- * Physical addresses also being the same is wrong, but there is no general way
- * of converting userspace addresses to physical as what appears to be
- * contiguous in userspace is physically fragmented.
- * Currently only the DMA memory is special-cased, but its conversion to bus
- * addresses is done in phys_to_bus.
- * This is known to break virtio as it is passing phys addresses to the virtual
- * device.
+ * We have no concept of the underlying physical addresses, since
+ * these are not exposed to userspace. We provide a stub
+ * implementation of user_to_phys() since this is required by
+ * alloc_memblock(). We provide no implementation of phys_to_user();
+ * any code attempting to access physical addresses will therefore
+ * (correctly) fail to link.
*/
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
#ifdef UACCESS_LINUX
#define UACCESS_PREFIX_linux
#else
#define UACCESS_PREFIX_linux __linux_
#endif
-static inline __always_inline userptr_t
-UACCESS_INLINE(linux, 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(linux, user_to_phys)(userptr_t userptr, off_t offset)
-{
- return userptr + offset;
+UACCESS_INLINE ( linux, user_to_phys ) ( userptr_t userptr, off_t offset ) {
+
+ /* We do not know the real underlying physical address. We
+ * provide this stub implementation only because it is
+ * required by alloc_memblock() (which allocates memory with
+ * specified physical address alignment). We assume that the
+ * low-order bits of virtual addresses match the low-order
+ * bits of physical addresses, and so simply returning the
+ * virtual address will suffice for the purpose of determining
+ * alignment.
+ */
+ return ( userptr + offset );
}
static inline __always_inline userptr_t
-UACCESS_INLINE(linux, virt_to_user)(volatile const void *addr)
-{
- return trivial_virt_to_user(addr);
+UACCESS_INLINE ( linux, virt_to_user ) ( volatile const void *addr ) {
+ return trivial_virt_to_user ( addr );
}
static inline __always_inline void *
-UACCESS_INLINE(linux, user_to_virt)(userptr_t userptr, off_t offset)
-{
- return trivial_user_to_virt(userptr, offset);
+UACCESS_INLINE ( linux, user_to_virt ) ( userptr_t userptr, off_t offset ) {
+ return trivial_user_to_virt ( userptr, offset );
}
static inline __always_inline userptr_t
-UACCESS_INLINE(linux, userptr_add)(userptr_t userptr, off_t offset)
-{
- return trivial_userptr_add(userptr, offset);
+UACCESS_INLINE ( linux, userptr_add ) ( userptr_t userptr, off_t offset ) {
+ return trivial_userptr_add ( userptr, offset );
}
static inline __always_inline off_t
-UACCESS_INLINE(linux, userptr_sub)(userptr_t userptr, userptr_t subtrahend)
-{
+UACCESS_INLINE ( linux, userptr_sub ) ( userptr_t userptr,
+ userptr_t subtrahend ) {
return trivial_userptr_sub ( userptr, subtrahend );
}
static inline __always_inline void
-UACCESS_INLINE(linux, 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);
+UACCESS_INLINE ( linux, 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(linux, 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);
+UACCESS_INLINE ( linux, 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 int
-UACCESS_INLINE(linux, memcmp_user)(userptr_t first, off_t first_off, userptr_t second, off_t second_off, size_t len)
-{
- return trivial_memcmp_user(first, first_off, second, second_off, len);
+UACCESS_INLINE ( linux, memcmp_user ) ( userptr_t first, off_t first_off,
+ userptr_t second, off_t second_off,
+ size_t len ) {
+ return trivial_memcmp_user ( first, first_off, second, second_off, len);
}
static inline __always_inline void
-UACCESS_INLINE(linux, memset_user)(userptr_t buffer, off_t offset, int c, size_t len)
-{
- trivial_memset_user(buffer, offset, c, len);
+UACCESS_INLINE ( linux, 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(linux, strlen_user)(userptr_t buffer, off_t offset)
-{
- return trivial_strlen_user(buffer, offset);
+UACCESS_INLINE ( linux, strlen_user ) ( userptr_t buffer, off_t offset ) {
+ return trivial_strlen_user ( buffer, offset );
}
static inline __always_inline off_t
-UACCESS_INLINE(linux, memchr_user)(userptr_t buffer, off_t offset, int c, size_t len)
-{
- return trivial_memchr_user(buffer, offset, c, len);
+UACCESS_INLINE ( linux, memchr_user ) ( userptr_t buffer, off_t offset,
+ int c, size_t len ) {
+ return trivial_memchr_user ( buffer, offset, c, len );
}
#endif /* _IPXE_LINUX_UACCESS_H */
diff --git a/roms/ipxe/src/include/ipxe/linux/linux_umalloc.h b/roms/ipxe/src/include/ipxe/linux/linux_umalloc.h
index 4de55ecf3..1811d0bc6 100644
--- a/roms/ipxe/src/include/ipxe/linux/linux_umalloc.h
+++ b/roms/ipxe/src/include/ipxe/linux/linux_umalloc.h
@@ -1,14 +1,14 @@
#ifndef _IPXE_LINUX_UMALLOC_H
#define _IPXE_LINUX_UMALLOC_H
-FILE_LICENCE(GPL2_OR_LATER);
-
/** @file
*
- * iPXE user memory allocation API for linux
+ * iPXE user memory allocation API for Linux
*
*/
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
#ifdef UMALLOC_LINUX
#define UMALLOC_PREFIX_linux
#else
diff --git a/roms/ipxe/src/include/ipxe/linux_compat.h b/roms/ipxe/src/include/ipxe/linux_compat.h
index 6f6ed97d7..4704c4817 100644
--- a/roms/ipxe/src/include/ipxe/linux_compat.h
+++ b/roms/ipxe/src/include/ipxe/linux_compat.h
@@ -10,7 +10,7 @@
* intended to be a substitute for proper porting.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <errno.h>
diff --git a/roms/ipxe/src/include/ipxe/list.h b/roms/ipxe/src/include/ipxe/list.h
index 581ec9806..6a9b76f91 100644
--- a/roms/ipxe/src/include/ipxe/list.h
+++ b/roms/ipxe/src/include/ipxe/list.h
@@ -9,7 +9,7 @@
* list.h.
*/
-FILE_LICENCE ( GPL2_ONLY );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <assert.h>
diff --git a/roms/ipxe/src/include/ipxe/login_ui.h b/roms/ipxe/src/include/ipxe/login_ui.h
index 01e5479f7..313e07349 100644
--- a/roms/ipxe/src/include/ipxe/login_ui.h
+++ b/roms/ipxe/src/include/ipxe/login_ui.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
extern int login_ui ( void );
diff --git a/roms/ipxe/src/include/ipxe/malloc.h b/roms/ipxe/src/include/ipxe/malloc.h
index bbd6cb898..dd158b8e6 100644
--- a/roms/ipxe/src/include/ipxe/malloc.h
+++ b/roms/ipxe/src/include/ipxe/malloc.h
@@ -9,7 +9,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/*
* Prototypes for the standard functions (malloc() et al) are in
@@ -77,8 +77,8 @@ static inline void * __malloc malloc_dma ( size_t size, size_t phys_align ) {
* If @c ptr is NULL, no action is taken.
*/
static inline void free_dma ( void *ptr, size_t size ) {
- free_memblock ( ptr, size );
VALGRIND_FREELIKE_BLOCK ( ptr, 0 );
+ free_memblock ( ptr, size );
}
/** A cache discarder */
diff --git a/roms/ipxe/src/include/ipxe/mca.h b/roms/ipxe/src/include/ipxe/mca.h
index d86dab195..11470ec93 100644
--- a/roms/ipxe/src/include/ipxe/mca.h
+++ b/roms/ipxe/src/include/ipxe/mca.h
@@ -5,7 +5,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifndef MCA_H
#define MCA_H
diff --git a/roms/ipxe/src/include/ipxe/md5.h b/roms/ipxe/src/include/ipxe/md5.h
index 860bc4769..05c3974c8 100644
--- a/roms/ipxe/src/include/ipxe/md5.h
+++ b/roms/ipxe/src/include/ipxe/md5.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/crypto.h>
diff --git a/roms/ipxe/src/include/ipxe/memblock.h b/roms/ipxe/src/include/ipxe/memblock.h
index 13af3e433..2bb38c460 100644
--- a/roms/ipxe/src/include/ipxe/memblock.h
+++ b/roms/ipxe/src/include/ipxe/memblock.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/uaccess.h>
diff --git a/roms/ipxe/src/include/ipxe/menu.h b/roms/ipxe/src/include/ipxe/menu.h
index f2b3caccc..3cc99be48 100644
--- a/roms/ipxe/src/include/ipxe/menu.h
+++ b/roms/ipxe/src/include/ipxe/menu.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/list.h>
diff --git a/roms/ipxe/src/include/ipxe/mii.h b/roms/ipxe/src/include/ipxe/mii.h
index f53ad4a62..c2245b49e 100644
--- a/roms/ipxe/src/include/ipxe/mii.h
+++ b/roms/ipxe/src/include/ipxe/mii.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <mii.h>
#include <ipxe/netdevice.h>
@@ -114,5 +114,7 @@ mii_dump ( struct mii_interface *mii ) {
extern int mii_restart ( struct mii_interface *mii );
extern int mii_reset ( struct mii_interface *mii );
+extern int mii_check_link ( struct mii_interface *mii,
+ struct net_device *netdev );
#endif /* _IPXE_MII_H */
diff --git a/roms/ipxe/src/include/ipxe/monojob.h b/roms/ipxe/src/include/ipxe/monojob.h
index aedc37eca..1661d91c2 100644
--- a/roms/ipxe/src/include/ipxe/monojob.h
+++ b/roms/ipxe/src/include/ipxe/monojob.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
struct interface;
diff --git a/roms/ipxe/src/include/ipxe/mount.h b/roms/ipxe/src/include/ipxe/mount.h
index ca958117a..2d42ba080 100644
--- a/roms/ipxe/src/include/ipxe/mount.h
+++ b/roms/ipxe/src/include/ipxe/mount.h
@@ -9,7 +9,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** NFS MOUNT protocol number */
#define ONCRPC_MOUNT 100005
diff --git a/roms/ipxe/src/include/ipxe/nap.h b/roms/ipxe/src/include/ipxe/nap.h
index afc887910..f4de778c4 100644
--- a/roms/ipxe/src/include/ipxe/nap.h
+++ b/roms/ipxe/src/include/ipxe/nap.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/api.h>
#include <config/nap.h>
diff --git a/roms/ipxe/src/include/ipxe/ndp.h b/roms/ipxe/src/include/ipxe/ndp.h
index 7388f938e..1815236f5 100644
--- a/roms/ipxe/src/include/ipxe/ndp.h
+++ b/roms/ipxe/src/include/ipxe/ndp.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/in.h>
diff --git a/roms/ipxe/src/include/ipxe/neighbour.h b/roms/ipxe/src/include/ipxe/neighbour.h
index f2a3946f1..1c1d1b6ca 100644
--- a/roms/ipxe/src/include/ipxe/neighbour.h
+++ b/roms/ipxe/src/include/ipxe/neighbour.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/refcnt.h>
diff --git a/roms/ipxe/src/include/ipxe/net80211_err.h b/roms/ipxe/src/include/ipxe/net80211_err.h
index 7df3d0d85..32ccc257f 100644
--- a/roms/ipxe/src/include/ipxe/net80211_err.h
+++ b/roms/ipxe/src/include/ipxe/net80211_err.h
@@ -10,7 +10,7 @@
* Copyright (c) 2009 Joshua Oreman <oremanj@rwcr.net>.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/include/ipxe/netdevice.h b/roms/ipxe/src/include/ipxe/netdevice.h
index 95ad1cf1b..a1d207ffc 100644
--- a/roms/ipxe/src/include/ipxe/netdevice.h
+++ b/roms/ipxe/src/include/ipxe/netdevice.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/list.h>
@@ -15,6 +15,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/refcnt.h>
#include <ipxe/settings.h>
#include <ipxe/interface.h>
+#include <ipxe/retry.h>
struct io_buffer;
struct net_device;
@@ -36,13 +37,12 @@ struct device;
/** Maximum length of a link-layer header
*
- * The longest currently-supported link-layer header is for 802.11: a
- * 24-byte frame header plus an 8-byte 802.3 LLC/SNAP header, plus a
- * possible 4-byte VLAN header. (The IPoIB link-layer pseudo-header
- * doesn't actually include link-layer addresses; see ipoib.c for
- * details.)
+ * The longest currently-supported link-layer header is for RNDIS: an
+ * 8-byte RNDIS header, a 32-byte RNDIS packet message header, a
+ * 14-byte Ethernet header and a possible 4-byte VLAN header. Round
+ * up to 64 bytes.
*/
-#define MAX_LL_HEADER_LEN 36
+#define MAX_LL_HEADER_LEN 64
/** Maximum length of a network-layer address */
#define MAX_NET_ADDR_LEN 16
@@ -393,6 +393,8 @@ struct net_device {
* indicates the error preventing link-up.
*/
int link_rc;
+ /** Link block timer */
+ struct retry_timer link_block;
/** Maximum packet length
*
* This length includes any link-layer headers.
@@ -428,6 +430,14 @@ struct net_device {
/** Network device receive queue processing is frozen */
#define NETDEV_RX_FROZEN 0x0004
+/** Network device interrupts are unsupported
+ *
+ * This flag can be used by a network device to indicate that
+ * interrupts are not supported despite the presence of an irq()
+ * method.
+ */
+#define NETDEV_IRQ_UNSUPPORTED 0x0008
+
/** Link-layer protocol table */
#define LL_PROTOCOLS __table ( struct ll_protocol, "ll_protocols" )
@@ -615,6 +625,17 @@ netdev_link_ok ( struct net_device *netdev ) {
}
/**
+ * Check link block state of network device
+ *
+ * @v netdev Network device
+ * @ret link_blocked Link is blocked
+ */
+static inline __attribute__ (( always_inline )) int
+netdev_link_blocked ( struct net_device *netdev ) {
+ return ( timer_running ( &netdev->link_block ) );
+}
+
+/**
* Check whether or not network device is open
*
* @v netdev Network device
@@ -633,7 +654,8 @@ netdev_is_open ( struct net_device *netdev ) {
*/
static inline __attribute__ (( always_inline )) int
netdev_irq_supported ( struct net_device *netdev ) {
- return ( netdev->op->irq != NULL );
+ return ( ( netdev->op->irq != NULL ) &&
+ ! ( netdev->state & NETDEV_IRQ_UNSUPPORTED ) );
}
/**
@@ -662,6 +684,9 @@ extern void netdev_rx_freeze ( struct net_device *netdev );
extern void netdev_rx_unfreeze ( struct net_device *netdev );
extern void netdev_link_err ( struct net_device *netdev, int rc );
extern void netdev_link_down ( struct net_device *netdev );
+extern void netdev_link_block ( struct net_device *netdev,
+ unsigned long timeout );
+extern void netdev_link_unblock ( struct net_device *netdev );
extern int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf );
extern void netdev_tx_defer ( struct net_device *netdev,
struct io_buffer *iobuf );
diff --git a/roms/ipxe/src/include/ipxe/nfs.h b/roms/ipxe/src/include/ipxe/nfs.h
index 498ed5a27..69b8b5381 100644
--- a/roms/ipxe/src/include/ipxe/nfs.h
+++ b/roms/ipxe/src/include/ipxe/nfs.h
@@ -10,7 +10,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** NFS protocol number */
#define ONCRPC_NFS 100003
diff --git a/roms/ipxe/src/include/ipxe/nfs_open.h b/roms/ipxe/src/include/ipxe/nfs_open.h
index caba977f7..8572c41b3 100644
--- a/roms/ipxe/src/include/ipxe/nfs_open.h
+++ b/roms/ipxe/src/include/ipxe/nfs_open.h
@@ -7,6 +7,6 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#endif /* _IPXE_NFS_OPEN_H */
diff --git a/roms/ipxe/src/include/ipxe/nfs_uri.h b/roms/ipxe/src/include/ipxe/nfs_uri.h
index d88bd6f65..aaa6d3749 100644
--- a/roms/ipxe/src/include/ipxe/nfs_uri.h
+++ b/roms/ipxe/src/include/ipxe/nfs_uri.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/uri.h>
diff --git a/roms/ipxe/src/include/ipxe/null_entropy.h b/roms/ipxe/src/include/ipxe/null_entropy.h
index 646d1a17e..91adefa69 100644
--- a/roms/ipxe/src/include/ipxe/null_entropy.h
+++ b/roms/ipxe/src/include/ipxe/null_entropy.h
@@ -9,7 +9,7 @@
* security-sensitive environment.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
diff --git a/roms/ipxe/src/include/ipxe/null_nap.h b/roms/ipxe/src/include/ipxe/null_nap.h
index 0c0704bc7..17145b48b 100644
--- a/roms/ipxe/src/include/ipxe/null_nap.h
+++ b/roms/ipxe/src/include/ipxe/null_nap.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifdef NAP_NULL
#define NAP_PREFIX_null
diff --git a/roms/ipxe/src/include/ipxe/null_reboot.h b/roms/ipxe/src/include/ipxe/null_reboot.h
index 3de36c5b3..5de38afc0 100644
--- a/roms/ipxe/src/include/ipxe/null_reboot.h
+++ b/roms/ipxe/src/include/ipxe/null_reboot.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifdef REBOOT_NULL
#define REBOOT_PREFIX_null
diff --git a/roms/ipxe/src/include/ipxe/null_sanboot.h b/roms/ipxe/src/include/ipxe/null_sanboot.h
index 2b3a2c74d..58f03339f 100644
--- a/roms/ipxe/src/include/ipxe/null_sanboot.h
+++ b/roms/ipxe/src/include/ipxe/null_sanboot.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifdef SANBOOT_NULL
#define SANBOOT_PREFIX_null
diff --git a/roms/ipxe/src/include/ipxe/null_time.h b/roms/ipxe/src/include/ipxe/null_time.h
index 2b72cdf50..d2b15194b 100644
--- a/roms/ipxe/src/include/ipxe/null_time.h
+++ b/roms/ipxe/src/include/ipxe/null_time.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifdef TIME_NULL
#define TIME_PREFIX_null
diff --git a/roms/ipxe/src/include/ipxe/nvo.h b/roms/ipxe/src/include/ipxe/nvo.h
index 1a629da78..7a3c7a3db 100644
--- a/roms/ipxe/src/include/ipxe/nvo.h
+++ b/roms/ipxe/src/include/ipxe/nvo.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/dhcpopts.h>
diff --git a/roms/ipxe/src/include/ipxe/nvs.h b/roms/ipxe/src/include/ipxe/nvs.h
index 4733123cf..5789f4c0d 100644
--- a/roms/ipxe/src/include/ipxe/nvs.h
+++ b/roms/ipxe/src/include/ipxe/nvs.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
diff --git a/roms/ipxe/src/include/ipxe/nvsvpd.h b/roms/ipxe/src/include/ipxe/nvsvpd.h
index 3450e5c71..4c50daf85 100644
--- a/roms/ipxe/src/include/ipxe/nvsvpd.h
+++ b/roms/ipxe/src/include/ipxe/nvsvpd.h
@@ -8,7 +8,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/nvs.h>
#include <ipxe/pcivpd.h>
diff --git a/roms/ipxe/src/include/ipxe/ocsp.h b/roms/ipxe/src/include/ipxe/ocsp.h
index 387e28f81..71fa41dc9 100644
--- a/roms/ipxe/src/include/ipxe/ocsp.h
+++ b/roms/ipxe/src/include/ipxe/ocsp.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdarg.h>
#include <time.h>
diff --git a/roms/ipxe/src/include/ipxe/oncrpc.h b/roms/ipxe/src/include/ipxe/oncrpc.h
index 76c1260f2..071468711 100644
--- a/roms/ipxe/src/include/ipxe/oncrpc.h
+++ b/roms/ipxe/src/include/ipxe/oncrpc.h
@@ -11,7 +11,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** ONC RCP Version */
#define ONCRPC_VERS 2
diff --git a/roms/ipxe/src/include/ipxe/oncrpc_iob.h b/roms/ipxe/src/include/ipxe/oncrpc_iob.h
index 4858d96b5..b55043770 100644
--- a/roms/ipxe/src/include/ipxe/oncrpc_iob.h
+++ b/roms/ipxe/src/include/ipxe/oncrpc_iob.h
@@ -13,7 +13,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* Add a string to the end of an I/O buffer
diff --git a/roms/ipxe/src/include/ipxe/open.h b/roms/ipxe/src/include/ipxe/open.h
index a522f0cd1..43d4cdc66 100644
--- a/roms/ipxe/src/include/ipxe/open.h
+++ b/roms/ipxe/src/include/ipxe/open.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdarg.h>
#include <ipxe/tables.h>
diff --git a/roms/ipxe/src/include/ipxe/params.h b/roms/ipxe/src/include/ipxe/params.h
index c2d82d9cf..dd3292efc 100644
--- a/roms/ipxe/src/include/ipxe/params.h
+++ b/roms/ipxe/src/include/ipxe/params.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/list.h>
#include <ipxe/refcnt.h>
diff --git a/roms/ipxe/src/include/ipxe/parseopt.h b/roms/ipxe/src/include/ipxe/parseopt.h
index 840de7497..829b3431c 100644
--- a/roms/ipxe/src/include/ipxe/parseopt.h
+++ b/roms/ipxe/src/include/ipxe/parseopt.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stddef.h>
diff --git a/roms/ipxe/src/include/ipxe/pccrc.h b/roms/ipxe/src/include/ipxe/pccrc.h
new file mode 100644
index 000000000..7f0963428
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/pccrc.h
@@ -0,0 +1,447 @@
+#ifndef _IPXE_PCCRC_H
+#define _IPXE_PCCRC_H
+
+/** @file
+ *
+ * Peer Content Caching and Retrieval: Content Identification [MS-PCCRC]
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
+#include <byteswap.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/crypto.h>
+
+/******************************************************************************
+ *
+ * Content Information versioning
+ *
+ ******************************************************************************
+ *
+ * Note that version 1 data structures are little-endian, but version
+ * 2 data structures are big-endian.
+ */
+
+/** Content Information version number */
+union peerdist_info_version {
+ /** Raw version number
+ *
+ * Always little-endian, regardless of whether the
+ * encompassing structure is version 1 (little-endian) or
+ * version 2 (big-endian).
+ */
+ uint16_t raw;
+ /** Major:minor version number */
+ struct {
+ /** Minor version number */
+ uint8_t minor;
+ /** Major version number */
+ uint8_t major;
+ } __attribute__ (( packed ));
+} __attribute__ (( packed ));
+
+/** Content Information version 1 */
+#define PEERDIST_INFO_V1 0x0100
+
+/** Content Information version 2 */
+#define PEERDIST_INFO_V2 0x0200
+
+/******************************************************************************
+ *
+ * Content Information version 1
+ *
+ ******************************************************************************
+ */
+
+/** Content Information version 1 data structure header
+ *
+ * All fields are little-endian.
+ */
+struct peerdist_info_v1 {
+ /** Version number */
+ union peerdist_info_version version;
+ /** Hash algorithm
+ *
+ * This is a @c PEERDIST_INFO_V1_HASH_XXX constant.
+ */
+ uint32_t hash;
+ /** Length to skip in first segment
+ *
+ * Length at the start of the first segment which is not
+ * included within the content range.
+ */
+ uint32_t first;
+ /** Length to read in last segment, or zero
+ *
+ * Length within the last segment which is included within the
+ * content range. A zero value indicates that the whole of
+ * the last segment is included within the content range.
+ */
+ uint32_t last;
+ /** Number of segments within the content information */
+ uint32_t segments;
+ /* Followed by a variable-length array of segment descriptions
+ * and a list of variable-length block descriptions:
+ *
+ * peerdist_info_v1_segment_t(digestsize) segment[segments];
+ * peerdist_info_v1_block_t(digestsize, block0.blocks) block0;
+ * peerdist_info_v1_block_t(digestsize, block1.blocks) block1;
+ * ...
+ * peerdist_info_v1_block_t(digestsize, blockN.blocks) blockN;
+ */
+} __attribute__ (( packed ));
+
+/** SHA-256 hash algorithm */
+#define PEERDIST_INFO_V1_HASH_SHA256 0x0000800cUL
+
+/** SHA-384 hash algorithm */
+#define PEERDIST_INFO_V1_HASH_SHA384 0x0000800dUL
+
+/** SHA-512 hash algorithm */
+#define PEERDIST_INFO_V1_HASH_SHA512 0x0000800eUL
+
+/** Content Information version 1 segment description header
+ *
+ * All fields are little-endian.
+ */
+struct peerdist_info_v1_segment {
+ /** Offset of this segment within the content */
+ uint64_t offset;
+ /** Length of this segment
+ *
+ * Should always be 32MB, except for the last segment within
+ * the content.
+ */
+ uint32_t len;
+ /** Block size for this segment
+ *
+ * Should always be 64kB. Note that the last block within the
+ * last segment may actually be less than 64kB.
+ */
+ uint32_t blksize;
+ /* Followed by two variable-length hashes:
+ *
+ * uint8_t hash[digestsize];
+ * uint8_t secret[digestsize];
+ *
+ * where digestsize is the digest size for the selected hash
+ * algorithm.
+ *
+ * Note that the hash is taken over (the hashes of all blocks
+ * within) the entire segment, even if the blocks do not
+ * intersect the content range (and so do not appear within
+ * the block list). It therefore functions only as a segment
+ * identifier; it cannot be used to verify the content of the
+ * segment (since we may not download all blocks within the
+ * segment).
+ */
+} __attribute__ (( packed ));
+
+/** Content Information version 1 segment description
+ *
+ * @v digestsize Digest size
+ */
+#define peerdist_info_v1_segment_t( digestsize ) \
+ struct { \
+ struct peerdist_info_v1_segment segment; \
+ uint8_t hash[digestsize]; \
+ uint8_t secret[digestsize]; \
+ } __attribute__ (( packed ))
+
+/** Content Information version 1 block description header
+ *
+ * All fields are little-endian.
+ */
+struct peerdist_info_v1_block {
+ /** Number of blocks within the block description
+ *
+ * This is the number of blocks within the segment which
+ * overlap the content range. It may therefore be less than
+ * the number of blocks within the segment.
+ */
+ uint32_t blocks;
+ /* Followed by an array of variable-length hashes:
+ *
+ * uint8_t hash[blocks][digestsize];
+ *
+ * where digestsize is the digest size for the selected hash
+ * algorithm.
+ */
+ } __attribute__ (( packed ));
+
+/** Content Information version 1 block description
+ *
+ * @v digestsize Digest size
+ * @v blocks Number of blocks
+ */
+#define peerdist_info_v1_block_t( digestsize, blocks ) \
+ struct { \
+ struct peerdist_info_v1_block block; \
+ uint8_t hash[blocks][digestsize]; \
+ } __attribute__ (( packed ))
+
+/******************************************************************************
+ *
+ * Content Information version 2
+ *
+ ******************************************************************************
+ */
+
+/** Content Information version 2 data structure header
+ *
+ * All fields are big-endian.
+ */
+struct peerdist_info_v2 {
+ /** Version number */
+ union peerdist_info_version version;
+ /** Hash algorithm
+ *
+ * This is a @c PEERDIST_INFO_V2_HASH_XXX constant.
+ */
+ uint8_t hash;
+ /** Offset of the first segment within the content */
+ uint64_t offset;
+ /** Index of the first segment within the content */
+ uint64_t index;
+ /** Length to skip in first segment
+ *
+ * Length at the start of the first segment which is not
+ * included within the content range.
+ */
+ uint32_t first;
+ /** Length of content range, or zero
+ *
+ * Length of the content range. A zero indicates that
+ * everything up to the end of the last segment is included in
+ * the content range.
+ */
+ uint64_t len;
+ /* Followed by a list of chunk descriptions */
+} __attribute__ (( packed ));
+
+/** SHA-512 hash algorithm with output truncated to first 256 bits */
+#define PEERDIST_INFO_V2_HASH_SHA512_TRUNC 0x04
+
+/** Content Information version 2 chunk description header
+ *
+ * All fields are big-endian.
+ */
+struct peerdist_info_v2_chunk {
+ /** Chunk type */
+ uint8_t type;
+ /** Chunk data length */
+ uint32_t len;
+ /* Followed by an array of segment descriptions:
+ *
+ * peerdist_info_v2_segment_t(digestsize) segment[segments]
+ *
+ * where digestsize is the digest size for the selected hash
+ * algorithm, and segments is equal to @c len divided by the
+ * size of each segment array entry.
+ */
+} __attribute__ (( packed ));
+
+/** Content Information version 2 chunk description
+ *
+ * @v digestsize Digest size
+ */
+#define peerdist_info_v2_chunk_t( digestsize ) \
+ struct { \
+ struct peerdist_info_v2_chunk chunk; \
+ peerdist_info_v2_segment_t ( digestsize ) segment[0]; \
+ } __attribute__ (( packed ))
+
+/** Chunk type */
+#define PEERDIST_INFO_V2_CHUNK_TYPE 0x00
+
+/** Content Information version 2 segment description header
+ *
+ * All fields are big-endian.
+ */
+struct peerdist_info_v2_segment {
+ /** Segment length */
+ uint32_t len;
+ /* Followed by two variable-length hashes:
+ *
+ * uint8_t hash[digestsize];
+ * uint8_t secret[digestsize];
+ *
+ * where digestsize is the digest size for the selected hash
+ * algorithm.
+ */
+} __attribute__ (( packed ));
+
+/** Content Information version 2 segment description
+ *
+ * @v digestsize Digest size
+ */
+#define peerdist_info_v2_segment_t( digestsize ) \
+ struct { \
+ struct peerdist_info_v2_segment segment; \
+ uint8_t hash[digestsize]; \
+ uint8_t secret[digestsize]; \
+ } __attribute__ (( packed ))
+
+/******************************************************************************
+ *
+ * Content Information
+ *
+ ******************************************************************************
+ */
+
+/** Maximum digest size for any supported algorithm
+ *
+ * The largest digest size that we support is for SHA-512 at 64 bytes
+ */
+#define PEERDIST_DIGEST_MAX_SIZE 64
+
+/** Raw content information */
+struct peerdist_raw {
+ /** Data buffer */
+ userptr_t data;
+ /** Length of data buffer */
+ size_t len;
+};
+
+/** A content range */
+struct peerdist_range {
+ /** Start offset */
+ size_t start;
+ /** End offset */
+ size_t end;
+};
+
+/** Content information */
+struct peerdist_info {
+ /** Raw content information */
+ struct peerdist_raw raw;
+
+ /** Content information operations */
+ struct peerdist_info_operations *op;
+ /** Digest algorithm */
+ struct digest_algorithm *digest;
+ /** Digest size
+ *
+ * Note that this may be shorter than the digest size of the
+ * digest algorithm. The truncation does not always take
+ * place as soon as a digest is calculated. For example,
+ * version 2 content information uses SHA-512 with a truncated
+ * digest size of 32 (256 bits), but the segment identifier
+ * ("HoHoDk") is calculated by using HMAC with the full
+ * SHA-512 digest and then truncating the HMAC output, rather
+ * than by simply using HMAC with the truncated SHA-512
+ * digest. This is, of course, totally undocumented.
+ */
+ size_t digestsize;
+ /** Content range */
+ struct peerdist_range range;
+ /** Trimmed content range */
+ struct peerdist_range trim;
+ /** Number of segments within the content information */
+ unsigned int segments;
+};
+
+/** A content information segment */
+struct peerdist_info_segment {
+ /** Content information */
+ const struct peerdist_info *info;
+ /** Segment index */
+ unsigned int index;
+
+ /** Content range
+ *
+ * Note that this range may exceed the overall content range.
+ */
+ struct peerdist_range range;
+ /** Number of blocks within this segment */
+ unsigned int blocks;
+ /** Block size */
+ size_t blksize;
+ /** Segment hash of data
+ *
+ * This is MS-PCCRC's "HoD".
+ */
+ uint8_t hash[PEERDIST_DIGEST_MAX_SIZE];
+ /** Segment secret
+ *
+ * This is MS-PCCRC's "Ke = Kp".
+ */
+ uint8_t secret[PEERDIST_DIGEST_MAX_SIZE];
+ /** Segment identifier
+ *
+ * This is MS-PCCRC's "HoHoDk".
+ */
+ uint8_t id[PEERDIST_DIGEST_MAX_SIZE];
+};
+
+/** Magic string constant used to calculate segment identifier
+ *
+ * Note that the MS-PCCRC specification states that this constant is
+ *
+ * "the null-terminated ASCII string constant "MS_P2P_CACHING";
+ * string literals are all ASCII strings with NULL terminators
+ * unless otherwise noted."
+ *
+ * The specification lies. This constant is a UTF-16LE string, not an
+ * ASCII string. The terminating wNUL *is* included within the
+ * constant.
+ */
+#define PEERDIST_SEGMENT_ID_MAGIC L"MS_P2P_CACHING"
+
+/** A content information block */
+struct peerdist_info_block {
+ /** Content information segment */
+ const struct peerdist_info_segment *segment;
+ /** Block index */
+ unsigned int index;
+
+ /** Content range
+ *
+ * Note that this range may exceed the overall content range.
+ */
+ struct peerdist_range range;
+ /** Trimmed content range */
+ struct peerdist_range trim;
+ /** Block hash */
+ uint8_t hash[PEERDIST_DIGEST_MAX_SIZE];
+};
+
+/** Content information operations */
+struct peerdist_info_operations {
+ /**
+ * Populate content information
+ *
+ * @v info Content information to fill in
+ * @ret rc Return status code
+ */
+ int ( * info ) ( struct peerdist_info *info );
+ /**
+ * Populate content information segment
+ *
+ * @v segment Content information segment to fill in
+ * @ret rc Return status code
+ */
+ int ( * segment ) ( struct peerdist_info_segment *segment );
+ /**
+ * Populate content information block
+ *
+ * @v block Content information block to fill in
+ * @ret rc Return status code
+ */
+ int ( * block ) ( struct peerdist_info_block *block );
+};
+
+extern struct digest_algorithm sha512_trunc_algorithm;
+
+extern int peerdist_info ( userptr_t data, size_t len,
+ struct peerdist_info *info );
+extern int peerdist_info_segment ( const struct peerdist_info *info,
+ struct peerdist_info_segment *segment,
+ unsigned int index );
+extern int peerdist_info_block ( const struct peerdist_info_segment *segment,
+ struct peerdist_info_block *block,
+ unsigned int index );
+
+#endif /* _IPXE_PCCRC_H */
diff --git a/roms/ipxe/src/include/ipxe/pccrd.h b/roms/ipxe/src/include/ipxe/pccrd.h
new file mode 100644
index 000000000..3daa92f29
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/pccrd.h
@@ -0,0 +1,47 @@
+#ifndef _IPXE_PCCRD_H
+#define _IPXE_PCCRD_H
+
+/** @file
+ *
+ * Peer Content Caching and Retrieval: Discovery Protocol [MS-PCCRD]
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/** PeerDist discovery port */
+#define PEERDIST_DISCOVERY_PORT 3702
+
+/** PeerDist discovery IPv4 address (239.255.255.250) */
+#define PEERDIST_DISCOVERY_IPV4 \
+ ( ( 239 << 24 ) | ( 255 << 16 ) | ( 255 << 8 ) | ( 250 << 0 ) )
+
+/** PeerDist discovery IPv6 address (ff02::c) */
+#define PEERDIST_DISCOVERY_IPV6 \
+ { 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xc }
+
+/** A PeerDist discovery reply block count */
+struct peerdist_discovery_block_count {
+ /** Count (as an eight-digit hex value) */
+ char hex[8];
+} __attribute__ (( packed ));
+
+/** A PeerDist discovery reply */
+struct peerdist_discovery_reply {
+ /** List of segment ID strings
+ *
+ * The list is terminated with a zero-length string.
+ */
+ char *ids;
+ /** List of peer locations
+ *
+ * The list is terminated with a zero-length string.
+ */
+ char *locations;
+};
+
+extern char * peerdist_discovery_request ( const char *uuid, const char *id );
+extern int peerdist_discovery_reply ( char *data, size_t len,
+ struct peerdist_discovery_reply *reply );
+
+#endif /* _IPXE_PCCRD_H */
diff --git a/roms/ipxe/src/include/ipxe/pccrr.h b/roms/ipxe/src/include/ipxe/pccrr.h
new file mode 100644
index 000000000..1ea86c40d
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/pccrr.h
@@ -0,0 +1,376 @@
+#ifndef _IPXE_PCCRR_H
+#define _IPXE_PCCRR_H
+
+/** @file
+ *
+ * Peer Content Caching and Retrieval: Retrieval Protocol [MS-PCCRR]
+ *
+ * All fields are in network byte order.
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
+#include <ipxe/uaccess.h>
+
+/** Magic retrieval URI path */
+#define PEERDIST_MAGIC_PATH "/116B50EB-ECE2-41ac-8429-9F9E963361B7/"
+
+/** Retrieval protocol version */
+union peerdist_msg_version {
+ /** Raw version number */
+ uint32_t raw;
+ /** Major:minor version number */
+ struct {
+ /** Minor version number */
+ uint16_t minor;
+ /** Major version number */
+ uint16_t major;
+ } __attribute__ (( packed ));
+} __attribute__ (( packed ));
+
+/** Retrieval protocol version 1.0 */
+#define PEERDIST_MSG_VERSION_1_0 0x00000001UL
+
+/** Retrieval protocol version 2.0 */
+#define PEERDIST_MSG_VERSION_2_0 0x00000002UL
+
+/** Retrieval protocol supported versions */
+struct peerdist_msg_versions {
+ /** Minimum supported protocol version */
+ union peerdist_msg_version min;
+ /** Maximum supported protocol version */
+ union peerdist_msg_version max;
+} __attribute__ (( packed ));
+
+/** Retrieval protocol block range */
+struct peerdist_msg_range {
+ /** First block in range */
+ uint32_t first;
+ /** Number of blocks in range */
+ uint32_t count;
+} __attribute__ (( packed ));
+
+/** Retrieval protocol segment ID header */
+struct peerdist_msg_segment {
+ /** Digest size (i.e. length of segment ID) */
+ uint32_t digestsize;
+ /* Followed by a single variable-length ID and padding:
+ *
+ * uint8_t id[digestsize];
+ * uint8_t pad[ (-digestsize) & 0x3 ];
+ */
+} __attribute__ (( packed ));
+
+/** Retrieval protocol segment ID
+ *
+ * @v digestsize Digest size
+ */
+#define peerdist_msg_segment_t( digestsize ) \
+ struct { \
+ struct peerdist_msg_segment segment; \
+ uint8_t id[digestsize]; \
+ uint8_t pad[ ( -(digestsize) ) & 0x3 ]; \
+ } __attribute__ (( packed ))
+
+/** Retrieval protocol block range list header */
+struct peerdist_msg_ranges {
+ /** Number of ranges */
+ uint32_t count;
+ /* Followed by an array of block ranges:
+ *
+ * struct peerdist_msg_range range[count];
+ */
+} __attribute__ (( packed ));
+
+/** Retrieval protocol block range list
+ *
+ * @v count Number of ranges
+ */
+#define peerdist_msg_ranges_t( count ) \
+ struct { \
+ struct peerdist_msg_ranges ranges; \
+ struct peerdist_msg_range range[count]; \
+ } __attribute__ (( packed ))
+
+/** Retrieval protocol data block header */
+struct peerdist_msg_block {
+ /** Length of data block */
+ uint32_t len;
+ /* Followed by the (encrypted) data block:
+ *
+ * uint8_t data[len];
+ */
+} __attribute__ (( packed ));
+
+/** Retrieval protocol data block */
+#define peerdist_msg_block_t( len ) \
+ struct { \
+ struct peerdist_msg_block block; \
+ uint8_t data[len]; \
+ } __attribute__ (( packed ))
+
+/** Retrieval protocol initialisation vector header */
+struct peerdist_msg_iv {
+ /** Cipher block size */
+ uint32_t blksize;
+ /* Followed by the initialisation vector:
+ *
+ * uint8_t data[blksize];
+ */
+} __attribute__ (( packed ));
+
+/** Retrieval protocol initialisation vector */
+#define peerdist_msg_iv_t( blksize ) \
+ struct { \
+ struct peerdist_msg_iv iv; \
+ uint8_t data[blksize]; \
+ } __attribute__ (( packed ))
+
+/** Retrieval protocol useless VRF data header */
+struct peerdist_msg_useless_vrf {
+ /** Length of useless VRF data */
+ uint32_t len;
+ /* Followed by a variable-length useless VRF data block and
+ * padding:
+ *
+ * uint8_t data[len];
+ * uint8_t pad[ (-len) & 0x3 ];
+ */
+} __attribute__ (( packed ));
+
+/** Retrieval protocol useless VRF data */
+#define peerdist_msg_useless_vrf_t( vrf_len ) \
+ struct { \
+ struct peerdist_msg_useless_vrf vrf; \
+ uint8_t data[vrf_len]; \
+ uint8_t pad[ ( -(vrf_len) ) & 0x3 ]; \
+ } __attribute__ (( packed ))
+
+/** Retrieval protocol message header */
+struct peerdist_msg_header {
+ /** Protocol version
+ *
+ * This is the protocol version in which the message type was
+ * first defined.
+ */
+ union peerdist_msg_version version;
+ /** Message type */
+ uint32_t type;
+ /** Message size (including this header) */
+ uint32_t len;
+ /** Cryptographic algorithm ID */
+ uint32_t algorithm;
+} __attribute__ (( packed ));
+
+/** Retrieval protocol cryptographic algorithm IDs */
+enum peerdist_msg_algorithm {
+ /** No encryption */
+ PEERDIST_MSG_PLAINTEXT = 0x00000000UL,
+ /** AES-128 in CBC mode */
+ PEERDIST_MSG_AES_128_CBC = 0x00000001UL,
+ /** AES-192 in CBC mode */
+ PEERDIST_MSG_AES_192_CBC = 0x00000002UL,
+ /** AES-256 in CBC mode */
+ PEERDIST_MSG_AES_256_CBC = 0x00000003UL,
+};
+
+/** Retrieval protocol transport response header */
+struct peerdist_msg_transport_header {
+ /** Length (excluding this header)
+ *
+ * This seems to be identical in both purpose and value to the
+ * length found within the message header, and therefore
+ * serves no useful purpose.
+ */
+ uint32_t len;
+} __attribute__ (( packed ));
+
+/** Retrieval protocol negotiation request */
+struct peerdist_msg_nego_req {
+ /** Message header */
+ struct peerdist_msg_header hdr;
+ /** Supported versions */
+ struct peerdist_msg_versions versions;
+} __attribute__ (( packed ));
+
+/** Retrieval protocol negotiation request version */
+#define PEERDIST_MSG_NEGO_REQ_VERSION PEERDIST_MSG_VERSION_1_0
+
+/** Retrieval protocol negotiation request type */
+#define PEERDIST_MSG_NEGO_REQ_TYPE 0x00000000UL
+
+/** Retrieval protocol negotiation response */
+struct peerdist_msg_nego_resp {
+ /** Message header */
+ struct peerdist_msg_header hdr;
+ /** Supported versions */
+ struct peerdist_msg_versions versions;
+} __attribute__ (( packed ));
+
+/** Retrieval protocol negotiation response version */
+#define PEERDIST_MSG_NEGO_RESP_VERSION PEERDIST_MSG_VERSION_1_0
+
+/** Retrieval protocol negotiation response type */
+#define PEERDIST_MSG_NEGO_RESP_TYPE 0x00000001UL
+
+/** Retrieval protocol block list request header */
+struct peerdist_msg_getblklist {
+ /** Message header */
+ struct peerdist_msg_header hdr;
+ /* Followed by a segment ID and a block range list:
+ *
+ * peerdist_msg_segment_t(digestsize) segment;
+ * peerdist_msg_ranges_t(count) ranges;
+ */
+} __attribute__ (( packed ));
+
+/** Retrieval protocol block list request
+ *
+ * @v digestsize Digest size
+ * @v count Block range count
+ */
+#define peerdist_msg_getblklist_t( digestsize, count ) \
+ struct { \
+ struct peerdist_msg_getblklist getblklist; \
+ peerdist_msg_segment_t ( digestsize ) segment; \
+ peerdist_msg_ranges_t ( count ) ranges; \
+ } __attribute__ (( packed ))
+
+/** Retrieval protocol block list request version */
+#define PEERDIST_MSG_GETBLKLIST_VERSION PEERDIST_MSG_VERSION_1_0
+
+/** Retrieval protocol block list request type */
+#define PEERDIST_MSG_GETBLKLIST_TYPE 0x00000002UL
+
+/** Retrieval protocol block fetch request header */
+struct peerdist_msg_getblks {
+ /** Message header */
+ struct peerdist_msg_header hdr;
+ /* Followed by a segment ID, a block range list, and a useless
+ * VRF block:
+ *
+ * peerdist_msg_segment_t(digestsize) segment;
+ * peerdist_msg_ranges_t(count) ranges;
+ * peerdist_msg_vrf_t(vrf_len) vrf;
+ */
+} __attribute__ (( packed ));
+
+/** Retrieval protocol block fetch request
+ *
+ * @v digestsize Digest size
+ * @v count Block range count
+ * @v vrf_len Length of uselessness
+ */
+#define peerdist_msg_getblks_t( digestsize, count, vrf_len ) \
+ struct { \
+ struct peerdist_msg_getblks getblks; \
+ peerdist_msg_segment_t ( digestsize ) segment; \
+ peerdist_msg_ranges_t ( count ) ranges; \
+ peerdist_msg_useless_vrf_t ( vrf_len ); \
+ } __attribute__ (( packed ))
+
+/** Retrieval protocol block fetch request version */
+#define PEERDIST_MSG_GETBLKS_VERSION PEERDIST_MSG_VERSION_1_0
+
+/** Retrieval protocol block fetch request type */
+#define PEERDIST_MSG_GETBLKS_TYPE 0x00000003UL
+
+/** Retrieval protocol block list response header */
+struct peerdist_msg_blklist {
+ /** Message header */
+ struct peerdist_msg_header hdr;
+ /* Followed by a segment ID, a block range list, and a next
+ * block index:
+ *
+ * peerdist_msg_segment_t(digestsize) segment;
+ * peerdist_msg_ranges_t(count) ranges;
+ * uint32_t next;
+ */
+} __attribute__ (( packed ));
+
+/** Retrieval protocol block list response
+ *
+ * @v digestsize Digest size
+ * @v count Block range count
+ */
+#define peerdist_msg_blklist_t( digestsize, count ) \
+ struct { \
+ struct peerdist_msg_blklist blklist; \
+ peerdist_msg_segment_t ( digestsize ) segment; \
+ peerdist_msg_ranges_t ( count ) ranges; \
+ uint32_t next; \
+ } __attribute__ (( packed ))
+
+/** Retrieval protocol block list response version */
+#define PEERDIST_MSG_BLKLIST_VERSION PEERDIST_MSG_VERSION_1_0
+
+/** Retrieval protocol block list response type */
+#define PEERDIST_MSG_BLKLIST_TYPE 0x00000004UL
+
+/** Retrieval protocol block fetch response header */
+struct peerdist_msg_blk {
+ /** Message header */
+ struct peerdist_msg_header hdr;
+ /* Followed by a segment ID, a block index, a next block
+ * index, a data block, a useless VRF block, and an
+ * initialisation vector:
+ *
+ * peerdist_msg_segment_t(digestsize) segment;
+ * uint32_t index;
+ * uint32_t next;
+ * peerdist_msg_block_t(len) data;
+ * peerdist_msg_useless_vrf_t(vrf_len) vrf;
+ * peerdist_msg_iv_t(blksize) iv;
+ */
+} __attribute__ (( packed ));
+
+/** Retrieval protocol block fetch response
+ *
+ * @v digestsize Digest size
+ * @v len Data block length
+ * @v vrf_len Length of uselessness
+ * @v blksize Cipher block size
+ */
+#define peerdist_msg_blk_t( digestsize, len, vrf_len, blksize ) \
+ struct { \
+ struct peerdist_msg_blk blk; \
+ peerdist_msg_segment_t ( digestsize ) segment; \
+ uint32_t index; \
+ uint32_t next; \
+ peerdist_msg_block_t ( len ) block; \
+ peerdist_msg_useless_vrf_t ( vrf_len ) vrf; \
+ peerdist_msg_iv_t ( blksize ) iv; \
+ } __attribute__ (( packed ))
+
+/** Retrieval protocol block fetch response version */
+#define PEERDIST_MSG_BLK_VERSION PEERDIST_MSG_VERSION_1_0
+
+/** Retrieval protocol block fetch response type */
+#define PEERDIST_MSG_BLK_TYPE 0x00000005UL
+
+/**
+ * Parse retrieval protocol block fetch response
+ *
+ * @v raw Raw data
+ * @v raw_len Length of raw data
+ * @v digestsize Digest size
+ * @v blksize Cipher block size
+ * @v blk Structure to fill in
+ * @ret rc Return status code
+ */
+#define peerdist_msg_blk( raw, raw_len, digestsize, blksize, blk ) ( { \
+ assert ( sizeof ( (blk)->segment.id ) == (digestsize) ); \
+ assert ( sizeof ( (blk)->block.data ) == 0 ); \
+ assert ( sizeof ( (blk)->vrf.data ) == 0 ); \
+ assert ( sizeof ( (blk)->iv.data ) == blksize ); \
+ peerdist_msg_blk_untyped ( (raw), (raw_len), (digestsize), \
+ (blksize), blk ); \
+ } )
+
+extern int peerdist_msg_blk_untyped ( userptr_t raw, size_t raw_len,
+ size_t digestsize, size_t blksize,
+ void *out );
+
+#endif /* _IPXE_PCCRR_H */
diff --git a/roms/ipxe/src/include/ipxe/pci.h b/roms/ipxe/src/include/ipxe/pci.h
index 692771ebe..a841e00ff 100644
--- a/roms/ipxe/src/include/ipxe/pci.h
+++ b/roms/ipxe/src/include/ipxe/pci.h
@@ -1,268 +1,132 @@
#ifndef _IPXE_PCI_H
#define _IPXE_PCI_H
-/*
- * Support for NE2000 PCI clones added David Monro June 1997
- * Generalised for other PCI NICs by Ken Yap July 1997
- * PCI support rewritten by Michael Brown 2006
+/** @file
+ *
+ * PCI bus
*
- * Most of this is taken from /usr/src/linux/include/linux/pci.h.
- */
-
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2, or (at
- * your option) any later version.
*/
-FILE_LICENCE ( GPL2_ONLY );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/device.h>
#include <ipxe/tables.h>
#include <ipxe/pci_io.h>
-#include "pci_ids.h"
-/*
- * PCI constants
- *
- */
-
-#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */
-#define PCI_COMMAND_MEM 0x2 /* Enable response in mem space */
-#define PCI_COMMAND_MASTER 0x4 /* Enable bus mastering */
-
-#define PCI_CACHE_LINE_SIZE 0x0c /* 8 bits */
-#define PCI_LATENCY_TIMER 0x0d /* 8 bits */
-
-#define PCI_COMMAND_SPECIAL 0x8 /* Enable response to special cycles */
-#define PCI_COMMAND_INVALIDATE 0x10 /* Use memory write and invalidate */
-#define PCI_COMMAND_VGA_PALETTE 0x20 /* Enable palette snooping */
-#define PCI_COMMAND_PARITY 0x40 /* Enable parity checking */
-#define PCI_COMMAND_WAIT 0x80 /* Enable address/data stepping */
-#define PCI_COMMAND_SERR 0x100 /* Enable SERR */
-#define PCI_COMMAND_FAST_BACK 0x200 /* Enable back-to-back writes */
-#define PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */
-
-
-#define PCI_VENDOR_ID 0x00 /* 16 bits */
-#define PCI_DEVICE_ID 0x02 /* 16 bits */
-#define PCI_COMMAND 0x04 /* 16 bits */
-
-#define PCI_STATUS 0x06 /* 16 bits */
-#define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */
-#define PCI_STATUS_66MHZ 0x20 /* Support 66 Mhz PCI 2.1 bus */
-#define PCI_STATUS_UDF 0x40 /* Support User Definable Features [obsolete] */
-#define PCI_STATUS_FAST_BACK 0x80 /* Accept fast-back to back */
-#define PCI_STATUS_PARITY 0x100 /* Detected parity error */
-#define PCI_STATUS_DEVSEL_MASK 0x600 /* DEVSEL timing */
-#define PCI_STATUS_DEVSEL_FAST 0x000
-#define PCI_STATUS_DEVSEL_MEDIUM 0x200
-#define PCI_STATUS_DEVSEL_SLOW 0x400
-#define PCI_STATUS_SIG_TARGET_ABORT 0x800 /* Set on target abort */
-#define PCI_STATUS_REC_TARGET_ABORT 0x1000 /* Master ack of " */
-#define PCI_STATUS_REC_MASTER_ABORT 0x2000 /* Set on master abort */
-#define PCI_STATUS_SIG_SYSTEM_ERROR 0x4000 /* Set when we drive SERR */
-#define PCI_STATUS_DETECTED_PARITY 0x8000 /* Set on parity error */
-
-#define PCI_REVISION 0x08 /* 8 bits */
-#define PCI_REVISION_ID 0x08 /* 8 bits */
-#define PCI_CLASS_REVISION 0x08 /* 32 bits */
-#define PCI_CLASS_CODE 0x0b /* 8 bits */
-#define PCI_SUBCLASS_CODE 0x0a /* 8 bits */
-#define PCI_HEADER_TYPE 0x0e /* 8 bits */
-#define PCI_HEADER_TYPE_NORMAL 0
-#define PCI_HEADER_TYPE_BRIDGE 1
-#define PCI_HEADER_TYPE_CARDBUS 2
-
-
-/* Header type 0 (normal devices) */
-#define PCI_CARDBUS_CIS 0x28
+/** PCI vendor ID */
+#define PCI_VENDOR_ID 0x00
+
+/** PCI device ID */
+#define PCI_DEVICE_ID 0x02
+
+/** PCI command */
+#define PCI_COMMAND 0x04
+#define PCI_COMMAND_IO 0x0001 /**< I/O space */
+#define PCI_COMMAND_MEM 0x0002 /**< Memory space */
+#define PCI_COMMAND_MASTER 0x0004 /**< Bus master */
+#define PCI_COMMAND_INVALIDATE 0x0010 /**< Mem. write & invalidate */
+#define PCI_COMMAND_PARITY 0x0040 /**< Parity error response */
+#define PCI_COMMAND_SERR 0x0100 /**< SERR# enable */
+#define PCI_COMMAND_INTX_DISABLE 0x0400 /**< Interrupt disable */
+
+/** PCI status */
+#define PCI_STATUS 0x06
+#define PCI_STATUS_CAP_LIST 0x0010 /**< Capabilities list */
+#define PCI_STATUS_PARITY 0x0100 /**< Master data parity error */
+#define PCI_STATUS_REC_TARGET_ABORT 0x1000 /**< Received target abort */
+#define PCI_STATUS_REC_MASTER_ABORT 0x2000 /**< Received master abort */
+#define PCI_STATUS_SIG_SYSTEM_ERROR 0x4000 /**< Signalled system error */
+#define PCI_STATUS_DETECTED_PARITY 0x8000 /**< Detected parity error */
+
+/** PCI revision */
+#define PCI_REVISION 0x08
+
+/** PCI cache line size */
+#define PCI_CACHE_LINE_SIZE 0x0c
+
+/** PCI latency timer */
+#define PCI_LATENCY_TIMER 0x0d
+
+/** PCI header type */
+#define PCI_HEADER_TYPE 0x0e
+#define PCI_HEADER_TYPE_NORMAL 0x00 /**< Normal header */
+#define PCI_HEADER_TYPE_BRIDGE 0x01 /**< PCI-to-PCI bridge header */
+#define PCI_HEADER_TYPE_CARDBUS 0x02 /**< CardBus header */
+#define PCI_HEADER_TYPE_MASK 0x7f /**< Header type mask */
+#define PCI_HEADER_TYPE_MULTI 0x80 /**< Multi-function device */
+
+/** PCI base address registers */
+#define PCI_BASE_ADDRESS(n) ( 0x10 + ( 4 * (n) ) )
+#define PCI_BASE_ADDRESS_0 PCI_BASE_ADDRESS ( 0 )
+#define PCI_BASE_ADDRESS_1 PCI_BASE_ADDRESS ( 1 )
+#define PCI_BASE_ADDRESS_2 PCI_BASE_ADDRESS ( 2 )
+#define PCI_BASE_ADDRESS_3 PCI_BASE_ADDRESS ( 3 )
+#define PCI_BASE_ADDRESS_4 PCI_BASE_ADDRESS ( 4 )
+#define PCI_BASE_ADDRESS_5 PCI_BASE_ADDRESS ( 5 )
+#define PCI_BASE_ADDRESS_SPACE_IO 0x00000001UL /**< I/O BAR */
+#define PCI_BASE_ADDRESS_IO_MASK 0x00000003UL /**< I/O BAR mask */
+#define PCI_BASE_ADDRESS_MEM_TYPE_64 0x00000004UL /**< 64-bit memory */
+#define PCI_BASE_ADDRESS_MEM_TYPE_MASK 0x00000006UL /**< Memory type mask */
+#define PCI_BASE_ADDRESS_MEM_MASK 0x0000000fUL /**< Memory BAR mask */
+
+/** PCI subsystem vendor ID */
#define PCI_SUBSYSTEM_VENDOR_ID 0x2c
+
+/** PCI subsystem ID */
#define PCI_SUBSYSTEM_ID 0x2e
-#define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */
-#define PCI_BASE_ADDRESS_1 0x14 /* 32 bits */
-#define PCI_BASE_ADDRESS_2 0x18 /* 32 bits */
-#define PCI_BASE_ADDRESS_3 0x1c /* 32 bits */
-#define PCI_BASE_ADDRESS_4 0x20 /* 32 bits */
-#define PCI_BASE_ADDRESS_5 0x24 /* 32 bits */
-
-#define PCI_BASE_ADDRESS_SPACE 0x01 /* 0 = memory, 1 = I/O */
-#define PCI_BASE_ADDRESS_SPACE_IO 0x01
-#define PCI_BASE_ADDRESS_SPACE_MEMORY 0x00
-
-#define PCI_BASE_ADDRESS_MEM_TYPE_MASK 0x06
-#define PCI_BASE_ADDRESS_MEM_TYPE_32 0x00 /* 32 bit address */
-#define PCI_BASE_ADDRESS_MEM_TYPE_1M 0x02 /* Below 1M [obsolete] */
-#define PCI_BASE_ADDRESS_MEM_TYPE_64 0x04 /* 64 bit address */
-#define PCI_BASE_ADDRESS_MEM_MASK (~0x0f)
-#define PCI_BASE_ADDRESS_IO_MASK (~0x03)
-#define PCI_ROM_ADDRESS 0x30 /* 32 bits */
-#define PCI_ROM_ADDRESS_ENABLE 0x01 /* Write 1 to enable ROM,
- bits 31..11 are address,
- 10..2 are reserved */
-
-#define PCI_CAPABILITY_LIST 0x34 /* Offset of first capability list entry */
-
-#define PCI_INTERRUPT_LINE 0x3c /* IRQ number (0-15) */
-#define PCI_INTERRUPT_PIN 0x3d /* IRQ pin on PCI bus (A-D) */
-
-/* Header type 1 (PCI-to-PCI bridges) */
-#define PCI_PRIMARY_BUS 0x18 /* Primary bus number */
-#define PCI_SECONDARY_BUS 0x19 /* Secondary bus number */
-#define PCI_SUBORDINATE_BUS 0x1a /* Highest bus number behind the bridge */
-#define PCI_SEC_LATENCY_TIMER 0x1b /* Latency timer for secondary interface */
-#define PCI_IO_BASE 0x1c /* I/O range behind the bridge */
-#define PCI_IO_LIMIT 0x1d
-#define PCI_IO_RANGE_TYPE_MASK 0x0f /* I/O bridging type */
-#define PCI_IO_RANGE_TYPE_16 0x00
-#define PCI_IO_RANGE_TYPE_32 0x01
-#define PCI_IO_RANGE_MASK ~0x0f
-#define PCI_SEC_STATUS 0x1e /* Secondary status register, only bit 14 used */
-#define PCI_MEMORY_BASE 0x20 /* Memory range behind */
-#define PCI_MEMORY_LIMIT 0x22
-#define PCI_MEMORY_RANGE_TYPE_MASK 0x0f
-#define PCI_MEMORY_RANGE_MASK ~0x0f
-#define PCI_PREF_MEMORY_BASE 0x24 /* Prefetchable memory range behind */
-#define PCI_PREF_MEMORY_LIMIT 0x26
-#define PCI_PREF_RANGE_TYPE_MASK 0x0f
-#define PCI_PREF_RANGE_TYPE_32 0x00
-#define PCI_PREF_RANGE_TYPE_64 0x01
-#define PCI_PREF_RANGE_MASK ~0x0f
-#define PCI_PREF_BASE_UPPER32 0x28 /* Upper half of prefetchable memory range */
-#define PCI_PREF_LIMIT_UPPER32 0x2c
-#define PCI_IO_BASE_UPPER16 0x30 /* Upper half of I/O addresses */
-#define PCI_IO_LIMIT_UPPER16 0x32
-/* 0x34 same as for htype 0 */
-/* 0x35-0x3b is reserved */
-#define PCI_ROM_ADDRESS1 0x38 /* Same as PCI_ROM_ADDRESS, but for htype 1 */
-/* 0x3c-0x3d are same as for htype 0 */
-#define PCI_BRIDGE_CONTROL 0x3e
-#define PCI_BRIDGE_CTL_PARITY 0x01 /* Enable parity detection on secondary interface */
-#define PCI_BRIDGE_CTL_SERR 0x02 /* The same for SERR forwarding */
-#define PCI_BRIDGE_CTL_NO_ISA 0x04 /* Disable bridging of ISA ports */
-#define PCI_BRIDGE_CTL_VGA 0x08 /* Forward VGA addresses */
-#define PCI_BRIDGE_CTL_MASTER_ABORT 0x20 /* Report master aborts */
-#define PCI_BRIDGE_CTL_BUS_RESET 0x40 /* Secondary bus reset */
-#define PCI_BRIDGE_CTL_FAST_BACK 0x80 /* Fast Back2Back enabled on secondary interface */
+/** PCI expansion ROM base address */
+#define PCI_ROM_ADDRESS 0x30
+/** PCI capabilities pointer */
+#define PCI_CAPABILITY_LIST 0x34
+
+/** CardBus capabilities pointer */
#define PCI_CB_CAPABILITY_LIST 0x14
-/* Capability lists */
-
-#define PCI_CAP_LIST_ID 0 /* Capability ID */
-#define PCI_CAP_ID_PM 0x01 /* Power Management */
-#define PCI_CAP_ID_AGP 0x02 /* Accelerated Graphics Port */
-#define PCI_CAP_ID_VPD 0x03 /* Vital Product Data */
-#define PCI_CAP_ID_SLOTID 0x04 /* Slot Identification */
-#define PCI_CAP_ID_MSI 0x05 /* Message Signalled Interrupts */
-#define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */
-#define PCI_CAP_ID_VNDR 0x09 /* Vendor specific */
-#define PCI_CAP_ID_EXP 0x10 /* PCI Express */
-#define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */
-#define PCI_CAP_FLAGS 2 /* Capability defined flags (16 bits) */
-#define PCI_CAP_SIZEOF 4
-
-/* Power Management Registers */
-
-#define PCI_PM_PMC 2 /* PM Capabilities Register */
-#define PCI_PM_CAP_VER_MASK 0x0007 /* Version */
-#define PCI_PM_CAP_PME_CLOCK 0x0008 /* PME clock required */
-#define PCI_PM_CAP_RESERVED 0x0010 /* Reserved field */
-#define PCI_PM_CAP_DSI 0x0020 /* Device specific initialization */
-#define PCI_PM_CAP_AUX_POWER 0x01C0 /* Auxiliary power support mask */
-#define PCI_PM_CAP_D1 0x0200 /* D1 power state support */
-#define PCI_PM_CAP_D2 0x0400 /* D2 power state support */
-#define PCI_PM_CAP_PME 0x0800 /* PME pin supported */
-#define PCI_PM_CAP_PME_MASK 0xF800 /* PME Mask of all supported states */
-#define PCI_PM_CAP_PME_D0 0x0800 /* PME# from D0 */
-#define PCI_PM_CAP_PME_D1 0x1000 /* PME# from D1 */
-#define PCI_PM_CAP_PME_D2 0x2000 /* PME# from D2 */
-#define PCI_PM_CAP_PME_D3 0x4000 /* PME# from D3 (hot) */
-#define PCI_PM_CAP_PME_D3cold 0x8000 /* PME# from D3 (cold) */
-#define PCI_PM_CTRL 4 /* PM control and status register */
-#define PCI_PM_CTRL_STATE_MASK 0x0003 /* Current power state (D0 to D3) */
-#define PCI_PM_CTRL_PME_ENABLE 0x0100 /* PME pin enable */
-#define PCI_PM_CTRL_DATA_SEL_MASK 0x1e00 /* Data select (??) */
-#define PCI_PM_CTRL_DATA_SCALE_MASK 0x6000 /* Data scale (??) */
-#define PCI_PM_CTRL_PME_STATUS 0x8000 /* PME pin status */
-#define PCI_PM_PPB_EXTENSIONS 6 /* PPB support extensions (??) */
-#define PCI_PM_PPB_B2_B3 0x40 /* Stop clock when in D3hot (??) */
-#define PCI_PM_BPCC_ENABLE 0x80 /* Bus power/clock control enable (??) */
-#define PCI_PM_DATA_REGISTER 7 /* (??) */
-#define PCI_PM_SIZEOF 8
-
-/* AGP registers */
-
-#define PCI_AGP_VERSION 2 /* BCD version number */
-#define PCI_AGP_RFU 3 /* Rest of capability flags */
-#define PCI_AGP_STATUS 4 /* Status register */
-#define PCI_AGP_STATUS_RQ_MASK 0xff000000 /* Maximum number of requests - 1 */
-#define PCI_AGP_STATUS_SBA 0x0200 /* Sideband addressing supported */
-#define PCI_AGP_STATUS_64BIT 0x0020 /* 64-bit addressing supported */
-#define PCI_AGP_STATUS_FW 0x0010 /* FW transfers supported */
-#define PCI_AGP_STATUS_RATE4 0x0004 /* 4x transfer rate supported */
-#define PCI_AGP_STATUS_RATE2 0x0002 /* 2x transfer rate supported */
-#define PCI_AGP_STATUS_RATE1 0x0001 /* 1x transfer rate supported */
-#define PCI_AGP_COMMAND 8 /* Control register */
-#define PCI_AGP_COMMAND_RQ_MASK 0xff000000 /* Master: Maximum number of requests */
-#define PCI_AGP_COMMAND_SBA 0x0200 /* Sideband addressing enabled */
-#define PCI_AGP_COMMAND_AGP 0x0100 /* Allow processing of AGP transactions */
-#define PCI_AGP_COMMAND_64BIT 0x0020 /* Allow processing of 64-bit addresses */
-#define PCI_AGP_COMMAND_FW 0x0010 /* Force FW transfers */
-#define PCI_AGP_COMMAND_RATE4 0x0004 /* Use 4x rate */
-#define PCI_AGP_COMMAND_RATE2 0x0002 /* Use 2x rate */
-#define PCI_AGP_COMMAND_RATE1 0x0001 /* Use 1x rate */
-#define PCI_AGP_SIZEOF 12
-
-/* Slot Identification */
-
-#define PCI_SID_ESR 2 /* Expansion Slot Register */
-#define PCI_SID_ESR_NSLOTS 0x1f /* Number of expansion slots available */
-#define PCI_SID_ESR_FIC 0x20 /* First In Chassis Flag */
-#define PCI_SID_CHASSIS_NR 3 /* Chassis Number */
-
-/* Message Signalled Interrupts registers */
-
-#define PCI_MSI_FLAGS 2 /* Various flags */
-#define PCI_MSI_FLAGS_64BIT 0x80 /* 64-bit addresses allowed */
-#define PCI_MSI_FLAGS_QSIZE 0x70 /* Message queue size configured */
-#define PCI_MSI_FLAGS_QMASK 0x0e /* Maximum queue size available */
-#define PCI_MSI_FLAGS_ENABLE 0x01 /* MSI feature enabled */
-#define PCI_MSI_RFU 3 /* Rest of capability flags */
-#define PCI_MSI_ADDRESS_LO 4 /* Lower 32 bits */
-#define PCI_MSI_ADDRESS_HI 8 /* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */
-#define PCI_MSI_DATA_32 8 /* 16 bits of data for 32-bit devices */
-#define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit devices */
-
-/* Advanced Error Reporting */
-
-#define PCI_ERR_UNCOR_STATUS 4 /* Uncorrectable Error Status */
-#define PCI_ERR_UNC_TRAIN 0x00000001 /* Training */
-#define PCI_ERR_UNC_DLP 0x00000010 /* Data Link Protocol */
-#define PCI_ERR_UNC_POISON_TLP 0x00001000 /* Poisoned TLP */
-#define PCI_ERR_UNC_FCP 0x00002000 /* Flow Control Protocol */
-#define PCI_ERR_UNC_COMP_TIME 0x00004000 /* Completion Timeout */
-#define PCI_ERR_UNC_COMP_ABORT 0x00008000 /* Completer Abort */
-#define PCI_ERR_UNC_UNX_COMP 0x00010000 /* Unexpected Completion */
-#define PCI_ERR_UNC_RX_OVER 0x00020000 /* Receiver Overflow */
-#define PCI_ERR_UNC_MALF_TLP 0x00040000 /* Malformed TLP */
-#define PCI_ERR_UNC_ECRC 0x00080000 /* ECRC Error Status */
-#define PCI_ERR_UNC_UNSUP 0x00100000 /* Unsupported Request */
-#define PCI_ERR_UNCOR_MASK 8 /* Uncorrectable Error Mask */
- /* Same bits as above */
-#define PCI_ERR_UNCOR_SEVER 12 /* Uncorrectable Error Severity */
- /* Same bits as above */
-#define PCI_ERR_COR_STATUS 16 /* Correctable Error Status */
-#define PCI_ERR_COR_RCVR 0x00000001 /* Receiver Error Status */
-#define PCI_ERR_COR_BAD_TLP 0x00000040 /* Bad TLP Status */
-#define PCI_ERR_COR_BAD_DLLP 0x00000080 /* Bad DLLP Status */
-#define PCI_ERR_COR_REP_ROLL 0x00000100 /* REPLAY_NUM Rollover */
-#define PCI_ERR_COR_REP_TIMER 0x00001000 /* Replay Timer Timeout */
-#define PCI_ERR_COR_MASK 20 /* Correctable Error Mask */
- /* Same bits as above */
+/** PCI interrupt line */
+#define PCI_INTERRUPT_LINE 0x3c
+
+/** Capability ID */
+#define PCI_CAP_ID 0x00
+#define PCI_CAP_ID_PM 0x01 /**< Power management */
+#define PCI_CAP_ID_VPD 0x03 /**< Vital product data */
+#define PCI_CAP_ID_VNDR 0x09 /**< Vendor-specific */
+#define PCI_CAP_ID_EXP 0x10 /**< PCI Express */
+
+/** Next capability */
+#define PCI_CAP_NEXT 0x01
+
+/** Power management control and status */
+#define PCI_PM_CTRL 0x04
+#define PCI_PM_CTRL_STATE_MASK 0x0003 /**< Current power state */
+#define PCI_PM_CTRL_PME_ENABLE 0x0100 /**< PME pin enable */
+#define PCI_PM_CTRL_PME_STATUS 0x8000 /**< PME pin status */
+
+/** Uncorrectable error status */
+#define PCI_ERR_UNCOR_STATUS 0x04
+
+/** Network controller */
+#define PCI_CLASS_NETWORK 0x02
+
+/** Serial bus controller */
+#define PCI_CLASS_SERIAL 0x0c
+#define PCI_CLASS_SERIAL_USB 0x03 /**< USB controller */
+#define PCI_CLASS_SERIAL_USB_UHCI 0x00 /**< UHCI USB controller */
+#define PCI_CLASS_SERIAL_USB_OHCI 0x10 /**< OHCI USB controller */
+#define PCI_CLASS_SERIAL_USB_EHCI 0x20 /**< ECHI USB controller */
+#define PCI_CLASS_SERIAL_USB_XHCI 0x30 /**< xHCI USB controller */
+
+/** Construct PCI class
+ *
+ * @v base Base class (or PCI_ANY_ID)
+ * @v sub Subclass (or PCI_ANY_ID)
+ * @v progif Programming interface (or PCI_ANY_ID)
+ */
+#define PCI_CLASS( base, sub, progif ) \
+ ( ( ( (base) & 0xff ) << 16 ) | ( ( (sub) & 0xff ) << 8 ) | \
+ ( ( (progif) & 0xff) << 0 ) )
/** A PCI device ID list entry */
struct pci_device_id {
@@ -279,6 +143,27 @@ struct pci_device_id {
/** Match-anything ID */
#define PCI_ANY_ID 0xffff
+/** A PCI class ID */
+struct pci_class_id {
+ /** Class */
+ uint32_t class;
+ /** Class mask */
+ uint32_t mask;
+};
+
+/** Construct PCI class ID
+ *
+ * @v base Base class (or PCI_ANY_ID)
+ * @v sub Subclass (or PCI_ANY_ID)
+ * @v progif Programming interface (or PCI_ANY_ID)
+ */
+#define PCI_CLASS_ID( base, sub, progif ) { \
+ .class = PCI_CLASS ( base, sub, progif ), \
+ .mask = ( ( ( ( (base) == PCI_ANY_ID ) ? 0x00 : 0xff ) << 16 ) | \
+ ( ( ( (sub) == PCI_ANY_ID ) ? 0x00 : 0xff ) << 8 ) | \
+ ( ( ( (progif) == PCI_ANY_ID ) ? 0x00 : 0xff ) << 0 ) ), \
+ }
+
/** A PCI device */
struct pci_device {
/** Generic device */
@@ -322,6 +207,8 @@ struct pci_driver {
struct pci_device_id *ids;
/** Number of entries in PCI ID table */
unsigned int id_count;
+ /** PCI class ID */
+ struct pci_class_id class;
/**
* Probe device
*
@@ -352,6 +239,7 @@ struct pci_driver {
#define PCI_BUSDEVFN( bus, slot, func ) \
( ( (bus) << 8 ) | ( (slot) << 3 ) | ( (func) << 0 ) )
#define PCI_FIRST_FUNC( busdevfn ) ( (busdevfn) & ~0x07 )
+#define PCI_LAST_FUNC( busdevfn ) ( (busdevfn) | 0x07 )
#define PCI_BASE_CLASS( class ) ( (class) >> 16 )
#define PCI_SUB_CLASS( class ) ( ( (class) >> 8 ) & 0xff )
diff --git a/roms/ipxe/src/include/ipxe/pci_ids.h b/roms/ipxe/src/include/ipxe/pci_ids.h
deleted file mode 100644
index 25c7782bc..000000000
--- a/roms/ipxe/src/include/ipxe/pci_ids.h
+++ /dev/null
@@ -1,351 +0,0 @@
-#ifndef _IPXE_PCI_IDS_H
-#define _IPXE_PCI_IDS_H
-
-/*
- * PCI Class, Vendor and Device IDs
- *
- * Please keep sorted.
- */
-
-FILE_LICENCE ( GPL2_ONLY );
-
-/* Device classes and subclasses */
-
-#define PCI_CLASS_NOT_DEFINED 0x0000
-#define PCI_CLASS_NOT_DEFINED_VGA 0x0001
-
-#define PCI_BASE_CLASS_STORAGE 0x01
-#define PCI_CLASS_STORAGE_SCSI 0x0100
-#define PCI_CLASS_STORAGE_IDE 0x0101
-#define PCI_CLASS_STORAGE_FLOPPY 0x0102
-#define PCI_CLASS_STORAGE_IPI 0x0103
-#define PCI_CLASS_STORAGE_RAID 0x0104
-#define PCI_CLASS_STORAGE_OTHER 0x0180
-
-#define PCI_BASE_CLASS_NETWORK 0x02
-#define PCI_CLASS_NETWORK_ETHERNET 0x0200
-#define PCI_CLASS_NETWORK_TOKEN_RING 0x0201
-#define PCI_CLASS_NETWORK_FDDI 0x0202
-#define PCI_CLASS_NETWORK_ATM 0x0203
-#define PCI_CLASS_NETWORK_OTHER 0x0280
-
-#define PCI_BASE_CLASS_DISPLAY 0x03
-#define PCI_CLASS_DISPLAY_VGA 0x0300
-#define PCI_CLASS_DISPLAY_XGA 0x0301
-#define PCI_CLASS_DISPLAY_3D 0x0302
-#define PCI_CLASS_DISPLAY_OTHER 0x0380
-
-#define PCI_BASE_CLASS_MULTIMEDIA 0x04
-#define PCI_CLASS_MULTIMEDIA_VIDEO 0x0400
-#define PCI_CLASS_MULTIMEDIA_AUDIO 0x0401
-#define PCI_CLASS_MULTIMEDIA_PHONE 0x0402
-#define PCI_CLASS_MULTIMEDIA_OTHER 0x0480
-
-#define PCI_BASE_CLASS_MEMORY 0x05
-#define PCI_CLASS_MEMORY_RAM 0x0500
-#define PCI_CLASS_MEMORY_FLASH 0x0501
-#define PCI_CLASS_MEMORY_OTHER 0x0580
-
-#define PCI_BASE_CLASS_BRIDGE 0x06
-#define PCI_CLASS_BRIDGE_HOST 0x0600
-#define PCI_CLASS_BRIDGE_ISA 0x0601
-#define PCI_CLASS_BRIDGE_EISA 0x0602
-#define PCI_CLASS_BRIDGE_MC 0x0603
-#define PCI_CLASS_BRIDGE_PCI 0x0604
-#define PCI_CLASS_BRIDGE_PCMCIA 0x0605
-#define PCI_CLASS_BRIDGE_NUBUS 0x0606
-#define PCI_CLASS_BRIDGE_CARDBUS 0x0607
-#define PCI_CLASS_BRIDGE_RACEWAY 0x0608
-#define PCI_CLASS_BRIDGE_OTHER 0x0680
-
-#define PCI_BASE_CLASS_COMMUNICATION 0x07
-#define PCI_CLASS_COMMUNICATION_SERIAL 0x0700
-#define PCI_CLASS_COMMUNICATION_PARALLEL 0x0701
-#define PCI_CLASS_COMMUNICATION_MULTISERIAL 0x0702
-#define PCI_CLASS_COMMUNICATION_MODEM 0x0703
-#define PCI_CLASS_COMMUNICATION_OTHER 0x0780
-
-#define PCI_BASE_CLASS_SYSTEM 0x08
-#define PCI_CLASS_SYSTEM_PIC 0x0800
-#define PCI_CLASS_SYSTEM_DMA 0x0801
-#define PCI_CLASS_SYSTEM_TIMER 0x0802
-#define PCI_CLASS_SYSTEM_RTC 0x0803
-#define PCI_CLASS_SYSTEM_PCI_HOTPLUG 0x0804
-#define PCI_CLASS_SYSTEM_OTHER 0x0880
-
-#define PCI_BASE_CLASS_INPUT 0x09
-#define PCI_CLASS_INPUT_KEYBOARD 0x0900
-#define PCI_CLASS_INPUT_PEN 0x0901
-#define PCI_CLASS_INPUT_MOUSE 0x0902
-#define PCI_CLASS_INPUT_SCANNER 0x0903
-#define PCI_CLASS_INPUT_GAMEPORT 0x0904
-#define PCI_CLASS_INPUT_OTHER 0x0980
-
-#define PCI_BASE_CLASS_DOCKING 0x0a
-#define PCI_CLASS_DOCKING_GENERIC 0x0a00
-#define PCI_CLASS_DOCKING_OTHER 0x0a80
-
-#define PCI_BASE_CLASS_PROCESSOR 0x0b
-#define PCI_CLASS_PROCESSOR_386 0x0b00
-#define PCI_CLASS_PROCESSOR_486 0x0b01
-#define PCI_CLASS_PROCESSOR_PENTIUM 0x0b02
-#define PCI_CLASS_PROCESSOR_ALPHA 0x0b10
-#define PCI_CLASS_PROCESSOR_POWERPC 0x0b20
-#define PCI_CLASS_PROCESSOR_MIPS 0x0b30
-#define PCI_CLASS_PROCESSOR_CO 0x0b40
-
-#define PCI_BASE_CLASS_SERIAL 0x0c
-#define PCI_CLASS_SERIAL_FIREWIRE 0x0c00
-#define PCI_CLASS_SERIAL_ACCESS 0x0c01
-#define PCI_CLASS_SERIAL_SSA 0x0c02
-#define PCI_CLASS_SERIAL_USB 0x0c03
-#define PCI_CLASS_SERIAL_FIBER 0x0c04
-#define PCI_CLASS_SERIAL_SMBUS 0x0c05
-
-#define PCI_BASE_CLASS_INTELLIGENT 0x0e
-#define PCI_CLASS_INTELLIGENT_I2O 0x0e00
-
-#define PCI_BASE_CLASS_SATELLITE 0x0f
-#define PCI_CLASS_SATELLITE_TV 0x0f00
-#define PCI_CLASS_SATELLITE_AUDIO 0x0f01
-#define PCI_CLASS_SATELLITE_VOICE 0x0f03
-#define PCI_CLASS_SATELLITE_DATA 0x0f04
-
-#define PCI_BASE_CLASS_CRYPT 0x10
-#define PCI_CLASS_CRYPT_NETWORK 0x1000
-#define PCI_CLASS_CRYPT_ENTERTAINMENT 0x1001
-#define PCI_CLASS_CRYPT_OTHER 0x1080
-
-#define PCI_BASE_CLASS_SIGNAL_PROCESSING 0x11
-#define PCI_CLASS_SP_DPIO 0x1100
-#define PCI_CLASS_SP_OTHER 0x1180
-
-#define PCI_CLASS_OTHERS 0xff
-
-/* Vendors */
-
-#define PCI_VENDOR_ID_DYNALINK 0x0675
-#define PCI_VENDOR_ID_BERKOM 0x0871
-#define PCI_VENDOR_ID_COMPAQ 0x0e11
-#define PCI_VENDOR_ID_NCR 0x1000
-#define PCI_VENDOR_ID_LSI_LOGIC 0x1000
-#define PCI_VENDOR_ID_ATI 0x1002
-#define PCI_VENDOR_ID_VLSI 0x1004
-#define PCI_VENDOR_ID_ADL 0x1005
-#define PCI_VENDOR_ID_NS 0x100b
-#define PCI_VENDOR_ID_TSENG 0x100c
-#define PCI_VENDOR_ID_WEITEK 0x100e
-#define PCI_VENDOR_ID_DEC 0x1011
-#define PCI_VENDOR_ID_CIRRUS 0x1013
-#define PCI_VENDOR_ID_IBM 0x1014
-#define PCI_VENDOR_ID_COMPEX2 0x101a
-/* pci.ids says "AT&T GIS (NCR)" */
-#define PCI_VENDOR_ID_WD 0x101c
-#define PCI_VENDOR_ID_AMI 0x101e
-#define PCI_VENDOR_ID_AMD 0x1022
-#define PCI_VENDOR_ID_TRIDENT 0x1023
-#define PCI_VENDOR_ID_AI 0x1025
-#define PCI_VENDOR_ID_DELL 0x1028
-#define PCI_VENDOR_ID_MATROX 0x102B
-#define PCI_VENDOR_ID_CT 0x102c
-#define PCI_VENDOR_ID_MIRO 0x1031
-#define PCI_VENDOR_ID_NEC 0x1033
-#define PCI_VENDOR_ID_FD 0x1036
-#define PCI_VENDOR_ID_SIS 0x1039
-#define PCI_VENDOR_ID_SI 0x1039
-#define PCI_VENDOR_ID_HP 0x103c
-#define PCI_VENDOR_ID_PCTECH 0x1042
-#define PCI_VENDOR_ID_ASUSTEK 0x1043
-#define PCI_VENDOR_ID_DPT 0x1044
-#define PCI_VENDOR_ID_OPTI 0x1045
-#define PCI_VENDOR_ID_ELSA 0x1048
-#define PCI_VENDOR_ID_ELSA 0x1048
-#define PCI_VENDOR_ID_SGS 0x104a
-#define PCI_VENDOR_ID_BUSLOGIC 0x104B
-#define PCI_VENDOR_ID_TI 0x104c
-#define PCI_VENDOR_ID_SONY 0x104d
-#define PCI_VENDOR_ID_OAK 0x104e
-/* Winbond have two vendor IDs! See 0x10ad as well */
-#define PCI_VENDOR_ID_WINBOND2 0x1050
-#define PCI_VENDOR_ID_ANIGMA 0x1051
-#define PCI_VENDOR_ID_EFAR 0x1055
-#define PCI_VENDOR_ID_MOTOROLA 0x1057
-#define PCI_VENDOR_ID_MOTOROLA_OOPS 0x1507
-#define PCI_VENDOR_ID_PROMISE 0x105a
-#define PCI_VENDOR_ID_N9 0x105d
-#define PCI_VENDOR_ID_UMC 0x1060
-#define PCI_VENDOR_ID_X 0x1061
-#define PCI_VENDOR_ID_MYLEX 0x1069
-#define PCI_VENDOR_ID_PICOP 0x1066
-#define PCI_VENDOR_ID_APPLE 0x106b
-#define PCI_VENDOR_ID_YAMAHA 0x1073
-#define PCI_VENDOR_ID_NEXGEN 0x1074
-#define PCI_VENDOR_ID_QLOGIC 0x1077
-#define PCI_VENDOR_ID_CYRIX 0x1078
-#define PCI_VENDOR_ID_LEADTEK 0x107d
-#define PCI_VENDOR_ID_INTERPHASE 0x107e
-#define PCI_VENDOR_ID_CONTAQ 0x1080
-#define PCI_VENDOR_ID_FOREX 0x1083
-#define PCI_VENDOR_ID_OLICOM 0x108d
-#define PCI_VENDOR_ID_SUN 0x108e
-#define PCI_VENDOR_ID_CMD 0x1095
-#define PCI_VENDOR_ID_VISION 0x1098
-#define PCI_VENDOR_ID_BROOKTREE 0x109e
-#define PCI_VENDOR_ID_SIERRA 0x10a8
-#define PCI_VENDOR_ID_SGI 0x10a9
-#define PCI_VENDOR_ID_ACC 0x10aa
-#define PCI_VENDOR_ID_WINBOND 0x10ad
-#define PCI_VENDOR_ID_DATABOOK 0x10b3
-#define PCI_VENDOR_ID_PLX 0x10b5
-#define PCI_VENDOR_ID_MADGE 0x10b6
-#define PCI_VENDOR_ID_3COM 0x10b7
-#define PCI_VENDOR_ID_SMC 0x10b8
-#define PCI_VENDOR_ID_SUNDANCE 0x13F0
-#define PCI_VENDOR_ID_AL 0x10b9
-#define PCI_VENDOR_ID_MITSUBISHI 0x10ba
-#define PCI_VENDOR_ID_SURECOM 0x10bd
-#define PCI_VENDOR_ID_NEOMAGIC 0x10c8
-#define PCI_VENDOR_ID_ASP 0x10cd
-#define PCI_VENDOR_ID_MACRONIX 0x10d9
-#define PCI_VENDOR_ID_TCONRAD 0x10da
-#define PCI_VENDOR_ID_CERN 0x10dc
-#define PCI_VENDOR_ID_NVIDIA 0x10de
-#define PCI_VENDOR_ID_IMS 0x10e0
-#define PCI_VENDOR_ID_TEKRAM2 0x10e1
-#define PCI_VENDOR_ID_TUNDRA 0x10e3
-#define PCI_VENDOR_ID_AMCC 0x10e8
-#define PCI_VENDOR_ID_INTERG 0x10ea
-#define PCI_VENDOR_ID_REALTEK 0x10ec
-#define PCI_VENDOR_ID_XILINX 0x10ee
-#define PCI_VENDOR_ID_TRUEVISION 0x10fa
-#define PCI_VENDOR_ID_INIT 0x1101
-#define PCI_VENDOR_ID_CREATIVE 0x1102
-/* duplicate: ECTIVA */
-#define PCI_VENDOR_ID_ECTIVA 0x1102
-/* duplicate: CREATIVE */
-#define PCI_VENDOR_ID_TTI 0x1103
-#define PCI_VENDOR_ID_VIA 0x1106
-#define PCI_VENDOR_ID_VIATEC 0x1106
-#define PCI_VENDOR_ID_SIEMENS 0x110A
-#define PCI_VENDOR_ID_SMC2 0x1113
-#define PCI_VENDOR_ID_VORTEX 0x1119
-#define PCI_VENDOR_ID_EF 0x111a
-#define PCI_VENDOR_ID_IDT 0x111d
-#define PCI_VENDOR_ID_FORE 0x1127
-#define PCI_VENDOR_ID_IMAGINGTECH 0x112f
-#define PCI_VENDOR_ID_PHILIPS 0x1131
-#define PCI_VENDOR_ID_EICON 0x1133
-#define PCI_VENDOR_ID_CYCLONE 0x113c
-#define PCI_VENDOR_ID_ALLIANCE 0x1142
-#define PCI_VENDOR_ID_SYSKONNECT 0x1148
-#define PCI_VENDOR_ID_VMIC 0x114a
-#define PCI_VENDOR_ID_DIGI 0x114f
-#define PCI_VENDOR_ID_MUTECH 0x1159
-#define PCI_VENDOR_ID_XIRCOM 0x115d
-#define PCI_VENDOR_ID_RENDITION 0x1163
-#define PCI_VENDOR_ID_SERVERWORKS 0x1166
-#define PCI_VENDOR_ID_SBE 0x1176
-#define PCI_VENDOR_ID_TOSHIBA 0x1179
-#define PCI_VENDOR_ID_RICOH 0x1180
-#define PCI_VENDOR_ID_DLINK 0x1186
-#define PCI_VENDOR_ID_ARTOP 0x1191
-#define PCI_VENDOR_ID_ZEITNET 0x1193
-#define PCI_VENDOR_ID_OMEGA 0x119b
-#define PCI_VENDOR_ID_FUJITSU_ME 0x119e
-#define PCI_SUBVENDOR_ID_KEYSPAN 0x11a9
-#define PCI_VENDOR_ID_GALILEO 0x11ab
-#define PCI_VENDOR_ID_LINKSYS 0x11ad
-#define PCI_VENDOR_ID_LITEON 0x11ad
-#define PCI_VENDOR_ID_V3 0x11b0
-#define PCI_VENDOR_ID_NP 0x11bc
-#define PCI_VENDOR_ID_ATT 0x11c1
-#define PCI_VENDOR_ID_SPECIALIX 0x11cb
-#define PCI_VENDOR_ID_AURAVISION 0x11d1
-#define PCI_VENDOR_ID_ANALOG_DEVICES 0x11d4
-#define PCI_VENDOR_ID_IKON 0x11d5
-#define PCI_VENDOR_ID_ZORAN 0x11de
-#define PCI_VENDOR_ID_KINETIC 0x11f4
-#define PCI_VENDOR_ID_COMPEX 0x11f6
-#define PCI_VENDOR_ID_RP 0x11fe
-#define PCI_VENDOR_ID_CYCLADES 0x120e
-#define PCI_VENDOR_ID_ESSENTIAL 0x120f
-#define PCI_VENDOR_ID_O2 0x1217
-#define PCI_VENDOR_ID_3DFX 0x121a
-#define PCI_VENDOR_ID_SIGMADES 0x1236
-#define PCI_VENDOR_ID_CCUBE 0x123f
-#define PCI_VENDOR_ID_AVM 0x1244
-#define PCI_VENDOR_ID_DIPIX 0x1246
-#define PCI_VENDOR_ID_STALLION 0x124d
-#define PCI_VENDOR_ID_OPTIBASE 0x1255
-#define PCI_VENDOR_ID_ESS 0x125d
-#define PCI_VENDOR_ID_HARRIS 0x1260
-#define PCI_VENDOR_ID_SATSAGEM 0x1267
-#define PCI_VENDOR_ID_HUGHES 0x1273
-#define PCI_VENDOR_ID_ENSONIQ 0x1274
-#define PCI_VENDOR_ID_ROCKWELL 0x127A
-#define PCI_VENDOR_ID_DAVICOM 0x1282
-#define PCI_VENDOR_ID_ITE 0x1283
-/* formerly Platform Tech */
-#define PCI_VENDOR_ID_ESS_OLD 0x1285
-#define PCI_VENDOR_ID_ALTEON 0x12ae
-#define PCI_VENDOR_ID_USR 0x12B9
-#define PCI_VENDOR_ID_HOLTEK 0x12c3
-#define PCI_SUBVENDOR_ID_CONNECT_TECH 0x12c4
-#define PCI_VENDOR_ID_PICTUREL 0x12c5
-#define PCI_VENDOR_ID_NVIDIA_SGS 0x12d2
-#define PCI_SUBVENDOR_ID_CHASE_PCIFAST 0x12E0
-#define PCI_SUBVENDOR_ID_CHASE_PCIRAS 0x124D
-#define PCI_VENDOR_ID_AUREAL 0x12eb
-#define PCI_VENDOR_ID_CBOARDS 0x1307
-#define PCI_VENDOR_ID_SIIG 0x131f
-#define PCI_VENDOR_ID_ADMTEK 0x1317
-#define PCI_VENDOR_ID_DOMEX 0x134a
-#define PCI_VENDOR_ID_QUATECH 0x135C
-#define PCI_VENDOR_ID_SEALEVEL 0x135e
-#define PCI_VENDOR_ID_HYPERCOPE 0x1365
-#define PCI_VENDOR_ID_KAWASAKI 0x136b
-#define PCI_VENDOR_ID_LMC 0x1376
-#define PCI_VENDOR_ID_NETGEAR 0x1385
-#define PCI_VENDOR_ID_APPLICOM 0x1389
-#define PCI_VENDOR_ID_MOXA 0x1393
-#define PCI_VENDOR_ID_CCD 0x1397
-#define PCI_VENDOR_ID_MICROGATE 0x13c0
-#define PCI_VENDOR_ID_3WARE 0x13C1
-#define PCI_VENDOR_ID_ABOCOM 0x13D1
-#define PCI_VENDOR_ID_CMEDIA 0x13f6
-#define PCI_VENDOR_ID_LAVA 0x1407
-#define PCI_VENDOR_ID_TIMEDIA 0x1409
-#define PCI_VENDOR_ID_OXSEMI 0x1415
-#define PCI_VENDOR_ID_AIRONET 0x14b9
-#define PCI_VENDOR_ID_MYRICOM 0x14c1
-#define PCI_VENDOR_ID_TITAN 0x14D2
-#define PCI_VENDOR_ID_PANACOM 0x14d4
-#define PCI_VENDOR_ID_BROADCOM 0x14e4
-#define PCI_VENDOR_ID_SYBA 0x1592
-#define PCI_VENDOR_ID_MORETON 0x15aa
-#define PCI_VENDOR_ID_ZOLTRIX 0x15b0
-#define PCI_VENDOR_ID_PDC 0x15e9
-#define PCI_VENDOR_ID_FSC 0x1734
-#define PCI_VENDOR_ID_SYMPHONY 0x1c1c
-#define PCI_VENDOR_ID_TEKRAM 0x1de1
-#define PCI_VENDOR_ID_3DLABS 0x3d3d
-#define PCI_VENDOR_ID_AVANCE 0x4005
-#define PCI_VENDOR_ID_AKS 0x416c
-#define PCI_VENDOR_ID_NETVIN 0x4a14
-#define PCI_VENDOR_ID_S3 0x5333
-#define PCI_VENDOR_ID_DCI 0x6666
-#define PCI_VENDOR_ID_GENROCO 0x5555
-#define PCI_VENDOR_ID_INTEL 0x8086
-#define PCI_VENDOR_ID_COMPUTONE 0x8e0e
-#define PCI_SUBVENDOR_ID_COMPUTONE 0x8e0e
-#define PCI_VENDOR_ID_KTI 0x8e2e
-#define PCI_VENDOR_ID_ADAPTEC 0x9004
-#define PCI_VENDOR_ID_ADAPTEC2 0x9005
-#define PCI_VENDOR_ID_ATRONICS 0x907f
-#define PCI_VENDOR_ID_HOLTEK2 0x9412
-#define PCI_VENDOR_ID_NETMOS 0x9710
-#define PCI_SUBVENDOR_ID_EXSYS 0xd84d
-#define PCI_VENDOR_ID_TIGERJET 0xe159
-#define PCI_VENDOR_ID_ARK 0xedd8
-
-#endif /* _IPXE_PCI_IDS_H */
diff --git a/roms/ipxe/src/include/ipxe/pci_io.h b/roms/ipxe/src/include/ipxe/pci_io.h
index 781b77fe1..10e69763e 100644
--- a/roms/ipxe/src/include/ipxe/pci_io.h
+++ b/roms/ipxe/src/include/ipxe/pci_io.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/api.h>
diff --git a/roms/ipxe/src/include/ipxe/pcibackup.h b/roms/ipxe/src/include/ipxe/pcibackup.h
index b9f55cf71..159d25392 100644
--- a/roms/ipxe/src/include/ipxe/pcibackup.h
+++ b/roms/ipxe/src/include/ipxe/pcibackup.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
diff --git a/roms/ipxe/src/include/ipxe/pcivpd.h b/roms/ipxe/src/include/ipxe/pcivpd.h
index 0abf8a956..fefb69740 100644
--- a/roms/ipxe/src/include/ipxe/pcivpd.h
+++ b/roms/ipxe/src/include/ipxe/pcivpd.h
@@ -8,7 +8,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <byteswap.h>
diff --git a/roms/ipxe/src/include/ipxe/peerblk.h b/roms/ipxe/src/include/ipxe/peerblk.h
new file mode 100644
index 000000000..6fc9172f6
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/peerblk.h
@@ -0,0 +1,144 @@
+#ifndef _IPXE_PEERBLK_H
+#define _IPXE_PEERBLK_H
+
+/** @file
+ *
+ * Peer Content Caching and Retrieval (PeerDist) protocol block downloads
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
+#include <ipxe/refcnt.h>
+#include <ipxe/interface.h>
+#include <ipxe/crypto.h>
+#include <ipxe/aes.h>
+#include <ipxe/xferbuf.h>
+#include <ipxe/retry.h>
+#include <ipxe/process.h>
+#include <ipxe/pccrc.h>
+#include <ipxe/peerdisc.h>
+
+/** A PeerDist retrieval protocol decryption buffer descriptor */
+struct peerdist_block_decrypt {
+ /** Data transfer buffer */
+ struct xfer_buffer *xferbuf;
+ /** Offset within data transfer buffer */
+ size_t offset;
+ /** Length to use from data transfer buffer */
+ size_t len;
+};
+
+/** PeerDist retrieval protocol decryption data transfer buffer indices */
+enum peerdist_block_decrypt_index {
+ /** Data before the trimmed content */
+ PEERBLK_BEFORE = 0,
+ /** Data within the trimmed content */
+ PEERBLK_DURING,
+ /** Data after the trimmed content */
+ PEERBLK_AFTER,
+ /** Number of decryption buffers */
+ PEERBLK_NUM_BUFFERS
+};
+
+/** A PeerDist block download */
+struct peerdist_block {
+ /** Reference count */
+ struct refcnt refcnt;
+ /** Data transfer interface */
+ struct interface xfer;
+ /** Raw data interface */
+ struct interface raw;
+ /** Retrieval protocol interface */
+ struct interface retrieval;
+
+ /** Original URI */
+ struct uri *uri;
+ /** Content range of this block */
+ struct peerdist_range range;
+ /** Trimmed range of this block */
+ struct peerdist_range trim;
+ /** Offset of first byte in trimmed range within overall download */
+ size_t offset;
+
+ /** Digest algorithm */
+ struct digest_algorithm *digest;
+ /** Digest size
+ *
+ * Note that this may be shorter than the digest size of the
+ * digest algorithm.
+ */
+ size_t digestsize;
+ /** Digest context (statically allocated at instantiation time) */
+ void *digestctx;
+
+ /** Cipher algorithm */
+ struct cipher_algorithm *cipher;
+ /** Cipher context (dynamically allocated as needed) */
+ void *cipherctx;
+
+ /** Segment index */
+ unsigned int segment;
+ /** Segment identifier */
+ uint8_t id[PEERDIST_DIGEST_MAX_SIZE];
+ /** Segment secret */
+ uint8_t secret[PEERDIST_DIGEST_MAX_SIZE];
+ /** Block index */
+ unsigned int block;
+ /** Block hash */
+ uint8_t hash[PEERDIST_DIGEST_MAX_SIZE];
+
+ /** Current position (relative to incoming data stream) */
+ size_t pos;
+ /** Start of trimmed content (relative to incoming data stream) */
+ size_t start;
+ /** End of trimmed content (relative to incoming data stream) */
+ size_t end;
+ /** Data buffer */
+ struct xfer_buffer buffer;
+
+ /** Decryption process */
+ struct process process;
+ /** Decryption data buffer descriptors */
+ struct peerdist_block_decrypt decrypt[PEERBLK_NUM_BUFFERS];
+ /** Remaining decryption length */
+ size_t cipher_remaining;
+ /** Remaining digest length (excluding AES padding bytes) */
+ size_t digest_remaining;
+
+ /** Discovery client */
+ struct peerdisc_client discovery;
+ /** Current position in discovered peer list */
+ struct peerdisc_peer *peer;
+ /** Retry timer */
+ struct retry_timer timer;
+ /** Number of full attempt cycles completed */
+ unsigned int cycles;
+ /** Most recent attempt failure */
+ int rc;
+
+ /** Time at which block download was started */
+ unsigned long started;
+ /** Time at which most recent attempt was started */
+ unsigned long attempted;
+};
+
+/** Retrieval protocol block fetch response (including transport header)
+ *
+ * @v digestsize Digest size
+ * @v len Data block length
+ * @v vrf_len Length of uselessness
+ * @v blksize Cipher block size
+ */
+#define peerblk_msg_blk_t( digestsize, len, vrf_len, blksize ) \
+ struct { \
+ struct peerdist_msg_transport_header hdr; \
+ peerdist_msg_blk_t ( digestsize, len, vrf_len, \
+ blksize ) msg; \
+ } __attribute__ (( packed ))
+
+extern int peerblk_open ( struct interface *xfer, struct uri *uri,
+ struct peerdist_info_block *block );
+
+#endif /* _IPXE_PEERBLK_H */
diff --git a/roms/ipxe/src/include/ipxe/peerdisc.h b/roms/ipxe/src/include/ipxe/peerdisc.h
new file mode 100644
index 000000000..f08ccaae2
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/peerdisc.h
@@ -0,0 +1,116 @@
+#ifndef _IPXE_PEERDISC_H
+#define _IPXE_PEERDISC_H
+
+/** @file
+ *
+ * Peer Content Caching and Retrieval (PeerDist) protocol peer discovery
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
+#include <ipxe/refcnt.h>
+#include <ipxe/list.h>
+#include <ipxe/tables.h>
+#include <ipxe/retry.h>
+#include <ipxe/socket.h>
+#include <ipxe/interface.h>
+#include <ipxe/pccrc.h>
+
+/** A PeerDist discovery socket */
+struct peerdisc_socket {
+ /** Name */
+ const char *name;
+ /** Data transfer interface */
+ struct interface xfer;
+ /** Socket address */
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+ } address;
+};
+
+/** PeerDist discovery socket table */
+#define PEERDISC_SOCKETS __table ( struct peerdisc_socket, "peerdisc_sockets" )
+
+/** Declare a PeerDist discovery socket */
+#define __peerdisc_socket __table_entry ( PEERDISC_SOCKETS, 01 )
+
+/** A PeerDist discovery segment */
+struct peerdisc_segment {
+ /** Reference count */
+ struct refcnt refcnt;
+ /** List of segments */
+ struct list_head list;
+ /** Segment identifier string
+ *
+ * This is MS-PCCRC's "HoHoDk", transcribed as an upper-case
+ * Base16-encoded string.
+ */
+ const char *id;
+ /** Message UUID string */
+ const char *uuid;
+ /** List of discovered peers
+ *
+ * The list of peers may be appended to during the lifetime of
+ * the discovery segment. Discovered peers will not be
+ * removed from the list until the last discovery has been
+ * closed; this allows users to safely maintain a pointer to a
+ * current position within the list.
+ */
+ struct list_head peers;
+ /** List of active clients */
+ struct list_head clients;
+ /** Transmission timer */
+ struct retry_timer timer;
+};
+
+/** A PeerDist discovery peer */
+struct peerdisc_peer {
+ /** List of peers */
+ struct list_head list;
+ /** Peer location */
+ char location[0];
+};
+
+/** A PeerDist discovery client */
+struct peerdisc_client {
+ /** Discovery segment */
+ struct peerdisc_segment *segment;
+ /** List of clients */
+ struct list_head list;
+ /** Operations */
+ struct peerdisc_client_operations *op;
+};
+
+/** PeerDist discovery client operations */
+struct peerdisc_client_operations {
+ /** New peers have been discovered
+ *
+ * @v peerdisc PeerDist discovery client
+ */
+ void ( * discovered ) ( struct peerdisc_client *peerdisc );
+};
+
+/**
+ * Initialise PeerDist discovery
+ *
+ * @v peerdisc PeerDist discovery client
+ * @v op Discovery operations
+ */
+static inline __attribute__ (( always_inline )) void
+peerdisc_init ( struct peerdisc_client *peerdisc,
+ struct peerdisc_client_operations *op ) {
+
+ peerdisc->op = op;
+}
+
+extern unsigned int peerdisc_timeout_secs;
+
+extern int peerdisc_open ( struct peerdisc_client *peerdisc, const void *id,
+ size_t len );
+extern void peerdisc_close ( struct peerdisc_client *peerdisc );
+
+#endif /* _IPXE_PEERDISC_H */
diff --git a/roms/ipxe/src/include/ipxe/peermux.h b/roms/ipxe/src/include/ipxe/peermux.h
new file mode 100644
index 000000000..44cbdb9d6
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/peermux.h
@@ -0,0 +1,73 @@
+#ifndef _IPXE_PEERMUX_H
+#define _IPXE_PEERMUX_H
+
+/** @file
+ *
+ * Peer Content Caching and Retrieval (PeerDist) protocol multiplexer
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
+#include <ipxe/list.h>
+#include <ipxe/refcnt.h>
+#include <ipxe/interface.h>
+#include <ipxe/process.h>
+#include <ipxe/uri.h>
+#include <ipxe/xferbuf.h>
+#include <ipxe/pccrc.h>
+
+/** Maximum number of concurrent block downloads */
+#define PEERMUX_MAX_BLOCKS 32
+
+/** PeerDist download content information cache */
+struct peerdist_info_cache {
+ /** Content information */
+ struct peerdist_info info;
+ /** Content information segment */
+ struct peerdist_info_segment segment;
+ /** Content information block */
+ struct peerdist_info_block block;
+};
+
+/** A PeerDist multiplexed block download */
+struct peerdist_multiplexed_block {
+ /** PeerDist download multiplexer */
+ struct peerdist_multiplexer *peermux;
+ /** List of multiplexed blocks */
+ struct list_head list;
+ /** Data transfer interface */
+ struct interface xfer;
+};
+
+/** A PeerDist download multiplexer */
+struct peerdist_multiplexer {
+ /** Reference count */
+ struct refcnt refcnt;
+ /** Data transfer interface */
+ struct interface xfer;
+ /** Content information interface */
+ struct interface info;
+ /** Original URI */
+ struct uri *uri;
+
+ /** Content information data transfer buffer */
+ struct xfer_buffer buffer;
+ /** Content information cache */
+ struct peerdist_info_cache cache;
+
+ /** Block download initiation process */
+ struct process process;
+ /** List of busy block downloads */
+ struct list_head busy;
+ /** List of idle block downloads */
+ struct list_head idle;
+ /** Block downloads */
+ struct peerdist_multiplexed_block block[PEERMUX_MAX_BLOCKS];
+};
+
+extern int peermux_filter ( struct interface *xfer, struct interface *info,
+ struct uri *uri );
+
+#endif /* _IPXE_PEERMUX_H */
diff --git a/roms/ipxe/src/include/ipxe/pending.h b/roms/ipxe/src/include/ipxe/pending.h
index e6a369813..be6ed05a1 100644
--- a/roms/ipxe/src/include/ipxe/pending.h
+++ b/roms/ipxe/src/include/ipxe/pending.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** A pending operation */
struct pending_operation {
diff --git a/roms/ipxe/src/include/ipxe/ping.h b/roms/ipxe/src/include/ipxe/ping.h
index 6cd376b6f..c55bd1ab2 100644
--- a/roms/ipxe/src/include/ipxe/ping.h
+++ b/roms/ipxe/src/include/ipxe/ping.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/iobuf.h>
#include <ipxe/tcpip.h>
diff --git a/roms/ipxe/src/include/ipxe/pinger.h b/roms/ipxe/src/include/ipxe/pinger.h
index 9932df6b0..227f002dc 100644
--- a/roms/ipxe/src/include/ipxe/pinger.h
+++ b/roms/ipxe/src/include/ipxe/pinger.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/interface.h>
diff --git a/roms/ipxe/src/include/ipxe/pixbuf.h b/roms/ipxe/src/include/ipxe/pixbuf.h
index 106b666e6..615744812 100644
--- a/roms/ipxe/src/include/ipxe/pixbuf.h
+++ b/roms/ipxe/src/include/ipxe/pixbuf.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <ipxe/refcnt.h>
diff --git a/roms/ipxe/src/include/ipxe/png.h b/roms/ipxe/src/include/ipxe/png.h
index f51d1e6fe..3505eefc8 100644
--- a/roms/ipxe/src/include/ipxe/png.h
+++ b/roms/ipxe/src/include/ipxe/png.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <byteswap.h>
diff --git a/roms/ipxe/src/include/ipxe/pnm.h b/roms/ipxe/src/include/ipxe/pnm.h
index 536c14d5f..860968cbc 100644
--- a/roms/ipxe/src/include/ipxe/pnm.h
+++ b/roms/ipxe/src/include/ipxe/pnm.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/uaccess.h>
diff --git a/roms/ipxe/src/include/ipxe/pool.h b/roms/ipxe/src/include/ipxe/pool.h
new file mode 100644
index 000000000..27066e9b3
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/pool.h
@@ -0,0 +1,127 @@
+#ifndef _IPXE_POOL_H
+#define _IPXE_POOL_H
+
+/** @file
+ *
+ * Pooled connections
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <ipxe/interface.h>
+#include <ipxe/list.h>
+#include <ipxe/retry.h>
+
+/** A pooled connection */
+struct pooled_connection {
+ /** List of pooled connections
+ *
+ * Note that each connecton in the pool has a running expiry
+ * timer which holds a reference to the connection. We
+ * therefore do not require the connection pool list to hold a
+ * reference for each pooled connection.
+ */
+ struct list_head list;
+ /** Expiry timer */
+ struct retry_timer timer;
+ /** Close expired pooled connection
+ *
+ * @v pool Pooled connection
+ */
+ void ( * expired ) ( struct pooled_connection *pool );
+ /** Flags */
+ unsigned int flags;
+};
+
+/** Pooled connection flags */
+enum pooled_connection_flags {
+ /** Connection should be recycled after closing */
+ POOL_RECYCLABLE = 0x0001,
+ /** Connection has been recycled */
+ POOL_RECYCLED = 0x0002,
+ /** Connection is known to be alive */
+ POOL_ALIVE = 0x0004,
+};
+
+extern void pool_add ( struct pooled_connection *pool, struct list_head *list,
+ unsigned long expiry );
+extern void pool_del ( struct pooled_connection *pool );
+extern void pool_expired ( struct retry_timer *timer, int over );
+
+/**
+ * Initialise a pooled connection
+ *
+ * @v pool Pooled connection
+ * @v expired Close expired pooled connection method
+ * @v refcnt Containing object reference counter
+ */
+static inline __attribute__ (( always_inline )) void
+pool_init ( struct pooled_connection *pool,
+ void ( * expired ) ( struct pooled_connection *pool ),
+ struct refcnt *refcnt ) {
+
+ INIT_LIST_HEAD ( &pool->list );
+ timer_init ( &pool->timer, pool_expired, refcnt );
+ pool->expired = expired;
+}
+
+/**
+ * Mark pooled connection as recyclable
+ *
+ * @v pool Pooled connection
+ */
+static inline __attribute__ (( always_inline )) void
+pool_recyclable ( struct pooled_connection *pool ) {
+
+ pool->flags |= POOL_RECYCLABLE;
+}
+
+/**
+ * Mark pooled connection as alive
+ *
+ * @v pool Pooled connection
+ */
+static inline __attribute__ (( always_inline )) void
+pool_alive ( struct pooled_connection *pool ) {
+
+ pool->flags |= POOL_ALIVE;
+}
+
+/**
+ * Check if pooled connection is recyclable
+ *
+ * @v pool Pooled connection
+ * @ret recyclable Pooled connection is recyclable
+ */
+static inline __attribute__ (( always_inline )) int
+pool_is_recyclable ( struct pooled_connection *pool ) {
+
+ return ( pool->flags & POOL_RECYCLABLE );
+}
+
+/**
+ * Check if pooled connection is reopenable
+ *
+ * @v pool Pooled connection
+ * @ret reopenable Pooled connection is reopenable
+ */
+static inline __attribute__ (( always_inline )) int
+pool_is_reopenable ( struct pooled_connection *pool ) {
+
+ /* A connection is reopenable if it has been recycled but is
+ * not yet known to be alive.
+ */
+ return ( ( pool->flags & POOL_RECYCLED ) &
+ ( ! ( pool->flags & POOL_ALIVE ) ) );
+}
+
+extern void pool_recycle ( struct interface *intf );
+#define pool_recycle_TYPE( object_type ) \
+ typeof ( void ( object_type ) )
+
+extern void pool_reopen ( struct interface *intf );
+#define pool_reopen_TYPE( object_type ) \
+ typeof ( void ( object_type ) )
+
+#endif /* _IPXE_POOL_H */
diff --git a/roms/ipxe/src/include/ipxe/portmap.h b/roms/ipxe/src/include/ipxe/portmap.h
index 9b735bbca..681ca2ec2 100644
--- a/roms/ipxe/src/include/ipxe/portmap.h
+++ b/roms/ipxe/src/include/ipxe/portmap.h
@@ -10,7 +10,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** PORTMAP default port */
#define PORTMAP_PORT 111
diff --git a/roms/ipxe/src/include/ipxe/posix_io.h b/roms/ipxe/src/include/ipxe/posix_io.h
index 11f3bb5c9..1a73b5e86 100644
--- a/roms/ipxe/src/include/ipxe/posix_io.h
+++ b/roms/ipxe/src/include/ipxe/posix_io.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/uaccess.h>
diff --git a/roms/ipxe/src/include/ipxe/privkey.h b/roms/ipxe/src/include/ipxe/privkey.h
index 39049ac9f..81108b6bf 100644
--- a/roms/ipxe/src/include/ipxe/privkey.h
+++ b/roms/ipxe/src/include/ipxe/privkey.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/asn1.h>
diff --git a/roms/ipxe/src/include/ipxe/process.h b/roms/ipxe/src/include/ipxe/process.h
index 2c76ff260..d600508e7 100644
--- a/roms/ipxe/src/include/ipxe/process.h
+++ b/roms/ipxe/src/include/ipxe/process.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/list.h>
#include <ipxe/refcnt.h>
diff --git a/roms/ipxe/src/include/ipxe/profile.h b/roms/ipxe/src/include/ipxe/profile.h
index 3a745fcfa..b6d2b19e0 100644
--- a/roms/ipxe/src/include/ipxe/profile.h
+++ b/roms/ipxe/src/include/ipxe/profile.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <bits/profile.h>
#include <ipxe/tables.h>
@@ -186,4 +186,18 @@ profile_exclude ( struct profiler *profiler ) {
profile_excluded += profile_elapsed ( profiler );
}
+/**
+ * Record profiling sample in custom units
+ *
+ * @v profiler Profiler
+ * @v sample Profiling sample
+ */
+static inline __attribute__ (( always_inline )) void
+profile_custom ( struct profiler *profiler, unsigned long sample ) {
+
+ /* If profiling is active then update stats */
+ if ( PROFILING )
+ profile_update ( profiler, sample );
+}
+
#endif /* _IPXE_PROFILE_H */
diff --git a/roms/ipxe/src/include/ipxe/random_nz.h b/roms/ipxe/src/include/ipxe/random_nz.h
index 6bb80d2ab..4c433fa38 100644
--- a/roms/ipxe/src/include/ipxe/random_nz.h
+++ b/roms/ipxe/src/include/ipxe/random_nz.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
diff --git a/roms/ipxe/src/include/ipxe/rarp.h b/roms/ipxe/src/include/ipxe/rarp.h
index f84301a43..9054db21a 100644
--- a/roms/ipxe/src/include/ipxe/rarp.h
+++ b/roms/ipxe/src/include/ipxe/rarp.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/netdevice.h>
diff --git a/roms/ipxe/src/include/ipxe/rbg.h b/roms/ipxe/src/include/ipxe/rbg.h
index 9689142f8..758238a65 100644
--- a/roms/ipxe/src/include/ipxe/rbg.h
+++ b/roms/ipxe/src/include/ipxe/rbg.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/drbg.h>
diff --git a/roms/ipxe/src/include/ipxe/reboot.h b/roms/ipxe/src/include/ipxe/reboot.h
index 97e0d5fb6..33606d9d5 100644
--- a/roms/ipxe/src/include/ipxe/reboot.h
+++ b/roms/ipxe/src/include/ipxe/reboot.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/api.h>
#include <config/reboot.h>
diff --git a/roms/ipxe/src/include/ipxe/refcnt.h b/roms/ipxe/src/include/ipxe/refcnt.h
index 0e8b8658c..7f489abc9 100644
--- a/roms/ipxe/src/include/ipxe/refcnt.h
+++ b/roms/ipxe/src/include/ipxe/refcnt.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <assert.h>
diff --git a/roms/ipxe/src/include/ipxe/resolv.h b/roms/ipxe/src/include/ipxe/resolv.h
index d9868a5d7..ff48d35ca 100644
--- a/roms/ipxe/src/include/ipxe/resolv.h
+++ b/roms/ipxe/src/include/ipxe/resolv.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/interface.h>
#include <ipxe/tables.h>
diff --git a/roms/ipxe/src/include/ipxe/retry.h b/roms/ipxe/src/include/ipxe/retry.h
index c514822b2..76d45fbd0 100644
--- a/roms/ipxe/src/include/ipxe/retry.h
+++ b/roms/ipxe/src/include/ipxe/retry.h
@@ -7,14 +7,14 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/list.h>
-/** Default timeout value */
+/** Default minimum timeout value (in ticks) */
#define DEFAULT_MIN_TIMEOUT ( TICKS_PER_SEC / 4 )
-/** Limit after which the timeout will be deemed permanent */
+/** Default maximum timeout value (in ticks) */
#define DEFAULT_MAX_TIMEOUT ( 10 * TICKS_PER_SEC )
/** A retry timer */
@@ -25,16 +25,18 @@ struct retry_timer {
unsigned int running;
/** Timeout value (in ticks) */
unsigned long timeout;
- /** Minimum timeout value (in ticks)
+ /** Minimum timeout value (in ticks), or zero to use default
*
- * A value of zero means "use default timeout."
+ * The timeout will never be reduced below this value.
*/
- unsigned long min_timeout;
- /** Maximum timeout value before failure (in ticks)
+ unsigned long min;
+ /** Maximum timeout value (in ticks), or zero to use default
*
- * A value of zero means "use default timeout."
+ * The timeout will be deemed permanent (according to the
+ * failure indicator passed to expired()) when it exceeds this
+ * value.
*/
- unsigned long max_timeout;
+ unsigned long max;
/** Start time (in ticks) */
unsigned long start;
/** Retry count */
@@ -46,7 +48,7 @@ struct retry_timer {
*
* The timer will already be stopped when this method is
* called. The failure indicator will be True if the retry
- * timeout has already exceeded @c MAX_TIMEOUT.
+ * timeout has already exceeded @c max_timeout.
*/
void ( * expired ) ( struct retry_timer *timer, int over );
/** Reference counter
@@ -109,4 +111,18 @@ timer_running ( struct retry_timer *timer ) {
return ( timer->running );
}
+/**
+ * Set minimum and maximum timeouts
+ *
+ * @v timer Retry timer
+ * @v min Minimum timeout (in ticks), or zero to use default
+ * @v max Maximum timeout (in ticks), or zero to use default
+ */
+static inline __attribute__ (( always_inline )) void
+set_timer_limits ( struct retry_timer *timer, unsigned long min,
+ unsigned long max ) {
+ timer->min = min;
+ timer->max = max;
+}
+
#endif /* _IPXE_RETRY_H */
diff --git a/roms/ipxe/src/include/ipxe/rndis.h b/roms/ipxe/src/include/ipxe/rndis.h
new file mode 100644
index 000000000..bcb6d8e6a
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/rndis.h
@@ -0,0 +1,370 @@
+#ifndef _IPXE_RNDIS_H
+#define _IPXE_RNDIS_H
+
+/** @file
+ *
+ * Remote Network Driver Interface Specification
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/iobuf.h>
+
+/** Maximum time to wait for a transaction to complete
+ *
+ * This is a policy decision.
+ */
+#define RNDIS_MAX_WAIT_MS 1000
+
+/** RNDIS message header */
+struct rndis_header {
+ /** Message type */
+ uint32_t type;
+ /** Message length */
+ uint32_t len;
+} __attribute__ (( packed ));
+
+/** RNDIS initialise message */
+#define RNDIS_INITIALISE_MSG 0x00000002UL
+
+/** RNDIS initialise message */
+struct rndis_initialise_message {
+ /** Request ID */
+ uint32_t id;
+ /** Major version */
+ uint32_t major;
+ /** Minor version */
+ uint32_t minor;
+ /** Maximum transfer size */
+ uint32_t mtu;
+} __attribute__ (( packed ));
+
+/** Request ID used for initialisation
+ *
+ * This is a policy decision.
+ */
+#define RNDIS_INIT_ID 0xe110e110UL
+
+/** RNDIS major version */
+#define RNDIS_VERSION_MAJOR 1
+
+/** RNDIS minor version */
+#define RNDIS_VERSION_MINOR 0
+
+/** RNDIS maximum transfer size
+ *
+ * This is a policy decision.
+ */
+#define RNDIS_MTU 2048
+
+/** RNDIS initialise completion */
+#define RNDIS_INITIALISE_CMPLT 0x80000002UL
+
+/** RNDIS initialise completion */
+struct rndis_initialise_completion {
+ /** Request ID */
+ uint32_t id;
+ /** Status */
+ uint32_t status;
+ /** Major version */
+ uint32_t major;
+ /** Minor version */
+ uint32_t minor;
+ /** Device flags */
+ uint32_t flags;
+ /** Medium */
+ uint32_t medium;
+ /** Maximum packets per transfer */
+ uint32_t max_pkts;
+ /** Maximum transfer size */
+ uint32_t mtu;
+ /** Packet alignment factor */
+ uint32_t align;
+ /** Reserved */
+ uint32_t reserved;
+} __attribute__ (( packed ));
+
+/** RNDIS halt message */
+#define RNDIS_HALT_MSG 0x00000003UL
+
+/** RNDIS halt message */
+struct rndis_halt_message {
+ /** Request ID */
+ uint32_t id;
+} __attribute__ (( packed ));
+
+/** RNDIS query OID message */
+#define RNDIS_QUERY_MSG 0x00000004UL
+
+/** RNDIS set OID message */
+#define RNDIS_SET_MSG 0x00000005UL
+
+/** RNDIS query or set OID message */
+struct rndis_oid_message {
+ /** Request ID */
+ uint32_t id;
+ /** Object ID */
+ uint32_t oid;
+ /** Information buffer length */
+ uint32_t len;
+ /** Information buffer offset */
+ uint32_t offset;
+ /** Reserved */
+ uint32_t reserved;
+} __attribute__ (( packed ));
+
+/** RNDIS query OID completion */
+#define RNDIS_QUERY_CMPLT 0x80000004UL
+
+/** RNDIS query OID completion */
+struct rndis_query_completion {
+ /** Request ID */
+ uint32_t id;
+ /** Status */
+ uint32_t status;
+ /** Information buffer length */
+ uint32_t len;
+ /** Information buffer offset */
+ uint32_t offset;
+} __attribute__ (( packed ));
+
+/** RNDIS set OID completion */
+#define RNDIS_SET_CMPLT 0x80000005UL
+
+/** RNDIS set OID completion */
+struct rndis_set_completion {
+ /** Request ID */
+ uint32_t id;
+ /** Status */
+ uint32_t status;
+} __attribute__ (( packed ));
+
+/** RNDIS reset message */
+#define RNDIS_RESET_MSG 0x00000006UL
+
+/** RNDIS reset message */
+struct rndis_reset_message {
+ /** Reserved */
+ uint32_t reserved;
+} __attribute__ (( packed ));
+
+/** RNDIS reset completion */
+#define RNDIS_RESET_CMPLT 0x80000006UL
+
+/** RNDIS reset completion */
+struct rndis_reset_completion {
+ /** Status */
+ uint32_t status;
+ /** Addressing reset */
+ uint32_t addr;
+} __attribute__ (( packed ));
+
+/** RNDIS indicate status message */
+#define RNDIS_INDICATE_STATUS_MSG 0x00000007UL
+
+/** RNDIS diagnostic information */
+struct rndis_diagnostic_info {
+ /** Status */
+ uint32_t status;
+ /** Error offset */
+ uint32_t offset;
+} __attribute__ (( packed ));
+
+/** RNDIS indicate status message */
+struct rndis_indicate_status_message {
+ /** Status */
+ uint32_t status;
+ /** Status buffer length */
+ uint32_t len;
+ /** Status buffer offset */
+ uint32_t offset;
+ /** Diagnostic information (optional) */
+ struct rndis_diagnostic_info diag[0];
+} __attribute__ (( packed ));
+
+/** RNDIS status codes */
+enum rndis_status {
+ /** Device is connected to a network medium */
+ RNDIS_STATUS_MEDIA_CONNECT = 0x4001000bUL,
+ /** Device is disconnected from the medium */
+ RNDIS_STATUS_MEDIA_DISCONNECT = 0x4001000cUL,
+ /** Unknown start-of-day status code */
+ RNDIS_STATUS_WTF_WORLD = 0x40020006UL,
+};
+
+/** RNDIS keepalive message */
+#define RNDIS_KEEPALIVE_MSG 0x00000008UL
+
+/** RNDIS keepalive message */
+struct rndis_keepalive_message {
+ /** Request ID */
+ uint32_t id;
+} __attribute__ (( packed ));
+
+/** RNDIS keepalive completion */
+#define RNDIS_KEEPALIVE_CMPLT 0x80000008UL
+
+/** RNDIS keepalive completion */
+struct rndis_keepalive_completion {
+ /** Request ID */
+ uint32_t id;
+ /** Status */
+ uint32_t status;
+} __attribute__ (( packed ));
+
+/** RNDIS packet message */
+#define RNDIS_PACKET_MSG 0x00000001UL
+
+/** RNDIS packet field */
+struct rndis_packet_field {
+ /** Offset */
+ uint32_t offset;
+ /** Length */
+ uint32_t len;
+} __attribute__ (( packed ));
+
+/** RNDIS packet message */
+struct rndis_packet_message {
+ /** Data */
+ struct rndis_packet_field data;
+ /** Out-of-band data records */
+ struct rndis_packet_field oob;
+ /** Number of out-of-band data records */
+ uint32_t oob_count;
+ /** Per-packet information record */
+ struct rndis_packet_field ppi;
+ /** Reserved */
+ uint32_t reserved;
+} __attribute__ (( packed ));
+
+/** RNDIS packet record */
+struct rndis_packet_record {
+ /** Length */
+ uint32_t len;
+ /** Type */
+ uint32_t type;
+ /** Offset */
+ uint32_t offset;
+} __attribute__ (( packed ));
+
+/** OID for packet filter */
+#define RNDIS_OID_GEN_CURRENT_PACKET_FILTER 0x0001010eUL
+
+/** Packet filter bits */
+enum rndis_packet_filter {
+ /** Unicast packets */
+ RNDIS_FILTER_UNICAST = 0x00000001UL,
+ /** Multicast packets */
+ RNDIS_FILTER_MULTICAST = 0x00000002UL,
+ /** All multicast packets */
+ RNDIS_FILTER_ALL_MULTICAST = 0x00000004UL,
+ /** Broadcast packets */
+ RNDIS_FILTER_BROADCAST = 0x00000008UL,
+ /** All packets */
+ RNDIS_FILTER_PROMISCUOUS = 0x00000020UL
+};
+
+/** OID for media status */
+#define RNDIS_OID_GEN_MEDIA_CONNECT_STATUS 0x00010114UL
+
+/** OID for permanent MAC address */
+#define RNDIS_OID_802_3_PERMANENT_ADDRESS 0x01010101UL
+
+/** OID for current MAC address */
+#define RNDIS_OID_802_3_CURRENT_ADDRESS 0x01010102UL
+
+struct rndis_device;
+
+/** RNDIS device operations */
+struct rndis_operations {
+ /**
+ * Open RNDIS device
+ *
+ * @v rndis RNDIS device
+ * @ret rc Return status code
+ */
+ int ( * open ) ( struct rndis_device *rndis );
+ /**
+ * Close RNDIS device
+ *
+ * @v rndis RNDIS device
+ */
+ void ( * close ) ( struct rndis_device *rndis );
+ /**
+ * Transmit packet
+ *
+ * @v rndis RNDIS device
+ * @v iobuf I/O buffer
+ * @ret rc Return status code
+ *
+ * If this method returns success then the RNDIS device must
+ * eventually report completion via rndis_tx_complete().
+ */
+ int ( * transmit ) ( struct rndis_device *rndis,
+ struct io_buffer *iobuf );
+ /**
+ * Poll for completed and received packets
+ *
+ * @v rndis RNDIS device
+ */
+ void ( * poll ) ( struct rndis_device *rndis );
+};
+
+/** An RNDIS device */
+struct rndis_device {
+ /** Network device */
+ struct net_device *netdev;
+ /** Device name */
+ const char *name;
+ /** RNDIS operations */
+ struct rndis_operations *op;
+ /** Driver private data */
+ void *priv;
+
+ /** Request ID for current blocking request */
+ unsigned int wait_id;
+ /** Return status code for current blocking request */
+ int wait_rc;
+};
+
+/**
+ * Initialise an RNDIS device
+ *
+ * @v rndis RNDIS device
+ * @v op RNDIS device operations
+ */
+static inline void rndis_init ( struct rndis_device *rndis,
+ struct rndis_operations *op ) {
+
+ rndis->op = op;
+}
+
+extern void rndis_tx_complete_err ( struct rndis_device *rndis,
+ struct io_buffer *iobuf, int rc );
+extern int rndis_tx_defer ( struct rndis_device *rndis,
+ struct io_buffer *iobuf );
+extern void rndis_rx ( struct rndis_device *rndis, struct io_buffer *iobuf );
+extern void rndis_rx_err ( struct rndis_device *rndis, struct io_buffer *iobuf,
+ int rc );
+
+extern struct rndis_device * alloc_rndis ( size_t priv_len );
+extern int register_rndis ( struct rndis_device *rndis );
+extern void unregister_rndis ( struct rndis_device *rndis );
+extern void free_rndis ( struct rndis_device *rndis );
+
+/**
+ * Complete message transmission
+ *
+ * @v rndis RNDIS device
+ * @v iobuf I/O buffer
+ */
+static inline void rndis_tx_complete ( struct rndis_device *rndis,
+ struct io_buffer *iobuf ) {
+
+ rndis_tx_complete_err ( rndis, iobuf, 0 );
+}
+
+#endif /* _IPXE_RNDIS_H */
diff --git a/roms/ipxe/src/include/ipxe/rootcert.h b/roms/ipxe/src/include/ipxe/rootcert.h
index 6525df87a..d4be2e1bc 100644
--- a/roms/ipxe/src/include/ipxe/rootcert.h
+++ b/roms/ipxe/src/include/ipxe/rootcert.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/x509.h>
diff --git a/roms/ipxe/src/include/ipxe/rotate.h b/roms/ipxe/src/include/ipxe/rotate.h
index ba271ca74..b5693e3ca 100644
--- a/roms/ipxe/src/include/ipxe/rotate.h
+++ b/roms/ipxe/src/include/ipxe/rotate.h
@@ -6,10 +6,30 @@
* Bit operations
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
+static inline __attribute__ (( always_inline )) uint8_t
+rol8 ( uint8_t data, unsigned int rotation ) {
+ return ( ( data << rotation ) | ( data >> ( 8 - rotation ) ) );
+}
+
+static inline __attribute__ (( always_inline )) uint8_t
+ror8 ( uint8_t data, unsigned int rotation ) {
+ return ( ( data >> rotation ) | ( data << ( 8 - rotation ) ) );
+}
+
+static inline __attribute__ (( always_inline )) uint16_t
+rol16 ( uint16_t data, unsigned int rotation ) {
+ return ( ( data << rotation ) | ( data >> ( 16 - rotation ) ) );
+}
+
+static inline __attribute__ (( always_inline )) uint16_t
+ror16 ( uint16_t data, unsigned int rotation ) {
+ return ( ( data >> rotation ) | ( data << ( 16 - rotation ) ) );
+}
+
static inline __attribute__ (( always_inline )) uint32_t
rol32 ( uint32_t data, unsigned int rotation ) {
return ( ( data << rotation ) | ( data >> ( 32 - rotation ) ) );
diff --git a/roms/ipxe/src/include/ipxe/rsa.h b/roms/ipxe/src/include/ipxe/rsa.h
index 1a5ad8bab..d947eec73 100644
--- a/roms/ipxe/src/include/ipxe/rsa.h
+++ b/roms/ipxe/src/include/ipxe/rsa.h
@@ -6,8 +6,9 @@
* RSA public-key cryptography
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+#include <stdarg.h>
#include <ipxe/crypto.h>
#include <ipxe/bigint.h>
#include <ipxe/asn1.h>
diff --git a/roms/ipxe/src/include/ipxe/sanboot.h b/roms/ipxe/src/include/ipxe/sanboot.h
index 14c8a5da4..57025f2c6 100644
--- a/roms/ipxe/src/include/ipxe/sanboot.h
+++ b/roms/ipxe/src/include/ipxe/sanboot.h
@@ -16,7 +16,7 @@
* the address parameter.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/api.h>
#include <config/sanboot.h>
diff --git a/roms/ipxe/src/include/ipxe/script.h b/roms/ipxe/src/include/ipxe/script.h
index 33420dae4..7e7a9a3a4 100644
--- a/roms/ipxe/src/include/ipxe/script.h
+++ b/roms/ipxe/src/include/ipxe/script.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/image.h>
diff --git a/roms/ipxe/src/include/ipxe/scsi.h b/roms/ipxe/src/include/ipxe/scsi.h
index 4428daac3..28b55b2d5 100644
--- a/roms/ipxe/src/include/ipxe/scsi.h
+++ b/roms/ipxe/src/include/ipxe/scsi.h
@@ -11,7 +11,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** Maximum block for READ/WRITE (10) commands */
#define SCSI_MAX_BLOCK_10 0xffffffffULL
diff --git a/roms/ipxe/src/include/ipxe/segment.h b/roms/ipxe/src/include/ipxe/segment.h
index 37bed0e19..9d5ecbd9b 100644
--- a/roms/ipxe/src/include/ipxe/segment.h
+++ b/roms/ipxe/src/include/ipxe/segment.h
@@ -8,7 +8,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/uaccess.h>
diff --git a/roms/ipxe/src/include/ipxe/serial.h b/roms/ipxe/src/include/ipxe/serial.h
index b47b1d125..83be59c31 100644
--- a/roms/ipxe/src/include/ipxe/serial.h
+++ b/roms/ipxe/src/include/ipxe/serial.h
@@ -3,15 +3,14 @@
/** @file
*
- * Serial driver functions
+ * Serial console
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
-extern void serial_putc ( int ch );
-extern int serial_getc ( void );
-extern int serial_ischar ( void );
-extern int serial_initialized;
+#include <ipxe/uart.h>
+
+extern struct uart serial_console;
#endif /* _IPXE_SERIAL_H */
diff --git a/roms/ipxe/src/include/ipxe/settings.h b/roms/ipxe/src/include/ipxe/settings.h
index d6929ecd0..95a553cc8 100644
--- a/roms/ipxe/src/include/ipxe/settings.h
+++ b/roms/ipxe/src/include/ipxe/settings.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/tables.h>
@@ -415,6 +415,7 @@ extern const struct setting_type setting_type_uint32 __setting_type;
extern const struct setting_type setting_type_hex __setting_type;
extern const struct setting_type setting_type_hexhyp __setting_type;
extern const struct setting_type setting_type_hexraw __setting_type;
+extern const struct setting_type setting_type_base64 __setting_type;
extern const struct setting_type setting_type_uuid __setting_type;
extern const struct setting_type setting_type_busdevfn __setting_type;
extern const struct setting_type setting_type_dnssl __setting_type;
diff --git a/roms/ipxe/src/include/ipxe/settings_ui.h b/roms/ipxe/src/include/ipxe/settings_ui.h
index 5f7be30cc..0bf21935d 100644
--- a/roms/ipxe/src/include/ipxe/settings_ui.h
+++ b/roms/ipxe/src/include/ipxe/settings_ui.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
struct settings;
diff --git a/roms/ipxe/src/include/ipxe/sha256.h b/roms/ipxe/src/include/ipxe/sha256.h
index 9aa9f3e57..e234cce33 100644
--- a/roms/ipxe/src/include/ipxe/sha256.h
+++ b/roms/ipxe/src/include/ipxe/sha256.h
@@ -7,11 +7,14 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/crypto.h>
+/** SHA-256 number of rounds */
+#define SHA256_ROUNDS 64
+
/** An SHA-256 digest */
struct sha256_digest {
/** Hash output */
@@ -58,6 +61,8 @@ union sha256_digest_data_dwords {
struct sha256_context {
/** Amount of accumulated data */
size_t len;
+ /** Digest size */
+ size_t digestsize;
/** Digest and accumulated data */
union sha256_digest_data_dwords ddd;
} __attribute__ (( packed ));
@@ -68,6 +73,16 @@ struct sha256_context {
/** SHA-256 digest size */
#define SHA256_DIGEST_SIZE sizeof ( struct sha256_digest )
+/** SHA-224 digest size */
+#define SHA224_DIGEST_SIZE ( SHA256_DIGEST_SIZE * 224 / 256 )
+
+extern void sha256_family_init ( struct sha256_context *context,
+ const struct sha256_digest *init,
+ size_t digestsize );
+extern void sha256_update ( void *ctx, const void *data, size_t len );
+extern void sha256_final ( void *ctx, void *out );
+
extern struct digest_algorithm sha256_algorithm;
+extern struct digest_algorithm sha224_algorithm;
#endif /* _IPXE_SHA256_H */
diff --git a/roms/ipxe/src/include/ipxe/sha512.h b/roms/ipxe/src/include/ipxe/sha512.h
new file mode 100644
index 000000000..8e22d8357
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/sha512.h
@@ -0,0 +1,98 @@
+#ifndef _IPXE_SHA512_H
+#define _IPXE_SHA512_H
+
+/** @file
+ *
+ * SHA-512 algorithm
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
+#include <ipxe/crypto.h>
+
+/** SHA-512 number of rounds */
+#define SHA512_ROUNDS 80
+
+/** An SHA-512 digest */
+struct sha512_digest {
+ /** Hash output */
+ uint64_t h[8];
+};
+
+/** An SHA-512 data block */
+union sha512_block {
+ /** Raw bytes */
+ uint8_t byte[128];
+ /** Raw qwords */
+ uint64_t qword[16];
+ /** Final block structure */
+ struct {
+ /** Padding */
+ uint8_t pad[112];
+ /** High 64 bits of length in bits */
+ uint64_t len_hi;
+ /** Low 64 bits of length in bits */
+ uint64_t len_lo;
+ } final;
+};
+
+/** SHA-512 digest and data block
+ *
+ * The order of fields within this structure is designed to minimise
+ * code size.
+ */
+struct sha512_digest_data {
+ /** Digest of data already processed */
+ struct sha512_digest digest;
+ /** Accumulated data */
+ union sha512_block data;
+} __attribute__ (( packed ));
+
+/** SHA-512 digest and data block */
+union sha512_digest_data_qwords {
+ /** Digest and data block */
+ struct sha512_digest_data dd;
+ /** Raw qwords */
+ uint64_t qword[ sizeof ( struct sha512_digest_data ) /
+ sizeof ( uint64_t ) ];
+};
+
+/** An SHA-512 context */
+struct sha512_context {
+ /** Amount of accumulated data */
+ size_t len;
+ /** Digest size */
+ size_t digestsize;
+ /** Digest and accumulated data */
+ union sha512_digest_data_qwords ddq;
+} __attribute__ (( packed ));
+
+/** SHA-512 context size */
+#define SHA512_CTX_SIZE sizeof ( struct sha512_context )
+
+/** SHA-512 digest size */
+#define SHA512_DIGEST_SIZE sizeof ( struct sha512_digest )
+
+/** SHA-384 digest size */
+#define SHA384_DIGEST_SIZE ( SHA512_DIGEST_SIZE * 384 / 512 )
+
+/** SHA-512/256 digest size */
+#define SHA512_256_DIGEST_SIZE ( SHA512_DIGEST_SIZE * 256 / 512 )
+
+/** SHA-512/224 digest size */
+#define SHA512_224_DIGEST_SIZE ( SHA512_DIGEST_SIZE * 224 / 512 )
+
+extern void sha512_family_init ( struct sha512_context *context,
+ const struct sha512_digest *init,
+ size_t digestsize );
+extern void sha512_update ( void *ctx, const void *data, size_t len );
+extern void sha512_final ( void *ctx, void *out );
+
+extern struct digest_algorithm sha512_algorithm;
+extern struct digest_algorithm sha384_algorithm;
+extern struct digest_algorithm sha512_256_algorithm;
+extern struct digest_algorithm sha512_224_algorithm;
+
+#endif /* IPXE_SHA512_H */
diff --git a/roms/ipxe/src/include/ipxe/shell.h b/roms/ipxe/src/include/ipxe/shell.h
index faa32f422..0d574e028 100644
--- a/roms/ipxe/src/include/ipxe/shell.h
+++ b/roms/ipxe/src/include/ipxe/shell.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** Shell stop states */
enum shell_stop_state {
diff --git a/roms/ipxe/src/include/ipxe/smbios.h b/roms/ipxe/src/include/ipxe/smbios.h
index ef5892a21..24b05ed62 100644
--- a/roms/ipxe/src/include/ipxe/smbios.h
+++ b/roms/ipxe/src/include/ipxe/smbios.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/api.h>
diff --git a/roms/ipxe/src/include/ipxe/socket.h b/roms/ipxe/src/include/ipxe/socket.h
index 7cb3912f4..8c70ea4c0 100644
--- a/roms/ipxe/src/include/ipxe/socket.h
+++ b/roms/ipxe/src/include/ipxe/socket.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/tables.h>
diff --git a/roms/ipxe/src/include/ipxe/spi.h b/roms/ipxe/src/include/ipxe/spi.h
index d92d1aec9..83b53bce3 100644
--- a/roms/ipxe/src/include/ipxe/spi.h
+++ b/roms/ipxe/src/include/ipxe/spi.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/nvs.h>
diff --git a/roms/ipxe/src/include/ipxe/spi_bit.h b/roms/ipxe/src/include/ipxe/spi_bit.h
index 9cfa7b825..049d30a22 100644
--- a/roms/ipxe/src/include/ipxe/spi_bit.h
+++ b/roms/ipxe/src/include/ipxe/spi_bit.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/spi.h>
#include <ipxe/bitbash.h>
diff --git a/roms/ipxe/src/include/ipxe/stp.h b/roms/ipxe/src/include/ipxe/stp.h
new file mode 100644
index 000000000..3d85e5ba4
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/stp.h
@@ -0,0 +1,76 @@
+#ifndef _IPXE_STP_H
+#define _IPXE_STP_H
+
+/** @file
+ *
+ * Spanning Tree Protocol (STP)
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
+#include <ipxe/if_ether.h>
+
+/** "Protocol" value for STP
+ *
+ * This is the concatenated {DSAP,SSAP} value used internally by iPXE
+ * as the network-layer protocol for LLC frames.
+ */
+#define ETH_P_STP 0x4242
+
+/** A switch identifier */
+struct stp_switch {
+ /** Priotity */
+ uint16_t priority;
+ /** MAC address */
+ uint8_t mac[ETH_ALEN];
+} __attribute__ (( packed ));
+
+/** A Spanning Tree bridge protocol data unit */
+struct stp_bpdu {
+ /** LLC DSAP */
+ uint8_t dsap;
+ /** LLC SSAP */
+ uint8_t ssap;
+ /** LLC control field */
+ uint8_t control;
+ /** Protocol ID */
+ uint16_t protocol;
+ /** Protocol version */
+ uint8_t version;
+ /** Message type */
+ uint8_t type;
+ /** Flags */
+ uint8_t flags;
+ /** Root switch */
+ struct stp_switch root;
+ /** Root path cost */
+ uint32_t cost;
+ /** Sender switch */
+ struct stp_switch sender;
+ /** Port */
+ uint16_t port;
+ /** Message age */
+ uint16_t age;
+ /** Maximum age */
+ uint16_t max;
+ /** Hello time */
+ uint16_t hello;
+ /** Forward delay */
+ uint16_t delay;
+} __attribute__ (( packed ));
+
+/** Spanning Tree protocol ID */
+#define STP_PROTOCOL 0x0000
+
+/** Rapid Spanning Tree protocol version */
+#define STP_VERSION_RSTP 0x02
+
+/** Rapid Spanning Tree bridge PDU type */
+#define STP_TYPE_RSTP 0x02
+
+/** Port is forwarding */
+#define STP_FL_FORWARDING 0x20
+
+#endif /* _IPXE_STP_H */
diff --git a/roms/ipxe/src/include/ipxe/string.h b/roms/ipxe/src/include/ipxe/string.h
new file mode 100644
index 000000000..a8cbe8faa
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/string.h
@@ -0,0 +1,14 @@
+#ifndef _IPXE_STRING_H
+#define _IPXE_STRING_H
+
+/** @file
+ *
+ * String functions
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+extern unsigned int digit_value ( unsigned int digit );
+
+#endif /* _IPXE_STRING_H */
diff --git a/roms/ipxe/src/include/ipxe/syslog.h b/roms/ipxe/src/include/ipxe/syslog.h
index 131692654..138440d66 100644
--- a/roms/ipxe/src/include/ipxe/syslog.h
+++ b/roms/ipxe/src/include/ipxe/syslog.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <syslog.h>
diff --git a/roms/ipxe/src/include/ipxe/tables.h b/roms/ipxe/src/include/ipxe/tables.h
index e35ce8220..60f8efdea 100644
--- a/roms/ipxe/src/include/ipxe/tables.h
+++ b/roms/ipxe/src/include/ipxe/tables.h
@@ -1,7 +1,7 @@
#ifndef _IPXE_TABLES_H
#define _IPXE_TABLES_H
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @page ifdef_harmful #ifdef considered harmful
*
diff --git a/roms/ipxe/src/include/ipxe/tcp.h b/roms/ipxe/src/include/ipxe/tcp.h
index 9baa6391c..063ebaa4b 100644
--- a/roms/ipxe/src/include/ipxe/tcp.h
+++ b/roms/ipxe/src/include/ipxe/tcp.h
@@ -9,7 +9,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/tcpip.h>
@@ -79,6 +79,48 @@ struct tcp_window_scale_padded_option {
*/
#define TCP_RX_WINDOW_SCALE 9
+/** TCP selective acknowledgement permitted option */
+struct tcp_sack_permitted_option {
+ uint8_t kind;
+ uint8_t length;
+} __attribute__ (( packed ));
+
+/** Padded TCP selective acknowledgement permitted option (used for sending) */
+struct tcp_sack_permitted_padded_option {
+ uint8_t nop[2];
+ struct tcp_sack_permitted_option spopt;
+} __attribute__ (( packed ));
+
+/** Code for the TCP selective acknowledgement permitted option */
+#define TCP_OPTION_SACK_PERMITTED 4
+
+/** TCP selective acknowledgement option */
+struct tcp_sack_option {
+ uint8_t kind;
+ uint8_t length;
+} __attribute__ (( packed ));
+
+/** TCP selective acknowledgement block */
+struct tcp_sack_block {
+ uint32_t left;
+ uint32_t right;
+} __attribute__ (( packed ));
+
+/** Maximum number of selective acknowledgement blocks
+ *
+ * This allows for the presence of the TCP timestamp option.
+ */
+#define TCP_SACK_MAX 3
+
+/** Padded TCP selective acknowledgement option (used for sending) */
+struct tcp_sack_padded_option {
+ uint8_t nop[2];
+ struct tcp_sack_option sackopt;
+} __attribute__ (( packed ));
+
+/** Code for the TCP selective acknowledgement option */
+#define TCP_OPTION_SACK 5
+
/** TCP timestamp option */
struct tcp_timestamp_option {
uint8_t kind;
@@ -102,6 +144,8 @@ struct tcp_options {
const struct tcp_mss_option *mssopt;
/** Window scale option, if present */
const struct tcp_window_scale_option *wsopt;
+ /** SACK permitted option, if present */
+ const struct tcp_sack_permitted_option *spopt;
/** Timestamp option, if present */
const struct tcp_timestamp_option *tsopt;
};
@@ -376,6 +420,13 @@ static inline int tcp_in_window ( uint32_t seq, uint32_t start,
return ( ( seq - start ) < len );
}
+/** TCP finish wait time
+ *
+ * Currently set to one second, since we should not allow a slowly
+ * responding server to substantially delay a call to shutdown().
+ */
+#define TCP_FINISH_TIMEOUT ( 1 * TICKS_PER_SEC )
+
extern struct tcpip_protocol tcp_protocol __tcpip_protocol;
#endif /* _IPXE_TCP_H */
diff --git a/roms/ipxe/src/include/ipxe/tcpip.h b/roms/ipxe/src/include/ipxe/tcpip.h
index 200630d6b..3cfc8e3ac 100644
--- a/roms/ipxe/src/include/ipxe/tcpip.h
+++ b/roms/ipxe/src/include/ipxe/tcpip.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/socket.h>
@@ -48,6 +48,12 @@ struct sockaddr_tcpip {
uint16_t st_flags;
/** TCP/IP port */
uint16_t st_port;
+ /** Scope ID
+ *
+ * For link-local or multicast addresses, this is the network
+ * device index.
+ */
+ uint16_t st_scope_id;
/** Padding
*
* This ensures that a struct @c sockaddr_tcpip is large
@@ -57,7 +63,8 @@ struct sockaddr_tcpip {
char pad[ sizeof ( struct sockaddr ) -
( sizeof ( sa_family_t ) /* st_family */ +
sizeof ( uint16_t ) /* st_flags */ +
- sizeof ( uint16_t ) /* st_port */ ) ];
+ sizeof ( uint16_t ) /* st_port */ +
+ sizeof ( uint16_t ) /* st_scope_id */ ) ];
} __attribute__ (( packed, may_alias ));
/**
diff --git a/roms/ipxe/src/include/ipxe/test.h b/roms/ipxe/src/include/ipxe/test.h
index 028ee29fb..0b65c299c 100644
--- a/roms/ipxe/src/include/ipxe/test.h
+++ b/roms/ipxe/src/include/ipxe/test.h
@@ -1,7 +1,7 @@
#ifndef _IPXE_TEST_H
#define _IPXE_TEST_H
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/include/ipxe/tftp.h b/roms/ipxe/src/include/ipxe/tftp.h
index aecafa2ae..e3661e1ac 100644
--- a/roms/ipxe/src/include/ipxe/tftp.h
+++ b/roms/ipxe/src/include/ipxe/tftp.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
diff --git a/roms/ipxe/src/include/ipxe/time.h b/roms/ipxe/src/include/ipxe/time.h
index 673fe098a..4c5bb2a00 100644
--- a/roms/ipxe/src/include/ipxe/time.h
+++ b/roms/ipxe/src/include/ipxe/time.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <sys/time.h>
#include <ipxe/api.h>
@@ -44,6 +44,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
/* Include all architecture-independent time API headers */
#include <ipxe/null_time.h>
+#include <ipxe/efi/efi_time.h>
#include <ipxe/linux/linux_time.h>
/* Include all architecture-dependent time API headers */
diff --git a/roms/ipxe/src/include/ipxe/timer.h b/roms/ipxe/src/include/ipxe/timer.h
index d0309655d..82fbb6764 100644
--- a/roms/ipxe/src/include/ipxe/timer.h
+++ b/roms/ipxe/src/include/ipxe/timer.h
@@ -9,7 +9,7 @@
* for a monotonically increasing tick counter.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/api.h>
#include <config/timer.h>
diff --git a/roms/ipxe/src/include/ipxe/tls.h b/roms/ipxe/src/include/ipxe/tls.h
index 586da26ec..7d982c326 100644
--- a/roms/ipxe/src/include/ipxe/tls.h
+++ b/roms/ipxe/src/include/ipxe/tls.h
@@ -7,7 +7,7 @@
* Transport Layer Security Protocol
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/refcnt.h>
@@ -20,6 +20,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/x509.h>
#include <ipxe/pending.h>
#include <ipxe/iobuf.h>
+#include <ipxe/tables.h>
/** A TLS header */
struct tls_header {
@@ -85,7 +86,10 @@ struct tls_header {
/* TLS hash algorithm identifiers */
#define TLS_MD5_ALGORITHM 1
#define TLS_SHA1_ALGORITHM 2
+#define TLS_SHA224_ALGORITHM 3
#define TLS_SHA256_ALGORITHM 4
+#define TLS_SHA384_ALGORITHM 5
+#define TLS_SHA512_ALGORITHM 6
/* TLS signature algorithm identifiers */
#define TLS_RSA_ALGORITHM 1
@@ -101,6 +105,9 @@ struct tls_header {
#define TLS_MAX_FRAGMENT_LENGTH_2048 3
#define TLS_MAX_FRAGMENT_LENGTH_4096 4
+/* TLS signature algorithms extension */
+#define TLS_SIGNATURE_ALGORITHMS 13
+
/** TLS RX state machine state */
enum tls_rx_state {
TLS_RX_HEADER = 0,
@@ -131,6 +138,14 @@ struct tls_cipher_suite {
uint16_t code;
};
+/** TLS cipher suite table */
+#define TLS_CIPHER_SUITES \
+ __table ( struct tls_cipher_suite, "tls_cipher_suites" )
+
+/** Declare a TLS cipher suite */
+#define __tls_cipher_suite( pref ) \
+ __table_entry ( TLS_CIPHER_SUITES, pref )
+
/** A TLS cipher specification */
struct tls_cipherspec {
/** Cipher suite */
@@ -165,6 +180,19 @@ struct tls_signature_hash_algorithm {
struct tls_signature_hash_id code;
};
+/** TLS signature hash algorithm table
+ *
+ * Note that the default (TLSv1.1 and earlier) algorithm using
+ * MD5+SHA1 is never explicitly specified.
+ */
+#define TLS_SIG_HASH_ALGORITHMS \
+ __table ( struct tls_signature_hash_algorithm, \
+ "tls_sig_hash_algorithms" )
+
+/** Declare a TLS signature hash algorithm */
+#define __tls_sig_hash_algorithm \
+ __table_entry ( TLS_SIG_HASH_ALGORITHMS, 01 )
+
/** TLS pre-master secret */
struct tls_pre_master_secret {
/** TLS version */
diff --git a/roms/ipxe/src/include/ipxe/uaccess.h b/roms/ipxe/src/include/ipxe/uaccess.h
index 055bb2ca7..a3f78566a 100644
--- a/roms/ipxe/src/include/ipxe/uaccess.h
+++ b/roms/ipxe/src/include/ipxe/uaccess.h
@@ -19,7 +19,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <string.h>
diff --git a/roms/ipxe/src/include/ipxe/uart.h b/roms/ipxe/src/include/ipxe/uart.h
new file mode 100644
index 000000000..c63eae615
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/uart.h
@@ -0,0 +1,132 @@
+#ifndef _IPXE_UART_H
+#define _IPXE_UART_H
+
+/** @file
+ *
+ * 16550-compatible UART
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
+
+/** Transmitter holding register */
+#define UART_THR 0x00
+
+/** Receiver buffer register */
+#define UART_RBR 0x00
+
+/** Interrupt enable register */
+#define UART_IER 0x01
+
+/** FIFO control register */
+#define UART_FCR 0x02
+#define UART_FCR_FE 0x01 /**< FIFO enable */
+
+/** Line control register */
+#define UART_LCR 0x03
+#define UART_LCR_WLS0 0x01 /**< Word length select bit 0 */
+#define UART_LCR_WLS1 0x02 /**< Word length select bit 1 */
+#define UART_LCR_STB 0x04 /**< Number of stop bits */
+#define UART_LCR_PEN 0x08 /**< Parity enable */
+#define UART_LCR_EPS 0x10 /**< Even parity select */
+#define UART_LCR_DLAB 0x80 /**< Divisor latch access bit */
+
+#define UART_LCR_WORD_LEN(x) ( ( (x) - 5 ) << 0 ) /**< Word length */
+#define UART_LCR_STOP_BITS(x) ( ( (x) - 1 ) << 2 ) /**< Stop bits */
+#define UART_LCR_PARITY(x) ( ( (x) - 0 ) << 3 ) /**< Parity */
+
+/**
+ * Calculate line control register value
+ *
+ * @v word_len Word length (5-8)
+ * @v parity Parity (0=none, 1=odd, 3=even)
+ * @v stop_bits Stop bits (1-2)
+ * @ret lcr Line control register value
+ */
+#define UART_LCR_WPS( word_len, parity, stop_bits ) \
+ ( UART_LCR_WORD_LEN ( (word_len) ) | \
+ UART_LCR_PARITY ( (parity) ) | \
+ UART_LCR_STOP_BITS ( (stop_bits) ) )
+
+/** Default LCR value: 8 data bits, no parity, one stop bit */
+#define UART_LCR_8N1 UART_LCR_WPS ( 8, 0, 1 )
+
+/** Modem control register */
+#define UART_MCR 0x04
+#define UART_MCR_DTR 0x01 /**< Data terminal ready */
+#define UART_MCR_RTS 0x02 /**< Request to send */
+
+/** Line status register */
+#define UART_LSR 0x05
+#define UART_LSR_DR 0x01 /**< Data ready */
+#define UART_LSR_THRE 0x20 /**< Transmitter holding register empty */
+#define UART_LSR_TEMT 0x40 /**< Transmitter empty */
+
+/** Scratch register */
+#define UART_SCR 0x07
+
+/** Divisor latch (least significant byte) */
+#define UART_DLL 0x00
+
+/** Divisor latch (most significant byte) */
+#define UART_DLM 0x01
+
+/** Maximum baud rate */
+#define UART_MAX_BAUD 115200
+
+/** A 16550-compatible UART */
+struct uart {
+ /** I/O port base address */
+ void *base;
+ /** Baud rate divisor */
+ uint16_t divisor;
+ /** Line control register */
+ uint8_t lcr;
+};
+
+/** Symbolic names for port indexes */
+enum uart_port {
+ COM1 = 1,
+ COM2 = 2,
+ COM3 = 3,
+ COM4 = 4,
+};
+
+#include <bits/uart.h>
+
+void uart_write ( struct uart *uart, unsigned int addr, uint8_t data );
+uint8_t uart_read ( struct uart *uart, unsigned int addr );
+int uart_select ( struct uart *uart, unsigned int port );
+
+/**
+ * Check if received data is ready
+ *
+ * @v uart UART
+ * @ret ready Data is ready
+ */
+static inline int uart_data_ready ( struct uart *uart ) {
+ uint8_t lsr;
+
+ lsr = uart_read ( uart, UART_LSR );
+ return ( lsr & UART_LSR_DR );
+}
+
+/**
+ * Receive data
+ *
+ * @v uart UART
+ * @ret data Data
+ */
+static inline uint8_t uart_receive ( struct uart *uart ) {
+
+ return uart_read ( uart, UART_RBR );
+}
+
+extern void uart_transmit ( struct uart *uart, uint8_t data );
+extern void uart_flush ( struct uart *uart );
+extern int uart_exists ( struct uart *uart );
+extern int uart_init ( struct uart *uart, unsigned int baud, uint8_t lcr );
+
+#endif /* _IPXE_UART_H */
diff --git a/roms/ipxe/src/include/ipxe/udp.h b/roms/ipxe/src/include/ipxe/udp.h
index 5717ef213..7b0de4dc0 100644
--- a/roms/ipxe/src/include/ipxe/udp.h
+++ b/roms/ipxe/src/include/ipxe/udp.h
@@ -9,7 +9,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <ipxe/iobuf.h>
diff --git a/roms/ipxe/src/include/ipxe/umalloc.h b/roms/ipxe/src/include/ipxe/umalloc.h
index 4b25e182a..3892ef53b 100644
--- a/roms/ipxe/src/include/ipxe/umalloc.h
+++ b/roms/ipxe/src/include/ipxe/umalloc.h
@@ -8,7 +8,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/api.h>
#include <config/umalloc.h>
diff --git a/roms/ipxe/src/include/ipxe/uri.h b/roms/ipxe/src/include/ipxe/uri.h
index 7613d578d..00e5a24c4 100644
--- a/roms/ipxe/src/include/ipxe/uri.h
+++ b/roms/ipxe/src/include/ipxe/uri.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <stdlib.h>
@@ -203,7 +203,7 @@ extern char * resolve_path ( const char *base_path,
const char *relative_path );
extern struct uri * resolve_uri ( const struct uri *base_uri,
struct uri *relative_uri );
-extern struct uri * tftp_uri ( struct in_addr next_server,
+extern struct uri * tftp_uri ( struct in_addr next_server, unsigned int port,
const char *filename );
extern void churi ( struct uri *uri );
diff --git a/roms/ipxe/src/include/ipxe/usb.h b/roms/ipxe/src/include/ipxe/usb.h
new file mode 100644
index 000000000..ab060b8f4
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/usb.h
@@ -0,0 +1,1319 @@
+#ifndef _IPXE_USB_H
+#define _IPXE_USB_H
+
+/** @file
+ *
+ * Universal Serial Bus (USB)
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <byteswap.h>
+#include <ipxe/list.h>
+#include <ipxe/device.h>
+#include <ipxe/process.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/tables.h>
+
+/** USB protocols */
+enum usb_protocol {
+ /** USB 2.0 */
+ USB_PROTO_2_0 = 0x0200,
+ /** USB 3.0 */
+ USB_PROTO_3_0 = 0x0300,
+ /** USB 3.1 */
+ USB_PROTO_3_1 = 0x0301,
+};
+
+/** Define a USB speed
+ *
+ * @v mantissa Mantissa
+ * @v exponent Exponent (in engineering terms: 1=k, 2=M, 3=G)
+ * @ret speed USB speed
+ */
+#define USB_SPEED( mantissa, exponent ) ( (exponent << 16) | (mantissa) )
+
+/** Extract USB speed mantissa */
+#define USB_SPEED_MANTISSA(speed) ( (speed) & 0xffff )
+
+/** Extract USB speed exponent */
+#define USB_SPEED_EXPONENT(speed) ( ( (speed) >> 16 ) & 0x3 )
+
+/** USB device speeds */
+enum usb_speed {
+ /** Not connected */
+ USB_SPEED_NONE = 0,
+ /** Low speed (1.5Mbps) */
+ USB_SPEED_LOW = USB_SPEED ( 1500, 1 ),
+ /** Full speed (12Mbps) */
+ USB_SPEED_FULL = USB_SPEED ( 12, 2 ),
+ /** High speed (480Mbps) */
+ USB_SPEED_HIGH = USB_SPEED ( 480, 2 ),
+ /** Super speed (5Gbps) */
+ USB_SPEED_SUPER = USB_SPEED ( 5, 3 ),
+};
+
+/** USB packet IDs */
+enum usb_pid {
+ /** IN PID */
+ USB_PID_IN = 0x69,
+ /** OUT PID */
+ USB_PID_OUT = 0xe1,
+ /** SETUP PID */
+ USB_PID_SETUP = 0x2d,
+};
+
+/** A USB setup data packet */
+struct usb_setup_packet {
+ /** Request */
+ uint16_t request;
+ /** Value paramer */
+ uint16_t value;
+ /** Index parameter */
+ uint16_t index;
+ /** Length of data stage */
+ uint16_t len;
+} __attribute__ (( packed ));
+
+/** Data transfer is from host to device */
+#define USB_DIR_OUT ( 0 << 7 )
+
+/** Data transfer is from device to host */
+#define USB_DIR_IN ( 1 << 7 )
+
+/** Standard request type */
+#define USB_TYPE_STANDARD ( 0 << 5 )
+
+/** Class-specific request type */
+#define USB_TYPE_CLASS ( 1 << 5 )
+
+/** Vendor-specific request type */
+#define USB_TYPE_VENDOR ( 2 << 5 )
+
+/** Request recipient is the device */
+#define USB_RECIP_DEVICE ( 0 << 0 )
+
+/** Request recipient is an interface */
+#define USB_RECIP_INTERFACE ( 1 << 0 )
+
+/** Request recipient is an endpoint */
+#define USB_RECIP_ENDPOINT ( 2 << 0 )
+
+/** Construct USB request type */
+#define USB_REQUEST_TYPE(type) ( (type) << 8 )
+
+/** Get status */
+#define USB_GET_STATUS ( USB_DIR_IN | USB_REQUEST_TYPE ( 0 ) )
+
+/** Clear feature */
+#define USB_CLEAR_FEATURE ( USB_DIR_OUT | USB_REQUEST_TYPE ( 1 ) )
+
+/** Set feature */
+#define USB_SET_FEATURE ( USB_DIR_OUT | USB_REQUEST_TYPE ( 3 ) )
+
+/** Set address */
+#define USB_SET_ADDRESS ( USB_DIR_OUT | USB_REQUEST_TYPE ( 5 ) )
+
+/** Get descriptor */
+#define USB_GET_DESCRIPTOR ( USB_DIR_IN | USB_REQUEST_TYPE ( 6 ) )
+
+/** Set descriptor */
+#define USB_SET_DESCRIPTOR ( USB_DIR_OUT | USB_REQUEST_TYPE ( 7 ) )
+
+/** Get configuration */
+#define USB_GET_CONFIGURATION ( USB_DIR_IN | USB_REQUEST_TYPE ( 8 ) )
+
+/** Set configuration */
+#define USB_SET_CONFIGURATION ( USB_DIR_OUT | USB_REQUEST_TYPE ( 9 ) )
+
+/** Get interface */
+#define USB_GET_INTERFACE \
+ ( USB_DIR_IN | USB_RECIP_INTERFACE | USB_REQUEST_TYPE ( 10 ) )
+
+/** Set interface */
+#define USB_SET_INTERFACE \
+ ( USB_DIR_OUT | USB_RECIP_INTERFACE | USB_REQUEST_TYPE ( 11 ) )
+
+/** Endpoint halt feature */
+#define USB_ENDPOINT_HALT 0
+
+/** A USB class code tuple */
+struct usb_class {
+ /** Class code */
+ uint8_t class;
+ /** Subclass code */
+ uint8_t subclass;
+ /** Protocol code */
+ uint8_t protocol;
+} __attribute__ (( packed ));
+
+/** Class code for USB hubs */
+#define USB_CLASS_HUB 9
+
+/** A USB descriptor header */
+struct usb_descriptor_header {
+ /** Length of descriptor */
+ uint8_t len;
+ /** Descriptor type */
+ uint8_t type;
+} __attribute__ (( packed ));
+
+/** A USB device descriptor */
+struct usb_device_descriptor {
+ /** Descriptor header */
+ struct usb_descriptor_header header;
+ /** USB specification release number in BCD */
+ uint16_t protocol;
+ /** Device class */
+ struct usb_class class;
+ /** Maximum packet size for endpoint zero */
+ uint8_t mtu;
+ /** Vendor ID */
+ uint16_t vendor;
+ /** Product ID */
+ uint16_t product;
+ /** Device release number in BCD */
+ uint16_t release;
+ /** Manufacturer string */
+ uint8_t manufacturer;
+ /** Product string */
+ uint8_t name;
+ /** Serial number string */
+ uint8_t serial;
+ /** Number of possible configurations */
+ uint8_t configurations;
+} __attribute__ (( packed ));
+
+/** A USB device descriptor */
+#define USB_DEVICE_DESCRIPTOR 1
+
+/** A USB configuration descriptor */
+struct usb_configuration_descriptor {
+ /** Descriptor header */
+ struct usb_descriptor_header header;
+ /** Total length */
+ uint16_t len;
+ /** Number of interfaces */
+ uint8_t interfaces;
+ /** Configuration value */
+ uint8_t config;
+ /** Configuration string */
+ uint8_t name;
+ /** Attributes */
+ uint8_t attributes;
+ /** Maximum power consumption */
+ uint8_t power;
+} __attribute__ (( packed ));
+
+/** A USB configuration descriptor */
+#define USB_CONFIGURATION_DESCRIPTOR 2
+
+/** A USB string descriptor */
+struct usb_string_descriptor {
+ /** Descriptor header */
+ struct usb_descriptor_header header;
+ /** String */
+ char string[0];
+} __attribute__ (( packed ));
+
+/** A USB string descriptor */
+#define USB_STRING_DESCRIPTOR 3
+
+/** A USB interface descriptor */
+struct usb_interface_descriptor {
+ /** Descriptor header */
+ struct usb_descriptor_header header;
+ /** Interface number */
+ uint8_t interface;
+ /** Alternate setting */
+ uint8_t alternate;
+ /** Number of endpoints */
+ uint8_t endpoints;
+ /** Interface class */
+ struct usb_class class;
+ /** Interface name */
+ uint8_t name;
+} __attribute__ (( packed ));
+
+/** A USB interface descriptor */
+#define USB_INTERFACE_DESCRIPTOR 4
+
+/** A USB endpoint descriptor */
+struct usb_endpoint_descriptor {
+ /** Descriptor header */
+ struct usb_descriptor_header header;
+ /** Endpoint address */
+ uint8_t endpoint;
+ /** Attributes */
+ uint8_t attributes;
+ /** Maximum packet size and burst size */
+ uint16_t sizes;
+ /** Polling interval */
+ uint8_t interval;
+} __attribute__ (( packed ));
+
+/** A USB endpoint descriptor */
+#define USB_ENDPOINT_DESCRIPTOR 5
+
+/** Endpoint attribute transfer type mask */
+#define USB_ENDPOINT_ATTR_TYPE_MASK 0x03
+
+/** Endpoint periodic type */
+#define USB_ENDPOINT_ATTR_PERIODIC 0x01
+
+/** Control endpoint transfer type */
+#define USB_ENDPOINT_ATTR_CONTROL 0x00
+
+/** Bulk endpoint transfer type */
+#define USB_ENDPOINT_ATTR_BULK 0x02
+
+/** Interrupt endpoint transfer type */
+#define USB_ENDPOINT_ATTR_INTERRUPT 0x03
+
+/** Bulk OUT endpoint (internal) type */
+#define USB_BULK_OUT ( USB_ENDPOINT_ATTR_BULK | USB_DIR_OUT )
+
+/** Bulk IN endpoint (internal) type */
+#define USB_BULK_IN ( USB_ENDPOINT_ATTR_BULK | USB_DIR_IN )
+
+/** Interrupt IN endpoint (internal) type */
+#define USB_INTERRUPT_IN ( USB_ENDPOINT_ATTR_INTERRUPT | USB_DIR_IN )
+
+/** Interrupt OUT endpoint (internal) type */
+#define USB_INTERRUPT_OUT ( USB_ENDPOINT_ATTR_INTERRUPT | USB_DIR_OUT )
+
+/** USB endpoint MTU */
+#define USB_ENDPOINT_MTU(sizes) ( ( (sizes) >> 0 ) & 0x07ff )
+
+/** USB endpoint maximum burst size */
+#define USB_ENDPOINT_BURST(sizes) ( ( (sizes) >> 11 ) & 0x0003 )
+
+/** A USB endpoint companion descriptor */
+struct usb_endpoint_companion_descriptor {
+ /** Descriptor header */
+ struct usb_descriptor_header header;
+ /** Maximum burst size */
+ uint8_t burst;
+ /** Extended attributes */
+ uint8_t extended;
+ /** Number of bytes per service interval */
+ uint16_t periodic;
+} __attribute__ (( packed ));
+
+/** A USB endpoint companion descriptor */
+#define USB_ENDPOINT_COMPANION_DESCRIPTOR 48
+
+/** A USB interface association descriptor */
+struct usb_interface_association_descriptor {
+ /** Descriptor header */
+ struct usb_descriptor_header header;
+ /** First interface number */
+ uint8_t first;
+ /** Interface count */
+ uint8_t count;
+ /** Association class */
+ struct usb_class class;
+ /** Association name */
+ uint8_t name;
+} __attribute__ (( packed ));
+
+/** A USB interface association descriptor */
+#define USB_INTERFACE_ASSOCIATION_DESCRIPTOR 11
+
+/** A class-specific interface descriptor */
+#define USB_CS_INTERFACE_DESCRIPTOR 36
+
+/** A class-specific endpoint descriptor */
+#define USB_CS_ENDPOINT_DESCRIPTOR 37
+
+/**
+ * Get next USB descriptor
+ *
+ * @v desc USB descriptor header
+ * @ret next Next USB descriptor header
+ */
+static inline __attribute__ (( always_inline )) struct usb_descriptor_header *
+usb_next_descriptor ( struct usb_descriptor_header *desc ) {
+
+ return ( ( ( void * ) desc ) + desc->len );
+}
+
+/**
+ * Check that descriptor lies within a configuration descriptor
+ *
+ * @v config Configuration descriptor
+ * @v desc Descriptor header
+ * @v is_within Descriptor is within the configuration descriptor
+ */
+static inline __attribute__ (( always_inline )) int
+usb_is_within_config ( struct usb_configuration_descriptor *config,
+ struct usb_descriptor_header *desc ) {
+ struct usb_descriptor_header *end =
+ ( ( ( void * ) config ) + le16_to_cpu ( config->len ) );
+
+ /* Check that descriptor starts within the configuration
+ * descriptor, and that the length does not exceed the
+ * configuration descriptor. This relies on the fact that
+ * usb_next_descriptor() needs to access only the first byte
+ * of the descriptor in order to determine the length.
+ */
+ return ( ( desc < end ) && ( usb_next_descriptor ( desc ) <= end ) );
+}
+
+/** Iterate over all configuration descriptors */
+#define for_each_config_descriptor( desc, config ) \
+ for ( desc = container_of ( &(config)->header, \
+ typeof ( *desc ), header ) ; \
+ usb_is_within_config ( (config), &desc->header ) ; \
+ desc = container_of ( usb_next_descriptor ( &desc->header ), \
+ typeof ( *desc ), header ) )
+
+/** Iterate over all configuration descriptors within an interface descriptor */
+#define for_each_interface_descriptor( desc, config, interface ) \
+ for ( desc = container_of ( usb_next_descriptor ( &(interface)-> \
+ header ), \
+ typeof ( *desc ), header ) ; \
+ ( usb_is_within_config ( (config), &desc->header ) && \
+ ( desc->header.type != USB_INTERFACE_DESCRIPTOR ) ) ; \
+ desc = container_of ( usb_next_descriptor ( &desc->header ), \
+ typeof ( *desc ), header ) )
+
+/** A USB endpoint */
+struct usb_endpoint {
+ /** USB device */
+ struct usb_device *usb;
+ /** Endpoint address */
+ unsigned int address;
+ /** Attributes */
+ unsigned int attributes;
+ /** Maximum transfer size */
+ size_t mtu;
+ /** Maximum burst size */
+ unsigned int burst;
+ /** Interval (in microframes) */
+ unsigned int interval;
+
+ /** Endpoint is open */
+ int open;
+ /** Buffer fill level */
+ unsigned int fill;
+
+ /** List of halted endpoints */
+ struct list_head halted;
+
+ /** Host controller operations */
+ struct usb_endpoint_host_operations *host;
+ /** Host controller private data */
+ void *priv;
+ /** Driver operations */
+ struct usb_endpoint_driver_operations *driver;
+
+ /** Recycled I/O buffer list */
+ struct list_head recycled;
+ /** Refill buffer length */
+ size_t len;
+ /** Maximum fill level */
+ unsigned int max;
+};
+
+/** USB endpoint host controller operations */
+struct usb_endpoint_host_operations {
+ /** Open endpoint
+ *
+ * @v ep USB endpoint
+ * @ret rc Return status code
+ */
+ int ( * open ) ( struct usb_endpoint *ep );
+ /** Close endpoint
+ *
+ * @v ep USB endpoint
+ */
+ void ( * close ) ( struct usb_endpoint *ep );
+ /**
+ * Reset endpoint
+ *
+ * @v ep USB endpoint
+ * @ret rc Return status code
+ */
+ int ( * reset ) ( struct usb_endpoint *ep );
+ /** Update MTU
+ *
+ * @v ep USB endpoint
+ * @ret rc Return status code
+ */
+ int ( * mtu ) ( struct usb_endpoint *ep );
+ /** Enqueue message transfer
+ *
+ * @v ep USB endpoint
+ * @v iobuf I/O buffer
+ * @ret rc Return status code
+ */
+ int ( * message ) ( struct usb_endpoint *ep,
+ struct io_buffer *iobuf );
+ /** Enqueue stream transfer
+ *
+ * @v ep USB endpoint
+ * @v iobuf I/O buffer
+ * @v terminate Terminate using a short packet
+ * @ret rc Return status code
+ */
+ int ( * stream ) ( struct usb_endpoint *ep, struct io_buffer *iobuf,
+ int terminate );
+};
+
+/** USB endpoint driver operations */
+struct usb_endpoint_driver_operations {
+ /** Complete transfer
+ *
+ * @v ep USB endpoint
+ * @v iobuf I/O buffer
+ * @v rc Completion status code
+ */
+ void ( * complete ) ( struct usb_endpoint *ep,
+ struct io_buffer *iobuf, int rc );
+};
+
+/** Control endpoint address */
+#define USB_EP0_ADDRESS 0x00
+
+/** Control endpoint attributes */
+#define USB_EP0_ATTRIBUTES 0x00
+
+/** Calculate default MTU based on device speed
+ *
+ * @v speed Device speed
+ * @ret mtu Default MTU
+ */
+#define USB_EP0_DEFAULT_MTU(speed) \
+ ( ( (speed) >= USB_SPEED_SUPER ) ? 512 : \
+ ( ( (speed) >= USB_SPEED_FULL ) ? 64 : 8 ) )
+
+/** Control endpoint maximum burst size */
+#define USB_EP0_BURST 0
+
+/** Control endpoint interval */
+#define USB_EP0_INTERVAL 0
+
+/** Maximum endpoint number */
+#define USB_ENDPOINT_MAX 0x0f
+
+/** Endpoint direction is in */
+#define USB_ENDPOINT_IN 0x80
+
+/** Construct endpoint index from endpoint address */
+#define USB_ENDPOINT_IDX(address) \
+ ( ( (address) & USB_ENDPOINT_MAX ) | \
+ ( ( (address) & USB_ENDPOINT_IN ) >> 3 ) )
+
+/**
+ * Initialise USB endpoint
+ *
+ * @v ep USB endpoint
+ * @v usb USB device
+ * @v driver Driver operations
+ */
+static inline __attribute__ (( always_inline )) void
+usb_endpoint_init ( struct usb_endpoint *ep, struct usb_device *usb,
+ struct usb_endpoint_driver_operations *driver ) {
+
+ ep->usb = usb;
+ ep->driver = driver;
+}
+
+/**
+ * Describe USB endpoint
+ *
+ * @v ep USB endpoint
+ * @v address Endpoint address
+ * @v attributes Attributes
+ * @v mtu Maximum packet size
+ * @v burst Maximum burst size
+ * @v interval Interval (in microframes)
+ */
+static inline __attribute__ (( always_inline )) void
+usb_endpoint_describe ( struct usb_endpoint *ep, unsigned int address,
+ unsigned int attributes, size_t mtu,
+ unsigned int burst, unsigned int interval ) {
+
+ ep->address = address;
+ ep->attributes = attributes;
+ ep->mtu = mtu;
+ ep->burst = burst;
+ ep->interval = interval;
+}
+
+/**
+ * Set USB endpoint host controller private data
+ *
+ * @v ep USB endpoint
+ * @v priv Host controller private data
+ */
+static inline __attribute__ (( always_inline )) void
+usb_endpoint_set_hostdata ( struct usb_endpoint *ep, void *priv ) {
+ ep->priv = priv;
+}
+
+/**
+ * Get USB endpoint host controller private data
+ *
+ * @v ep USB endpoint
+ * @ret priv Host controller private data
+ */
+static inline __attribute__ (( always_inline )) void *
+usb_endpoint_get_hostdata ( struct usb_endpoint *ep ) {
+ return ep->priv;
+}
+
+extern const char * usb_endpoint_name ( struct usb_endpoint *ep );
+extern int
+usb_endpoint_described ( struct usb_endpoint *ep,
+ struct usb_configuration_descriptor *config,
+ struct usb_interface_descriptor *interface,
+ unsigned int type, unsigned int index );
+extern int usb_endpoint_open ( struct usb_endpoint *ep );
+extern void usb_endpoint_close ( struct usb_endpoint *ep );
+extern int usb_message ( struct usb_endpoint *ep, unsigned int request,
+ unsigned int value, unsigned int index,
+ struct io_buffer *iobuf );
+extern int usb_stream ( struct usb_endpoint *ep, struct io_buffer *iobuf,
+ int terminate );
+extern void usb_complete_err ( struct usb_endpoint *ep,
+ struct io_buffer *iobuf, int rc );
+
+/**
+ * Initialise USB endpoint refill
+ *
+ * @v ep USB endpoint
+ * @v len Refill buffer length (or zero to use endpoint's MTU)
+ * @v max Maximum fill level
+ */
+static inline __attribute__ (( always_inline )) void
+usb_refill_init ( struct usb_endpoint *ep, size_t len, unsigned int max ) {
+
+ INIT_LIST_HEAD ( &ep->recycled );
+ ep->len = len;
+ ep->max = max;
+}
+
+/**
+ * Recycle I/O buffer
+ *
+ * @v ep USB endpoint
+ * @v iobuf I/O buffer
+ */
+static inline __attribute__ (( always_inline )) void
+usb_recycle ( struct usb_endpoint *ep, struct io_buffer *iobuf ) {
+
+ list_add_tail ( &iobuf->list, &ep->recycled );
+}
+
+extern int usb_prefill ( struct usb_endpoint *ep );
+extern int usb_refill ( struct usb_endpoint *ep );
+extern void usb_flush ( struct usb_endpoint *ep );
+
+/**
+ * A USB function
+ *
+ * A USB function represents an association of interfaces within a USB
+ * device.
+ */
+struct usb_function {
+ /** Name */
+ const char *name;
+ /** USB device */
+ struct usb_device *usb;
+ /** Class */
+ struct usb_class class;
+ /** Number of interfaces */
+ unsigned int count;
+ /** Generic device */
+ struct device dev;
+ /** List of functions within this USB device */
+ struct list_head list;
+
+ /** Driver */
+ struct usb_driver *driver;
+ /** Driver private data */
+ void *priv;
+
+ /** List of interface numbers
+ *
+ * This must be the last field within the structure.
+ */
+ uint8_t interface[0];
+};
+
+/**
+ * Set USB function driver private data
+ *
+ * @v func USB function
+ * @v priv Driver private data
+ */
+static inline __attribute__ (( always_inline )) void
+usb_func_set_drvdata ( struct usb_function *func, void *priv ) {
+ func->priv = priv;
+}
+
+/**
+ * Get USB function driver private data
+ *
+ * @v function USB function
+ * @ret priv Driver private data
+ */
+static inline __attribute__ (( always_inline )) void *
+usb_func_get_drvdata ( struct usb_function *func ) {
+ return func->priv;
+}
+
+/** A USB device */
+struct usb_device {
+ /** Name */
+ char name[32];
+ /** USB port */
+ struct usb_port *port;
+ /** List of devices on this bus */
+ struct list_head list;
+ /** Device address, if assigned */
+ unsigned int address;
+ /** Device descriptor */
+ struct usb_device_descriptor device;
+ /** List of functions */
+ struct list_head functions;
+
+ /** Host controller operations */
+ struct usb_device_host_operations *host;
+ /** Host controller private data */
+ void *priv;
+
+ /** Endpoint list */
+ struct usb_endpoint *ep[32];
+
+ /** Control endpoint */
+ struct usb_endpoint control;
+ /** Completed control transfers */
+ struct list_head complete;
+};
+
+/** USB device host controller operations */
+struct usb_device_host_operations {
+ /** Open device
+ *
+ * @v usb USB device
+ * @ret rc Return status code
+ */
+ int ( * open ) ( struct usb_device *usb );
+ /** Close device
+ *
+ * @v usb USB device
+ */
+ void ( * close ) ( struct usb_device *usb );
+ /** Assign device address
+ *
+ * @v usb USB device
+ * @ret rc Return status code
+ */
+ int ( * address ) ( struct usb_device *usb );
+};
+
+/**
+ * Set USB device host controller private data
+ *
+ * @v usb USB device
+ * @v priv Host controller private data
+ */
+static inline __attribute__ (( always_inline )) void
+usb_set_hostdata ( struct usb_device *usb, void *priv ) {
+ usb->priv = priv;
+}
+
+/**
+ * Get USB device host controller private data
+ *
+ * @v usb USB device
+ * @ret priv Host controller private data
+ */
+static inline __attribute__ (( always_inline )) void *
+usb_get_hostdata ( struct usb_device *usb ) {
+ return usb->priv;
+}
+
+/**
+ * Get USB endpoint
+ *
+ * @v usb USB device
+ * @v address Endpoint address
+ * @ret ep USB endpoint, or NULL if not opened
+ */
+static inline struct usb_endpoint * usb_endpoint ( struct usb_device *usb,
+ unsigned int address ) {
+
+ return usb->ep[ USB_ENDPOINT_IDX ( address ) ];
+}
+
+/** A USB port */
+struct usb_port {
+ /** USB hub */
+ struct usb_hub *hub;
+ /** Port address */
+ unsigned int address;
+ /** Port protocol */
+ unsigned int protocol;
+ /** Port speed */
+ unsigned int speed;
+ /** Port disconnection has been detected
+ *
+ * This should be set whenever the underlying hardware reports
+ * a connection status change.
+ */
+ int disconnected;
+ /** Port has an attached device */
+ int attached;
+ /** Currently attached device (if in use)
+ *
+ * Note that this field will be NULL if the attached device
+ * has been freed (e.g. because there were no drivers found).
+ */
+ struct usb_device *usb;
+ /** List of changed ports */
+ struct list_head changed;
+};
+
+/** A USB hub */
+struct usb_hub {
+ /** Name */
+ const char *name;
+ /** USB bus */
+ struct usb_bus *bus;
+ /** Underlying USB device, if any */
+ struct usb_device *usb;
+ /** Hub protocol */
+ unsigned int protocol;
+ /** Number of ports */
+ unsigned int ports;
+
+ /** List of hubs */
+ struct list_head list;
+
+ /** Host controller operations */
+ struct usb_hub_host_operations *host;
+ /** Driver operations */
+ struct usb_hub_driver_operations *driver;
+ /** Driver private data */
+ void *priv;
+
+ /** Port list
+ *
+ * This must be the last field within the structure.
+ */
+ struct usb_port port[0];
+};
+
+/** USB hub host controller operations */
+struct usb_hub_host_operations {
+ /** Open hub
+ *
+ * @v hub USB hub
+ * @ret rc Return status code
+ */
+ int ( * open ) ( struct usb_hub *hub );
+ /** Close hub
+ *
+ * @v hub USB hub
+ */
+ void ( * close ) ( struct usb_hub *hub );
+};
+
+/** USB hub driver operations */
+struct usb_hub_driver_operations {
+ /** Open hub
+ *
+ * @v hub USB hub
+ * @ret rc Return status code
+ */
+ int ( * open ) ( struct usb_hub *hub );
+ /** Close hub
+ *
+ * @v hub USB hub
+ */
+ void ( * close ) ( struct usb_hub *hub );
+ /** Enable port
+ *
+ * @v hub USB hub
+ * @v port USB port
+ * @ret rc Return status code
+ */
+ int ( * enable ) ( struct usb_hub *hub, struct usb_port *port );
+ /** Disable port
+ *
+ * @v hub USB hub
+ * @v port USB port
+ * @ret rc Return status code
+ */
+ int ( * disable ) ( struct usb_hub *hub, struct usb_port *port );
+ /** Update port speed
+ *
+ * @v hub USB hub
+ * @v port USB port
+ * @ret rc Return status code
+ */
+ int ( * speed ) ( struct usb_hub *hub, struct usb_port *port );
+ /** Clear transaction translator buffer
+ *
+ * @v hub USB hub
+ * @v port USB port
+ * @v ep USB endpoint
+ * @ret rc Return status code
+ */
+ int ( * clear_tt ) ( struct usb_hub *hub, struct usb_port *port,
+ struct usb_endpoint *ep );
+};
+
+/**
+ * Set USB hub driver private data
+ *
+ * @v hub USB hub
+ * @v priv Driver private data
+ */
+static inline __attribute__ (( always_inline )) void
+usb_hub_set_drvdata ( struct usb_hub *hub, void *priv ) {
+ hub->priv = priv;
+}
+
+/**
+ * Get USB hub driver private data
+ *
+ * @v hub USB hub
+ * @ret priv Driver private data
+ */
+static inline __attribute__ (( always_inline )) void *
+usb_hub_get_drvdata ( struct usb_hub *hub ) {
+ return hub->priv;
+}
+
+/**
+ * Get USB port
+ *
+ * @v hub USB hub
+ * @v address Port address
+ * @ret port USB port
+ */
+static inline __attribute__ (( always_inline )) struct usb_port *
+usb_port ( struct usb_hub *hub, unsigned int address ) {
+
+ return &hub->port[ address - 1 ];
+}
+
+/** A USB bus */
+struct usb_bus {
+ /** Name */
+ const char *name;
+ /** Underlying hardware device */
+ struct device *dev;
+ /** Host controller operations set */
+ struct usb_host_operations *op;
+
+ /** Largest transfer allowed on the bus */
+ size_t mtu;
+ /** Address in-use mask
+ *
+ * This is used only by buses which perform manual address
+ * assignment. USB allows for addresses in the range [1,127].
+ * We use a simple bitmask which restricts us to the range
+ * [1,64]; this is unlikely to be a problem in practice. For
+ * comparison: controllers which perform autonomous address
+ * assignment (such as xHCI) typically allow for only 32
+ * devices per bus anyway.
+ */
+ unsigned long long addresses;
+
+ /** Root hub */
+ struct usb_hub *hub;
+
+ /** List of USB buses */
+ struct list_head list;
+ /** List of devices */
+ struct list_head devices;
+ /** List of hubs */
+ struct list_head hubs;
+
+ /** Host controller operations */
+ struct usb_bus_host_operations *host;
+ /** Host controller private data */
+ void *priv;
+};
+
+/** USB bus host controller operations */
+struct usb_bus_host_operations {
+ /** Open bus
+ *
+ * @v bus USB bus
+ * @ret rc Return status code
+ */
+ int ( * open ) ( struct usb_bus *bus );
+ /** Close bus
+ *
+ * @v bus USB bus
+ */
+ void ( * close ) ( struct usb_bus *bus );
+ /** Poll bus
+ *
+ * @v bus USB bus
+ */
+ void ( * poll ) ( struct usb_bus *bus );
+};
+
+/** USB host controller operations */
+struct usb_host_operations {
+ /** Endpoint operations */
+ struct usb_endpoint_host_operations endpoint;
+ /** Device operations */
+ struct usb_device_host_operations device;
+ /** Bus operations */
+ struct usb_bus_host_operations bus;
+ /** Hub operations */
+ struct usb_hub_host_operations hub;
+ /** Root hub operations */
+ struct usb_hub_driver_operations root;
+};
+
+/**
+ * Set USB bus host controller private data
+ *
+ * @v bus USB bus
+ * @v priv Host controller private data
+ */
+static inline __attribute__ (( always_inline )) void
+usb_bus_set_hostdata ( struct usb_bus *bus, void *priv ) {
+ bus->priv = priv;
+}
+
+/**
+ * Get USB bus host controller private data
+ *
+ * @v bus USB bus
+ * @ret priv Host controller private data
+ */
+static inline __attribute__ (( always_inline )) void *
+usb_bus_get_hostdata ( struct usb_bus *bus ) {
+ return bus->priv;
+}
+
+/**
+ * Poll USB bus
+ *
+ * @v bus USB bus
+ */
+static inline __attribute__ (( always_inline )) void
+usb_poll ( struct usb_bus *bus ) {
+ bus->host->poll ( bus );
+}
+
+/** Iterate over all USB buses */
+#define for_each_usb_bus( bus ) \
+ list_for_each_entry ( (bus), &usb_buses, list )
+
+/**
+ * Complete transfer (without error)
+ *
+ * @v ep USB endpoint
+ * @v iobuf I/O buffer
+ */
+static inline __attribute__ (( always_inline )) void
+usb_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf ) {
+ usb_complete_err ( ep, iobuf, 0 );
+}
+
+extern int usb_control ( struct usb_device *usb, unsigned int request,
+ unsigned int value, unsigned int index, void *data,
+ size_t len );
+extern int usb_get_string_descriptor ( struct usb_device *usb,
+ unsigned int index,
+ unsigned int language,
+ char *buf, size_t len );
+
+/**
+ * Get status
+ *
+ * @v usb USB device
+ * @v type Request type
+ * @v index Target index
+ * @v data Status to fill in
+ * @v len Length of status descriptor
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+usb_get_status ( struct usb_device *usb, unsigned int type, unsigned int index,
+ void *data, size_t len ) {
+
+ return usb_control ( usb, ( USB_GET_STATUS | type ), 0, index,
+ data, len );
+}
+
+/**
+ * Clear feature
+ *
+ * @v usb USB device
+ * @v type Request type
+ * @v feature Feature selector
+ * @v index Target index
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+usb_clear_feature ( struct usb_device *usb, unsigned int type,
+ unsigned int feature, unsigned int index ) {
+
+ return usb_control ( usb, ( USB_CLEAR_FEATURE | type ),
+ feature, index, NULL, 0 );
+}
+
+/**
+ * Set feature
+ *
+ * @v usb USB device
+ * @v type Request type
+ * @v feature Feature selector
+ * @v index Target index
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+usb_set_feature ( struct usb_device *usb, unsigned int type,
+ unsigned int feature, unsigned int index ) {
+
+ return usb_control ( usb, ( USB_SET_FEATURE | type ),
+ feature, index, NULL, 0 );
+}
+
+/**
+ * Set address
+ *
+ * @v usb USB device
+ * @v address Device address
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+usb_set_address ( struct usb_device *usb, unsigned int address ) {
+
+ return usb_control ( usb, USB_SET_ADDRESS, address, 0, NULL, 0 );
+}
+
+/**
+ * Get USB descriptor
+ *
+ * @v usb USB device
+ * @v type Request type
+ * @v desc Descriptor type
+ * @v index Descriptor index
+ * @v language Language ID (for string descriptors)
+ * @v data Descriptor to fill in
+ * @v len Maximum length of descriptor
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+usb_get_descriptor ( struct usb_device *usb, unsigned int type,
+ unsigned int desc, unsigned int index,
+ unsigned int language, struct usb_descriptor_header *data,
+ size_t len ) {
+
+ return usb_control ( usb, ( USB_GET_DESCRIPTOR | type ),
+ ( ( desc << 8 ) | index ), language, data, len );
+}
+
+/**
+ * Get first part of USB device descriptor (up to and including MTU)
+ *
+ * @v usb USB device
+ * @v data Device descriptor to (partially) fill in
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+usb_get_mtu ( struct usb_device *usb, struct usb_device_descriptor *data ) {
+
+ return usb_get_descriptor ( usb, 0, USB_DEVICE_DESCRIPTOR, 0, 0,
+ &data->header,
+ ( offsetof ( typeof ( *data ), mtu ) +
+ sizeof ( data->mtu ) ) );
+}
+
+/**
+ * Get USB device descriptor
+ *
+ * @v usb USB device
+ * @v data Device descriptor to fill in
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+usb_get_device_descriptor ( struct usb_device *usb,
+ struct usb_device_descriptor *data ) {
+
+ return usb_get_descriptor ( usb, 0, USB_DEVICE_DESCRIPTOR, 0, 0,
+ &data->header, sizeof ( *data ) );
+}
+
+/**
+ * Get USB configuration descriptor
+ *
+ * @v usb USB device
+ * @v index Configuration index
+ * @v data Configuration descriptor to fill in
+ * @ret rc Return status code
+ */
+static inline __attribute (( always_inline )) int
+usb_get_config_descriptor ( struct usb_device *usb, unsigned int index,
+ struct usb_configuration_descriptor *data,
+ size_t len ) {
+
+ return usb_get_descriptor ( usb, 0, USB_CONFIGURATION_DESCRIPTOR, index,
+ 0, &data->header, len );
+}
+
+/**
+ * Set USB configuration
+ *
+ * @v usb USB device
+ * @v index Configuration index
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+usb_set_configuration ( struct usb_device *usb, unsigned int index ) {
+
+ return usb_control ( usb, USB_SET_CONFIGURATION, index, 0, NULL, 0 );
+}
+
+/**
+ * Set USB interface alternate setting
+ *
+ * @v usb USB device
+ * @v interface Interface number
+ * @v alternate Alternate setting
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+usb_set_interface ( struct usb_device *usb, unsigned int interface,
+ unsigned int alternate ) {
+
+ return usb_control ( usb, USB_SET_INTERFACE, alternate, interface,
+ NULL, 0 );
+}
+
+extern struct list_head usb_buses;
+
+extern struct usb_interface_descriptor *
+usb_interface_descriptor ( struct usb_configuration_descriptor *config,
+ unsigned int interface, unsigned int alternate );
+extern struct usb_endpoint_descriptor *
+usb_endpoint_descriptor ( struct usb_configuration_descriptor *config,
+ struct usb_interface_descriptor *interface,
+ unsigned int type, unsigned int index );
+extern struct usb_endpoint_companion_descriptor *
+usb_endpoint_companion_descriptor ( struct usb_configuration_descriptor *config,
+ struct usb_endpoint_descriptor *desc );
+
+extern struct usb_hub * alloc_usb_hub ( struct usb_bus *bus,
+ struct usb_device *usb,
+ unsigned int ports,
+ struct usb_hub_driver_operations *op );
+extern int register_usb_hub ( struct usb_hub *hub );
+extern void unregister_usb_hub ( struct usb_hub *hub );
+extern void free_usb_hub ( struct usb_hub *hub );
+
+extern void usb_port_changed ( struct usb_port *port );
+
+extern struct usb_bus * alloc_usb_bus ( struct device *dev,
+ unsigned int ports, size_t mtu,
+ struct usb_host_operations *op );
+extern int register_usb_bus ( struct usb_bus *bus );
+extern void unregister_usb_bus ( struct usb_bus *bus );
+extern void free_usb_bus ( struct usb_bus *bus );
+extern struct usb_bus * find_usb_bus_by_location ( unsigned int bus_type,
+ unsigned int location );
+
+extern int usb_alloc_address ( struct usb_bus *bus );
+extern void usb_free_address ( struct usb_bus *bus, unsigned int address );
+extern unsigned int usb_route_string ( struct usb_device *usb );
+extern unsigned int usb_depth ( struct usb_device *usb );
+extern struct usb_port * usb_root_hub_port ( struct usb_device *usb );
+extern struct usb_port * usb_transaction_translator ( struct usb_device *usb );
+
+/** Minimum reset time
+ *
+ * Section 7.1.7.5 of the USB2 specification states that root hub
+ * ports should assert reset signalling for at least 50ms.
+ */
+#define USB_RESET_DELAY_MS 50
+
+/** Reset recovery time
+ *
+ * Section 9.2.6.2 of the USB2 specification states that the
+ * "recovery" interval after a port reset is 10ms.
+ */
+#define USB_RESET_RECOVER_DELAY_MS 10
+
+/** Maximum time to wait for a control transaction to complete
+ *
+ * Section 9.2.6.1 of the USB2 specification states that the upper
+ * limit for commands to be processed is 5 seconds.
+ */
+#define USB_CONTROL_MAX_WAIT_MS 5000
+
+/** Set address recovery time
+ *
+ * Section 9.2.6.3 of the USB2 specification states that devices are
+ * allowed a 2ms recovery interval after receiving a new address.
+ */
+#define USB_SET_ADDRESS_RECOVER_DELAY_MS 2
+
+/** Time to wait for ports to stabilise
+ *
+ * Section 7.1.7.3 of the USB specification states that we must allow
+ * 100ms for devices to signal attachment, and an additional 100ms for
+ * connection debouncing. (This delay is parallelised across all
+ * ports on a hub; we do not delay separately for each port.)
+ */
+#define USB_PORT_DELAY_MS 200
+
+/** A USB device ID */
+struct usb_device_id {
+ /** Name */
+ const char *name;
+ /** Vendor ID */
+ uint16_t vendor;
+ /** Product ID */
+ uint16_t product;
+ /** Class */
+ struct usb_class class;
+};
+
+/** Match-anything ID */
+#define USB_ANY_ID 0xffff
+
+/** A USB driver */
+struct usb_driver {
+ /** USB ID table */
+ struct usb_device_id *ids;
+ /** Number of entries in ID table */
+ unsigned int id_count;
+ /**
+ * Probe device
+ *
+ * @v func USB function
+ * @v config Configuration descriptor
+ * @ret rc Return status code
+ */
+ int ( * probe ) ( struct usb_function *func,
+ struct usb_configuration_descriptor *config );
+ /**
+ * Remove device
+ *
+ * @v func USB function
+ */
+ void ( * remove ) ( struct usb_function *func );
+};
+
+/** USB driver table */
+#define USB_DRIVERS __table ( struct usb_driver, "usb_drivers" )
+
+/** Declare a USB driver */
+#define __usb_driver __table_entry ( USB_DRIVERS, 01 )
+
+#endif /* _IPXE_USB_H */
diff --git a/roms/ipxe/src/include/ipxe/usbhid.h b/roms/ipxe/src/include/ipxe/usbhid.h
new file mode 100644
index 000000000..fe9d84455
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/usbhid.h
@@ -0,0 +1,106 @@
+#ifndef _IPXE_USBHID_H
+#define _IPXE_USBHID_H
+
+/** @file
+ *
+ * USB human interface devices (HID)
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <ipxe/usb.h>
+
+/** Class code for human interface devices */
+#define USB_CLASS_HID 3
+
+/** Subclass code for boot devices */
+#define USB_SUBCLASS_HID_BOOT 1
+
+/** Set protocol */
+#define USBHID_SET_PROTOCOL \
+ ( USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE | \
+ USB_REQUEST_TYPE ( 0x0b ) )
+
+/** Boot protocol */
+#define USBHID_PROTOCOL_BOOT 0
+
+/** Report protocol */
+#define USBHID_PROTOCOL_REPORT 1
+
+/** Set idle time */
+#define USBHID_SET_IDLE \
+ ( USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE | \
+ USB_REQUEST_TYPE ( 0x0a ) )
+
+/** A USB human interface device */
+struct usb_hid {
+ /** USB function */
+ struct usb_function *func;
+ /** Interrupt IN endpoint */
+ struct usb_endpoint in;
+ /** Interrupt OUT endpoint (optional) */
+ struct usb_endpoint out;
+};
+
+/**
+ * Initialise USB human interface device
+ *
+ * @v hid USB human interface device
+ * @v func USB function
+ * @v in Interrupt IN endpoint operations
+ * @v out Interrupt OUT endpoint operations (or NULL)
+ */
+static inline __attribute__ (( always_inline )) void
+usbhid_init ( struct usb_hid *hid, struct usb_function *func,
+ struct usb_endpoint_driver_operations *in,
+ struct usb_endpoint_driver_operations *out ) {
+ struct usb_device *usb = func->usb;
+
+ hid->func = func;
+ usb_endpoint_init ( &hid->in, usb, in );
+ if ( out )
+ usb_endpoint_init ( &hid->out, usb, out );
+}
+
+/**
+ * Set protocol
+ *
+ * @v usb USB device
+ * @v interface Interface number
+ * @v protocol HID protocol
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+usbhid_set_protocol ( struct usb_device *usb, unsigned int interface,
+ unsigned int protocol ) {
+
+ return usb_control ( usb, USBHID_SET_PROTOCOL, protocol, interface,
+ NULL, 0 );
+}
+
+/**
+ * Set idle time
+ *
+ * @v usb USB device
+ * @v interface Interface number
+ * @v report Report ID
+ * @v duration Duration (in 4ms units)
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+usbhid_set_idle ( struct usb_device *usb, unsigned int interface,
+ unsigned int report, unsigned int duration ) {
+
+ return usb_control ( usb, USBHID_SET_IDLE,
+ ( ( duration << 8 ) | report ),
+ interface, NULL, 0 );
+}
+
+extern int usbhid_open ( struct usb_hid *hid );
+extern void usbhid_close ( struct usb_hid *hid );
+extern int usbhid_refill ( struct usb_hid *hid );
+extern int usbhid_describe ( struct usb_hid *hid,
+ struct usb_configuration_descriptor *config );
+
+#endif /* _IPXE_USBHID_H */
diff --git a/roms/ipxe/src/include/ipxe/usbnet.h b/roms/ipxe/src/include/ipxe/usbnet.h
new file mode 100644
index 000000000..33a8f3f58
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/usbnet.h
@@ -0,0 +1,62 @@
+#ifndef _IPXE_USBNET_H
+#define _IPXE_USBNET_H
+
+/** @file
+ *
+ * USB network devices
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <ipxe/usb.h>
+
+/** A USB network device */
+struct usbnet_device {
+ /** USB function */
+ struct usb_function *func;
+
+ /** Communications interface */
+ unsigned int comms;
+ /** Data interface */
+ unsigned int data;
+ /** Alternate setting for data interface */
+ unsigned int alternate;
+
+ /** Interrupt endpoint */
+ struct usb_endpoint intr;
+ /** Bulk IN endpoint */
+ struct usb_endpoint in;
+ /** Bulk OUT endpoint */
+ struct usb_endpoint out;
+};
+
+/**
+ * Initialise USB network device
+ *
+ * @v usbnet USB network device
+ * @v func USB function
+ * @v intr Interrupt endpoint operations
+ * @v in Bulk IN endpoint operations
+ * @v out Bulk OUT endpoint operations
+ */
+static inline __attribute__ (( always_inline )) void
+usbnet_init ( struct usbnet_device *usbnet, struct usb_function *func,
+ struct usb_endpoint_driver_operations *intr,
+ struct usb_endpoint_driver_operations *in,
+ struct usb_endpoint_driver_operations *out ) {
+ struct usb_device *usb = func->usb;
+
+ usbnet->func = func;
+ usb_endpoint_init ( &usbnet->intr, usb, intr );
+ usb_endpoint_init ( &usbnet->in, usb, in );
+ usb_endpoint_init ( &usbnet->out, usb, out );
+}
+
+extern int usbnet_open ( struct usbnet_device *usbnet );
+extern void usbnet_close ( struct usbnet_device *usbnet );
+extern int usbnet_refill ( struct usbnet_device *usbnet );
+extern int usbnet_describe ( struct usbnet_device *usbnet,
+ struct usb_configuration_descriptor *config );
+
+#endif /* _IPXE_USBNET_H */
diff --git a/roms/ipxe/src/include/ipxe/uuid.h b/roms/ipxe/src/include/ipxe/uuid.h
index ad515d0cb..6c45eb9aa 100644
--- a/roms/ipxe/src/include/ipxe/uuid.h
+++ b/roms/ipxe/src/include/ipxe/uuid.h
@@ -6,7 +6,7 @@
* Universally unique IDs
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <byteswap.h>
diff --git a/roms/ipxe/src/include/ipxe/validator.h b/roms/ipxe/src/include/ipxe/validator.h
index 23bdab423..0aee56eb0 100644
--- a/roms/ipxe/src/include/ipxe/validator.h
+++ b/roms/ipxe/src/include/ipxe/validator.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/interface.h>
#include <ipxe/x509.h>
diff --git a/roms/ipxe/src/include/ipxe/version.h b/roms/ipxe/src/include/ipxe/version.h
index ae4275db1..a43a33425 100644
--- a/roms/ipxe/src/include/ipxe/version.h
+++ b/roms/ipxe/src/include/ipxe/version.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <wchar.h>
diff --git a/roms/ipxe/src/include/ipxe/vlan.h b/roms/ipxe/src/include/ipxe/vlan.h
index 083c21916..439e0c16d 100644
--- a/roms/ipxe/src/include/ipxe/vlan.h
+++ b/roms/ipxe/src/include/ipxe/vlan.h
@@ -8,7 +8,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** A VLAN header */
struct vlan_header {
diff --git a/roms/ipxe/src/include/ipxe/vmbus.h b/roms/ipxe/src/include/ipxe/vmbus.h
new file mode 100644
index 000000000..26fc578c6
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/vmbus.h
@@ -0,0 +1,634 @@
+#ifndef _IPXE_VMBUS_H
+#define _IPXE_VMBUS_H
+
+/** @file
+ *
+ * Hyper-V virtual machine bus
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <byteswap.h>
+#include <ipxe/uuid.h>
+#include <ipxe/device.h>
+#include <ipxe/tables.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/hyperv.h>
+
+/** VMBus message connection ID */
+#define VMBUS_MESSAGE_ID 1
+
+/** VMBus event connection ID */
+#define VMBUS_EVENT_ID 2
+
+/** VMBus message type */
+#define VMBUS_MESSAGE_TYPE 1
+
+/** VMBus message synthetic interrupt */
+#define VMBUS_MESSAGE_SINT 2
+
+/** VMBus version number */
+union vmbus_version {
+ /** Raw version */
+ uint32_t raw;
+ /** Major/minor version */
+ struct {
+ /** Minor version */
+ uint16_t minor;
+ /** Major version */
+ uint16_t major;
+ };
+} __attribute__ (( packed ));
+
+/** Known VMBus protocol versions */
+enum vmbus_raw_version {
+ /** Windows Server 2008 */
+ VMBUS_VERSION_WS2008 = ( ( 0 << 16 ) | ( 13 << 0 ) ),
+ /** Windows 7 */
+ VMBUS_VERSION_WIN7 = ( ( 1 << 16 ) | ( 1 << 0 ) ),
+ /** Windows 8 */
+ VMBUS_VERSION_WIN8 = ( ( 2 << 16 ) | ( 4 << 0 ) ),
+ /** Windows 8.1 */
+ VMBUS_VERSION_WIN8_1 = ( ( 3 << 16 ) | ( 0 << 0 ) ),
+};
+
+/** Guest physical address range descriptor */
+struct vmbus_gpa_range {
+ /** Byte count */
+ uint32_t len;
+ /** Starting byte offset */
+ uint32_t offset;
+ /** Page frame numbers
+ *
+ * The length of this array is implied by the byte count and
+ * starting offset.
+ */
+ uint64_t pfn[0];
+} __attribute__ (( packed ));
+
+/** VMBus message header */
+struct vmbus_message_header {
+ /** Message type */
+ uint32_t type;
+ /** Reserved */
+ uint32_t reserved;
+} __attribute__ (( packed ));
+
+/** VMBus message types */
+enum vmbus_message_type {
+ VMBUS_OFFER_CHANNEL = 1,
+ VMBUS_REQUEST_OFFERS = 3,
+ VMBUS_ALL_OFFERS_DELIVERED = 4,
+ VMBUS_OPEN_CHANNEL = 5,
+ VMBUS_OPEN_CHANNEL_RESULT = 6,
+ VMBUS_CLOSE_CHANNEL = 7,
+ VMBUS_GPADL_HEADER = 8,
+ VMBUS_GPADL_CREATED = 10,
+ VMBUS_GPADL_TEARDOWN = 11,
+ VMBUS_GPADL_TORNDOWN = 12,
+ VMBUS_INITIATE_CONTACT = 14,
+ VMBUS_VERSION_RESPONSE = 15,
+ VMBUS_UNLOAD = 16,
+ VMBUS_UNLOAD_RESPONSE = 17,
+};
+
+/** VMBus "offer channel" message */
+struct vmbus_offer_channel {
+ /** Message header */
+ struct vmbus_message_header header;
+ /** Channel type */
+ union uuid type;
+ /** Channel instance */
+ union uuid instance;
+ /** Reserved */
+ uint8_t reserved_a[16];
+ /** Flags */
+ uint16_t flags;
+ /** Reserved */
+ uint8_t reserved_b[2];
+ /** User data */
+ uint8_t data[120];
+ /** Reserved */
+ uint8_t reserved_c[4];
+ /** Channel ID */
+ uint32_t channel;
+ /** Monitor ID */
+ uint8_t monitor;
+ /** Monitor exists */
+ uint8_t monitored;
+ /** Reserved */
+ uint8_t reserved[2];
+ /** Connection ID */
+ uint32_t connection;
+} __attribute__ (( packed ));
+
+/** VMBus "open channel" message */
+struct vmbus_open_channel {
+ /** Message header */
+ struct vmbus_message_header header;
+ /** Channel ID */
+ uint32_t channel;
+ /** Open ID */
+ uint32_t id;
+ /** Ring buffer GPADL ID */
+ uint32_t gpadl;
+ /** Reserved */
+ uint32_t reserved;
+ /** Outbound ring buffer size (in pages) */
+ uint32_t out_pages;
+ /** User-specific data */
+ uint8_t data[120];
+} __attribute__ (( packed ));
+
+/** VMBus "open channel result" message */
+struct vmbus_open_channel_result {
+ /** Message header */
+ struct vmbus_message_header header;
+ /** Channel ID */
+ uint32_t channel;
+ /** Open ID */
+ uint32_t id;
+ /** Status */
+ uint32_t status;
+} __attribute__ (( packed ));
+
+/** VMBus "close channel" message */
+struct vmbus_close_channel {
+ /** Message header */
+ struct vmbus_message_header header;
+ /** Channel ID */
+ uint32_t channel;
+} __attribute__ (( packed ));
+
+/** VMBus "GPADL header" message */
+struct vmbus_gpadl_header {
+ /** Message header */
+ struct vmbus_message_header header;
+ /** Channel ID */
+ uint32_t channel;
+ /** GPADL ID */
+ uint32_t gpadl;
+ /** Length of range descriptors */
+ uint16_t range_len;
+ /** Number of range descriptors */
+ uint16_t range_count;
+ /** Range descriptors */
+ struct vmbus_gpa_range range[0];
+} __attribute__ (( packed ));
+
+/** VMBus "GPADL created" message */
+struct vmbus_gpadl_created {
+ /** Message header */
+ struct vmbus_message_header header;
+ /** Channel ID */
+ uint32_t channel;
+ /** GPADL ID */
+ uint32_t gpadl;
+ /** Creation status */
+ uint32_t status;
+} __attribute__ (( packed ));
+
+/** VMBus "GPADL teardown" message */
+struct vmbus_gpadl_teardown {
+ /** Message header */
+ struct vmbus_message_header header;
+ /** Channel ID */
+ uint32_t channel;
+ /** GPADL ID */
+ uint32_t gpadl;
+} __attribute__ (( packed ));
+
+/** VMBus "GPADL torndown" message */
+struct vmbus_gpadl_torndown {
+ /** Message header */
+ struct vmbus_message_header header;
+ /** GPADL ID */
+ uint32_t gpadl;
+} __attribute__ (( packed ));
+
+/** VMBus "initiate contact" message */
+struct vmbus_initiate_contact {
+ /** Message header */
+ struct vmbus_message_header header;
+ /** Requested version */
+ union vmbus_version version;
+ /** Target virtual CPU */
+ uint32_t vcpu;
+ /** Interrupt page base address */
+ uint64_t intr;
+ /** Parent to child monitor page base address */
+ uint64_t monitor_in;
+ /** Child to parent monitor page base address */
+ uint64_t monitor_out;
+} __attribute__ (( packed ));
+
+/** VMBus "version response" message */
+struct vmbus_version_response {
+ /** Message header */
+ struct vmbus_message_header header;
+ /** Version is supported */
+ uint8_t supported;
+ /** Reserved */
+ uint8_t reserved[3];
+ /** Version */
+ union vmbus_version version;
+} __attribute__ (( packed ));
+
+/** VMBus message */
+union vmbus_message {
+ /** Common message header */
+ struct vmbus_message_header header;
+ /** "Offer channel" message */
+ struct vmbus_offer_channel offer;
+ /** "Open channel" message */
+ struct vmbus_open_channel open;
+ /** "Open channel result" message */
+ struct vmbus_open_channel_result opened;
+ /** "Close channel" message */
+ struct vmbus_close_channel close;
+ /** "GPADL header" message */
+ struct vmbus_gpadl_header gpadlhdr;
+ /** "GPADL created" message */
+ struct vmbus_gpadl_created created;
+ /** "GPADL teardown" message */
+ struct vmbus_gpadl_teardown teardown;
+ /** "GPADL torndown" message */
+ struct vmbus_gpadl_torndown torndown;
+ /** "Initiate contact" message */
+ struct vmbus_initiate_contact initiate;
+ /** "Version response" message */
+ struct vmbus_version_response version;
+};
+
+/** VMBus packet header */
+struct vmbus_packet_header {
+ /** Type */
+ uint16_t type;
+ /** Length of packet header (in quadwords) */
+ uint16_t hdr_qlen;
+ /** Length of packet (in quadwords) */
+ uint16_t qlen;
+ /** Flags */
+ uint16_t flags;
+ /** Transaction ID
+ *
+ * This is an opaque token: we therefore treat it as
+ * native-endian and don't worry about byte-swapping.
+ */
+ uint64_t xid;
+} __attribute__ (( packed ));
+
+/** VMBus packet types */
+enum vmbus_packet_type {
+ VMBUS_DATA_INBAND = 6,
+ VMBUS_DATA_XFER_PAGES = 7,
+ VMBUS_DATA_GPA_DIRECT = 9,
+ VMBUS_CANCELLATION = 10,
+ VMBUS_COMPLETION = 11,
+};
+
+/** VMBus packet flags */
+enum vmbus_packet_flags {
+ VMBUS_COMPLETION_REQUESTED = 0x0001,
+};
+
+/** VMBus GPA direct header */
+struct vmbus_gpa_direct_header {
+ /** Packet header */
+ struct vmbus_packet_header header;
+ /** Reserved */
+ uint32_t reserved;
+ /** Number of range descriptors */
+ uint32_t range_count;
+ /** Range descriptors */
+ struct vmbus_gpa_range range[0];
+} __attribute__ (( packed ));
+
+/** VMBus transfer page range */
+struct vmbus_xfer_page_range {
+ /** Length */
+ uint32_t len;
+ /** Offset */
+ uint32_t offset;
+} __attribute__ (( packed ));
+
+/** VMBus transfer page header */
+struct vmbus_xfer_page_header {
+ /** Packet header */
+ struct vmbus_packet_header header;
+ /** Page set ID */
+ uint16_t pageset;
+ /** Sender owns page set */
+ uint8_t owner;
+ /** Reserved */
+ uint8_t reserved;
+ /** Number of range descriptors */
+ uint32_t range_count;
+ /** Range descriptors */
+ struct vmbus_xfer_page_range range[0];
+} __attribute__ (( packed ));
+
+/** Maximum expected size of VMBus packet header */
+#define VMBUS_PACKET_MAX_HEADER_LEN 64
+
+/** VMBus maximum-sized packet header */
+union vmbus_packet_header_max {
+ /** Common header */
+ struct vmbus_packet_header header;
+ /** GPA direct header */
+ struct vmbus_gpa_direct_header gpa;
+ /** Transfer page header */
+ struct vmbus_xfer_page_header xfer;
+ /** Padding to maximum supported size */
+ uint8_t padding[VMBUS_PACKET_MAX_HEADER_LEN];
+} __attribute__ (( packed ));
+
+/** VMBus packet footer */
+struct vmbus_packet_footer {
+ /** Reserved */
+ uint32_t reserved;
+ /** Producer index of the first byte of the packet */
+ uint32_t prod;
+} __attribute__ (( packed ));
+
+/** VMBus ring buffer
+ *
+ * This is the structure of the each of the ring buffers created when
+ * a VMBus channel is opened.
+ */
+struct vmbus_ring {
+ /** Producer index (modulo ring length) */
+ uint32_t prod;
+ /** Consumer index (modulo ring length) */
+ uint32_t cons;
+ /** Interrupt mask */
+ uint32_t intr_mask;
+ /** Reserved */
+ uint8_t reserved[4084];
+ /** Ring buffer contents */
+ uint8_t data[0];
+} __attribute__ (( packed ));
+
+/** VMBus interrupt page */
+struct vmbus_interrupt {
+ /** Inbound interrupts */
+ uint8_t in[ PAGE_SIZE / 2 ];
+ /** Outbound interrupts */
+ uint8_t out[ PAGE_SIZE / 2 ];
+} __attribute__ (( packed ));
+
+/** A virtual machine bus */
+struct vmbus {
+ /** Interrupt page */
+ struct vmbus_interrupt *intr;
+ /** Inbound notifications */
+ struct hv_monitor *monitor_in;
+ /** Outbound notifications */
+ struct hv_monitor *monitor_out;
+ /** Received message buffer */
+ const union vmbus_message *message;
+};
+
+struct vmbus_device;
+
+/** VMBus channel operations */
+struct vmbus_channel_operations {
+ /**
+ * Handle received control packet
+ *
+ * @v vmdev VMBus device
+ * @v xid Transaction ID
+ * @v data Data
+ * @v len Length of data
+ * @ret rc Return status code
+ */
+ int ( * recv_control ) ( struct vmbus_device *vmdev, uint64_t xid,
+ const void *data, size_t len );
+ /**
+ * Handle received data packet
+ *
+ * @v vmdev VMBus device
+ * @v xid Transaction ID
+ * @v data Data
+ * @v len Length of data
+ * @v list List of I/O buffers
+ * @ret rc Return status code
+ *
+ * This function takes ownership of the I/O buffer. It should
+ * eventually call vmbus_send_completion() to indicate to the
+ * host that the buffer can be reused.
+ */
+ int ( * recv_data ) ( struct vmbus_device *vmdev, uint64_t xid,
+ const void *data, size_t len,
+ struct list_head *list );
+ /**
+ * Handle received completion packet
+ *
+ * @v vmdev VMBus device
+ * @v xid Transaction ID
+ * @v data Data
+ * @v len Length of data
+ * @ret rc Return status code
+ */
+ int ( * recv_completion ) ( struct vmbus_device *vmdev, uint64_t xid,
+ const void *data, size_t len );
+ /**
+ * Handle received cancellation packet
+ *
+ * @v vmdev VMBus device
+ * @v xid Transaction ID
+ * @ret rc Return status code
+ */
+ int ( * recv_cancellation ) ( struct vmbus_device *vmdev,
+ uint64_t xid );
+};
+
+struct vmbus_xfer_pages;
+
+/** VMBus transfer page set operations */
+struct vmbus_xfer_pages_operations {
+ /**
+ * Copy data from transfer page
+ *
+ * @v pages Transfer page set
+ * @v data Data buffer
+ * @v offset Offset within page set
+ * @v len Length within page set
+ * @ret rc Return status code
+ */
+ int ( * copy ) ( struct vmbus_xfer_pages *pages, void *data,
+ size_t offset, size_t len );
+};
+
+/** VMBus transfer page set */
+struct vmbus_xfer_pages {
+ /** List of all transfer page sets */
+ struct list_head list;
+ /** Page set ID (in protocol byte order) */
+ uint16_t pageset;
+ /** Page set operations */
+ struct vmbus_xfer_pages_operations *op;
+};
+
+/** A VMBus device */
+struct vmbus_device {
+ /** Generic iPXE device */
+ struct device dev;
+ /** Hyper-V hypervisor */
+ struct hv_hypervisor *hv;
+
+ /** Channel ID */
+ unsigned int channel;
+ /** Monitor ID */
+ unsigned int monitor;
+ /** Signal channel
+ *
+ * @v vmdev VMBus device
+ */
+ void ( * signal ) ( struct vmbus_device *vmdev );
+
+ /** Outbound ring buffer length */
+ uint32_t out_len;
+ /** Inbound ring buffer length */
+ uint32_t in_len;
+ /** Outbound ring buffer */
+ struct vmbus_ring *out;
+ /** Inbound ring buffer */
+ struct vmbus_ring *in;
+ /** Ring buffer GPADL ID */
+ unsigned int gpadl;
+
+ /** Channel operations */
+ struct vmbus_channel_operations *op;
+ /** Maximum expected data packet length */
+ size_t mtu;
+ /** Packet buffer */
+ void *packet;
+ /** List of transfer page sets */
+ struct list_head pages;
+
+ /** Driver */
+ struct vmbus_driver *driver;
+ /** Driver-private data */
+ void *priv;
+};
+
+/** A VMBus device driver */
+struct vmbus_driver {
+ /** Name */
+ const char *name;
+ /** Device type */
+ union uuid type;
+ /** Probe device
+ *
+ * @v vmdev VMBus device
+ * @ret rc Return status code
+ */
+ int ( * probe ) ( struct vmbus_device *vmdev );
+ /** Remove device
+ *
+ * @v vmdev VMBus device
+ */
+ void ( * remove ) ( struct vmbus_device *vmdev );
+};
+
+/** VMBus device driver table */
+#define VMBUS_DRIVERS __table ( struct vmbus_driver, "vmbus_drivers" )
+
+/** Declare a VMBus device driver */
+#define __vmbus_driver __table_entry ( VMBUS_DRIVERS, 01 )
+
+/**
+ * Set VMBus device driver-private data
+ *
+ * @v vmdev VMBus device
+ * @v priv Private data
+ */
+static inline void vmbus_set_drvdata ( struct vmbus_device *vmdev, void *priv ){
+ vmdev->priv = priv;
+}
+
+/**
+ * Get VMBus device driver-private data
+ *
+ * @v vmdev VMBus device
+ * @ret priv Private data
+ */
+static inline void * vmbus_get_drvdata ( struct vmbus_device *vmdev ) {
+ return vmdev->priv;
+}
+
+/** Construct VMBus type */
+#define VMBUS_TYPE( a, b, c, d, e0, e1, e2, e3, e4, e5 ) { \
+ .canonical = { \
+ cpu_to_le32 ( a ), cpu_to_le16 ( b ), \
+ cpu_to_le16 ( c ), cpu_to_be16 ( d ), \
+ { e0, e1, e2, e3, e4, e5 } \
+ } }
+
+/**
+ * Check if data is present in ring buffer
+ *
+ * @v vmdev VMBus device
+ * @v has_data Data is present
+ */
+static inline __attribute__ (( always_inline )) int
+vmbus_has_data ( struct vmbus_device *vmdev ) {
+
+ return ( vmdev->in->prod != vmdev->in->cons );
+}
+
+/**
+ * Register transfer page set
+ *
+ * @v vmdev VMBus device
+ * @v pages Transfer page set
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+vmbus_register_pages ( struct vmbus_device *vmdev,
+ struct vmbus_xfer_pages *pages ) {
+
+ list_add ( &pages->list, &vmdev->pages );
+ return 0;
+}
+
+/**
+ * Unregister transfer page set
+ *
+ * @v vmdev VMBus device
+ * @v pages Transfer page set
+ */
+static inline __attribute__ (( always_inline )) void
+vmbus_unregister_pages ( struct vmbus_device *vmdev,
+ struct vmbus_xfer_pages *pages ) {
+
+ list_check_contains_entry ( pages, &vmdev->pages, list );
+ list_del ( &pages->list );
+}
+
+extern int vmbus_establish_gpadl ( struct vmbus_device *vmdev, userptr_t data,
+ size_t len );
+extern int vmbus_gpadl_teardown ( struct vmbus_device *vmdev,
+ unsigned int gpadl );
+extern int vmbus_open ( struct vmbus_device *vmdev,
+ struct vmbus_channel_operations *op,
+ size_t out_len, size_t in_len, size_t mtu );
+extern void vmbus_close ( struct vmbus_device *vmdev );
+extern int vmbus_send_control ( struct vmbus_device *vmdev, uint64_t xid,
+ const void *data, size_t len );
+extern int vmbus_send_data ( struct vmbus_device *vmdev, uint64_t xid,
+ const void *data, size_t len,
+ struct io_buffer *iobuf );
+extern int vmbus_send_completion ( struct vmbus_device *vmdev, uint64_t xid,
+ const void *data, size_t len );
+extern int vmbus_send_cancellation ( struct vmbus_device *vmdev, uint64_t xid );
+extern int vmbus_poll ( struct vmbus_device *vmdev );
+extern void vmbus_dump_channel ( struct vmbus_device *vmdev );
+
+extern int vmbus_probe ( struct hv_hypervisor *hv, struct device *parent );
+extern void vmbus_remove ( struct hv_hypervisor *hv, struct device *parent );
+
+#endif /* _IPXE_VMBUS_H */
diff --git a/roms/ipxe/src/include/ipxe/vsprintf.h b/roms/ipxe/src/include/ipxe/vsprintf.h
index c48c97a87..9e6297715 100644
--- a/roms/ipxe/src/include/ipxe/vsprintf.h
+++ b/roms/ipxe/src/include/ipxe/vsprintf.h
@@ -31,7 +31,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdarg.h>
diff --git a/roms/ipxe/src/include/ipxe/x509.h b/roms/ipxe/src/include/ipxe/x509.h
index 802480e54..0daaf5e59 100644
--- a/roms/ipxe/src/include/ipxe/x509.h
+++ b/roms/ipxe/src/include/ipxe/x509.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stddef.h>
diff --git a/roms/ipxe/src/include/ipxe/xen.h b/roms/ipxe/src/include/ipxe/xen.h
index 60aabe03e..eac1145ad 100644
--- a/roms/ipxe/src/include/ipxe/xen.h
+++ b/roms/ipxe/src/include/ipxe/xen.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/* Define Xen interface version before including any Xen header files */
#define __XEN_INTERFACE_VERSION__ 0x00040400
diff --git a/roms/ipxe/src/include/ipxe/xenbus.h b/roms/ipxe/src/include/ipxe/xenbus.h
index ef2b5496f..ec5782eed 100644
--- a/roms/ipxe/src/include/ipxe/xenbus.h
+++ b/roms/ipxe/src/include/ipxe/xenbus.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/device.h>
#include <ipxe/tables.h>
diff --git a/roms/ipxe/src/include/ipxe/xenevent.h b/roms/ipxe/src/include/ipxe/xenevent.h
index 1dd6a0c0b..f0bd3465e 100644
--- a/roms/ipxe/src/include/ipxe/xenevent.h
+++ b/roms/ipxe/src/include/ipxe/xenevent.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/xen.h>
#include <xen/event_channel.h>
diff --git a/roms/ipxe/src/include/ipxe/xengrant.h b/roms/ipxe/src/include/ipxe/xengrant.h
index f9b3beb21..451a3ceee 100644
--- a/roms/ipxe/src/include/ipxe/xengrant.h
+++ b/roms/ipxe/src/include/ipxe/xengrant.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/include/ipxe/xenmem.h b/roms/ipxe/src/include/ipxe/xenmem.h
index 9b9aeda9c..dcc38d460 100644
--- a/roms/ipxe/src/include/ipxe/xenmem.h
+++ b/roms/ipxe/src/include/ipxe/xenmem.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/xen.h>
#include <xen/memory.h>
diff --git a/roms/ipxe/src/include/ipxe/xenstore.h b/roms/ipxe/src/include/ipxe/xenstore.h
index f25f15704..892640755 100644
--- a/roms/ipxe/src/include/ipxe/xenstore.h
+++ b/roms/ipxe/src/include/ipxe/xenstore.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/xen.h>
diff --git a/roms/ipxe/src/include/ipxe/xenver.h b/roms/ipxe/src/include/ipxe/xenver.h
index 5d678c5a3..b29dfb321 100644
--- a/roms/ipxe/src/include/ipxe/xenver.h
+++ b/roms/ipxe/src/include/ipxe/xenver.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/xen.h>
#include <xen/version.h>
diff --git a/roms/ipxe/src/include/ipxe/xfer.h b/roms/ipxe/src/include/ipxe/xfer.h
index 1167e5cba..3a35fa924 100644
--- a/roms/ipxe/src/include/ipxe/xfer.h
+++ b/roms/ipxe/src/include/ipxe/xfer.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <stdarg.h>
@@ -103,5 +103,7 @@ extern int xfer_vprintf ( struct interface *intf,
extern int __attribute__ (( format ( printf, 2, 3 ) ))
xfer_printf ( struct interface *intf, const char *format, ... );
extern int xfer_seek ( struct interface *intf, off_t offset );
+extern int xfer_check_order ( struct xfer_metadata *meta, size_t *pos,
+ size_t len );
#endif /* _IPXE_XFER_H */
diff --git a/roms/ipxe/src/include/ipxe/xferbuf.h b/roms/ipxe/src/include/ipxe/xferbuf.h
index 2ca871e59..cb0b1a0e8 100644
--- a/roms/ipxe/src/include/ipxe/xferbuf.h
+++ b/roms/ipxe/src/include/ipxe/xferbuf.h
@@ -7,10 +7,12 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/iobuf.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/interface.h>
#include <ipxe/xfer.h>
/** A data transfer buffer */
@@ -21,11 +23,83 @@ struct xfer_buffer {
size_t len;
/** Current offset within data */
size_t pos;
+ /** Data transfer buffer operations */
+ struct xfer_buffer_operations *op;
};
-extern void xferbuf_done ( struct xfer_buffer *xferbuf );
+/** Data transfer buffer operations */
+struct xfer_buffer_operations {
+ /** Reallocate data buffer
+ *
+ * @v xferbuf Data transfer buffer
+ * @v len New length (or zero to free buffer)
+ * @ret rc Return status code
+ */
+ int ( * realloc ) ( struct xfer_buffer *xferbuf, size_t len );
+ /** Write data to buffer
+ *
+ * @v xferbuf Data transfer buffer
+ * @v offset Starting offset
+ * @v data Data to write
+ * @v len Length of data
+ *
+ * This call is simply a wrapper for the appropriate
+ * memcpy()-like operation: the caller is responsible for
+ * ensuring that the write does not exceed the buffer length.
+ */
+ void ( * write ) ( struct xfer_buffer *xferbuf, size_t offset,
+ const void *data, size_t len );
+ /** Read data from buffer
+ *
+ * @v xferbuf Data transfer buffer
+ * @v offset Starting offset
+ * @v data Data to read
+ * @v len Length of data
+ *
+ * This call is simply a wrapper for the appropriate
+ * memcpy()-like operation: the caller is responsible for
+ * ensuring that the read does not exceed the buffer length.
+ */
+ void ( * read ) ( struct xfer_buffer *xferbuf, size_t offset,
+ void *data, size_t len );
+};
+
+extern struct xfer_buffer_operations xferbuf_malloc_operations;
+extern struct xfer_buffer_operations xferbuf_umalloc_operations;
+
+/**
+ * Initialise malloc()-based data transfer buffer
+ *
+ * @v xferbuf Data transfer buffer
+ */
+static inline __attribute__ (( always_inline )) void
+xferbuf_malloc_init ( struct xfer_buffer *xferbuf ) {
+ xferbuf->op = &xferbuf_malloc_operations;
+}
+
+/**
+ * Initialise umalloc()-based data transfer buffer
+ *
+ * @v xferbuf Data transfer buffer
+ * @v data User pointer
+ */
+static inline __attribute__ (( always_inline )) void
+xferbuf_umalloc_init ( struct xfer_buffer *xferbuf, userptr_t *data ) {
+ xferbuf->data = data;
+ xferbuf->op = &xferbuf_umalloc_operations;
+}
+
+extern void xferbuf_free ( struct xfer_buffer *xferbuf );
+extern int xferbuf_write ( struct xfer_buffer *xferbuf, size_t offset,
+ const void *data, size_t len );
+extern int xferbuf_read ( struct xfer_buffer *xferbuf, size_t offset,
+ void *data, size_t len );
extern int xferbuf_deliver ( struct xfer_buffer *xferbuf,
struct io_buffer *iobuf,
struct xfer_metadata *meta );
+extern struct xfer_buffer * xfer_buffer ( struct interface *intf );
+#define xfer_buffer_TYPE( object_type ) \
+ typeof ( struct xfer_buffer * ( object_type ) )
+
#endif /* _IPXE_XFERBUF_H */
diff --git a/roms/ipxe/src/include/libgen.h b/roms/ipxe/src/include/libgen.h
index 7e94881a9..ae0861270 100644
--- a/roms/ipxe/src/include/libgen.h
+++ b/roms/ipxe/src/include/libgen.h
@@ -1,7 +1,7 @@
#ifndef _LIBGEN_H
#define _LIBGEN_H
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
extern char * basename ( char *path );
extern char * dirname ( char *path );
diff --git a/roms/ipxe/src/include/little_bswap.h b/roms/ipxe/src/include/little_bswap.h
deleted file mode 100644
index 92dd26ba1..000000000
--- a/roms/ipxe/src/include/little_bswap.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef ETHERBOOT_LITTLE_BSWAP_H
-#define ETHERBOOT_LITTLE_BSWAP_H
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#define htonll(x) __bswap_64(x)
-#define ntohll(x) __bswap_64(x)
-#define ntohl(x) __bswap_32(x)
-#define htonl(x) __bswap_32(x)
-#define ntohs(x) __bswap_16(x)
-#define htons(x) __bswap_16(x)
-#define cpu_to_le64(x) (x)
-#define cpu_to_le32(x) (x)
-#define cpu_to_le16(x) (x)
-#define cpu_to_be64(x) __bswap_64(x)
-#define cpu_to_be32(x) __bswap_32(x)
-#define cpu_to_be16(x) __bswap_16(x)
-#define le64_to_cpu(x) (x)
-#define le32_to_cpu(x) (x)
-#define le16_to_cpu(x) (x)
-#define be64_to_cpu(x) __bswap_64(x)
-#define be32_to_cpu(x) __bswap_32(x)
-#define be16_to_cpu(x) __bswap_16(x)
-#define cpu_to_le64s(x) do {} while (0)
-#define cpu_to_le32s(x) do {} while (0)
-#define cpu_to_le16s(x) do {} while (0)
-#define cpu_to_be64s(x) __bswap_64s(x)
-#define cpu_to_be32s(x) __bswap_32s(x)
-#define cpu_to_be16s(x) __bswap_16s(x)
-#define le64_to_cpus(x) do {} while (0)
-#define le32_to_cpus(x) do {} while (0)
-#define le16_to_cpus(x) do {} while (0)
-#define be64_to_cpus(x) __bswap_64s(x)
-#define be32_to_cpus(x) __bswap_32s(x)
-#define be16_to_cpus(x) __bswap_16s(x)
-
-#endif /* ETHERBOOT_LITTLE_BSWAP_H */
diff --git a/roms/ipxe/src/include/nic.h b/roms/ipxe/src/include/nic.h
index 9aaede8a7..4c91f57a6 100644
--- a/roms/ipxe/src/include/nic.h
+++ b/roms/ipxe/src/include/nic.h
@@ -1,8 +1,18 @@
- /*
+/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2, or (at
- * your option) any later version.
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
@@ -266,6 +276,7 @@ static inline void * legacy_isa_get_drvdata ( void *hwdev ) {
_name ## _isa_legacy_remove ( struct isa_device *isa ) { \
return legacy_remove ( isa, legacy_isa_get_drvdata, \
_name ## _disable ); \
- }
+ } \
+ PROVIDE_REQUIRING_SYMBOL()
#endif /* NIC_H */
diff --git a/roms/ipxe/src/include/readline/readline.h b/roms/ipxe/src/include/readline/readline.h
index 0449a3f98..afafbbdf5 100644
--- a/roms/ipxe/src/include/readline/readline.h
+++ b/roms/ipxe/src/include/readline/readline.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** A readline history entry */
struct readline_history_entry {
diff --git a/roms/ipxe/src/include/stdarg.h b/roms/ipxe/src/include/stdarg.h
index f317238a9..89e94ce22 100644
--- a/roms/ipxe/src/include/stdarg.h
+++ b/roms/ipxe/src/include/stdarg.h
@@ -1,7 +1,7 @@
#ifndef _STDARG_H
#define _STDARG_H
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
typedef __builtin_va_list va_list;
#define va_start( ap, last ) __builtin_va_start ( ap, last )
diff --git a/roms/ipxe/src/include/stddef.h b/roms/ipxe/src/include/stddef.h
index bf792771f..3c056294f 100644
--- a/roms/ipxe/src/include/stddef.h
+++ b/roms/ipxe/src/include/stddef.h
@@ -1,25 +1,43 @@
#ifndef STDDEF_H
#define STDDEF_H
-FILE_LICENCE ( GPL2_ONLY );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
-/* for size_t */
#include <stdint.h>
+/** EFI headers also define NULL */
#undef NULL
-#define NULL ((void *)0)
-#undef offsetof
-#if ( defined ( __GNUC__ ) && ( __GNUC__ > 3 ) )
-#define offsetof(TYPE, MEMBER) __builtin_offsetof(TYPE, MEMBER)
+/** Null pointer */
+#define NULL ( ( void * ) 0 )
+
+/**
+ * Get offset of a field within a structure
+ *
+ * @v type Structure type
+ * @v field Field within structure
+ * @ret offset Offset within structure
+ */
+#if defined ( __GNUC__ ) && ( __GNUC__ > 3 )
+#define offsetof( type, field ) __builtin_offsetof ( type, field )
#else
-#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#define offsetof( type, field ) ( ( size_t ) &( ( ( type * ) NULL )->field ) )
#endif
-#undef container_of
-#define container_of(ptr, type, member) ({ \
- const typeof( ((type *)0)->member ) *__mptr = (ptr); \
- (type *)( (char *)__mptr - offsetof(type,member) );})
+/**
+ * Get containing structure
+ *
+ * @v ptr Pointer to contained field
+ * @v type Containing structure type
+ * @v field Field within containing structure
+ * @ret container Pointer to containing structure
+ */
+#define container_of( ptr, type, field ) ( { \
+ type *__container; \
+ const typeof ( __container->field ) *__field = (ptr); \
+ __container = ( ( ( void * ) __field ) - \
+ offsetof ( type, field ) ); \
+ __container; } )
/* __WCHAR_TYPE__ is defined by gcc and will change if -fshort-wchar is used */
#ifndef __WCHAR_TYPE__
diff --git a/roms/ipxe/src/include/stdint.h b/roms/ipxe/src/include/stdint.h
index 8cc9b84a5..0a239a517 100644
--- a/roms/ipxe/src/include/stdint.h
+++ b/roms/ipxe/src/include/stdint.h
@@ -1,7 +1,7 @@
#ifndef _STDINT_H
#define _STDINT_H
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/*
* This is a standard predefined macro on all gcc's I've seen. It's
diff --git a/roms/ipxe/src/include/stdio.h b/roms/ipxe/src/include/stdio.h
index 91840af5b..a618482ce 100644
--- a/roms/ipxe/src/include/stdio.h
+++ b/roms/ipxe/src/include/stdio.h
@@ -1,7 +1,7 @@
#ifndef _STDIO_H
#define _STDIO_H
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdarg.h>
diff --git a/roms/ipxe/src/include/stdlib.h b/roms/ipxe/src/include/stdlib.h
index 2951522b8..d7748a07e 100644
--- a/roms/ipxe/src/include/stdlib.h
+++ b/roms/ipxe/src/include/stdlib.h
@@ -1,7 +1,7 @@
#ifndef STDLIB_H
#define STDLIB_H
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <assert.h>
@@ -13,31 +13,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
****************************************************************************
*/
-static inline int strtoul_base ( const char **pp, int base )
-{
- const char *p = *pp;
-
- if ( base == 0 ) {
- base = 10;
- if ( *p == '0' ) {
- p++;
- base = 8;
- if ( ( *p | 0x20 ) == 'x' ) {
- p++;
- base = 16;
- }
- }
- }
-
- *pp = p;
-
- return base;
-}
-
-extern unsigned int strtoul_charval ( unsigned int charval );
-extern unsigned long strtoul ( const char *p, char **endp, int base );
-extern unsigned long long strtoull ( const char *p, char **endp, int base );
-
+extern unsigned long strtoul ( const char *string, char **endp, int base );
+extern unsigned long long strtoull ( const char *string, char **endp,
+ int base );
/*****************************************************************************
*
diff --git a/roms/ipxe/src/include/string.h b/roms/ipxe/src/include/string.h
index 3482e1b22..0fab6c74b 100644
--- a/roms/ipxe/src/include/string.h
+++ b/roms/ipxe/src/include/string.h
@@ -1,52 +1,53 @@
-/*
- * Copyright (C) 1991, 1992 Linus Torvalds
- * Copyright (C) 2004 Tobias Lorenz
+#ifndef _STRING_H
+#define _STRING_H
+
+/** @file
*
- * string handling functions
- * based on linux/include/linux/ctype.h
- * and linux/include/linux/string.h
+ * String functions
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
-FILE_LICENCE ( GPL2_ONLY );
-
-#ifndef ETHERBOOT_STRING_H
-#define ETHERBOOT_STRING_H
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <bits/string.h>
-int __pure strnicmp(const char *s1, const char *s2, size_t len) __nonnull;
-char * strcpy(char * dest,const char *src) __nonnull;
-char * strncpy(char * dest,const char *src,size_t count) __nonnull;
-char * strcat(char * dest, const char * src) __nonnull;
-char * strncat(char *dest, const char *src, size_t count) __nonnull;
-int __pure strcmp(const char * cs,const char * ct) __nonnull;
-int __pure strncmp(const char * cs,const char * ct,
- size_t count) __nonnull;
-char * __pure strchr(const char * s, int c) __nonnull;
-char * __pure strrchr(const char * s, int c) __nonnull;
-size_t __pure strlen(const char * s) __nonnull;
-size_t __pure strnlen(const char * s, size_t count) __nonnull;
-size_t __pure strspn(const char *s, const char *accept) __nonnull;
-size_t __pure strcspn(const char *s, const char *reject) __nonnull;
-char * __pure strpbrk(const char * cs,const char * ct) __nonnull;
-char * strtok(char * s,const char * ct) __nonnull;
-char * strsep(char **s, const char *ct) __nonnull;
-void * memset(void * s,int c,size_t count) __nonnull;
+/* Architecture-specific code is expected to provide these functions,
+ * but may instead explicitly choose to use the generic versions.
+ */
+void * memset ( void *dest, int character, size_t len ) __nonnull;
void * memcpy ( void *dest, const void *src, size_t len ) __nonnull;
-void * memmove(void * dest,const void *src,size_t count) __nonnull;
-int __pure memcmp(const void * cs,const void * ct,
- size_t count) __nonnull;
-void * __pure memscan(const void * addr, int c, size_t size) __nonnull;
-char * __pure strstr(const char * s1,const char * s2) __nonnull;
-void * __pure memchr(const void *s, int c, size_t n) __nonnull;
-char * __malloc strdup(const char *s) __nonnull;
-char * __malloc strndup(const char *s, size_t n) __nonnull;
+void * memmove ( void *dest, const void *src, size_t len ) __nonnull;
+extern void * generic_memset ( void *dest, int character,
+ size_t len ) __nonnull;
+extern void * generic_memcpy ( void *dest, const void *src,
+ size_t len ) __nonnull;
+extern void * generic_memmove ( void *dest, const void *src,
+ size_t len ) __nonnull;
+
+extern int __pure memcmp ( const void *first, const void *second,
+ size_t len ) __nonnull;
+extern void * __pure memchr ( const void *src, int character,
+ size_t len ) __nonnull;
+extern void * memswap ( void *dest, void *src, size_t len ) __nonnull;
+extern int __pure strcmp ( const char *first, const char *second ) __nonnull;
+extern int __pure strncmp ( const char *first, const char *second,
+ size_t max ) __nonnull;
+extern size_t __pure strlen ( const char *src ) __nonnull;
+extern size_t __pure strnlen ( const char *src, size_t max ) __nonnull;
+extern char * __pure strchr ( const char *src, int character ) __nonnull;
+extern char * __pure strrchr ( const char *src, int character ) __nonnull;
+extern char * __pure strstr ( const char *haystack,
+ const char *needle ) __nonnull;
+extern char * strcpy ( char *dest, const char *src ) __nonnull;
+extern char * strncpy ( char *dest, const char *src, size_t max ) __nonnull;
+extern char * strcat ( char *dest, const char *src ) __nonnull;
+extern char * __malloc strdup ( const char *src ) __nonnull;
+extern char * __malloc strndup ( const char *src, size_t max ) __nonnull;
+extern char * __pure strpbrk ( const char *string,
+ const char *delim ) __nonnull;
+extern char * strsep ( char **string, const char *delim ) __nonnull;
-extern const char * __pure strerror ( int errno );
+extern char * __pure strerror ( int errno );
-#endif /* ETHERBOOT_STRING */
+#endif /* _STRING_H */
diff --git a/roms/ipxe/src/include/strings.h b/roms/ipxe/src/include/strings.h
index 6912a1e45..fab26dc28 100644
--- a/roms/ipxe/src/include/strings.h
+++ b/roms/ipxe/src/include/strings.h
@@ -1,12 +1,71 @@
#ifndef _STRINGS_H
#define _STRINGS_H
-FILE_LICENCE ( GPL2_OR_LATER );
+/** @file
+ *
+ * String functions
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
-#include <limits.h>
#include <string.h>
#include <bits/strings.h>
+/**
+ * Find first (i.e. least significant) set bit
+ *
+ * @v x Value
+ * @ret lsb Least significant bit set in value (LSB=1), or zero
+ */
+static inline __attribute__ (( always_inline )) int
+__constant_ffsll ( unsigned long long x ) {
+ int r = 0;
+
+ if ( ! ( x & 0x00000000ffffffffULL ) ) {
+ x >>= 32;
+ r += 32;
+ }
+ if ( ! ( x & 0x0000ffffUL ) ) {
+ x >>= 16;
+ r += 16;
+ }
+ if ( ! ( x & 0x00ff ) ) {
+ x >>= 8;
+ r += 8;
+ }
+ if ( ! ( x & 0x0f ) ) {
+ x >>= 4;
+ r += 4;
+ }
+ if ( ! ( x & 0x3 ) ) {
+ x >>= 2;
+ r += 2;
+ }
+ if ( ! ( x & 0x1 ) ) {
+ x >>= 1;
+ r += 1;
+ }
+ return ( x ? ( r + 1 ) : 0 );
+}
+
+/**
+ * Find first (i.e. least significant) set bit
+ *
+ * @v x Value
+ * @ret lsb Least significant bit set in value (LSB=1), or zero
+ */
+static inline __attribute__ (( always_inline )) int
+__constant_ffsl ( unsigned long x ) {
+ return __constant_ffsll ( x );
+}
+
+/**
+ * Find last (i.e. most significant) set bit
+ *
+ * @v x Value
+ * @ret msb Most significant bit set in value (LSB=1), or zero
+ */
static inline __attribute__ (( always_inline )) int
__constant_flsll ( unsigned long long x ) {
int r = 0;
@@ -35,38 +94,100 @@ __constant_flsll ( unsigned long long x ) {
x >>= 1;
r += 1;
}
- if ( x & 0x1 ) {
- r += 1;
- }
- return r;
+ return ( x ? ( r + 1 ) : 0 );
}
+/**
+ * Find last (i.e. most significant) set bit
+ *
+ * @v x Value
+ * @ret msb Most significant bit set in value (LSB=1), or zero
+ */
static inline __attribute__ (( always_inline )) int
__constant_flsl ( unsigned long x ) {
return __constant_flsll ( x );
}
+int __ffsll ( long long x );
+int __ffsl ( long x );
int __flsll ( long long x );
int __flsl ( long x );
+/**
+ * Find first (i.e. least significant) set bit
+ *
+ * @v x Value
+ * @ret lsb Least significant bit set in value (LSB=1), or zero
+ */
+#define ffsll( x ) \
+ ( __builtin_constant_p ( x ) ? __constant_ffsll ( x ) : __ffsll ( x ) )
+
+/**
+ * Find first (i.e. least significant) set bit
+ *
+ * @v x Value
+ * @ret lsb Least significant bit set in value (LSB=1), or zero
+ */
+#define ffsl( x ) \
+ ( __builtin_constant_p ( x ) ? __constant_ffsl ( x ) : __ffsl ( x ) )
+
+/**
+ * Find first (i.e. least significant) set bit
+ *
+ * @v x Value
+ * @ret lsb Least significant bit set in value (LSB=1), or zero
+ */
+#define ffs( x ) ffsl ( x )
+
+/**
+ * Find last (i.e. most significant) set bit
+ *
+ * @v x Value
+ * @ret msb Most significant bit set in value (LSB=1), or zero
+ */
#define flsll( x ) \
( __builtin_constant_p ( x ) ? __constant_flsll ( x ) : __flsll ( x ) )
+/**
+ * Find last (i.e. most significant) set bit
+ *
+ * @v x Value
+ * @ret msb Most significant bit set in value (LSB=1), or zero
+ */
#define flsl( x ) \
( __builtin_constant_p ( x ) ? __constant_flsl ( x ) : __flsl ( x ) )
+/**
+ * Find last (i.e. most significant) set bit
+ *
+ * @v x Value
+ * @ret msb Most significant bit set in value (LSB=1), or zero
+ */
#define fls( x ) flsl ( x )
-extern int strcasecmp ( const char *s1, const char *s2 );
-
+/**
+ * Copy memory
+ *
+ * @v src Source
+ * @v dest Destination
+ * @v len Length
+ */
static inline __attribute__ (( always_inline )) void
-bcopy ( const void *src, void *dest, size_t n ) {
- memmove ( dest, src, n );
+bcopy ( const void *src, void *dest, size_t len ) {
+ memmove ( dest, src, len );
}
+/**
+ * Zero memory
+ *
+ * @v dest Destination
+ * @v len Length
+ */
static inline __attribute__ (( always_inline )) void
-bzero ( void *s, size_t n ) {
- memset ( s, 0, n );
+bzero ( void *dest, size_t len ) {
+ memset ( dest, 0, len );
}
+int __pure strcasecmp ( const char *first, const char *second ) __nonnull;
+
#endif /* _STRINGS_H */
diff --git a/roms/ipxe/src/include/sys/time.h b/roms/ipxe/src/include/sys/time.h
index 2647d3588..6e2a24447 100644
--- a/roms/ipxe/src/include/sys/time.h
+++ b/roms/ipxe/src/include/sys/time.h
@@ -6,7 +6,7 @@
* Date and time
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
diff --git a/roms/ipxe/src/include/syslog.h b/roms/ipxe/src/include/syslog.h
index 93f32f867..748a4faec 100644
--- a/roms/ipxe/src/include/syslog.h
+++ b/roms/ipxe/src/include/syslog.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdarg.h>
#include <ipxe/ansiesc.h>
diff --git a/roms/ipxe/src/include/time.h b/roms/ipxe/src/include/time.h
index 452a544bb..462ac6999 100644
--- a/roms/ipxe/src/include/time.h
+++ b/roms/ipxe/src/include/time.h
@@ -6,7 +6,7 @@
* Date and time
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <sys/time.h>
#include <ipxe/time.h>
diff --git a/roms/ipxe/src/include/unistd.h b/roms/ipxe/src/include/unistd.h
index 3a50a2521..d09e1ae30 100644
--- a/roms/ipxe/src/include/unistd.h
+++ b/roms/ipxe/src/include/unistd.h
@@ -1,7 +1,7 @@
#ifndef _UNISTD_H
#define _UNISTD_H
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <stdarg.h>
diff --git a/roms/ipxe/src/include/usr/autoboot.h b/roms/ipxe/src/include/usr/autoboot.h
index bc51aae79..4db226b9c 100644
--- a/roms/ipxe/src/include/usr/autoboot.h
+++ b/roms/ipxe/src/include/usr/autoboot.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/device.h>
@@ -35,7 +35,7 @@ extern int uriboot ( struct uri *filename, struct uri *root_path, int drive,
extern struct uri *
fetch_next_server_and_filename ( struct settings *settings );
extern int netboot ( struct net_device *netdev );
-extern void ipxe ( struct net_device *netdev );
+extern int ipxe ( struct net_device *netdev );
extern int pxe_menu_boot ( struct net_device *netdev );
diff --git a/roms/ipxe/src/include/usr/dhcpmgmt.h b/roms/ipxe/src/include/usr/dhcpmgmt.h
index af1eceb17..ed669eb9d 100644
--- a/roms/ipxe/src/include/usr/dhcpmgmt.h
+++ b/roms/ipxe/src/include/usr/dhcpmgmt.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
struct net_device;
diff --git a/roms/ipxe/src/include/usr/fcmgmt.h b/roms/ipxe/src/include/usr/fcmgmt.h
index 9441cefb4..eb568fd20 100644
--- a/roms/ipxe/src/include/usr/fcmgmt.h
+++ b/roms/ipxe/src/include/usr/fcmgmt.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
struct fc_port;
struct fc_peer;
diff --git a/roms/ipxe/src/include/usr/ifmgmt.h b/roms/ipxe/src/include/usr/ifmgmt.h
index db77f1f1b..5c386327b 100644
--- a/roms/ipxe/src/include/usr/ifmgmt.h
+++ b/roms/ipxe/src/include/usr/ifmgmt.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
struct net_device;
struct net_device_configurator;
diff --git a/roms/ipxe/src/include/usr/imgmgmt.h b/roms/ipxe/src/include/usr/imgmgmt.h
index 5e25c562b..806df0bfb 100644
--- a/roms/ipxe/src/include/usr/imgmgmt.h
+++ b/roms/ipxe/src/include/usr/imgmgmt.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/image.h>
diff --git a/roms/ipxe/src/include/usr/imgtrust.h b/roms/ipxe/src/include/usr/imgtrust.h
index f47105af0..414e07a80 100644
--- a/roms/ipxe/src/include/usr/imgtrust.h
+++ b/roms/ipxe/src/include/usr/imgtrust.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/image.h>
diff --git a/roms/ipxe/src/include/usr/ipstat.h b/roms/ipxe/src/include/usr/ipstat.h
index 5ff8b40c3..803254bcb 100644
--- a/roms/ipxe/src/include/usr/ipstat.h
+++ b/roms/ipxe/src/include/usr/ipstat.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
extern void ipstat ( void );
diff --git a/roms/ipxe/src/include/usr/lotest.h b/roms/ipxe/src/include/usr/lotest.h
index aa4bbac4d..ce0fe5eda 100644
--- a/roms/ipxe/src/include/usr/lotest.h
+++ b/roms/ipxe/src/include/usr/lotest.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
extern int loopback_test ( struct net_device *sender,
struct net_device *receiver, size_t mtu );
diff --git a/roms/ipxe/src/include/usr/neighmgmt.h b/roms/ipxe/src/include/usr/neighmgmt.h
index 3c2b704af..06f03716e 100644
--- a/roms/ipxe/src/include/usr/neighmgmt.h
+++ b/roms/ipxe/src/include/usr/neighmgmt.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
extern void nstat ( void );
diff --git a/roms/ipxe/src/include/usr/pingmgmt.h b/roms/ipxe/src/include/usr/pingmgmt.h
index d4c2d6cd5..c7a8434be 100644
--- a/roms/ipxe/src/include/usr/pingmgmt.h
+++ b/roms/ipxe/src/include/usr/pingmgmt.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
diff --git a/roms/ipxe/src/include/usr/profstat.h b/roms/ipxe/src/include/usr/profstat.h
index 06ea251a0..b7812ca7f 100644
--- a/roms/ipxe/src/include/usr/profstat.h
+++ b/roms/ipxe/src/include/usr/profstat.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
extern void profstat ( void );
diff --git a/roms/ipxe/src/include/usr/prompt.h b/roms/ipxe/src/include/usr/prompt.h
index 57e43d2dc..8d3eeee3c 100644
--- a/roms/ipxe/src/include/usr/prompt.h
+++ b/roms/ipxe/src/include/usr/prompt.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
extern int prompt ( const char *text, unsigned long timeout, int key );
diff --git a/roms/ipxe/src/include/usr/route.h b/roms/ipxe/src/include/usr/route.h
index b914f4b84..7ec4a3509 100644
--- a/roms/ipxe/src/include/usr/route.h
+++ b/roms/ipxe/src/include/usr/route.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/tables.h>
diff --git a/roms/ipxe/src/include/usr/sync.h b/roms/ipxe/src/include/usr/sync.h
index 0047d4ed9..b6f12ad6e 100644
--- a/roms/ipxe/src/include/usr/sync.h
+++ b/roms/ipxe/src/include/usr/sync.h
@@ -7,7 +7,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
extern int sync ( unsigned long timeout );
diff --git a/roms/ipxe/src/arch/x86/include/valgrind/memcheck.h b/roms/ipxe/src/include/valgrind/memcheck.h
index 7d4b56d31..7d4b56d31 100644
--- a/roms/ipxe/src/arch/x86/include/valgrind/memcheck.h
+++ b/roms/ipxe/src/include/valgrind/memcheck.h
diff --git a/roms/ipxe/src/arch/x86/include/valgrind/valgrind.h b/roms/ipxe/src/include/valgrind/valgrind.h
index d48bbccae..d48bbccae 100644
--- a/roms/ipxe/src/arch/x86/include/valgrind/valgrind.h
+++ b/roms/ipxe/src/include/valgrind/valgrind.h
diff --git a/roms/ipxe/src/include/wchar.h b/roms/ipxe/src/include/wchar.h
index ba349aae8..d054b8d5b 100644
--- a/roms/ipxe/src/include/wchar.h
+++ b/roms/ipxe/src/include/wchar.h
@@ -1,7 +1,7 @@
#ifndef WCHAR_H
#define WCHAR_H
-FILE_LICENCE ( GPL2_ONLY );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
diff --git a/roms/ipxe/src/interface/bofm/bofm.c b/roms/ipxe/src/interface/bofm/bofm.c
index b0e92b27c..545088dc6 100644
--- a/roms/ipxe/src/interface/bofm/bofm.c
+++ b/roms/ipxe/src/interface/bofm/bofm.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <string.h>
diff --git a/roms/ipxe/src/interface/efi/efi_autoboot.c b/roms/ipxe/src/interface/efi/efi_autoboot.c
index ab0f36541..a9e807e23 100644
--- a/roms/ipxe/src/interface/efi/efi_autoboot.c
+++ b/roms/ipxe/src/interface/efi/efi_autoboot.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/efi/efi.h>
#include <ipxe/efi/efi_autoboot.h>
diff --git a/roms/ipxe/src/interface/efi/efi_bofm.c b/roms/ipxe/src/interface/efi/efi_bofm.c
index bdb705196..ea0e15f7f 100644
--- a/roms/ipxe/src/interface/efi/efi_bofm.c
+++ b/roms/ipxe/src/interface/efi/efi_bofm.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <errno.h>
#include <ipxe/bofm.h>
diff --git a/roms/ipxe/src/interface/efi/efi_debug.c b/roms/ipxe/src/interface/efi/efi_debug.c
index d23960140..473803951 100644
--- a/roms/ipxe/src/interface/efi/efi_debug.c
+++ b/roms/ipxe/src/interface/efi/efi_debug.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @file
@@ -326,7 +330,7 @@ const char * efi_devpath_text ( EFI_DEVICE_PATH_PROTOCOL *path ) {
max_len = ( ( sizeof ( text ) - 1 /* NUL */ ) / 2 /* "xx" */ );
if ( len > max_len )
len = max_len;
- base16_encode ( start, len, text );
+ base16_encode ( start, len, text, sizeof ( text ) );
return text;
}
diff --git a/roms/ipxe/src/interface/efi/efi_file.c b/roms/ipxe/src/interface/efi/efi_file.c
index 2ef3c5734..3715b70bf 100644
--- a/roms/ipxe/src/interface/efi/efi_file.c
+++ b/roms/ipxe/src/interface/efi/efi_file.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @file
diff --git a/roms/ipxe/src/interface/efi/efi_guid.c b/roms/ipxe/src/interface/efi/efi_guid.c
index 52ba58ae4..ab1c91e9f 100644
--- a/roms/ipxe/src/interface/efi/efi_guid.c
+++ b/roms/ipxe/src/interface/efi/efi_guid.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/efi/efi.h>
#include <ipxe/efi/Protocol/Arp.h>
diff --git a/roms/ipxe/src/interface/efi/efi_hii.c b/roms/ipxe/src/interface/efi/efi_hii.c
index 834060b54..0ea970e67 100644
--- a/roms/ipxe/src/interface/efi/efi_hii.c
+++ b/roms/ipxe/src/interface/efi/efi_hii.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdlib.h>
#include <stddef.h>
diff --git a/roms/ipxe/src/interface/efi/efi_pci.c b/roms/ipxe/src/interface/efi/efi_pci.c
index 86c781d82..97ea72bb9 100644
--- a/roms/ipxe/src/interface/efi/efi_pci.c
+++ b/roms/ipxe/src/interface/efi/efi_pci.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdlib.h>
#include <errno.h>
diff --git a/roms/ipxe/src/interface/efi/efi_reboot.c b/roms/ipxe/src/interface/efi/efi_reboot.c
index 96638c48e..35919221e 100644
--- a/roms/ipxe/src/interface/efi/efi_reboot.c
+++ b/roms/ipxe/src/interface/efi/efi_reboot.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @file
diff --git a/roms/ipxe/src/interface/efi/efi_snp.c b/roms/ipxe/src/interface/efi/efi_snp.c
index 67fba342e..3dfcc5e16 100644
--- a/roms/ipxe/src/interface/efi/efi_snp.c
+++ b/roms/ipxe/src/interface/efi/efi_snp.c
@@ -32,8 +32,10 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/efi/efi_driver.h>
#include <ipxe/efi/efi_strings.h>
#include <ipxe/efi/efi_utils.h>
+#include <ipxe/efi/efi_watchdog.h>
#include <ipxe/efi/efi_snp.h>
#include <usr/autoboot.h>
+#include <config/general.h>
/** List of SNP devices */
static LIST_HEAD ( efi_snp_devices );
@@ -41,6 +43,39 @@ static LIST_HEAD ( efi_snp_devices );
/** Network devices are currently claimed for use by iPXE */
static int efi_snp_claimed;
+/* Downgrade user experience if configured to do so
+ *
+ * The default UEFI user experience for network boot is somewhat
+ * excremental: only TFTP is available as a download protocol, and if
+ * anything goes wrong the user will be shown just a dot on an
+ * otherwise blank screen. (Some programmer was clearly determined to
+ * win a bet that they could outshine Apple at producing uninformative
+ * error messages.)
+ *
+ * For comparison, the default iPXE user experience provides the
+ * option to use protocols designed more recently than 1980 (such as
+ * HTTP and iSCSI), and if anything goes wrong the the user will be
+ * shown one of over 1200 different error messages, complete with a
+ * link to a wiki page describing that specific error.
+ *
+ * We default to upgrading the user experience to match that available
+ * in a "legacy" BIOS environment, by installing our own instance of
+ * EFI_LOAD_FILE_PROTOCOL.
+ *
+ * Note that unfortunately we can't sensibly provide the choice of
+ * both options to the user in the same build, because the UEFI boot
+ * menu ignores the multitude of ways in which a network device handle
+ * can be described and opaquely labels both menu entries as just "EFI
+ * Network".
+ */
+#ifdef EFI_DOWNGRADE_UX
+static EFI_GUID dummy_load_file_protocol_guid = {
+ 0x6f6c7323, 0x2077, 0x7523,
+ { 0x6e, 0x68, 0x65, 0x6c, 0x70, 0x66, 0x75, 0x6c }
+};
+#define efi_load_file_protocol_guid dummy_load_file_protocol_guid
+#endif
+
/**
* Set EFI SNP mode state
*
@@ -98,28 +133,43 @@ static void efi_snp_set_mode ( struct efi_snp_device *snpdev ) {
}
/**
+ * Flush transmit ring and receive queue
+ *
+ * @v snpdev SNP device
+ */
+static void efi_snp_flush ( struct efi_snp_device *snpdev ) {
+ struct io_buffer *iobuf;
+ struct io_buffer *tmp;
+
+ /* Reset transmit completion ring */
+ snpdev->tx_prod = 0;
+ snpdev->tx_cons = 0;
+
+ /* Discard any queued receive buffers */
+ list_for_each_entry_safe ( iobuf, tmp, &snpdev->rx, list ) {
+ list_del ( &iobuf->list );
+ free_iob ( iobuf );
+ }
+}
+
+/**
* Poll net device and count received packets
*
* @v snpdev SNP device
*/
static void efi_snp_poll ( struct efi_snp_device *snpdev ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
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++;
+ /* Poll network device */
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;
+ /* Retrieve any received packets */
+ while ( ( iobuf = netdev_rx_dequeue ( snpdev->netdev ) ) ) {
+ list_add_tail ( &iobuf->list, &snpdev->rx );
+ snpdev->interrupts |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
+ bs->SignalEvent ( &snpdev->snp.WaitForPacket );
+ }
}
/**
@@ -221,6 +271,7 @@ efi_snp_reset ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ext_verify ) {
netdev_close ( snpdev->netdev );
efi_snp_set_state ( snpdev );
+ efi_snp_flush ( snpdev );
if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) {
DBGC ( snpdev, "SNPDEV %p could not reopen %s: %s\n",
@@ -251,6 +302,7 @@ efi_snp_shutdown ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) {
netdev_close ( snpdev->netdev );
efi_snp_set_state ( snpdev );
+ efi_snp_flush ( snpdev );
return 0;
}
@@ -446,20 +498,22 @@ efi_snp_nvdata ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN read,
*
* @v snp SNP interface
* @v interrupts Interrupt status, or NULL
- * @v txbufs Recycled transmit buffer address, or NULL
+ * @v txbuf 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 ) {
+ UINT32 *interrupts, VOID **txbuf ) {
struct efi_snp_device *snpdev =
container_of ( snp, struct efi_snp_device, snp );
DBGC2 ( snpdev, "SNPDEV %p GET_STATUS", snpdev );
/* Fail if net device is currently claimed for use by iPXE */
- if ( efi_snp_claimed )
+ if ( efi_snp_claimed ) {
+ DBGC2 ( snpdev, "\n" );
return EFI_NOT_READY;
+ }
/* Poll the network device */
efi_snp_poll ( snpdev );
@@ -468,47 +522,19 @@ efi_snp_get_status ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
* 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--;
- }
+ *interrupts = snpdev->interrupts;
DBGC2 ( snpdev, " INTS:%02x", *interrupts );
+ snpdev->interrupts = 0;
}
- /* 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--;
+ /* TX completions */
+ if ( txbuf ) {
+ if ( snpdev->tx_prod != snpdev->tx_cons ) {
+ *txbuf = snpdev->tx[snpdev->tx_cons++ % EFI_SNP_NUM_TX];
} else {
- *txbufs = NULL;
+ *txbuf = NULL;
}
- DBGC2 ( snpdev, " TX:%s", ( *txbufs ? "some" : "none" ) );
+ DBGC2 ( snpdev, " TX:%p", *txbuf );
}
DBGC2 ( snpdev, "\n" );
@@ -537,6 +563,7 @@ efi_snp_transmit ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
struct io_buffer *iobuf;
size_t payload_len;
+ unsigned int tx_fill;
int rc;
DBGC2 ( snpdev, "SNPDEV %p TRANSMIT %p+%lx", snpdev, data,
@@ -624,12 +651,27 @@ efi_snp_transmit ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
goto err_tx;
}
- /* Record transmission as outstanding */
- snpdev->tx_count_interrupts++;
- snpdev->tx_count_txbufs++;
+ /* Record in transmit completion ring. If we run out of
+ * space, report the failure even though we have already
+ * transmitted the packet.
+ *
+ * This allows us to report completions only for packets for
+ * which we had reported successfully initiating transmission,
+ * while continuing to support clients that never poll for
+ * transmit completions.
+ */
+ tx_fill = ( snpdev->tx_prod - snpdev->tx_cons );
+ if ( tx_fill >= EFI_SNP_NUM_TX ) {
+ DBGC ( snpdev, "SNPDEV %p TX completion ring full\n", snpdev );
+ rc = -ENOBUFS;
+ goto err_ring_full;
+ }
+ snpdev->tx[ snpdev->tx_prod++ % EFI_SNP_NUM_TX ] = data;
+ snpdev->interrupts |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
return 0;
+ err_ring_full:
err_tx:
err_ll_push:
free_iob ( iobuf );
@@ -676,12 +718,13 @@ efi_snp_receive ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
efi_snp_poll ( snpdev );
/* Dequeue a packet, if one is available */
- iobuf = netdev_rx_dequeue ( snpdev->netdev );
+ iobuf = list_first_entry ( &snpdev->rx, struct io_buffer, list );
if ( ! iobuf ) {
DBGC2 ( snpdev, "\n" );
rc = -EAGAIN;
goto out_no_packet;
}
+ list_del ( &iobuf->list );
DBGC2 ( snpdev, "+%zx\n", iob_len ( iobuf ) );
/* Return packet to caller */
@@ -721,9 +764,8 @@ efi_snp_receive ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
* @v event Event
* @v context Event context
*/
-static VOID EFIAPI efi_snp_wait_for_packet ( EFI_EVENT event,
+static VOID EFIAPI efi_snp_wait_for_packet ( EFI_EVENT event __unused,
VOID *context ) {
- EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
struct efi_snp_device *snpdev = context;
DBGCP ( snpdev, "SNPDEV %p WAIT_FOR_PACKET\n", snpdev );
@@ -738,14 +780,6 @@ static VOID EFIAPI efi_snp_wait_for_packet ( EFI_EVENT event,
/* 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 */
@@ -837,6 +871,7 @@ efi_snp_load_file ( EFI_LOAD_FILE_PROTOCOL *load_file,
struct efi_snp_device *snpdev =
container_of ( load_file, struct efi_snp_device, load_file );
struct net_device *netdev = snpdev->netdev;
+ int rc;
/* Fail unless this is a boot attempt */
if ( ! booting ) {
@@ -848,14 +883,17 @@ efi_snp_load_file ( EFI_LOAD_FILE_PROTOCOL *load_file,
/* Claim network devices for use by iPXE */
efi_snp_claim();
+ /* Start watchdog holdoff timer */
+ efi_watchdog_start();
+
/* Boot from network device */
- ipxe ( netdev );
+ if ( ( rc = ipxe ( netdev ) ) != 0 )
+ goto err_ipxe;
- /* Release network devices for use via SNP */
+ err_ipxe:
+ efi_watchdog_stop();
efi_snp_release();
-
- /* Assume boot process was aborted */
- return EFI_ABORTED;
+ return EFIRC ( rc );
}
/** Load file protocol */
@@ -922,6 +960,7 @@ static int efi_snp_probe ( struct net_device *netdev ) {
}
snpdev->netdev = netdev_get ( netdev );
snpdev->efidev = efidev;
+ INIT_LIST_HEAD ( &snpdev->rx );
/* Sanity check */
if ( netdev->ll_protocol->ll_addr_len > sizeof ( EFI_MAC_ADDRESS ) ) {
diff --git a/roms/ipxe/src/interface/efi/efi_snp_hii.c b/roms/ipxe/src/interface/efi/efi_snp_hii.c
index c49c76a32..720402bdb 100644
--- a/roms/ipxe/src/interface/efi/efi_snp_hii.c
+++ b/roms/ipxe/src/interface/efi/efi_snp_hii.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @file
@@ -59,6 +63,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/efi/efi_hii.h>
#include <ipxe/efi/efi_snp.h>
#include <ipxe/efi/efi_strings.h>
+#include <config/branding.h>
/** EFI platform setup formset GUID */
static EFI_GUID efi_hii_platform_setup_formset_guid
@@ -136,7 +141,7 @@ static void efi_snp_hii_questions ( struct efi_snp_device *snpdev,
previous = setting;
name_id = efi_ifr_string ( ifr, "%s", setting->name );
prompt_id = efi_ifr_string ( ifr, "%s", setting->description );
- help_id = efi_ifr_string ( ifr, "http://ipxe.org/cfg/%s",
+ help_id = efi_ifr_string ( ifr, PRODUCT_SETTING_URI,
setting->name );
question_id = setting->tag;
efi_ifr_string_op ( ifr, prompt_id, help_id,
diff --git a/roms/ipxe/src/interface/efi/efi_strings.c b/roms/ipxe/src/interface/efi/efi_strings.c
index 751589b46..aa3afc64f 100644
--- a/roms/ipxe/src/interface/efi/efi_strings.c
+++ b/roms/ipxe/src/interface/efi/efi_strings.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <stdarg.h>
diff --git a/roms/ipxe/src/interface/efi/efi_time.c b/roms/ipxe/src/interface/efi/efi_time.c
new file mode 100644
index 000000000..983a0ef5c
--- /dev/null
+++ b/roms/ipxe/src/interface/efi/efi_time.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2015 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <ipxe/time.h>
+#include <ipxe/efi/efi.h>
+
+/** @file
+ *
+ * EFI time source
+ *
+ */
+
+/**
+ * Get current time in seconds
+ *
+ * @ret time Time, in seconds
+ */
+static time_t efi_get_time ( void ) {
+ EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices;
+ EFI_TIME time;
+ struct tm tm;
+ EFI_STATUS efirc;
+ int rc;
+
+ /* Get current time and date */
+ if ( ( efirc = rs->GetTime ( &time, NULL ) ) != 0 ) {
+ rc = -EEFI ( efirc );
+ DBGC ( rs, "EFITIME could not get system time: %s\n",
+ strerror ( rc ) );
+ /* Nothing meaningful we can return */
+ return 0;
+ }
+
+ /* Construct broken-down time */
+ memset ( &tm, 0, sizeof ( tm ) );
+ tm.tm_sec = time.Second;
+ tm.tm_min = time.Minute;
+ tm.tm_hour = time.Hour;
+ tm.tm_mday = time.Day;
+ tm.tm_mon = ( time.Month - 1 );
+ tm.tm_year = ( time.Year - 1900 );
+ DBGC ( rs, "EFITIME is %04d-%02d-%02d %02d:%02d:%02d\n",
+ ( tm.tm_year + 1900 ), ( tm.tm_mon + 1 ),
+ tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec );
+
+ /* Convert to seconds since the Epoch */
+ return mktime ( &tm );
+}
+
+PROVIDE_TIME ( efi, time_now, efi_get_time );
diff --git a/roms/ipxe/src/interface/efi/efi_timer.c b/roms/ipxe/src/interface/efi/efi_timer.c
index 7a1ff7869..81620c92c 100644
--- a/roms/ipxe/src/interface/efi/efi_timer.c
+++ b/roms/ipxe/src/interface/efi/efi_timer.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <errno.h>
diff --git a/roms/ipxe/src/interface/efi/efi_uaccess.c b/roms/ipxe/src/interface/efi/efi_uaccess.c
index 8b429b9ee..e058be66b 100644
--- a/roms/ipxe/src/interface/efi/efi_uaccess.c
+++ b/roms/ipxe/src/interface/efi/efi_uaccess.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/uaccess.h>
#include <ipxe/efi/efi.h>
diff --git a/roms/ipxe/src/interface/efi/efi_umalloc.c b/roms/ipxe/src/interface/efi/efi_umalloc.c
index 356efaa6f..e3f1dacc2 100644
--- a/roms/ipxe/src/interface/efi/efi_umalloc.c
+++ b/roms/ipxe/src/interface/efi/efi_umalloc.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <errno.h>
diff --git a/roms/ipxe/src/interface/efi/efi_watchdog.c b/roms/ipxe/src/interface/efi/efi_watchdog.c
new file mode 100644
index 000000000..7061f81d8
--- /dev/null
+++ b/roms/ipxe/src/interface/efi/efi_watchdog.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/**
+ * @file
+ *
+ * EFI watchdog holdoff timer
+ *
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <ipxe/retry.h>
+#include <ipxe/timer.h>
+#include <ipxe/efi/efi.h>
+#include <ipxe/efi/efi_watchdog.h>
+
+/** Watchdog holdoff interval (in seconds) */
+#define WATCHDOG_HOLDOFF_SECS 10
+
+/** Watchdog timeout (in seconds) */
+#define WATCHDOG_TIMEOUT_SECS ( 5 * 60 )
+
+/** Watchdog code (to be logged on watchdog timeout) */
+#define WATCHDOG_CODE 0x6950584544454144ULL
+
+/** Watchdog data (to be logged on watchdog timeout) */
+#define WATCHDOG_DATA L"iPXE";
+
+/**
+ * Hold off watchdog timer
+ *
+ * @v retry Retry timer
+ * @v over Failure indicator
+ */
+static void efi_watchdog_expired ( struct retry_timer *timer,
+ int over __unused ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ static CHAR16 data[] = WATCHDOG_DATA;
+ EFI_STATUS efirc;
+ int rc;
+
+ DBGC2 ( timer, "EFI holding off watchdog timer\n" );
+
+ /* Restart this holdoff timer */
+ start_timer_fixed ( timer, ( WATCHDOG_HOLDOFF_SECS * TICKS_PER_SEC ) );
+
+ /* Reset watchdog timer */
+ if ( ( efirc = bs->SetWatchdogTimer ( WATCHDOG_TIMEOUT_SECS,
+ WATCHDOG_CODE, sizeof ( data ),
+ data ) ) != 0 ) {
+ rc = -EEFI ( efirc );
+ DBGC ( timer, "EFI could not set watchdog timer: %s\n",
+ strerror ( rc ) );
+ return;
+ }
+}
+
+/** Watchdog holdoff timer */
+struct retry_timer efi_watchdog = TIMER_INIT ( efi_watchdog_expired );
diff --git a/roms/ipxe/src/interface/efi/efi_wrap.c b/roms/ipxe/src/interface/efi/efi_wrap.c
index ff46b76ed..2ea184e97 100644
--- a/roms/ipxe/src/interface/efi/efi_wrap.c
+++ b/roms/ipxe/src/interface/efi/efi_wrap.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @file
diff --git a/roms/ipxe/src/interface/hyperv/vmbus.c b/roms/ipxe/src/interface/hyperv/vmbus.c
new file mode 100644
index 000000000..795929eae
--- /dev/null
+++ b/roms/ipxe/src/interface/hyperv/vmbus.c
@@ -0,0 +1,1333 @@
+/*
+ * Copyright (C) 2014 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/** @file
+ *
+ * Hyper-V virtual machine bus
+ *
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <ipxe/nap.h>
+#include <ipxe/malloc.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/hyperv.h>
+#include <ipxe/vmbus.h>
+
+/** VMBus initial GPADL ID
+ *
+ * This is an opaque value with no meaning. The Linux kernel uses
+ * 0xe1e10.
+ */
+#define VMBUS_GPADL_MAGIC 0x18ae0000
+
+/**
+ * Post message
+ *
+ * @v hv Hyper-V hypervisor
+ * @v header Message header
+ * @v len Length of message (including header)
+ * @ret rc Return status code
+ */
+static int vmbus_post_message ( struct hv_hypervisor *hv,
+ const struct vmbus_message_header *header,
+ size_t len ) {
+ struct vmbus *vmbus = hv->vmbus;
+ int rc;
+
+ /* Post message */
+ if ( ( rc = hv_post_message ( hv, VMBUS_MESSAGE_ID, VMBUS_MESSAGE_TYPE,
+ header, len ) ) != 0 ) {
+ DBGC ( vmbus, "VMBUS %p could not post message: %s\n",
+ vmbus, strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Post empty message
+ *
+ * @v hv Hyper-V hypervisor
+ * @v type Message type
+ * @ret rc Return status code
+ */
+static int vmbus_post_empty_message ( struct hv_hypervisor *hv,
+ unsigned int type ) {
+ struct vmbus_message_header header = { .type = cpu_to_le32 ( type ) };
+
+ return vmbus_post_message ( hv, &header, sizeof ( header ) );
+}
+
+/**
+ * Wait for received message
+ *
+ * @v hv Hyper-V hypervisor
+ * @ret rc Return status code
+ */
+static int vmbus_wait_for_message ( struct hv_hypervisor *hv ) {
+ struct vmbus *vmbus = hv->vmbus;
+ int rc;
+
+ /* Wait for message */
+ if ( ( rc = hv_wait_for_message ( hv, VMBUS_MESSAGE_SINT ) ) != 0 ) {
+ DBGC ( vmbus, "VMBUS %p failed waiting for message: %s\n",
+ vmbus, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Sanity check */
+ if ( hv->message->received.type != cpu_to_le32 ( VMBUS_MESSAGE_TYPE ) ){
+ DBGC ( vmbus, "VMBUS %p invalid message type %d\n",
+ vmbus, le32_to_cpu ( hv->message->received.type ) );
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * Initiate contact
+ *
+ * @v hv Hyper-V hypervisor
+ * @v raw VMBus protocol (raw) version
+ * @ret rc Return status code
+ */
+static int vmbus_initiate_contact ( struct hv_hypervisor *hv,
+ unsigned int raw ) {
+ struct vmbus *vmbus = hv->vmbus;
+ const struct vmbus_version_response *version = &vmbus->message->version;
+ struct vmbus_initiate_contact initiate;
+ int rc;
+
+ /* Construct message */
+ memset ( &initiate, 0, sizeof ( initiate ) );
+ initiate.header.type = cpu_to_le32 ( VMBUS_INITIATE_CONTACT );
+ initiate.version.raw = cpu_to_le32 ( raw );
+ initiate.intr = virt_to_phys ( vmbus->intr );
+ initiate.monitor_in = virt_to_phys ( vmbus->monitor_in );
+ initiate.monitor_out = virt_to_phys ( vmbus->monitor_out );
+
+ /* Post message */
+ if ( ( rc = vmbus_post_message ( hv, &initiate.header,
+ sizeof ( initiate ) ) ) != 0 )
+ return rc;
+
+ /* Wait for response */
+ if ( ( rc = vmbus_wait_for_message ( hv ) ) != 0 )
+ return rc;
+
+ /* Check response */
+ if ( version->header.type != cpu_to_le32 ( VMBUS_VERSION_RESPONSE ) ) {
+ DBGC ( vmbus, "VMBUS %p unexpected version response type %d\n",
+ vmbus, le32_to_cpu ( version->header.type ) );
+ return -EPROTO;
+ }
+ if ( ! version->supported ) {
+ DBGC ( vmbus, "VMBUS %p requested version not supported\n",
+ vmbus );
+ return -ENOTSUP;
+ }
+ if ( version->version.raw != cpu_to_le32 ( raw ) ) {
+ DBGC ( vmbus, "VMBUS %p unexpected version %d.%d\n",
+ vmbus, le16_to_cpu ( version->version.major ),
+ le16_to_cpu ( version->version.minor ) );
+ return -EPROTO;
+ }
+
+ DBGC ( vmbus, "VMBUS %p initiated contact using version %d.%d\n",
+ vmbus, le16_to_cpu ( version->version.major ),
+ le16_to_cpu ( version->version.minor ) );
+ return 0;
+}
+
+/**
+ * Terminate contact
+ *
+ * @v hv Hyper-V hypervisor
+ * @ret rc Return status code
+ */
+static int vmbus_unload ( struct hv_hypervisor *hv ) {
+ struct vmbus *vmbus = hv->vmbus;
+ const struct vmbus_message_header *header = &vmbus->message->header;
+ int rc;
+
+ /* Post message */
+ if ( ( rc = vmbus_post_empty_message ( hv, VMBUS_UNLOAD ) ) != 0 )
+ return rc;
+
+ /* Wait for response */
+ if ( ( rc = vmbus_wait_for_message ( hv ) ) != 0 )
+ return rc;
+
+ /* Check response */
+ if ( header->type != cpu_to_le32 ( VMBUS_UNLOAD_RESPONSE ) ) {
+ DBGC ( vmbus, "VMBUS %p unexpected unload response type %d\n",
+ vmbus, le32_to_cpu ( header->type ) );
+ return -EPROTO;
+ }
+
+ return 0;
+}
+
+/**
+ * Negotiate protocol version
+ *
+ * @v hv Hyper-V hypervisor
+ * @ret rc Return status code
+ */
+static int vmbus_negotiate_version ( struct hv_hypervisor *hv ) {
+ int rc;
+
+ /* We require the ability to disconnect from and reconnect to
+ * VMBus; if we don't have this then there is no (viable) way
+ * for a loaded operating system to continue to use any VMBus
+ * devices. (There is also a small but non-zero risk that the
+ * host will continue to write to our interrupt and monitor
+ * pages, since the VMBUS_UNLOAD message in earlier versions
+ * is essentially a no-op.)
+ *
+ * This requires us to ensure that the host supports protocol
+ * version 3.0 (VMBUS_VERSION_WIN8_1). However, we can't
+ * actually _use_ protocol version 3.0, since doing so causes
+ * an iSCSI-booted Windows Server 2012 R2 VM to crash due to a
+ * NULL pointer dereference in vmbus.sys.
+ *
+ * To work around this problem, we first ensure that we can
+ * connect using protocol v3.0, then disconnect and reconnect
+ * using the oldest known protocol.
+ */
+
+ /* Initiate contact to check for required protocol support */
+ if ( ( rc = vmbus_initiate_contact ( hv, VMBUS_VERSION_WIN8_1 ) ) != 0 )
+ return rc;
+
+ /* Terminate contact */
+ if ( ( rc = vmbus_unload ( hv ) ) != 0 )
+ return rc;
+
+ /* Reinitiate contact using the oldest known protocol version */
+ if ( ( rc = vmbus_initiate_contact ( hv, VMBUS_VERSION_WS2008 ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/**
+ * Establish GPA descriptor list
+ *
+ * @v vmdev VMBus device
+ * @v data Data buffer
+ * @v len Length of data buffer
+ * @ret gpadl GPADL ID, or negative error
+ */
+int vmbus_establish_gpadl ( struct vmbus_device *vmdev, userptr_t data,
+ size_t len ) {
+ struct hv_hypervisor *hv = vmdev->hv;
+ struct vmbus *vmbus = hv->vmbus;
+ physaddr_t addr = user_to_phys ( data, 0 );
+ unsigned int pfn_count = hv_pfn_count ( addr, len );
+ struct {
+ struct vmbus_gpadl_header gpadlhdr;
+ struct vmbus_gpa_range range;
+ uint64_t pfn[pfn_count];
+ } __attribute__ (( packed )) gpadlhdr;
+ const struct vmbus_gpadl_created *created = &vmbus->message->created;
+ static unsigned int gpadl = VMBUS_GPADL_MAGIC;
+ unsigned int i;
+ int rc;
+
+ /* Allocate GPADL ID */
+ gpadl++;
+
+ /* Construct message */
+ memset ( &gpadlhdr, 0, sizeof ( gpadlhdr ) );
+ gpadlhdr.gpadlhdr.header.type = cpu_to_le32 ( VMBUS_GPADL_HEADER );
+ gpadlhdr.gpadlhdr.channel = cpu_to_le32 ( vmdev->channel );
+ gpadlhdr.gpadlhdr.gpadl = cpu_to_le32 ( gpadl );
+ gpadlhdr.gpadlhdr.range_len =
+ cpu_to_le16 ( ( sizeof ( gpadlhdr.range ) +
+ sizeof ( gpadlhdr.pfn ) ) );
+ gpadlhdr.gpadlhdr.range_count = cpu_to_le16 ( 1 );
+ gpadlhdr.range.len = cpu_to_le32 ( len );
+ gpadlhdr.range.offset = cpu_to_le32 ( addr & ( PAGE_SIZE - 1 ) );
+ for ( i = 0 ; i < pfn_count ; i++ )
+ gpadlhdr.pfn[i] = ( ( addr / PAGE_SIZE ) + i );
+
+ /* Post message */
+ if ( ( rc = vmbus_post_message ( hv, &gpadlhdr.gpadlhdr.header,
+ sizeof ( gpadlhdr ) ) ) != 0 )
+ return rc;
+
+ /* Wait for response */
+ if ( ( rc = vmbus_wait_for_message ( hv ) ) != 0 )
+ return rc;
+
+ /* Check response */
+ if ( created->header.type != cpu_to_le32 ( VMBUS_GPADL_CREATED ) ) {
+ DBGC ( vmdev, "VMBUS %s unexpected GPADL response type %d\n",
+ vmdev->dev.name, le32_to_cpu ( created->header.type ) );
+ return -EPROTO;
+ }
+ if ( created->channel != cpu_to_le32 ( vmdev->channel ) ) {
+ DBGC ( vmdev, "VMBUS %s unexpected GPADL channel %d\n",
+ vmdev->dev.name, le32_to_cpu ( created->channel ) );
+ return -EPROTO;
+ }
+ if ( created->gpadl != cpu_to_le32 ( gpadl ) ) {
+ DBGC ( vmdev, "VMBUS %s unexpected GPADL ID %#08x\n",
+ vmdev->dev.name, le32_to_cpu ( created->gpadl ) );
+ return -EPROTO;
+ }
+ if ( created->status != 0 ) {
+ DBGC ( vmdev, "VMBUS %s GPADL creation failed: %#08x\n",
+ vmdev->dev.name, le32_to_cpu ( created->status ) );
+ return -EPROTO;
+ }
+
+ DBGC ( vmdev, "VMBUS %s GPADL %#08x is [%08lx,%08lx)\n",
+ vmdev->dev.name, gpadl, addr, ( addr + len ) );
+ return gpadl;
+}
+
+/**
+ * Tear down GPA descriptor list
+ *
+ * @v vmdev VMBus device
+ * @v gpadl GPADL ID
+ * @ret rc Return status code
+ */
+int vmbus_gpadl_teardown ( struct vmbus_device *vmdev, unsigned int gpadl ) {
+ struct hv_hypervisor *hv = vmdev->hv;
+ struct vmbus *vmbus = hv->vmbus;
+ struct vmbus_gpadl_teardown teardown;
+ const struct vmbus_gpadl_torndown *torndown = &vmbus->message->torndown;
+ int rc;
+
+ /* Construct message */
+ memset ( &teardown, 0, sizeof ( teardown ) );
+ teardown.header.type = cpu_to_le32 ( VMBUS_GPADL_TEARDOWN );
+ teardown.channel = cpu_to_le32 ( vmdev->channel );
+ teardown.gpadl = cpu_to_le32 ( gpadl );
+
+ /* Post message */
+ if ( ( rc = vmbus_post_message ( hv, &teardown.header,
+ sizeof ( teardown ) ) ) != 0 )
+ return rc;
+
+ /* Wait for response */
+ if ( ( rc = vmbus_wait_for_message ( hv ) ) != 0 )
+ return rc;
+
+ /* Check response */
+ if ( torndown->header.type != cpu_to_le32 ( VMBUS_GPADL_TORNDOWN ) ) {
+ DBGC ( vmdev, "VMBUS %s unexpected GPADL response type %d\n",
+ vmdev->dev.name, le32_to_cpu ( torndown->header.type ) );
+ return -EPROTO;
+ }
+ if ( torndown->gpadl != cpu_to_le32 ( gpadl ) ) {
+ DBGC ( vmdev, "VMBUS %s unexpected GPADL ID %#08x\n",
+ vmdev->dev.name, le32_to_cpu ( torndown->gpadl ) );
+ return -EPROTO;
+ }
+
+ return 0;
+}
+
+/**
+ * Open VMBus channel
+ *
+ * @v vmdev VMBus device
+ * @v op Channel operations
+ * @v out_len Outbound ring buffer length
+ * @v in_len Inbound ring buffer length
+ * @v mtu Maximum expected data packet length (including headers)
+ * @ret rc Return status code
+ *
+ * Both outbound and inbound ring buffer lengths must be a power of
+ * two and a multiple of PAGE_SIZE. The requirement to be a power of
+ * two is a policy decision taken to simplify the ring buffer indexing
+ * logic.
+ */
+int vmbus_open ( struct vmbus_device *vmdev,
+ struct vmbus_channel_operations *op,
+ size_t out_len, size_t in_len, size_t mtu ) {
+ struct hv_hypervisor *hv = vmdev->hv;
+ struct vmbus *vmbus = hv->vmbus;
+ struct vmbus_open_channel open;
+ const struct vmbus_open_channel_result *opened =
+ &vmbus->message->opened;
+ size_t len;
+ void *ring;
+ void *packet;
+ int gpadl;
+ uint32_t open_id;
+ int rc;
+
+ /* Sanity checks */
+ assert ( ( out_len % PAGE_SIZE ) == 0 );
+ assert ( ( out_len & ( out_len - 1 ) ) == 0 );
+ assert ( ( in_len % PAGE_SIZE ) == 0 );
+ assert ( ( in_len & ( in_len - 1 ) ) == 0 );
+ assert ( mtu >= ( sizeof ( struct vmbus_packet_header ) +
+ sizeof ( struct vmbus_packet_footer ) ) );
+
+ /* Allocate packet buffer */
+ packet = malloc ( mtu );
+ if ( ! packet ) {
+ rc = -ENOMEM;
+ goto err_alloc_packet;
+ }
+
+ /* Allocate ring buffer */
+ len = ( sizeof ( *vmdev->out ) + out_len +
+ sizeof ( *vmdev->in ) + in_len );
+ assert ( ( len % PAGE_SIZE ) == 0 );
+ ring = malloc_dma ( len, PAGE_SIZE );
+ if ( ! ring ) {
+ rc = -ENOMEM;
+ goto err_alloc_ring;
+ }
+ memset ( ring, 0, len );
+
+ /* Establish GPADL for ring buffer */
+ gpadl = vmbus_establish_gpadl ( vmdev, virt_to_user ( ring ), len );
+ if ( gpadl < 0 ) {
+ rc = gpadl;
+ goto err_establish;
+ }
+
+ /* Construct message */
+ memset ( &open, 0, sizeof ( open ) );
+ open.header.type = cpu_to_le32 ( VMBUS_OPEN_CHANNEL );
+ open.channel = cpu_to_le32 ( vmdev->channel );
+ open_id = random();
+ open.id = open_id; /* Opaque random value: endianness irrelevant */
+ open.gpadl = cpu_to_le32 ( gpadl );
+ open.out_pages = ( ( sizeof ( *vmdev->out ) / PAGE_SIZE ) +
+ ( out_len / PAGE_SIZE ) );
+
+ /* Post message */
+ if ( ( rc = vmbus_post_message ( hv, &open.header,
+ sizeof ( open ) ) ) != 0 )
+ return rc;
+
+ /* Wait for response */
+ if ( ( rc = vmbus_wait_for_message ( hv ) ) != 0 )
+ return rc;
+
+ /* Check response */
+ if ( opened->header.type != cpu_to_le32 ( VMBUS_OPEN_CHANNEL_RESULT ) ){
+ DBGC ( vmdev, "VMBUS %s unexpected open response type %d\n",
+ vmdev->dev.name, le32_to_cpu ( opened->header.type ) );
+ return -EPROTO;
+ }
+ if ( opened->channel != cpu_to_le32 ( vmdev->channel ) ) {
+ DBGC ( vmdev, "VMBUS %s unexpected opened channel %#08x\n",
+ vmdev->dev.name, le32_to_cpu ( opened->channel ) );
+ return -EPROTO;
+ }
+ if ( opened->id != open_id /* Non-endian */ ) {
+ DBGC ( vmdev, "VMBUS %s unexpected open ID %#08x\n",
+ vmdev->dev.name, le32_to_cpu ( opened->id ) );
+ return -EPROTO;
+ }
+ if ( opened->status != 0 ) {
+ DBGC ( vmdev, "VMBUS %s open failed: %#08x\n",
+ vmdev->dev.name, le32_to_cpu ( opened->status ) );
+ return -EPROTO;
+ }
+
+ /* Store channel parameters */
+ vmdev->out_len = out_len;
+ vmdev->in_len = in_len;
+ vmdev->out = ring;
+ vmdev->in = ( ring + sizeof ( *vmdev->out ) + out_len );
+ vmdev->gpadl = gpadl;
+ vmdev->op = op;
+ vmdev->mtu = mtu;
+ vmdev->packet = packet;
+
+ DBGC ( vmdev, "VMBUS %s channel GPADL %#08x ring "
+ "[%#08lx,%#08lx,%#08lx)\n", vmdev->dev.name, vmdev->gpadl,
+ virt_to_phys ( vmdev->out ), virt_to_phys ( vmdev->in ),
+ ( virt_to_phys ( vmdev->out ) + len ) );
+ return 0;
+
+ vmbus_gpadl_teardown ( vmdev, vmdev->gpadl );
+ err_establish:
+ free_dma ( ring, len );
+ err_alloc_ring:
+ free ( packet );
+ err_alloc_packet:
+ return rc;
+}
+
+/**
+ * Close VMBus channel
+ *
+ * @v vmdev VMBus device
+ */
+void vmbus_close ( struct vmbus_device *vmdev ) {
+ struct hv_hypervisor *hv = vmdev->hv;
+ struct vmbus_close_channel close;
+ size_t len;
+ int rc;
+
+ /* Construct message */
+ memset ( &close, 0, sizeof ( close ) );
+ close.header.type = cpu_to_le32 ( VMBUS_CLOSE_CHANNEL );
+ close.channel = cpu_to_le32 ( vmdev->channel );
+
+ /* Post message */
+ if ( ( rc = vmbus_post_message ( hv, &close.header,
+ sizeof ( close ) ) ) != 0 ) {
+ DBGC ( vmdev, "VMBUS %s failed to close: %s\n",
+ vmdev->dev.name, strerror ( rc ) );
+ /* Continue to attempt to tear down GPADL, so that our
+ * memory is no longer accessible by the remote VM.
+ */
+ }
+
+ /* Tear down GPADL */
+ if ( ( rc = vmbus_gpadl_teardown ( vmdev,
+ vmdev->gpadl ) ) != 0 ) {
+ DBGC ( vmdev, "VMBUS %s failed to tear down channel GPADL: "
+ "%s\n", vmdev->dev.name, strerror ( rc ) );
+ /* We can't prevent the remote VM from continuing to
+ * access this memory, so leak it.
+ */
+ return;
+ }
+
+ /* Free ring buffer */
+ len = ( sizeof ( *vmdev->out ) + vmdev->out_len +
+ sizeof ( *vmdev->in ) + vmdev->in_len );
+ free_dma ( vmdev->out, len );
+ vmdev->out = NULL;
+ vmdev->in = NULL;
+
+ /* Free packet buffer */
+ free ( vmdev->packet );
+ vmdev->packet = NULL;
+
+ DBGC ( vmdev, "VMBUS %s closed\n", vmdev->dev.name );
+}
+
+/**
+ * Signal channel via monitor page
+ *
+ * @v vmdev VMBus device
+ */
+static void vmbus_signal_monitor ( struct vmbus_device *vmdev ) {
+ struct hv_hypervisor *hv = vmdev->hv;
+ struct vmbus *vmbus = hv->vmbus;
+ struct hv_monitor_trigger *trigger;
+ unsigned int group;
+ unsigned int bit;
+
+ /* Set bit in monitor trigger group */
+ group = ( vmdev->monitor / ( 8 * sizeof ( trigger->pending ) ));
+ bit = ( vmdev->monitor % ( 8 * sizeof ( trigger->pending ) ) );
+ trigger = &vmbus->monitor_out->trigger[group];
+ hv_set_bit ( trigger, bit );
+}
+
+/**
+ * Signal channel via hypervisor event
+ *
+ * @v vmdev VMBus device
+ */
+static void vmbus_signal_event ( struct vmbus_device *vmdev ) {
+ struct hv_hypervisor *hv = vmdev->hv;
+ int rc;
+
+ /* Signal hypervisor event */
+ if ( ( rc = hv_signal_event ( hv, VMBUS_EVENT_ID, 0 ) ) != 0 ) {
+ DBGC ( vmdev, "VMBUS %s could not signal event: %s\n",
+ vmdev->dev.name, strerror ( rc ) );
+ return;
+ }
+}
+
+/**
+ * Fill outbound ring buffer
+ *
+ * @v vmdev VMBus device
+ * @v prod Producer index
+ * @v data Data
+ * @v len Length
+ * @ret prod New producer index
+ *
+ * The caller must ensure that there is sufficient space in the ring
+ * buffer.
+ */
+static size_t vmbus_produce ( struct vmbus_device *vmdev, size_t prod,
+ const void *data, size_t len ) {
+ size_t first;
+ size_t second;
+
+ /* Determine fragment lengths */
+ first = ( vmdev->out_len - prod );
+ if ( first > len )
+ first = len;
+ second = ( len - first );
+
+ /* Copy fragment(s) */
+ memcpy ( &vmdev->out->data[prod], data, first );
+ if ( second )
+ memcpy ( &vmdev->out->data[0], ( data + first ), second );
+
+ return ( ( prod + len ) & ( vmdev->out_len - 1 ) );
+}
+
+/**
+ * Consume inbound ring buffer
+ *
+ * @v vmdev VMBus device
+ * @v cons Consumer index
+ * @v data Data buffer, or NULL
+ * @v len Length to consume
+ * @ret cons New consumer index
+ */
+static size_t vmbus_consume ( struct vmbus_device *vmdev, size_t cons,
+ void *data, size_t len ) {
+ size_t first;
+ size_t second;
+
+ /* Determine fragment lengths */
+ first = ( vmdev->in_len - cons );
+ if ( first > len )
+ first = len;
+ second = ( len - first );
+
+ /* Copy fragment(s) */
+ memcpy ( data, &vmdev->in->data[cons], first );
+ if ( second )
+ memcpy ( ( data + first ), &vmdev->in->data[0], second );
+
+ return ( ( cons + len ) & ( vmdev->in_len - 1 ) );
+}
+
+/**
+ * Send packet via ring buffer
+ *
+ * @v vmdev VMBus device
+ * @v header Packet header
+ * @v data Data
+ * @v len Length of data
+ * @ret rc Return status code
+ *
+ * Send a packet via the outbound ring buffer. All fields in the
+ * packet header must be filled in, with the exception of the total
+ * packet length.
+ */
+static int vmbus_send ( struct vmbus_device *vmdev,
+ struct vmbus_packet_header *header,
+ const void *data, size_t len ) {
+ struct hv_hypervisor *hv = vmdev->hv;
+ struct vmbus *vmbus = hv->vmbus;
+ static uint8_t padding[ 8 - 1 ];
+ struct vmbus_packet_footer footer;
+ size_t header_len;
+ size_t pad_len;
+ size_t footer_len;
+ size_t ring_len;
+ size_t cons;
+ size_t prod;
+ size_t old_prod;
+ size_t fill;
+
+ /* Sanity check */
+ assert ( vmdev->out != NULL );
+
+ /* Calculate lengths */
+ header_len = ( le16_to_cpu ( header->hdr_qlen ) * 8 );
+ pad_len = ( ( -len ) & ( 8 - 1 ) );
+ footer_len = sizeof ( footer );
+ ring_len = ( header_len + len + pad_len + footer_len );
+
+ /* Check that we have enough room in the outbound ring buffer */
+ cons = le32_to_cpu ( vmdev->out->cons );
+ prod = le32_to_cpu ( vmdev->out->prod );
+ old_prod = prod;
+ fill = ( ( prod - cons ) & ( vmdev->out_len - 1 ) );
+ if ( ( fill + ring_len ) >= vmdev->out_len ) {
+ DBGC ( vmdev, "VMBUS %s ring buffer full\n", vmdev->dev.name );
+ return -ENOBUFS;
+ }
+
+ /* Complete header */
+ header->qlen = cpu_to_le16 ( ( ring_len - footer_len ) / 8 );
+
+ /* Construct footer */
+ footer.reserved = 0;
+ footer.prod = vmdev->out->prod;
+
+ /* Copy packet to buffer */
+ DBGC2 ( vmdev, "VMBUS %s sending:\n", vmdev->dev.name );
+ DBGC2_HDA ( vmdev, prod, header, header_len );
+ prod = vmbus_produce ( vmdev, prod, header, header_len );
+ DBGC2_HDA ( vmdev, prod, data, len );
+ prod = vmbus_produce ( vmdev, prod, data, len );
+ prod = vmbus_produce ( vmdev, prod, padding, pad_len );
+ DBGC2_HDA ( vmdev, prod, &footer, sizeof ( footer ) );
+ prod = vmbus_produce ( vmdev, prod, &footer, sizeof ( footer ) );
+ assert ( ( ( prod - old_prod ) & ( vmdev->out_len - 1 ) ) == ring_len );
+
+ /* Update producer index */
+ wmb();
+ vmdev->out->prod = cpu_to_le32 ( prod );
+
+ /* Return if we do not need to signal the host. This follows
+ * the logic of hv_need_to_signal() in the Linux driver.
+ */
+ mb();
+ if ( vmdev->out->intr_mask )
+ return 0;
+ rmb();
+ cons = le32_to_cpu ( vmdev->out->cons );
+ if ( cons != old_prod )
+ return 0;
+
+ /* Set channel bit in interrupt page */
+ hv_set_bit ( vmbus->intr->out, vmdev->channel );
+
+ /* Signal the host */
+ vmdev->signal ( vmdev );
+
+ return 0;
+}
+
+/**
+ * Send control packet via ring buffer
+ *
+ * @v vmdev VMBus device
+ * @v xid Transaction ID (or zero to not request completion)
+ * @v data Data
+ * @v len Length of data
+ * @ret rc Return status code
+ *
+ * Send data using a VMBUS_DATA_INBAND packet.
+ */
+int vmbus_send_control ( struct vmbus_device *vmdev, uint64_t xid,
+ const void *data, size_t len ) {
+ struct vmbus_packet_header *header = vmdev->packet;
+
+ /* Construct header in packet buffer */
+ assert ( header != NULL );
+ header->type = cpu_to_le16 ( VMBUS_DATA_INBAND );
+ header->hdr_qlen = cpu_to_le16 ( sizeof ( *header ) / 8 );
+ header->flags = ( xid ?
+ cpu_to_le16 ( VMBUS_COMPLETION_REQUESTED ) : 0 );
+ header->xid = xid; /* Non-endian */
+
+ return vmbus_send ( vmdev, header, data, len );
+}
+
+/**
+ * Send data packet via ring buffer
+ *
+ * @v vmdev VMBus device
+ * @v xid Transaction ID
+ * @v data Data
+ * @v len Length of data
+ * @v iobuf I/O buffer
+ * @ret rc Return status code
+ *
+ * Send data using a VMBUS_DATA_GPA_DIRECT packet. The caller is
+ * responsible for ensuring that the I/O buffer remains untouched
+ * until the corresponding completion has been received.
+ */
+int vmbus_send_data ( struct vmbus_device *vmdev, uint64_t xid,
+ const void *data, size_t len, struct io_buffer *iobuf ) {
+ physaddr_t addr = virt_to_phys ( iobuf->data );
+ unsigned int pfn_count = hv_pfn_count ( addr, iob_len ( iobuf ) );
+ struct {
+ struct vmbus_gpa_direct_header gpa;
+ struct vmbus_gpa_range range;
+ uint64_t pfn[pfn_count];
+ } __attribute__ (( packed )) *header = vmdev->packet;
+ unsigned int i;
+
+ /* Sanity check */
+ assert ( header != NULL );
+ assert ( sizeof ( *header ) <= vmdev->mtu );
+
+ /* Construct header in packet buffer */
+ header->gpa.header.type = cpu_to_le16 ( VMBUS_DATA_GPA_DIRECT );
+ header->gpa.header.hdr_qlen = cpu_to_le16 ( sizeof ( *header ) / 8 );
+ header->gpa.header.flags = cpu_to_le16 ( VMBUS_COMPLETION_REQUESTED );
+ header->gpa.header.xid = xid; /* Non-endian */
+ header->gpa.range_count = 1;
+ header->range.len = cpu_to_le32 ( iob_len ( iobuf ) );
+ header->range.offset = cpu_to_le32 ( addr & ( PAGE_SIZE - 1 ) );
+ for ( i = 0 ; i < pfn_count ; i++ )
+ header->pfn[i] = ( ( addr / PAGE_SIZE ) + i );
+
+ return vmbus_send ( vmdev, &header->gpa.header, data, len );
+}
+
+/**
+ * Send completion packet via ring buffer
+ *
+ * @v vmdev VMBus device
+ * @v xid Transaction ID
+ * @v data Data
+ * @v len Length of data
+ * @ret rc Return status code
+ *
+ * Send data using a VMBUS_COMPLETION packet.
+ */
+int vmbus_send_completion ( struct vmbus_device *vmdev, uint64_t xid,
+ const void *data, size_t len ) {
+ struct vmbus_packet_header *header = vmdev->packet;
+
+ /* Construct header in packet buffer */
+ assert ( header != NULL );
+ header->type = cpu_to_le16 ( VMBUS_COMPLETION );
+ header->hdr_qlen = cpu_to_le16 ( sizeof ( *header ) / 8 );
+ header->flags = 0;
+ header->xid = xid; /* Non-endian */
+
+ return vmbus_send ( vmdev, header, data, len );
+}
+
+/**
+ * Send cancellation packet via ring buffer
+ *
+ * @v vmdev VMBus device
+ * @v xid Transaction ID
+ * @ret rc Return status code
+ *
+ * Send data using a VMBUS_CANCELLATION packet.
+ */
+int vmbus_send_cancellation ( struct vmbus_device *vmdev, uint64_t xid ) {
+ struct vmbus_packet_header *header = vmdev->packet;
+
+ /* Construct header in packet buffer */
+ assert ( header != NULL );
+ header->type = cpu_to_le16 ( VMBUS_CANCELLATION );
+ header->hdr_qlen = cpu_to_le16 ( sizeof ( *header ) / 8 );
+ header->flags = 0;
+ header->xid = xid; /* Non-endian */
+
+ return vmbus_send ( vmdev, header, NULL, 0 );
+}
+
+/**
+ * Get transfer page set from pageset ID
+ *
+ * @v vmdev VMBus device
+ * @v pageset Page set ID (in protocol byte order)
+ * @ret pages Page set, or NULL if not found
+ */
+static struct vmbus_xfer_pages * vmbus_xfer_pages ( struct vmbus_device *vmdev,
+ uint16_t pageset ) {
+ struct vmbus_xfer_pages *pages;
+
+ /* Locate page set */
+ list_for_each_entry ( pages, &vmdev->pages, list ) {
+ if ( pages->pageset == pageset )
+ return pages;
+ }
+
+ DBGC ( vmdev, "VMBUS %s unrecognised page set ID %#04x\n",
+ vmdev->dev.name, le16_to_cpu ( pageset ) );
+ return NULL;
+}
+
+/**
+ * Construct I/O buffer list from transfer pages
+ *
+ * @v vmdev VMBus device
+ * @v header Transfer page header
+ * @v list I/O buffer list to populate
+ * @ret rc Return status code
+ */
+static int vmbus_xfer_page_iobufs ( struct vmbus_device *vmdev,
+ struct vmbus_packet_header *header,
+ struct list_head *list ) {
+ struct vmbus_xfer_page_header *page_header =
+ container_of ( header, struct vmbus_xfer_page_header, header );
+ struct vmbus_xfer_pages *pages;
+ struct io_buffer *iobuf;
+ struct io_buffer *tmp;
+ size_t len;
+ size_t offset;
+ unsigned int range_count;
+ unsigned int i;
+ int rc;
+
+ /* Sanity check */
+ assert ( header->type == cpu_to_le16 ( VMBUS_DATA_XFER_PAGES ) );
+
+ /* Locate page set */
+ pages = vmbus_xfer_pages ( vmdev, page_header->pageset );
+ if ( ! pages ) {
+ rc = -ENOENT;
+ goto err_pages;
+ }
+
+ /* Allocate and populate I/O buffers */
+ range_count = le32_to_cpu ( page_header->range_count );
+ for ( i = 0 ; i < range_count ; i++ ) {
+
+ /* Parse header */
+ len = le32_to_cpu ( page_header->range[i].len );
+ offset = le32_to_cpu ( page_header->range[i].offset );
+
+ /* Allocate I/O buffer */
+ iobuf = alloc_iob ( len );
+ if ( ! iobuf ) {
+ DBGC ( vmdev, "VMBUS %s could not allocate %zd-byte "
+ "I/O buffer\n", vmdev->dev.name, len );
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+
+ /* Add I/O buffer to list */
+ list_add ( &iobuf->list, list );
+
+ /* Populate I/O buffer */
+ if ( ( rc = pages->op->copy ( pages, iob_put ( iobuf, len ),
+ offset, len ) ) != 0 ) {
+ DBGC ( vmdev, "VMBUS %s could not populate I/O buffer "
+ "range [%zd,%zd): %s\n",
+ vmdev->dev.name, offset, len, strerror ( rc ) );
+ goto err_copy;
+ }
+ }
+
+ return 0;
+
+ err_copy:
+ err_alloc:
+ list_for_each_entry_safe ( iobuf, tmp, list, list ) {
+ list_del ( &iobuf->list );
+ free_iob ( iobuf );
+ }
+ err_pages:
+ return rc;
+}
+
+/**
+ * Poll ring buffer
+ *
+ * @v vmdev VMBus device
+ * @ret rc Return status code
+ */
+int vmbus_poll ( struct vmbus_device *vmdev ) {
+ struct vmbus_packet_header *header = vmdev->packet;
+ struct list_head list;
+ void *data;
+ size_t header_len;
+ size_t len;
+ size_t footer_len;
+ size_t ring_len;
+ size_t cons;
+ size_t old_cons;
+ uint64_t xid;
+ int rc;
+
+ /* Sanity checks */
+ assert ( vmdev->packet != NULL );
+ assert ( vmdev->in != NULL );
+
+ /* Return immediately if buffer is empty */
+ if ( ! vmbus_has_data ( vmdev ) )
+ return 0;
+ cons = le32_to_cpu ( vmdev->in->cons );
+ old_cons = cons;
+
+ /* Consume (start of) header */
+ cons = vmbus_consume ( vmdev, cons, header, sizeof ( *header ) );
+
+ /* Parse and sanity check header */
+ header_len = ( le16_to_cpu ( header->hdr_qlen ) * 8 );
+ if ( header_len < sizeof ( *header ) ) {
+ DBGC ( vmdev, "VMBUS %s received underlength header (%zd "
+ "bytes)\n", vmdev->dev.name, header_len );
+ return -EINVAL;
+ }
+ len = ( ( le16_to_cpu ( header->qlen ) * 8 ) - header_len );
+ footer_len = sizeof ( struct vmbus_packet_footer );
+ ring_len = ( header_len + len + footer_len );
+ if ( ring_len > vmdev->mtu ) {
+ DBGC ( vmdev, "VMBUS %s received overlength packet (%zd "
+ "bytes)\n", vmdev->dev.name, ring_len );
+ return -ERANGE;
+ }
+ xid = le64_to_cpu ( header->xid );
+
+ /* Consume remainder of packet */
+ cons = vmbus_consume ( vmdev, cons,
+ ( ( ( void * ) header ) + sizeof ( *header ) ),
+ ( ring_len - sizeof ( *header ) ) );
+ DBGC2 ( vmdev, "VMBUS %s received:\n", vmdev->dev.name );
+ DBGC2_HDA ( vmdev, old_cons, header, ring_len );
+ assert ( ( ( cons - old_cons ) & ( vmdev->in_len - 1 ) ) == ring_len );
+
+ /* Allocate I/O buffers, if applicable */
+ INIT_LIST_HEAD ( &list );
+ if ( header->type == cpu_to_le16 ( VMBUS_DATA_XFER_PAGES ) ) {
+ if ( ( rc = vmbus_xfer_page_iobufs ( vmdev, header,
+ &list ) ) != 0 )
+ return rc;
+ }
+
+ /* Update producer index */
+ rmb();
+ vmdev->in->cons = cpu_to_le32 ( cons );
+
+ /* Handle packet */
+ data = ( ( ( void * ) header ) + header_len );
+ switch ( header->type ) {
+
+ case cpu_to_le16 ( VMBUS_DATA_INBAND ) :
+ if ( ( rc = vmdev->op->recv_control ( vmdev, xid, data,
+ len ) ) != 0 ) {
+ DBGC ( vmdev, "VMBUS %s could not handle control "
+ "packet: %s\n",
+ vmdev->dev.name, strerror ( rc ) );
+ return rc;
+ }
+ break;
+
+ case cpu_to_le16 ( VMBUS_DATA_XFER_PAGES ) :
+ if ( ( rc = vmdev->op->recv_data ( vmdev, xid, data, len,
+ &list ) ) != 0 ) {
+ DBGC ( vmdev, "VMBUS %s could not handle data packet: "
+ "%s\n", vmdev->dev.name, strerror ( rc ) );
+ return rc;
+ }
+ break;
+
+ case cpu_to_le16 ( VMBUS_COMPLETION ) :
+ if ( ( rc = vmdev->op->recv_completion ( vmdev, xid, data,
+ len ) ) != 0 ) {
+ DBGC ( vmdev, "VMBUS %s could not handle completion: "
+ "%s\n", vmdev->dev.name, strerror ( rc ) );
+ return rc;
+ }
+ break;
+
+ case cpu_to_le16 ( VMBUS_CANCELLATION ) :
+ if ( ( rc = vmdev->op->recv_cancellation ( vmdev, xid ) ) != 0){
+ DBGC ( vmdev, "VMBUS %s could not handle cancellation: "
+ "%s\n", vmdev->dev.name, strerror ( rc ) );
+ return rc;
+ }
+ break;
+
+ default:
+ DBGC ( vmdev, "VMBUS %s unknown packet type %d\n",
+ vmdev->dev.name, le16_to_cpu ( header->type ) );
+ return -ENOTSUP;
+ }
+
+ return 0;
+}
+
+/**
+ * Dump channel status (for debugging)
+ *
+ * @v vmdev VMBus device
+ */
+void vmbus_dump_channel ( struct vmbus_device *vmdev ) {
+ size_t out_prod = le32_to_cpu ( vmdev->out->prod );
+ size_t out_cons = le32_to_cpu ( vmdev->out->cons );
+ size_t in_prod = le32_to_cpu ( vmdev->in->prod );
+ size_t in_cons = le32_to_cpu ( vmdev->in->cons );
+ size_t in_len;
+ size_t first;
+ size_t second;
+
+ /* Dump ring status */
+ DBGC ( vmdev, "VMBUS %s out %03zx:%03zx%s in %03zx:%03zx%s\n",
+ vmdev->dev.name, out_prod, out_cons,
+ ( vmdev->out->intr_mask ? "(m)" : "" ), in_prod, in_cons,
+ ( vmdev->in->intr_mask ? "(m)" : "" ) );
+
+ /* Dump inbound ring contents, if any */
+ if ( in_prod != in_cons ) {
+ in_len = ( ( in_prod - in_cons ) &
+ ( vmdev->in_len - 1 ) );
+ first = ( vmdev->in_len - in_cons );
+ if ( first > in_len )
+ first = in_len;
+ second = ( in_len - first );
+ DBGC_HDA ( vmdev, in_cons, &vmdev->in->data[in_cons], first );
+ DBGC_HDA ( vmdev, 0, &vmdev->in->data[0], second );
+ }
+}
+
+/**
+ * Find driver for VMBus device
+ *
+ * @v vmdev VMBus device
+ * @ret driver Driver, or NULL
+ */
+static struct vmbus_driver * vmbus_find_driver ( const union uuid *type ) {
+ struct vmbus_driver *vmdrv;
+
+ for_each_table_entry ( vmdrv, VMBUS_DRIVERS ) {
+ if ( memcmp ( &vmdrv->type, type, sizeof ( *type ) ) == 0 )
+ return vmdrv;
+ }
+ return NULL;
+}
+
+/**
+ * Probe channels
+ *
+ * @v hv Hyper-V hypervisor
+ * @v parent Parent device
+ * @ret rc Return status code
+ */
+static int vmbus_probe_channels ( struct hv_hypervisor *hv,
+ struct device *parent ) {
+ struct vmbus *vmbus = hv->vmbus;
+ const struct vmbus_message_header *header = &vmbus->message->header;
+ const struct vmbus_offer_channel *offer = &vmbus->message->offer;
+ const union uuid *type;
+ struct vmbus_driver *driver;
+ struct vmbus_device *vmdev;
+ struct vmbus_device *tmp;
+ unsigned int channel;
+ int rc;
+
+ /* Post message */
+ if ( ( rc = vmbus_post_empty_message ( hv, VMBUS_REQUEST_OFFERS ) ) !=0)
+ goto err_post_message;
+
+ /* Collect responses */
+ while ( 1 ) {
+
+ /* Wait for response */
+ if ( ( rc = vmbus_wait_for_message ( hv ) ) != 0 )
+ goto err_wait_for_message;
+
+ /* Handle response */
+ if ( header->type == cpu_to_le32 ( VMBUS_OFFER_CHANNEL ) ) {
+
+ /* Parse offer */
+ type = &offer->type;
+ channel = le32_to_cpu ( offer->channel );
+ DBGC2 ( vmbus, "VMBUS %p offer %d type %s",
+ vmbus, channel, uuid_ntoa ( type ) );
+ if ( offer->monitored )
+ DBGC2 ( vmbus, " monitor %d", offer->monitor );
+ DBGC2 ( vmbus, "\n" );
+
+ /* Look for a driver */
+ driver = vmbus_find_driver ( type );
+ if ( ! driver ) {
+ DBGC2 ( vmbus, "VMBUS %p has no driver for "
+ "type %s\n", vmbus, uuid_ntoa ( type ));
+ /* Not a fatal error */
+ continue;
+ }
+
+ /* Allocate and initialise device */
+ vmdev = zalloc ( sizeof ( *vmdev ) );
+ if ( ! vmdev ) {
+ rc = -ENOMEM;
+ goto err_alloc_vmdev;
+ }
+ snprintf ( vmdev->dev.name, sizeof ( vmdev->dev.name ),
+ "vmbus:%02x", channel );
+ vmdev->dev.desc.bus_type = BUS_TYPE_HV;
+ INIT_LIST_HEAD ( &vmdev->dev.children );
+ list_add_tail ( &vmdev->dev.siblings,
+ &parent->children );
+ vmdev->dev.parent = parent;
+ vmdev->hv = hv;
+ vmdev->channel = channel;
+ vmdev->monitor = offer->monitor;
+ vmdev->signal = ( offer->monitored ?
+ vmbus_signal_monitor :
+ vmbus_signal_event );
+ INIT_LIST_HEAD ( &vmdev->pages );
+ vmdev->driver = driver;
+ vmdev->dev.driver_name = driver->name;
+ DBGC ( vmdev, "VMBUS %s has driver \"%s\"\n",
+ vmdev->dev.name, vmdev->driver->name );
+
+ } else if ( header->type ==
+ cpu_to_le32 ( VMBUS_ALL_OFFERS_DELIVERED ) ) {
+
+ break;
+
+ } else {
+ DBGC ( vmbus, "VMBUS %p unexpected offer response type "
+ "%d\n", vmbus, le32_to_cpu ( header->type ) );
+ rc = -EPROTO;
+ goto err_unexpected_offer;
+ }
+ }
+
+ /* Probe all devices. We do this only after completing
+ * enumeration since devices will need to send and receive
+ * VMBus messages.
+ */
+ list_for_each_entry ( vmdev, &parent->children, dev.siblings ) {
+ if ( ( rc = vmdev->driver->probe ( vmdev ) ) != 0 ) {
+ DBGC ( vmdev, "VMBUS %s could not probe: %s\n",
+ vmdev->dev.name, strerror ( rc ) );
+ goto err_probe;
+ }
+ }
+
+ return 0;
+
+ err_probe:
+ /* Remove driver from each device that was already probed */
+ list_for_each_entry_continue_reverse ( vmdev, &parent->children,
+ dev.siblings ) {
+ vmdev->driver->remove ( vmdev );
+ }
+ err_unexpected_offer:
+ err_alloc_vmdev:
+ err_wait_for_message:
+ /* Free any devices allocated (but potentially not yet probed) */
+ list_for_each_entry_safe ( vmdev, tmp, &parent->children,
+ dev.siblings ) {
+ list_del ( &vmdev->dev.siblings );
+ free ( vmdev );
+ }
+ err_post_message:
+ return rc;
+}
+
+/**
+ * Remove channels
+ *
+ * @v hv Hyper-V hypervisor
+ * @v parent Parent device
+ */
+static void vmbus_remove_channels ( struct hv_hypervisor *hv __unused,
+ struct device *parent ) {
+ struct vmbus_device *vmdev;
+ struct vmbus_device *tmp;
+
+ /* Remove devices */
+ list_for_each_entry_safe ( vmdev, tmp, &parent->children,
+ dev.siblings ) {
+ vmdev->driver->remove ( vmdev );
+ assert ( list_empty ( &vmdev->dev.children ) );
+ assert ( vmdev->out == NULL );
+ assert ( vmdev->in == NULL );
+ assert ( vmdev->packet == NULL );
+ assert ( list_empty ( &vmdev->pages ) );
+ list_del ( &vmdev->dev.siblings );
+ free ( vmdev );
+ }
+}
+
+/**
+ * Probe Hyper-V virtual machine bus
+ *
+ * @v hv Hyper-V hypervisor
+ * @v parent Parent device
+ * @ret rc Return status code
+ */
+int vmbus_probe ( struct hv_hypervisor *hv, struct device *parent ) {
+ struct vmbus *vmbus;
+ int rc;
+
+ /* Allocate and initialise structure */
+ vmbus = zalloc ( sizeof ( *vmbus ) );
+ if ( ! vmbus ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ hv->vmbus = vmbus;
+
+ /* Initialise message buffer pointer
+ *
+ * We use a pointer to the fixed-size Hyper-V received message
+ * buffer. This allows us to access fields within received
+ * messages without first checking the message size: any
+ * fields beyond the end of the message will read as zero.
+ */
+ vmbus->message = ( ( void * ) hv->message->received.data );
+ assert ( sizeof ( *vmbus->message ) <=
+ sizeof ( hv->message->received.data ) );
+
+ /* Allocate interrupt and monitor pages */
+ if ( ( rc = hv_alloc_pages ( hv, &vmbus->intr, &vmbus->monitor_in,
+ &vmbus->monitor_out, NULL ) ) != 0 )
+ goto err_alloc_pages;
+
+ /* Enable message interrupt */
+ hv_enable_sint ( hv, VMBUS_MESSAGE_SINT );
+
+ /* Negotiate protocol version */
+ if ( ( rc = vmbus_negotiate_version ( hv ) ) != 0 )
+ goto err_negotiate_version;
+
+ /* Enumerate channels */
+ if ( ( rc = vmbus_probe_channels ( hv, parent ) ) != 0 )
+ goto err_probe_channels;
+
+ return 0;
+
+ vmbus_remove_channels ( hv, parent );
+ err_probe_channels:
+ vmbus_unload ( hv );
+ err_negotiate_version:
+ hv_disable_sint ( hv, VMBUS_MESSAGE_SINT );
+ hv_free_pages ( hv, vmbus->intr, vmbus->monitor_in, vmbus->monitor_out,
+ NULL );
+ err_alloc_pages:
+ free ( vmbus );
+ err_alloc:
+ return rc;
+}
+
+/**
+ * Remove Hyper-V virtual machine bus
+ *
+ * @v hv Hyper-V hypervisor
+ * @v parent Parent device
+ */
+void vmbus_remove ( struct hv_hypervisor *hv, struct device *parent ) {
+ struct vmbus *vmbus = hv->vmbus;
+
+ vmbus_remove_channels ( hv, parent );
+ vmbus_unload ( hv );
+ hv_disable_sint ( hv, VMBUS_MESSAGE_SINT );
+ hv_free_pages ( hv, vmbus->intr, vmbus->monitor_in, vmbus->monitor_out,
+ NULL );
+ free ( vmbus );
+}
diff --git a/roms/ipxe/src/interface/linux/linux_entropy.c b/roms/ipxe/src/interface/linux/linux_entropy.c
index 4671a48da..0f8e45d36 100644
--- a/roms/ipxe/src/interface/linux/linux_entropy.c
+++ b/roms/ipxe/src/interface/linux/linux_entropy.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/interface/linux/linux_pci.c b/roms/ipxe/src/interface/linux/linux_pci.c
index cbd825c18..0c140cb89 100644
--- a/roms/ipxe/src/interface/linux/linux_pci.c
+++ b/roms/ipxe/src/interface/linux/linux_pci.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdio.h>
#include <errno.h>
diff --git a/roms/ipxe/src/interface/linux/linux_time.c b/roms/ipxe/src/interface/linux/linux_time.c
index e3cbafec6..9e99fe9cd 100644
--- a/roms/ipxe/src/interface/linux/linux_time.c
+++ b/roms/ipxe/src/interface/linux/linux_time.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/interface/linux/linux_uaccess.c b/roms/ipxe/src/interface/linux/linux_uaccess.c
index 5ab0b6b65..ea2d8057c 100644
--- a/roms/ipxe/src/interface/linux/linux_uaccess.c
+++ b/roms/ipxe/src/interface/linux/linux_uaccess.c
@@ -27,7 +27,6 @@ FILE_LICENCE(GPL2_OR_LATER);
*
*/
-PROVIDE_UACCESS_INLINE(linux, phys_to_user);
PROVIDE_UACCESS_INLINE(linux, user_to_phys);
PROVIDE_UACCESS_INLINE(linux, virt_to_user);
PROVIDE_UACCESS_INLINE(linux, user_to_virt);
diff --git a/roms/ipxe/src/interface/smbios/smbios.c b/roms/ipxe/src/interface/smbios/smbios.c
index 856943428..1dcf819c2 100644
--- a/roms/ipxe/src/interface/smbios/smbios.c
+++ b/roms/ipxe/src/interface/smbios/smbios.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <string.h>
diff --git a/roms/ipxe/src/interface/smbios/smbios_settings.c b/roms/ipxe/src/interface/smbios/smbios_settings.c
index 83e4320e9..5eadfa081 100644
--- a/roms/ipxe/src/interface/smbios/smbios_settings.c
+++ b/roms/ipxe/src/interface/smbios/smbios_settings.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <string.h>
diff --git a/roms/ipxe/src/interface/xen/xenbus.c b/roms/ipxe/src/interface/xen/xenbus.c
index ffc8aba3e..c328af443 100644
--- a/roms/ipxe/src/interface/xen/xenbus.c
+++ b/roms/ipxe/src/interface/xen/xenbus.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdio.h>
#include <errno.h>
diff --git a/roms/ipxe/src/interface/xen/xengrant.c b/roms/ipxe/src/interface/xen/xengrant.c
index be12b23dc..269cd5836 100644
--- a/roms/ipxe/src/interface/xen/xengrant.c
+++ b/roms/ipxe/src/interface/xen/xengrant.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <strings.h>
diff --git a/roms/ipxe/src/interface/xen/xenstore.c b/roms/ipxe/src/interface/xen/xenstore.c
index b96982927..23424a926 100644
--- a/roms/ipxe/src/interface/xen/xenstore.c
+++ b/roms/ipxe/src/interface/xen/xenstore.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdarg.h>
@@ -238,6 +242,10 @@ static int xenstore_response ( struct xen_hypervisor *xen, uint32_t req_id,
char *string;
int rc;
+ /* Wait for response to become available */
+ while ( ! xenevent_pending ( xen, xen->store.port ) )
+ cpu_nap();
+
/* Receive message header */
xenstore_recv ( xen, &msg, sizeof ( msg ) );
*len = msg.len;
diff --git a/roms/ipxe/src/net/80211/net80211.c b/roms/ipxe/src/net/80211/net80211.c
index 434944523..d4970ad5c 100644
--- a/roms/ipxe/src/net/80211/net80211.c
+++ b/roms/ipxe/src/net/80211/net80211.c
@@ -805,6 +805,10 @@ int net80211_register ( struct net80211_device *dev,
NET80211_MAX_CHANNELS * sizeof ( dev->channels[0] ) );
dev->channel = 0;
+ /* Mark device as not supporting interrupts, if applicable */
+ if ( ! ops->irq )
+ dev->netdev->state |= NETDEV_IRQ_UNSUPPORTED;
+
list_add_tail ( &dev->list, &net80211_devices );
return register_netdev ( dev->netdev );
}
@@ -2826,3 +2830,9 @@ struct errortab common_wireless_errors[] __errortab = {
__einfo_errortab ( EINFO_ECONNREFUSED_ASSOC_DENIED ),
__einfo_errortab ( EINFO_ECONNREFUSED_AUTH_ALGO_UNSUPP ),
};
+
+/* Drag in objects via net80211_ll_protocol */
+REQUIRING_SYMBOL ( net80211_ll_protocol );
+
+/* Drag in 802.11 configuration */
+REQUIRE_OBJECT ( config_net80211 );
diff --git a/roms/ipxe/src/net/80211/wpa.c b/roms/ipxe/src/net/80211/wpa.c
index e2c4945f9..77f66d825 100644
--- a/roms/ipxe/src/net/80211/wpa.c
+++ b/roms/ipxe/src/net/80211/wpa.c
@@ -912,4 +912,5 @@ struct eapol_handler eapol_key_handler __eapol_handler = {
};
/* WPA always needs EAPOL in order to be useful */
+REQUIRING_SYMBOL ( eapol_key_handler );
REQUIRE_OBJECT ( eapol );
diff --git a/roms/ipxe/src/net/80211/wpa_ccmp.c b/roms/ipxe/src/net/80211/wpa_ccmp.c
index f98ebea26..a073c6a3c 100644
--- a/roms/ipxe/src/net/80211/wpa_ccmp.c
+++ b/roms/ipxe/src/net/80211/wpa_ccmp.c
@@ -480,7 +480,7 @@ static void ccmp_kie_mic ( const void *kck, const void *msg, size_t len,
{
u8 sha1_ctx[SHA1_CTX_SIZE];
u8 kckb[16];
- u8 hash[SHA1_SIZE];
+ u8 hash[SHA1_DIGEST_SIZE];
size_t kck_len = 16;
memcpy ( kckb, kck, kck_len );
diff --git a/roms/ipxe/src/net/80211/wpa_tkip.c b/roms/ipxe/src/net/80211/wpa_tkip.c
index fa3e0763b..3b1934b59 100644
--- a/roms/ipxe/src/net/80211/wpa_tkip.c
+++ b/roms/ipxe/src/net/80211/wpa_tkip.c
@@ -136,7 +136,7 @@ static const u16 Sbox[256] = {
*/
static inline u16 S ( u16 v )
{
- return Sbox[v & 0xFF] ^ swap16 ( Sbox[v >> 8] );
+ return Sbox[v & 0xFF] ^ bswap_16 ( Sbox[v >> 8] );
}
/**
diff --git a/roms/ipxe/src/net/aoe.c b/roms/ipxe/src/net/aoe.c
index a6d7b3e7b..2da8655b4 100644
--- a/roms/ipxe/src/net/aoe.c
+++ b/roms/ipxe/src/net/aoe.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <string.h>
diff --git a/roms/ipxe/src/net/arp.c b/roms/ipxe/src/net/arp.c
index 261e681e1..1e27c44e7 100644
--- a/roms/ipxe/src/net/arp.c
+++ b/roms/ipxe/src/net/arp.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
@@ -52,9 +56,9 @@ struct net_protocol arp_protocol __net_protocol;
* @v net_source Source network-layer address
* @ret rc Return status code
*/
-static int arp_tx_request ( struct net_device *netdev,
- struct net_protocol *net_protocol,
- const void *net_dest, const void *net_source ) {
+int arp_tx_request ( struct net_device *netdev,
+ struct net_protocol *net_protocol,
+ const void *net_dest, const void *net_source ) {
struct ll_protocol *ll_protocol = netdev->ll_protocol;
struct io_buffer *iobuf;
struct arphdr *arphdr;
diff --git a/roms/ipxe/src/net/dhcpopts.c b/roms/ipxe/src/net/dhcpopts.c
index 8cd19cf80..cdb632b46 100644
--- a/roms/ipxe/src/net/dhcpopts.c
+++ b/roms/ipxe/src/net/dhcpopts.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/net/dhcppkt.c b/roms/ipxe/src/net/dhcppkt.c
index a9a6d3a94..4e64f85e4 100644
--- a/roms/ipxe/src/net/dhcppkt.c
+++ b/roms/ipxe/src/net/dhcppkt.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/net/eth_slow.c b/roms/ipxe/src/net/eth_slow.c
index db54b55a4..049c26cb3 100644
--- a/roms/ipxe/src/net/eth_slow.c
+++ b/roms/ipxe/src/net/eth_slow.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdlib.h>
#include <string.h>
diff --git a/roms/ipxe/src/net/ethernet.c b/roms/ipxe/src/net/ethernet.c
index 03978c2a8..6ddf05344 100644
--- a/roms/ipxe/src/net/ethernet.c
+++ b/roms/ipxe/src/net/ethernet.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
@@ -43,6 +47,24 @@ FILE_LICENCE ( GPL2_OR_LATER );
uint8_t eth_broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
/**
+ * Check if Ethernet packet has an 802.3 LLC header
+ *
+ * @v ethhdr Ethernet header
+ * @ret is_llc Packet has 802.3 LLC header
+ */
+static inline int eth_is_llc_packet ( struct ethhdr *ethhdr ) {
+ uint8_t len_msb;
+
+ /* Check if the protocol field contains a value short enough
+ * to be a frame length. The slightly convoluted form of the
+ * comparison is designed to reduce to a single x86
+ * instruction.
+ */
+ len_msb = *( ( uint8_t * ) &ethhdr->h_protocol );
+ return ( len_msb < 0x06 );
+}
+
+/**
* Add Ethernet link-layer header
*
* @v netdev Network device
@@ -80,9 +102,14 @@ int eth_pull ( struct net_device *netdev __unused, struct io_buffer *iobuf,
const void **ll_dest, const void **ll_source,
uint16_t *net_proto, unsigned int *flags ) {
struct ethhdr *ethhdr = iobuf->data;
+ uint16_t *llc_proto;
- /* Sanity check */
- if ( iob_len ( iobuf ) < sizeof ( *ethhdr ) ) {
+ /* Sanity check. While in theory we could receive a one-byte
+ * packet, this will never happen in practice and performing
+ * the combined length check here avoids the need for an
+ * additional comparison if we detect an LLC frame.
+ */
+ if ( iob_len ( iobuf ) < ( sizeof ( *ethhdr ) + sizeof ( *llc_proto ))){
DBG ( "Ethernet packet too short (%zd bytes)\n",
iob_len ( iobuf ) );
return -EINVAL;
@@ -100,6 +127,17 @@ int eth_pull ( struct net_device *netdev __unused, struct io_buffer *iobuf,
( is_broadcast_ether_addr ( ethhdr->h_dest ) ?
LL_BROADCAST : 0 ) );
+ /* If this is an LLC frame (with a length in place of the
+ * protocol field), then use the next two bytes (which happen
+ * to be the LLC DSAP and SSAP) as the protocol. This allows
+ * for minimal-overhead support for receiving (rare) LLC
+ * frames, without requiring a full LLC protocol layer.
+ */
+ if ( eth_is_llc_packet ( ethhdr ) ) {
+ llc_proto = ( &ethhdr->h_protocol + 1 );
+ *net_proto = *llc_proto;
+ }
+
return 0;
}
@@ -235,5 +273,11 @@ struct net_device * alloc_etherdev ( size_t priv_size ) {
return netdev;
}
+/* Drag in objects via ethernet_protocol */
+REQUIRING_SYMBOL ( ethernet_protocol );
+
+/* Drag in Ethernet configuration */
+REQUIRE_OBJECT ( config_ethernet );
+
/* Drag in Ethernet slow protocols */
REQUIRE_OBJECT ( eth_slow );
diff --git a/roms/ipxe/src/net/fakedhcp.c b/roms/ipxe/src/net/fakedhcp.c
index 3dec88b11..b6c456a59 100644
--- a/roms/ipxe/src/net/fakedhcp.c
+++ b/roms/ipxe/src/net/fakedhcp.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/net/fc.c b/roms/ipxe/src/net/fc.c
index 58008995c..2e8070272 100644
--- a/roms/ipxe/src/net/fc.c
+++ b/roms/ipxe/src/net/fc.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <stdlib.h>
@@ -1935,3 +1939,9 @@ struct fc_ulp * fc_ulp_get_port_id_type ( struct fc_port *port,
err_peer_get_wwn:
return NULL;
}
+
+/* Drag in objects via fc_ports */
+REQUIRING_SYMBOL ( fc_ports );
+
+/* Drag in Fibre Channel configuration */
+REQUIRE_OBJECT ( config_fc );
diff --git a/roms/ipxe/src/net/fcels.c b/roms/ipxe/src/net/fcels.c
index 1cfe90727..5fc27cef4 100644
--- a/roms/ipxe/src/net/fcels.c
+++ b/roms/ipxe/src/net/fcels.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/net/fcns.c b/roms/ipxe/src/net/fcns.c
index 3ca4ad557..be4dfea24 100644
--- a/roms/ipxe/src/net/fcns.c
+++ b/roms/ipxe/src/net/fcns.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/net/fcoe.c b/roms/ipxe/src/net/fcoe.c
index e9e404ec3..c3258f15e 100644
--- a/roms/ipxe/src/net/fcoe.c
+++ b/roms/ipxe/src/net/fcoe.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/net/fcp.c b/roms/ipxe/src/net/fcp.c
index 9c36a4c72..930bf7dd4 100644
--- a/roms/ipxe/src/net/fcp.c
+++ b/roms/ipxe/src/net/fcp.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <stdint.h>
diff --git a/roms/ipxe/src/net/fragment.c b/roms/ipxe/src/net/fragment.c
index 410915b3b..781b9bc60 100644
--- a/roms/ipxe/src/net/fragment.c
+++ b/roms/ipxe/src/net/fragment.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/net/icmp.c b/roms/ipxe/src/net/icmp.c
index 1bbf8bd30..5371277e4 100644
--- a/roms/ipxe/src/net/icmp.c
+++ b/roms/ipxe/src/net/icmp.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <byteswap.h>
diff --git a/roms/ipxe/src/net/icmpv4.c b/roms/ipxe/src/net/icmpv4.c
index 996ba1490..0858ff37f 100644
--- a/roms/ipxe/src/net/icmpv4.c
+++ b/roms/ipxe/src/net/icmpv4.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <errno.h>
diff --git a/roms/ipxe/src/net/icmpv6.c b/roms/ipxe/src/net/icmpv6.c
index 479800e7d..8555aaf0b 100644
--- a/roms/ipxe/src/net/icmpv6.c
+++ b/roms/ipxe/src/net/icmpv6.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <errno.h>
@@ -34,6 +38,65 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
*/
+/* Disambiguate the various error causes */
+#define EHOSTUNREACH_ROUTE \
+ __einfo_error ( EINFO_EHOSTUNREACH_ROUTE )
+#define EINFO_EHOSTUNREACH_ROUTE \
+ __einfo_uniqify ( EINFO_EHOSTUNREACH, 0, \
+ "No route to destination" )
+#define EHOSTUNREACH_PROHIBITED \
+ __einfo_error ( EINFO_EHOSTUNREACH_PROHIBITED )
+#define EINFO_EHOSTUNREACH_PROHIBITED \
+ __einfo_uniqify ( EINFO_EHOSTUNREACH, 1, \
+ "Communication administratively prohibited" )
+#define EHOSTUNREACH_ADDRESS \
+ __einfo_error ( EINFO_EHOSTUNREACH_ADDRESS )
+#define EINFO_EHOSTUNREACH_ADDRESS \
+ __einfo_uniqify ( EINFO_EHOSTUNREACH, 3, \
+ "Address unreachable" )
+#define EHOSTUNREACH_PORT \
+ __einfo_error ( EINFO_EHOSTUNREACH_PORT )
+#define EINFO_EHOSTUNREACH_PORT \
+ __einfo_uniqify ( EINFO_EHOSTUNREACH, 4, \
+ "Port unreachable" )
+#define EHOSTUNREACH_CODE( code ) \
+ EUNIQ ( EINFO_EHOSTUNREACH, ( (code) & 0x1f ), \
+ EHOSTUNREACH_ROUTE, EHOSTUNREACH_PROHIBITED, \
+ EHOSTUNREACH_ADDRESS, EHOSTUNREACH_PORT )
+
+#define ETIMEDOUT_HOP \
+ __einfo_error ( EINFO_ETIMEDOUT_HOP )
+#define EINFO_ETIMEDOUT_HOP \
+ __einfo_uniqify ( EINFO_ETIMEDOUT, 0, \
+ "Hop limit exceeded in transit" )
+#define ETIMEDOUT_REASSEMBLY \
+ __einfo_error ( EINFO_ETIMEDOUT_REASSEMBLY )
+#define EINFO_ETIMEDOUT_REASSEMBLY \
+ __einfo_uniqify ( EINFO_ETIMEDOUT, 1, \
+ "Fragment reassembly time exceeded" )
+#define ETIMEDOUT_CODE( code ) \
+ EUNIQ ( EINFO_ETIMEDOUT, ( (code) & 0x1f ), \
+ ETIMEDOUT_HOP, ETIMEDOUT_REASSEMBLY )
+
+#define EPROTO_BAD_HEADER \
+ __einfo_error ( EINFO_EPROTO_BAD_HEADER )
+#define EINFO_EPROTO_BAD_HEADER \
+ __einfo_uniqify ( EINFO_EPROTO, 0, \
+ "Erroneous header field" )
+#define EPROTO_NEXT_HEADER \
+ __einfo_error ( EINFO_EPROTO_NEXT_HEADER )
+#define EINFO_EPROTO_NEXT_HEADER \
+ __einfo_uniqify ( EINFO_EPROTO, 1, \
+ "Unrecognised next header type" )
+#define EPROTO_OPTION \
+ __einfo_error ( EINFO_EPROTO_OPTION )
+#define EINFO_EPROTO_OPTION \
+ __einfo_uniqify ( EINFO_EPROTO, 2, \
+ "Unrecognised IPv6 option" )
+#define EPROTO_CODE( code ) \
+ EUNIQ ( EINFO_EPROTO, ( (code) & 0x1f ), \
+ EPROTO_BAD_HEADER, EPROTO_NEXT_HEADER, EPROTO_OPTION )
+
struct icmp_echo_protocol icmpv6_echo_protocol __icmp_echo_protocol;
/**
@@ -144,8 +207,25 @@ static int icmpv6_rx ( struct io_buffer *iobuf, struct net_device *netdev,
/* Identify handler */
handler = icmpv6_handler ( icmp->type );
if ( ! handler ) {
- DBGC ( netdev, "ICMPv6 unrecognised type %d\n", icmp->type );
- rc = -ENOTSUP;
+ switch ( icmp->type ) {
+ case ICMPV6_DESTINATION_UNREACHABLE:
+ rc = -EHOSTUNREACH_CODE ( icmp->code );
+ break;
+ case ICMPV6_PACKET_TOO_BIG:
+ rc = -ERANGE;
+ break;
+ case ICMPV6_TIME_EXCEEDED:
+ rc = -ETIMEDOUT_CODE ( icmp->code );
+ break;
+ case ICMPV6_PARAMETER_PROBLEM:
+ rc = -EPROTO_CODE ( icmp->code );
+ break;
+ default:
+ DBGC ( netdev, "ICMPv6 unrecognised type %d code %d\n",
+ icmp->type, icmp->code );
+ rc = -ENOTSUP;
+ break;
+ };
goto done;
}
diff --git a/roms/ipxe/src/net/infiniband.c b/roms/ipxe/src/net/infiniband.c
index 12d1d83ce..2e3d76d54 100644
--- a/roms/ipxe/src/net/infiniband.c
+++ b/roms/ipxe/src/net/infiniband.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
@@ -714,6 +718,9 @@ int ib_mcast_attach ( struct ib_device *ibdev, struct ib_queue_pair *qp,
struct ib_multicast_gid *mgid;
int rc;
+ /* Sanity check */
+ assert ( qp != NULL );
+
/* Add to software multicast GID list */
mgid = zalloc ( sizeof ( *mgid ) );
if ( ! mgid ) {
@@ -747,6 +754,9 @@ void ib_mcast_detach ( struct ib_device *ibdev, struct ib_queue_pair *qp,
union ib_gid *gid ) {
struct ib_multicast_gid *mgid;
+ /* Sanity check */
+ assert ( qp != NULL );
+
/* Remove from hardware multicast GID list */
ibdev->op->mcast_detach ( ibdev, qp, gid );
@@ -995,5 +1005,11 @@ struct ib_device * last_opened_ibdev ( void ) {
return ibdev;
}
+/* Drag in objects via register_ibdev() */
+REQUIRING_SYMBOL ( register_ibdev );
+
+/* Drag in Infiniband configuration */
+REQUIRE_OBJECT ( config_infiniband );
+
/* Drag in IPoIB */
REQUIRE_OBJECT ( ipoib );
diff --git a/roms/ipxe/src/net/infiniband/ib_cm.c b/roms/ipxe/src/net/infiniband/ib_cm.c
index 797639bc8..85982f09d 100644
--- a/roms/ipxe/src/net/infiniband/ib_cm.c
+++ b/roms/ipxe/src/net/infiniband/ib_cm.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/net/infiniband/ib_mcast.c b/roms/ipxe/src/net/infiniband/ib_mcast.c
index 0a5e72a37..fc4ff7f0a 100644
--- a/roms/ipxe/src/net/infiniband/ib_mcast.c
+++ b/roms/ipxe/src/net/infiniband/ib_mcast.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <string.h>
@@ -146,6 +150,9 @@ int ib_mcast_join ( struct ib_device *ibdev, struct ib_queue_pair *qp,
DBGC ( ibdev, "IBDEV %p QPN %lx joining " IB_GID_FMT "\n",
ibdev, qp->qpn, IB_GID_ARGS ( gid ) );
+ /* Sanity check */
+ assert ( qp != NULL );
+
/* Initialise structure */
membership->qp = qp;
memcpy ( &membership->gid, gid, sizeof ( membership->gid ) );
@@ -195,6 +202,9 @@ void ib_mcast_leave ( struct ib_device *ibdev, struct ib_queue_pair *qp,
DBGC ( ibdev, "IBDEV %p QPN %lx leaving " IB_GID_FMT "\n",
ibdev, qp->qpn, IB_GID_ARGS ( gid ) );
+ /* Sanity check */
+ assert ( qp != NULL );
+
/* Detach from multicast GID */
ib_mcast_detach ( ibdev, qp, &membership->gid );
diff --git a/roms/ipxe/src/net/infiniband/ib_mi.c b/roms/ipxe/src/net/infiniband/ib_mi.c
index ef6d539f1..b43212974 100644
--- a/roms/ipxe/src/net/infiniband/ib_mi.c
+++ b/roms/ipxe/src/net/infiniband/ib_mi.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/net/infiniband/ib_packet.c b/roms/ipxe/src/net/infiniband/ib_packet.c
index 6c850e39b..d3a22d309 100644
--- a/roms/ipxe/src/net/infiniband/ib_packet.c
+++ b/roms/ipxe/src/net/infiniband/ib_packet.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/net/infiniband/ib_pathrec.c b/roms/ipxe/src/net/infiniband/ib_pathrec.c
index 1b95cbfa8..f9cbab87f 100644
--- a/roms/ipxe/src/net/infiniband/ib_pathrec.c
+++ b/roms/ipxe/src/net/infiniband/ib_pathrec.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/net/infiniband/ib_sma.c b/roms/ipxe/src/net/infiniband/ib_sma.c
index 86553732a..a05d7c924 100644
--- a/roms/ipxe/src/net/infiniband/ib_sma.c
+++ b/roms/ipxe/src/net/infiniband/ib_sma.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/net/infiniband/ib_smc.c b/roms/ipxe/src/net/infiniband/ib_smc.c
index 4d947d568..c1741b26c 100644
--- a/roms/ipxe/src/net/infiniband/ib_smc.c
+++ b/roms/ipxe/src/net/infiniband/ib_smc.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/net/infiniband/ib_srp.c b/roms/ipxe/src/net/infiniband/ib_srp.c
index 7b2b2b4ea..3700184c0 100644
--- a/roms/ipxe/src/net/infiniband/ib_srp.c
+++ b/roms/ipxe/src/net/infiniband/ib_srp.c
@@ -291,7 +291,7 @@ static int ib_srp_parse_byte_string ( const char *rp_comp, uint8_t *bytes,
return -EINVAL_BYTE_STRING_LEN;
/* Parse byte string */
- decoded_size = base16_decode ( rp_comp, bytes );
+ decoded_size = base16_decode ( rp_comp, bytes, size );
if ( decoded_size < 0 )
return decoded_size;
diff --git a/roms/ipxe/src/net/iobpad.c b/roms/ipxe/src/net/iobpad.c
index 9cc8328e9..936b4bde4 100644
--- a/roms/ipxe/src/net/iobpad.c
+++ b/roms/ipxe/src/net/iobpad.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @file
diff --git a/roms/ipxe/src/net/ipv4.c b/roms/ipxe/src/net/ipv4.c
index 9c5cf2eb4..a54784049 100644
--- a/roms/ipxe/src/net/ipv4.c
+++ b/roms/ipxe/src/net/ipv4.c
@@ -1,3 +1,27 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
+ * Copyright (C) 2006 Nikhil Chandru Rao
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
@@ -24,7 +48,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/* Unique IP datagram identification number (high byte) */
static uint8_t next_ident_high = 0;
@@ -115,6 +139,7 @@ static void del_ipv4_miniroute ( struct ipv4_miniroute *miniroute ) {
/**
* Perform IPv4 routing
*
+ * @v scope_id Destination address scope ID
* @v dest Final destination address
* @ret dest Next hop destination address
* @ret miniroute Routing table entry to use, or NULL if no route
@@ -122,22 +147,42 @@ static void del_ipv4_miniroute ( struct ipv4_miniroute *miniroute ) {
* If the route requires use of a gateway, the next hop destination
* address will be overwritten with the gateway address.
*/
-static struct ipv4_miniroute * ipv4_route ( struct in_addr *dest ) {
+static struct ipv4_miniroute * ipv4_route ( unsigned int scope_id,
+ struct in_addr *dest ) {
struct ipv4_miniroute *miniroute;
- int local;
- int has_gw;
/* Find first usable route in routing table */
list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) {
+
+ /* Skip closed network devices */
if ( ! netdev_is_open ( miniroute->netdev ) )
continue;
- local = ( ( ( dest->s_addr ^ miniroute->address.s_addr )
- & miniroute->netmask.s_addr ) == 0 );
- has_gw = ( miniroute->gateway.s_addr );
- if ( local || has_gw ) {
- if ( ! local )
+
+ if ( IN_IS_MULTICAST ( dest->s_addr ) ) {
+
+ /* If destination is non-global, and the scope ID
+ * matches this network device, then use this route.
+ */
+ if ( miniroute->netdev->index == scope_id )
+ return miniroute;
+
+ } else {
+
+ /* If destination is an on-link global
+ * address, then use this route.
+ */
+ if ( ( ( dest->s_addr ^ miniroute->address.s_addr )
+ & miniroute->netmask.s_addr ) == 0 )
+ return miniroute;
+
+ /* If destination is an off-link global
+ * address, and we have a default gateway,
+ * then use this route.
+ */
+ if ( miniroute->gateway.s_addr ) {
*dest = miniroute->gateway;
- return miniroute;
+ return miniroute;
+ }
}
}
@@ -156,7 +201,7 @@ static struct net_device * ipv4_netdev ( struct sockaddr_tcpip *st_dest ) {
struct ipv4_miniroute *miniroute;
/* Find routing table entry */
- miniroute = ipv4_route ( &dest );
+ miniroute = ipv4_route ( sin_dest->sin_scope_id, &dest );
if ( ! miniroute )
return NULL;
@@ -290,8 +335,8 @@ static int ipv4_tx ( struct io_buffer *iobuf,
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 ) ) {
+ ( ( miniroute = ipv4_route ( sin_dest->sin_scope_id,
+ &next_hop ) ) != NULL ) ) {
iphdr->src = miniroute->address;
netmask = miniroute->netmask;
netdev = miniroute->netdev;
@@ -329,7 +374,7 @@ static int ipv4_tx ( struct io_buffer *iobuf,
/* Broadcast address */
ipv4_stats.out_bcast_pkts++;
ll_dest = netdev->ll_broadcast;
- } else if ( IN_MULTICAST ( ntohl ( next_hop.s_addr ) ) ) {
+ } else if ( IN_IS_MULTICAST ( next_hop.s_addr ) ) {
/* Multicast address */
ipv4_stats.out_mcast_pkts++;
if ( ( rc = netdev->ll_protocol->mc_hash ( AF_INET, &next_hop,
@@ -569,10 +614,42 @@ static int ipv4_arp_check ( struct net_device *netdev, const void *net_addr ) {
}
/**
+ * Parse IPv4 address
+ *
+ * @v string IPv4 address string
+ * @ret in IPv4 address to fill in
+ * @ret ok IPv4 address is valid
+ *
+ * Note that this function returns nonzero iff the address is valid,
+ * to match the standard BSD API function of the same name. Unlike
+ * most other iPXE functions, a zero therefore indicates failure.
+ */
+int inet_aton ( const char *string, struct in_addr *in ) {
+ const char *separator = "...";
+ uint8_t *byte = ( ( uint8_t * ) in );
+ char *endp;
+ unsigned long value;
+
+ while ( 1 ) {
+ value = strtoul ( string, &endp, 0 );
+ if ( string == endp )
+ return 0;
+ if ( value > 0xff )
+ return 0;
+ *(byte++) = value;
+ if ( *endp != *separator )
+ return 0;
+ if ( ! *(separator++) )
+ return 1;
+ string = ( endp + 1 );
+ }
+}
+
+/**
* Convert IPv4 address to dotted-quad notation
*
- * @v in IP address
- * @ret string IP address in dotted-quad notation
+ * @v in IPv4 address
+ * @ret string IPv4 address in dotted-quad notation
*/
char * inet_ntoa ( struct in_addr in ) {
static char buf[16]; /* "xxx.xxx.xxx.xxx" */
@@ -583,10 +660,10 @@ char * inet_ntoa ( struct in_addr in ) {
}
/**
- * Transcribe IP address
+ * Transcribe IPv4 address
*
- * @v net_addr IP address
- * @ret string IP address in dotted-quad notation
+ * @v net_addr IPv4 address
+ * @ret string IPv4 address in dotted-quad notation
*
*/
static const char * ipv4_ntoa ( const void *net_addr ) {
@@ -760,12 +837,12 @@ static int ipv4_create_routes ( void ) {
fetch_ipv4_setting ( settings, &netmask_setting, &netmask );
/* Calculate default netmask, if necessary */
if ( ! netmask.s_addr ) {
- if ( IN_CLASSA ( ntohl ( address.s_addr ) ) ) {
- netmask.s_addr = htonl ( IN_CLASSA_NET );
- } else if ( IN_CLASSB ( ntohl ( address.s_addr ) ) ) {
- netmask.s_addr = htonl ( IN_CLASSB_NET );
- } else if ( IN_CLASSC ( ntohl ( address.s_addr ) ) ) {
- netmask.s_addr = htonl ( IN_CLASSC_NET );
+ if ( IN_IS_CLASSA ( address.s_addr ) ) {
+ netmask.s_addr = INADDR_NET_CLASSA;
+ } else if ( IN_IS_CLASSB ( address.s_addr ) ) {
+ netmask.s_addr = INADDR_NET_CLASSB;
+ } else if ( IN_IS_CLASSC ( address.s_addr ) ) {
+ netmask.s_addr = INADDR_NET_CLASSC;
}
}
/* Get default gateway, if present */
@@ -785,5 +862,8 @@ struct settings_applicator ipv4_settings_applicator __settings_applicator = {
.apply = ipv4_create_routes,
};
+/* Drag in objects via ipv4_protocol */
+REQUIRING_SYMBOL ( ipv4_protocol );
+
/* Drag in ICMPv4 */
REQUIRE_OBJECT ( icmpv4 );
diff --git a/roms/ipxe/src/net/ipv6.c b/roms/ipxe/src/net/ipv6.c
index 3c374168c..a75e72ddb 100644
--- a/roms/ipxe/src/net/ipv6.c
+++ b/roms/ipxe/src/net/ipv6.c
@@ -290,8 +290,7 @@ static struct ipv6_miniroute * ipv6_route ( unsigned int scope_id,
if ( ! ( miniroute->flags & IPV6_HAS_ADDRESS ) )
continue;
- if ( IN6_IS_ADDR_LINKLOCAL ( *dest ) ||
- IN6_IS_ADDR_MULTICAST ( *dest ) ) {
+ if ( IN6_IS_ADDR_NONGLOBAL ( *dest ) ) {
/* If destination is non-global, and the scope ID
* matches this network device, then use this route.
@@ -901,7 +900,7 @@ static const char * ipv6_sock_ntoa ( struct sockaddr *sa ) {
const char *netdev_name;
/* Identify network device, if applicable */
- if ( IN6_IS_ADDR_LINKLOCAL ( in ) || IN6_IS_ADDR_MULTICAST ( in ) ) {
+ if ( IN6_IS_ADDR_NONGLOBAL ( in ) ) {
netdev = find_netdev_by_index ( sin6->sin6_scope_id );
netdev_name = ( netdev ? netdev->name : "UNKNOWN" );
} else {
@@ -956,14 +955,26 @@ static int ipv6_sock_aton ( const char *string, struct sockaddr *sa ) {
if ( ( rc = inet6_aton ( in_string, &in ) ) != 0 )
goto err_inet6_aton;
- /* Parse network device name, if present */
+ /* Parse scope ID, if applicable */
if ( netdev_string ) {
+
+ /* Parse explicit network device name, if present */
netdev = find_netdev ( netdev_string );
if ( ! netdev ) {
rc = -ENODEV;
goto err_find_netdev;
}
sin6->sin6_scope_id = netdev->index;
+
+ } else if ( IN6_IS_ADDR_NONGLOBAL ( &in ) ) {
+
+ /* If no network device is explicitly specified for a
+ * link-local or multicast address, default to using
+ * "netX" (if existent).
+ */
+ netdev = last_opened_netdev();
+ if ( netdev )
+ sin6->sin6_scope_id = netdev->index;
}
/* Copy IPv6 address portion to socket address */
@@ -1104,6 +1115,9 @@ struct net_driver ipv6_driver __net_driver = {
.remove = ipv6_remove,
};
+/* Drag in objects via ipv6_protocol */
+REQUIRING_SYMBOL ( ipv6_protocol );
+
/* Drag in ICMPv6 */
REQUIRE_OBJECT ( icmpv6 );
diff --git a/roms/ipxe/src/net/neighbour.c b/roms/ipxe/src/net/neighbour.c
index e3026ce46..7f66d9992 100644
--- a/roms/ipxe/src/net/neighbour.c
+++ b/roms/ipxe/src/net/neighbour.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
@@ -91,8 +95,8 @@ static struct neighbour * neighbour_create ( struct net_device *netdev,
memcpy ( neighbour->net_dest, net_dest,
net_protocol->net_addr_len );
timer_init ( &neighbour->timer, neighbour_expired, &neighbour->refcnt );
- neighbour->timer.min_timeout = NEIGHBOUR_MIN_TIMEOUT;
- neighbour->timer.max_timeout = NEIGHBOUR_MAX_TIMEOUT;
+ set_timer_limits ( &neighbour->timer, NEIGHBOUR_MIN_TIMEOUT,
+ NEIGHBOUR_MAX_TIMEOUT );
INIT_LIST_HEAD ( &neighbour->tx_queue );
/* Transfer ownership to cache */
@@ -318,7 +322,7 @@ int neighbour_tx ( struct io_buffer *iobuf, struct net_device *netdev,
netdev->name, net_protocol->name,
net_protocol->ntoa ( net_dest ) );
list_add_tail ( &iobuf->list, &neighbour->tx_queue );
- return -EAGAIN;
+ return 0;
}
}
diff --git a/roms/ipxe/src/net/netdev_settings.c b/roms/ipxe/src/net/netdev_settings.c
index b3b2e68d8..edd4c4b9f 100644
--- a/roms/ipxe/src/net/netdev_settings.c
+++ b/roms/ipxe/src/net/netdev_settings.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <errno.h>
@@ -121,6 +125,10 @@ static int netdev_fetch_bustype ( struct net_device *netdev, void *data,
[BUS_TYPE_MCA] = "MCA",
[BUS_TYPE_ISA] = "ISA",
[BUS_TYPE_TAP] = "TAP",
+ [BUS_TYPE_EFI] = "EFI",
+ [BUS_TYPE_XEN] = "XEN",
+ [BUS_TYPE_HV] = "HV",
+ [BUS_TYPE_USB] = "USB",
};
struct device_description *desc = &netdev->dev->desc;
const char *bustype;
diff --git a/roms/ipxe/src/net/netdevice.c b/roms/ipxe/src/net/netdevice.c
index a55e6b7d7..7c40a2ac8 100644
--- a/roms/ipxe/src/net/netdevice.c
+++ b/roms/ipxe/src/net/netdevice.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
@@ -35,6 +39,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/device.h>
#include <ipxe/errortab.h>
#include <ipxe/profile.h>
+#include <ipxe/fault.h>
#include <ipxe/vlan.h>
#include <ipxe/netdevice.h>
@@ -157,6 +162,9 @@ void netdev_rx_unfreeze ( struct net_device *netdev ) {
*/
void netdev_link_err ( struct net_device *netdev, int rc ) {
+ /* Stop link block timer */
+ stop_timer ( &netdev->link_block );
+
/* Record link state */
netdev->link_rc = rc;
if ( netdev->link_rc == 0 ) {
@@ -187,6 +195,50 @@ void netdev_link_down ( struct net_device *netdev ) {
}
/**
+ * Mark network device link as being blocked
+ *
+ * @v netdev Network device
+ * @v timeout Timeout (in ticks)
+ */
+void netdev_link_block ( struct net_device *netdev, unsigned long timeout ) {
+
+ /* Start link block timer */
+ if ( ! netdev_link_blocked ( netdev ) ) {
+ DBGC ( netdev, "NETDEV %s link blocked for %ld ticks\n",
+ netdev->name, timeout );
+ }
+ start_timer_fixed ( &netdev->link_block, timeout );
+}
+
+/**
+ * Mark network device link as being unblocked
+ *
+ * @v netdev Network device
+ */
+void netdev_link_unblock ( struct net_device *netdev ) {
+
+ /* Stop link block timer */
+ if ( netdev_link_blocked ( netdev ) )
+ DBGC ( netdev, "NETDEV %s link unblocked\n", netdev->name );
+ stop_timer ( &netdev->link_block );
+}
+
+/**
+ * Handle network device link block timer expiry
+ *
+ * @v timer Link block timer
+ * @v fail Failure indicator
+ */
+static void netdev_link_block_expired ( struct retry_timer *timer,
+ int fail __unused ) {
+ struct net_device *netdev =
+ container_of ( timer, struct net_device, link_block );
+
+ /* Assume link is no longer blocked */
+ DBGC ( netdev, "NETDEV %s link block expired\n", netdev->name );
+}
+
+/**
* Record network device statistic
*
* @v stats Network device statistics
@@ -252,11 +304,8 @@ int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ) {
}
/* Discard packet (for test purposes) if applicable */
- if ( ( NETDEV_DISCARD_RATE > 0 ) &&
- ( ( random() % NETDEV_DISCARD_RATE ) == 0 ) ) {
- rc = -EAGAIN;
+ if ( ( rc = inject_fault ( NETDEV_DISCARD_RATE ) ) != 0 )
goto err;
- }
/* Transmit packet */
if ( ( rc = netdev->op->transmit ( netdev, iobuf ) ) != 0 )
@@ -406,14 +455,14 @@ static void netdev_tx_flush ( struct net_device *netdev ) {
* function takes ownership of the I/O buffer.
*/
void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ) {
+ int rc;
DBGC2 ( netdev, "NETDEV %s received %p (%p+%zx)\n",
netdev->name, iobuf, iobuf->data, iob_len ( iobuf ) );
/* Discard packet (for test purposes) if applicable */
- if ( ( NETDEV_DISCARD_RATE > 0 ) &&
- ( ( random() % NETDEV_DISCARD_RATE ) == 0 ) ) {
- netdev_rx_err ( netdev, iobuf, -EAGAIN );
+ if ( ( rc = inject_fault ( NETDEV_DISCARD_RATE ) ) != 0 ) {
+ netdev_rx_err ( netdev, iobuf, rc );
return;
}
@@ -541,7 +590,8 @@ static struct interface_descriptor netdev_config_desc =
static void free_netdev ( struct refcnt *refcnt ) {
struct net_device *netdev =
container_of ( refcnt, struct net_device, refcnt );
-
+
+ stop_timer ( &netdev->link_block );
netdev_tx_flush ( netdev );
netdev_rx_flush ( netdev );
clear_settings ( netdev_settings ( netdev ) );
@@ -571,6 +621,8 @@ struct net_device * alloc_netdev ( size_t priv_len ) {
if ( netdev ) {
ref_init ( &netdev->refcnt, free_netdev );
netdev->link_rc = -EUNKNOWN_LINK_STATUS;
+ timer_init ( &netdev->link_block, netdev_link_block_expired,
+ &netdev->refcnt );
INIT_LIST_HEAD ( &netdev->tx_queue );
INIT_LIST_HEAD ( &netdev->tx_deferred );
INIT_LIST_HEAD ( &netdev->rx_queue );
@@ -624,11 +676,11 @@ int register_netdev ( struct net_device *netdev ) {
}
/* Record device index and create device name */
- netdev->index = netdev_index++;
if ( netdev->name[0] == '\0' ) {
snprintf ( netdev->name, sizeof ( netdev->name ), "net%d",
- netdev->index );
+ netdev_index );
}
+ netdev->index = ++netdev_index;
/* Use least significant bits of the link-layer address to
* improve the randomness of the (non-cryptographic) random
diff --git a/roms/ipxe/src/net/nullnet.c b/roms/ipxe/src/net/nullnet.c
index 4ac50f64b..2948b38c0 100644
--- a/roms/ipxe/src/net/nullnet.c
+++ b/roms/ipxe/src/net/nullnet.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <errno.h>
diff --git a/roms/ipxe/src/net/pccrc.c b/roms/ipxe/src/net/pccrc.c
new file mode 100644
index 000000000..4cd82cd1c
--- /dev/null
+++ b/roms/ipxe/src/net/pccrc.c
@@ -0,0 +1,818 @@
+/*
+ * Copyright (C) 2015 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <errno.h>
+#include <assert.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/sha256.h>
+#include <ipxe/sha512.h>
+#include <ipxe/hmac.h>
+#include <ipxe/base16.h>
+#include <ipxe/pccrc.h>
+
+/** @file
+ *
+ * Peer Content Caching and Retrieval: Content Identification [MS-PCCRC]
+ *
+ */
+
+/******************************************************************************
+ *
+ * Utility functions
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Transcribe hash value (for debugging)
+ *
+ * @v info Content information
+ * @v hash Hash value
+ * @ret string Hash value string
+ */
+static inline const char *
+peerdist_info_hash_ntoa ( const struct peerdist_info *info, const void *hash ) {
+ static char buf[ ( 2 * PEERDIST_DIGEST_MAX_SIZE ) + 1 /* NUL */ ];
+ size_t digestsize = info->digestsize;
+
+ /* Sanity check */
+ assert ( info != NULL );
+ assert ( digestsize != 0 );
+ assert ( base16_encoded_len ( digestsize ) < sizeof ( buf ) );
+
+ /* Transcribe hash value */
+ base16_encode ( hash, digestsize, buf, sizeof ( buf ) );
+ return buf;
+}
+
+/**
+ * Get raw data
+ *
+ * @v info Content information
+ * @v data Data buffer
+ * @v offset Starting offset
+ * @v len Length
+ * @ret rc Return status code
+ */
+static int peerdist_info_get ( const struct peerdist_info *info, void *data,
+ size_t offset, size_t len ) {
+
+ /* Sanity check */
+ if ( ( offset > info->raw.len ) ||
+ ( len > ( info->raw.len - offset ) ) ) {
+ DBGC ( info, "PCCRC %p data underrun at [%zx,%zx) of %zx\n",
+ info, offset, ( offset + len ), info->raw.len );
+ return -ERANGE;
+ }
+
+ /* Copy data */
+ copy_from_user ( data, info->raw.data, offset, len );
+
+ return 0;
+}
+
+/**
+ * Populate segment hashes
+ *
+ * @v segment Content information segment to fill in
+ * @v hash Segment hash of data
+ * @v secret Segment secret
+ */
+static void peerdist_info_segment_hash ( struct peerdist_info_segment *segment,
+ const void *hash, const void *secret ){
+ const struct peerdist_info *info = segment->info;
+ struct digest_algorithm *digest = info->digest;
+ uint8_t ctx[digest->ctxsize];
+ size_t digestsize = info->digestsize;
+ size_t secretsize = digestsize;
+ static const uint16_t magic[] = PEERDIST_SEGMENT_ID_MAGIC;
+
+ /* Sanity check */
+ assert ( digestsize <= sizeof ( segment->hash ) );
+ assert ( digestsize <= sizeof ( segment->secret ) );
+ assert ( digestsize <= sizeof ( segment->id ) );
+
+ /* Get segment hash of data */
+ memcpy ( segment->hash, hash, digestsize );
+
+ /* Get segment secret */
+ memcpy ( segment->secret, secret, digestsize );
+
+ /* Calculate segment identifier */
+ hmac_init ( digest, ctx, segment->secret, &secretsize );
+ assert ( secretsize == digestsize );
+ hmac_update ( digest, ctx, segment->hash, digestsize );
+ hmac_update ( digest, ctx, magic, sizeof ( magic ) );
+ hmac_final ( digest, ctx, segment->secret, &secretsize, segment->id );
+ assert ( secretsize == digestsize );
+}
+
+/******************************************************************************
+ *
+ * Content Information version 1
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Get number of blocks within a block description
+ *
+ * @v info Content information
+ * @v offset Block description offset
+ * @ret blocks Number of blocks, or negative error
+ */
+static int peerdist_info_v1_blocks ( const struct peerdist_info *info,
+ size_t offset ) {
+ struct peerdist_info_v1_block raw;
+ unsigned int blocks;
+ int rc;
+
+ /* Get block description header */
+ if ( ( rc = peerdist_info_get ( info, &raw, offset,
+ sizeof ( raw ) ) ) != 0 )
+ return rc;
+
+ /* Calculate number of blocks */
+ blocks = le32_to_cpu ( raw.blocks );
+
+ return blocks;
+}
+
+/**
+ * Locate block description
+ *
+ * @v info Content information
+ * @v index Segment index
+ * @ret offset Block description offset, or negative error
+ */
+static ssize_t peerdist_info_v1_block_offset ( const struct peerdist_info *info,
+ unsigned int index ) {
+ size_t digestsize = info->digestsize;
+ unsigned int i;
+ size_t offset;
+ int blocks;
+ int rc;
+
+ /* Sanity check */
+ assert ( index < info->segments );
+
+ /* Calculate offset of first block description */
+ offset = ( sizeof ( struct peerdist_info_v1 ) +
+ ( info->segments *
+ sizeof ( peerdist_info_v1_segment_t ( digestsize ) ) ) );
+
+ /* Iterate over block descriptions until we find this segment */
+ for ( i = 0 ; i < index ; i++ ) {
+
+ /* Get number of blocks */
+ blocks = peerdist_info_v1_blocks ( info, offset );
+ if ( blocks < 0 ) {
+ rc = blocks;
+ DBGC ( info, "PCCRC %p segment %d could not get number "
+ "of blocks: %s\n", info, i, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Move to next block description */
+ offset += sizeof ( peerdist_info_v1_block_t ( digestsize,
+ blocks ) );
+ }
+
+ return offset;
+}
+
+/**
+ * Populate content information
+ *
+ * @v info Content information to fill in
+ * @ret rc Return status code
+ */
+static int peerdist_info_v1 ( struct peerdist_info *info ) {
+ struct peerdist_info_v1 raw;
+ struct peerdist_info_segment first;
+ struct peerdist_info_segment last;
+ size_t first_skip;
+ size_t last_skip;
+ size_t last_read;
+ int rc;
+
+ /* Get raw header */
+ if ( ( rc = peerdist_info_get ( info, &raw, 0, sizeof ( raw ) ) ) != 0){
+ DBGC ( info, "PCCRC %p could not get V1 content information: "
+ "%s\n", info, strerror ( rc ) );
+ return rc;
+ }
+ assert ( raw.version.raw == cpu_to_le16 ( PEERDIST_INFO_V1 ) );
+
+ /* Determine hash algorithm */
+ switch ( raw.hash ) {
+ case cpu_to_le32 ( PEERDIST_INFO_V1_HASH_SHA256 ) :
+ info->digest = &sha256_algorithm;
+ break;
+ case cpu_to_le32 ( PEERDIST_INFO_V1_HASH_SHA384 ) :
+ info->digest = &sha384_algorithm;
+ break;
+ case cpu_to_le32 ( PEERDIST_INFO_V1_HASH_SHA512 ) :
+ info->digest = &sha512_algorithm;
+ break;
+ default:
+ DBGC ( info, "PCCRC %p unsupported hash algorithm %#08x\n",
+ info, le32_to_cpu ( raw.hash ) );
+ return -ENOTSUP;
+ }
+ info->digestsize = info->digest->digestsize;
+ assert ( info->digest != NULL );
+ DBGC2 ( info, "PCCRC %p using %s[%zd]\n",
+ info, info->digest->name, ( info->digestsize * 8 ) );
+
+ /* Calculate number of segments */
+ info->segments = le32_to_cpu ( raw.segments );
+
+ /* Get first segment */
+ if ( ( rc = peerdist_info_segment ( info, &first, 0 ) ) != 0 )
+ return rc;
+
+ /* Calculate range start offset */
+ info->range.start = first.range.start;
+
+ /* Calculate trimmed range start offset */
+ first_skip = le32_to_cpu ( raw.first );
+ info->trim.start = ( first.range.start + first_skip );
+
+ /* Get last segment */
+ if ( ( rc = peerdist_info_segment ( info, &last,
+ ( info->segments - 1 ) ) ) != 0 )
+ return rc;
+
+ /* Calculate range end offset */
+ info->range.end = last.range.end;
+
+ /* Calculate trimmed range end offset */
+ if ( raw.last ) {
+ /* Explicit length to include from last segment is given */
+ last_read = le32_to_cpu ( raw.last );
+ last_skip = ( last.index ? 0 : first_skip );
+ info->trim.end = ( last.range.start + last_skip + last_read );
+ } else {
+ /* No explicit length given: range extends to end of segment */
+ info->trim.end = last.range.end;
+ }
+
+ return 0;
+}
+
+/**
+ * Populate content information segment
+ *
+ * @v segment Content information segment to fill in
+ * @ret rc Return status code
+ */
+static int peerdist_info_v1_segment ( struct peerdist_info_segment *segment ) {
+ const struct peerdist_info *info = segment->info;
+ size_t digestsize = info->digestsize;
+ peerdist_info_v1_segment_t ( digestsize ) raw;
+ ssize_t raw_offset;
+ int blocks;
+ int rc;
+
+ /* Sanity checks */
+ assert ( segment->index < info->segments );
+
+ /* Get raw description */
+ raw_offset = ( sizeof ( struct peerdist_info_v1 ) +
+ ( segment->index * sizeof ( raw ) ) );
+ if ( ( rc = peerdist_info_get ( info, &raw, raw_offset,
+ sizeof ( raw ) ) ) != 0 ) {
+ DBGC ( info, "PCCRC %p segment %d could not get segment "
+ "description: %s\n", info, segment->index,
+ strerror ( rc ) );
+ return rc;
+ }
+
+ /* Calculate start offset of this segment */
+ segment->range.start = le64_to_cpu ( raw.segment.offset );
+
+ /* Calculate end offset of this segment */
+ segment->range.end = ( segment->range.start +
+ le32_to_cpu ( raw.segment.len ) );
+
+ /* Calculate block size of this segment */
+ segment->blksize = le32_to_cpu ( raw.segment.blksize );
+
+ /* Locate block description for this segment */
+ raw_offset = peerdist_info_v1_block_offset ( info, segment->index );
+ if ( raw_offset < 0 ) {
+ rc = raw_offset;
+ return rc;
+ }
+
+ /* Get number of blocks */
+ blocks = peerdist_info_v1_blocks ( info, raw_offset );
+ if ( blocks < 0 ) {
+ rc = blocks;
+ DBGC ( info, "PCCRC %p segment %d could not get number of "
+ "blocks: %s\n", info, segment->index, strerror ( rc ) );
+ return rc;
+ }
+ segment->blocks = blocks;
+
+ /* Calculate segment hashes */
+ peerdist_info_segment_hash ( segment, raw.hash, raw.secret );
+
+ return 0;
+}
+
+/**
+ * Populate content information block
+ *
+ * @v block Content information block to fill in
+ * @ret rc Return status code
+ */
+static int peerdist_info_v1_block ( struct peerdist_info_block *block ) {
+ const struct peerdist_info_segment *segment = block->segment;
+ const struct peerdist_info *info = segment->info;
+ size_t digestsize = info->digestsize;
+ peerdist_info_v1_block_t ( digestsize, segment->blocks ) raw;
+ ssize_t raw_offset;
+ int rc;
+
+ /* Sanity checks */
+ assert ( block->index < segment->blocks );
+
+ /* Calculate start offset of this block */
+ block->range.start = ( segment->range.start +
+ ( block->index * segment->blksize ) );
+
+ /* Calculate end offset of this block */
+ block->range.end = ( block->range.start + segment->blksize );
+ if ( block->range.end > segment->range.end )
+ block->range.end = segment->range.end;
+
+ /* Locate block description */
+ raw_offset = peerdist_info_v1_block_offset ( info, segment->index );
+ if ( raw_offset < 0 ) {
+ rc = raw_offset;
+ return rc;
+ }
+
+ /* Get block hash */
+ raw_offset += offsetof ( typeof ( raw ), hash[block->index] );
+ if ( ( rc = peerdist_info_get ( info, block->hash, raw_offset,
+ digestsize ) ) != 0 ) {
+ DBGC ( info, "PCCRC %p segment %d block %d could not get "
+ "hash: %s\n", info, segment->index, block->index,
+ strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/** Content information version 1 operations */
+static struct peerdist_info_operations peerdist_info_v1_operations = {
+ .info = peerdist_info_v1,
+ .segment = peerdist_info_v1_segment,
+ .block = peerdist_info_v1_block,
+};
+
+/******************************************************************************
+ *
+ * Content Information version 2
+ *
+ ******************************************************************************
+ */
+
+/** A segment cursor */
+struct peerdist_info_v2_cursor {
+ /** Raw data offset */
+ size_t offset;
+ /** Number of segments remaining within this chunk */
+ unsigned int remaining;
+ /** Accumulated segment length */
+ size_t len;
+};
+
+/**
+ * Initialise segment cursor
+ *
+ * @v cursor Segment cursor
+ */
+static inline void
+peerdist_info_v2_cursor_init ( struct peerdist_info_v2_cursor *cursor ) {
+
+ /* Initialise cursor */
+ cursor->offset = ( sizeof ( struct peerdist_info_v2 ) +
+ sizeof ( struct peerdist_info_v2_chunk ) );
+ cursor->remaining = 0;
+ cursor->len = 0;
+}
+
+/**
+ * Update segment cursor to next segment description
+ *
+ * @v info Content information
+ * @v offset Current offset
+ * @v remaining Number of segments remaining within this chunk
+ * @ret rc Return status code
+ */
+static int
+peerdist_info_v2_cursor_next ( const struct peerdist_info *info,
+ struct peerdist_info_v2_cursor *cursor ) {
+ size_t digestsize = info->digestsize;
+ peerdist_info_v2_segment_t ( digestsize ) raw;
+ struct peerdist_info_v2_chunk chunk;
+ int rc;
+
+ /* Get chunk description if applicable */
+ if ( ! cursor->remaining ) {
+
+ /* Get chunk description */
+ if ( ( rc = peerdist_info_get ( info, &chunk,
+ ( cursor->offset -
+ sizeof ( chunk ) ),
+ sizeof ( chunk ) ) ) != 0 )
+ return rc;
+
+ /* Update number of segments remaining */
+ cursor->remaining = ( be32_to_cpu ( chunk.len ) /
+ sizeof ( raw ) );
+ }
+
+ /* Get segment description header */
+ if ( ( rc = peerdist_info_get ( info, &raw.segment, cursor->offset,
+ sizeof ( raw.segment ) ) ) != 0 )
+ return rc;
+
+ /* Update cursor */
+ cursor->offset += sizeof ( raw );
+ cursor->remaining--;
+ if ( ! cursor->remaining )
+ cursor->offset += sizeof ( chunk );
+ cursor->len += be32_to_cpu ( raw.segment.len );
+
+ return 0;
+}
+
+/**
+ * Get number of segments and total length
+ *
+ * @v info Content information
+ * @v len Length to fill in
+ * @ret rc Number of segments, or negative error
+ */
+static int peerdist_info_v2_segments ( const struct peerdist_info *info,
+ size_t *len ) {
+ struct peerdist_info_v2_cursor cursor;
+ unsigned int segments;
+ int rc;
+
+ /* Iterate over all segments */
+ for ( peerdist_info_v2_cursor_init ( &cursor ), segments = 0 ;
+ cursor.offset < info->raw.len ; segments++ ) {
+
+ /* Update segment cursor */
+ if ( ( rc = peerdist_info_v2_cursor_next ( info,
+ &cursor ) ) != 0 ) {
+ DBGC ( info, "PCCRC %p segment %d could not update "
+ "segment cursor: %s\n",
+ info, segments, strerror ( rc ) );
+ return rc;
+ }
+ }
+
+ /* Record accumulated length */
+ *len = cursor.len;
+
+ return segments;
+}
+
+/**
+ * Populate content information
+ *
+ * @v info Content information to fill in
+ * @ret rc Return status code
+ */
+static int peerdist_info_v2 ( struct peerdist_info *info ) {
+ struct peerdist_info_v2 raw;
+ size_t len = 0;
+ int segments;
+ int rc;
+
+ /* Get raw header */
+ if ( ( rc = peerdist_info_get ( info, &raw, 0, sizeof ( raw ) ) ) != 0){
+ DBGC ( info, "PCCRC %p could not get V2 content information: "
+ "%s\n", info, strerror ( rc ) );
+ return rc;
+ }
+ assert ( raw.version.raw == cpu_to_le16 ( PEERDIST_INFO_V2 ) );
+
+ /* Determine hash algorithm */
+ switch ( raw.hash ) {
+ case PEERDIST_INFO_V2_HASH_SHA512_TRUNC :
+ info->digest = &sha512_algorithm;
+ info->digestsize = ( 256 / 8 );
+ break;
+ default:
+ DBGC ( info, "PCCRC %p unsupported hash algorithm %#02x\n",
+ info, raw.hash );
+ return -ENOTSUP;
+ }
+ assert ( info->digest != NULL );
+ DBGC2 ( info, "PCCRC %p using %s[%zd]\n",
+ info, info->digest->name, ( info->digestsize * 8 ) );
+
+ /* Calculate number of segments and total length */
+ segments = peerdist_info_v2_segments ( info, &len );
+ if ( segments < 0 ) {
+ rc = segments;
+ DBGC ( info, "PCCRC %p could not get segment count and length: "
+ "%s\n", info, strerror ( rc ) );
+ return rc;
+ }
+ info->segments = segments;
+
+ /* Calculate range start offset */
+ info->range.start = be64_to_cpu ( raw.offset );
+
+ /* Calculate trimmed range start offset */
+ info->trim.start = ( info->range.start + be32_to_cpu ( raw.first ) );
+
+ /* Calculate range end offset */
+ info->range.end = ( info->range.start + len );
+
+ /* Calculate trimmed range end offset */
+ info->trim.end = ( raw.len ? be64_to_cpu ( raw.len ) :
+ info->range.end );
+
+ return 0;
+}
+
+/**
+ * Populate content information segment
+ *
+ * @v segment Content information segment to fill in
+ * @ret rc Return status code
+ */
+static int peerdist_info_v2_segment ( struct peerdist_info_segment *segment ) {
+ const struct peerdist_info *info = segment->info;
+ size_t digestsize = info->digestsize;
+ peerdist_info_v2_segment_t ( digestsize ) raw;
+ struct peerdist_info_v2_cursor cursor;
+ unsigned int index;
+ size_t len;
+ int rc;
+
+ /* Sanity checks */
+ assert ( segment->index < info->segments );
+
+ /* Iterate over all segments before the target segment */
+ for ( peerdist_info_v2_cursor_init ( &cursor ), index = 0 ;
+ index < segment->index ; index++ ) {
+
+ /* Update segment cursor */
+ if ( ( rc = peerdist_info_v2_cursor_next ( info,
+ &cursor ) ) != 0 ) {
+ DBGC ( info, "PCCRC %p segment %d could not update "
+ "segment cursor: %s\n",
+ info, index, strerror ( rc ) );
+ return rc;
+ }
+ }
+
+ /* Get raw description */
+ if ( ( rc = peerdist_info_get ( info, &raw, cursor.offset,
+ sizeof ( raw ) ) ) != 0 ) {
+ DBGC ( info, "PCCRC %p segment %d could not get segment "
+ "description: %s\n",
+ info, segment->index, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Calculate start offset of this segment */
+ segment->range.start = ( info->range.start + cursor.len );
+
+ /* Calculate end offset of this segment */
+ len = be32_to_cpu ( raw.segment.len );
+ segment->range.end = ( segment->range.start + len );
+
+ /* Model as a segment containing a single block */
+ segment->blocks = 1;
+ segment->blksize = len;
+
+ /* Calculate segment hashes */
+ peerdist_info_segment_hash ( segment, raw.hash, raw.secret );
+
+ return 0;
+}
+
+/**
+ * Populate content information block
+ *
+ * @v block Content information block to fill in
+ * @ret rc Return status code
+ */
+static int peerdist_info_v2_block ( struct peerdist_info_block *block ) {
+ const struct peerdist_info_segment *segment = block->segment;
+ const struct peerdist_info *info = segment->info;
+ size_t digestsize = info->digestsize;
+
+ /* Sanity checks */
+ assert ( block->index < segment->blocks );
+
+ /* Model as a block covering the whole segment */
+ memcpy ( &block->range, &segment->range, sizeof ( block->range ) );
+ memcpy ( block->hash, segment->hash, digestsize );
+
+ return 0;
+}
+
+/** Content information version 2 operations */
+static struct peerdist_info_operations peerdist_info_v2_operations = {
+ .block = peerdist_info_v2_block,
+ .segment = peerdist_info_v2_segment,
+ .info = peerdist_info_v2,
+};
+
+/******************************************************************************
+ *
+ * Content Information
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Populate content information
+ *
+ * @v data Raw data
+ * @v len Length of raw data
+ * @v info Content information to fill in
+ * @ret rc Return status code
+ */
+int peerdist_info ( userptr_t data, size_t len, struct peerdist_info *info ) {
+ union peerdist_info_version version;
+ int rc;
+
+ /* Initialise structure */
+ memset ( info, 0, sizeof ( *info ) );
+ info->raw.data = data;
+ info->raw.len = len;
+
+ /* Get version */
+ if ( ( rc = peerdist_info_get ( info, &version, 0,
+ sizeof ( version ) ) ) != 0 ) {
+ DBGC ( info, "PCCRC %p could not get version: %s\n",
+ info, strerror ( rc ) );
+ return rc;
+ }
+ DBGC2 ( info, "PCCRC %p version %d.%d\n",
+ info, version.major, version.minor );
+
+ /* Determine version */
+ switch ( version.raw ) {
+ case cpu_to_le16 ( PEERDIST_INFO_V1 ) :
+ info->op = &peerdist_info_v1_operations;
+ break;
+ case cpu_to_le16 ( PEERDIST_INFO_V2 ) :
+ info->op = &peerdist_info_v2_operations;
+ break;
+ default:
+ DBGC ( info, "PCCRC %p unsupported version %d.%d\n",
+ info, version.major, version.minor );
+ return -ENOTSUP;
+ }
+ assert ( info->op != NULL );
+ assert ( info->op->info != NULL );
+
+ /* Populate content information */
+ if ( ( rc = info->op->info ( info ) ) != 0 )
+ return rc;
+
+ DBGC2 ( info, "PCCRC %p range [%08zx,%08zx) covers [%08zx,%08zx) with "
+ "%d segments\n", info, info->range.start, info->range.end,
+ info->trim.start, info->trim.end, info->segments );
+ return 0;
+}
+
+/**
+ * Populate content information segment
+ *
+ * @v info Content information
+ * @v segment Content information segment to fill in
+ * @v index Segment index
+ * @ret rc Return status code
+ */
+int peerdist_info_segment ( const struct peerdist_info *info,
+ struct peerdist_info_segment *segment,
+ unsigned int index ) {
+ int rc;
+
+ /* Sanity checks */
+ assert ( info != NULL );
+ assert ( info->op != NULL );
+ assert ( info->op->segment != NULL );
+ if ( index >= info->segments ) {
+ DBGC ( info, "PCCRC %p segment %d of [0,%d) out of range\n",
+ info, index, info->segments );
+ return -ERANGE;
+ }
+
+ /* Initialise structure */
+ memset ( segment, 0, sizeof ( *segment ) );
+ segment->info = info;
+ segment->index = index;
+
+ /* Populate content information segment */
+ if ( ( rc = info->op->segment ( segment ) ) != 0 )
+ return rc;
+
+ DBGC2 ( info, "PCCRC %p segment %d range [%08zx,%08zx) with %d "
+ "blocks\n", info, segment->index, segment->range.start,
+ segment->range.end, segment->blocks );
+ DBGC2 ( info, "PCCRC %p segment %d digest %s\n", info, segment->index,
+ peerdist_info_hash_ntoa ( info, segment->hash ) );
+ DBGC2 ( info, "PCCRC %p segment %d secret %s\n", info, segment->index,
+ peerdist_info_hash_ntoa ( info, segment->secret ) );
+ DBGC2 ( info, "PCCRC %p segment %d identf %s\n", info, segment->index,
+ peerdist_info_hash_ntoa ( info, segment->id ) );
+ return 0;
+}
+
+/**
+ * Populate content information block
+ *
+ * @v segment Content information segment
+ * @v block Content information block to fill in
+ * @v index Block index
+ * @ret rc Return status code
+ */
+int peerdist_info_block ( const struct peerdist_info_segment *segment,
+ struct peerdist_info_block *block,
+ unsigned int index ) {
+ const struct peerdist_info *info = segment->info;
+ size_t start;
+ size_t end;
+ int rc;
+
+ /* Sanity checks */
+ assert ( segment != NULL );
+ assert ( info != NULL );
+ assert ( info->op != NULL );
+ assert ( info->op->block != NULL );
+ if ( index >= segment->blocks ) {
+ DBGC ( info, "PCCRC %p segment %d block %d of [0,%d) out of "
+ "range\n", info, segment->index, index, segment->blocks);
+ return -ERANGE;
+ }
+
+ /* Initialise structure */
+ memset ( block, 0, sizeof ( *block ) );
+ block->segment = segment;
+ block->index = index;
+
+ /* Populate content information block */
+ if ( ( rc = info->op->block ( block ) ) != 0 )
+ return rc;
+
+ /* Calculate trimmed range */
+ start = block->range.start;
+ if ( start < info->trim.start )
+ start = info->trim.start;
+ end = block->range.end;
+ if ( end > info->trim.end )
+ end = info->trim.end;
+ if ( end < start )
+ end = start;
+ block->trim.start = start;
+ block->trim.end = end;
+
+ DBGC2 ( info, "PCCRC %p segment %d block %d hash %s\n",
+ info, segment->index, block->index,
+ peerdist_info_hash_ntoa ( info, block->hash ) );
+ DBGC2 ( info, "PCCRC %p segment %d block %d range [%08zx,%08zx) covers "
+ "[%08zx,%08zx)\n", info, segment->index, block->index,
+ block->range.start, block->range.end, block->trim.start,
+ block->trim.end );
+ return 0;
+}
diff --git a/roms/ipxe/src/net/pccrd.c b/roms/ipxe/src/net/pccrd.c
new file mode 100644
index 000000000..04b5dd86c
--- /dev/null
+++ b/roms/ipxe/src/net/pccrd.c
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2015 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <assert.h>
+#include <ipxe/pccrd.h>
+
+/** @file
+ *
+ * Peer Content Caching and Retrieval: Discovery Protocol [MS-PCCRD]
+ *
+ * This protocol manages to ingeniously combine the excessive
+ * verbosity of XML with a paucity of actual information. For
+ * example: even in version 2.0 of the protocol it is still not
+ * possible to discover which peers hold a specific block within a
+ * given segment.
+ *
+ * For added bonus points, version 1.0 of the protocol is specified to
+ * use a case-sensitive string comparison (for SHA2 digest values) but
+ * nothing specifies whether the strings in question should be in
+ * upper or lower case. There are example strings given in the
+ * specification, but the author skilfully manages to leave the issue
+ * unresolved by using the somewhat implausible digest value of
+ * "0200000000000000000000000000000000000000000000000000000000000000".
+ *
+ * Just in case you were thinking that the silver lining of the choice
+ * to use an XML-based protocol would be the ability to generate and
+ * process messages with standard tools, version 2.0 of the protocol
+ * places most of the critical information inside a Base64-encoded
+ * custom binary data structure. Within an XML element, naturally.
+ *
+ * I hereby announce this specification to be the 2015 winner of the
+ * prestigious "UEFI HII API" award for incompetent design.
+ */
+
+/** Discovery request format */
+#define PEERDIST_DISCOVERY_REQUEST \
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>" \
+ "<soap:Envelope " \
+ "xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\" " \
+ "xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/08/addressing\" " \
+ "xmlns:wsd=\"http://schemas.xmlsoap.org/ws/2005/04/discovery\" " \
+ "xmlns:PeerDist=\"http://schemas.microsoft.com/p2p/" \
+ "2007/09/PeerDistributionDiscovery\">" \
+ "<soap:Header>" \
+ "<wsa:To>" \
+ "urn:schemas-xmlsoap-org:ws:2005:04:discovery" \
+ "</wsa:To>" \
+ "<wsa:Action>" \
+ "http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe" \
+ "</wsa:Action>" \
+ "<wsa:MessageID>" \
+ "urn:uuid:%s" \
+ "</wsa:MessageID>" \
+ "</soap:Header>" \
+ "<soap:Body>" \
+ "<wsd:Probe>" \
+ "<wsd:Types>" \
+ "PeerDist:PeerDistData" \
+ "</wsd:Types>" \
+ "<wsd:Scopes MatchBy=\"http://schemas.xmlsoap.org/ws/" \
+ "2005/04/discovery/strcmp0\">" \
+ "%s" \
+ "</wsd:Scopes>" \
+ "</wsd:Probe>" \
+ "</soap:Body>" \
+ "</soap:Envelope>"
+
+/**
+ * Construct discovery request
+ *
+ * @v uuid Message UUID string
+ * @v id Segment identifier string
+ * @ret request Discovery request, or NULL on failure
+ *
+ * The request is dynamically allocated; the caller must eventually
+ * free() the request.
+ */
+char * peerdist_discovery_request ( const char *uuid, const char *id ) {
+ char *request;
+ int len;
+
+ /* Construct request */
+ len = asprintf ( &request, PEERDIST_DISCOVERY_REQUEST, uuid, id );
+ if ( len < 0 )
+ return NULL;
+
+ return request;
+}
+
+/**
+ * Locate discovery reply tag
+ *
+ * @v data Reply data (not NUL-terminated)
+ * @v len Length of reply data
+ * @v tag XML tag
+ * @ret found Found tag (or NULL if not found)
+ */
+static char * peerdist_discovery_reply_tag ( char *data, size_t len,
+ const char *tag ) {
+ size_t tag_len = strlen ( tag );
+
+ /* Search, allowing for the fact that the reply data is not
+ * cleanly NUL-terminated and may contain embedded NULs due to
+ * earlier parsing.
+ */
+ for ( ; len >= tag_len ; data++, len-- ) {
+ if ( strncmp ( data, tag, tag_len ) == 0 )
+ return data;
+ }
+ return NULL;
+}
+
+/**
+ * Locate discovery reply values
+ *
+ * @v data Reply data (not NUL-terminated, will be modified)
+ * @v len Length of reply data
+ * @v name XML tag name
+ * @ret values Tag values (or NULL if not found)
+ *
+ * The reply data is modified by adding NULs and moving characters as
+ * needed to produce a NUL-separated list of values, terminated with a
+ * zero-length string.
+ *
+ * This is not supposed to be a full XML parser; it's supposed to
+ * include just enough functionality to allow PeerDist discovery to
+ * work with existing implementations.
+ */
+static char * peerdist_discovery_reply_values ( char *data, size_t len,
+ const char *name ) {
+ char buf[ 2 /* "</" */ + strlen ( name ) + 1 /* ">" */ + 1 /* NUL */ ];
+ char *open;
+ char *close;
+ char *start;
+ char *end;
+ char *in;
+ char *out;
+ char c;
+
+ /* Locate opening tag */
+ snprintf ( buf, sizeof ( buf ), "<%s>", name );
+ open = peerdist_discovery_reply_tag ( data, len, buf );
+ if ( ! open )
+ return NULL;
+ start = ( open + strlen ( buf ) );
+ len -= ( start - data );
+ data = start;
+
+ /* Locate closing tag */
+ snprintf ( buf, sizeof ( buf ), "</%s>", name );
+ close = peerdist_discovery_reply_tag ( data, len, buf );
+ if ( ! close )
+ return NULL;
+ assert ( close >= open );
+ end = close;
+
+ /* Strip initial whitespace, convert other whitespace
+ * sequences to single NULs, add terminating pair of NULs.
+ * This will probably overwrite part of the closing tag.
+ */
+ for ( in = start, out = start ; in < end ; in++ ) {
+ c = *in;
+ if ( isspace ( c ) ) {
+ if ( ( out > start ) && ( out[-1] != '\0' ) )
+ *(out++) = '\0';
+ } else {
+ *(out++) = c;
+ }
+ }
+ *(out++) = '\0';
+ *(out++) = '\0';
+ assert ( out < ( close + strlen ( buf ) ) );
+
+ return start;
+}
+
+/**
+ * Parse discovery reply
+ *
+ * @v data Reply data (not NUL-terminated, will be modified)
+ * @v len Length of reply data
+ * @v reply Discovery reply to fill in
+ * @ret rc Return status code
+ *
+ * The discovery reply includes pointers to strings within the
+ * modified reply data.
+ */
+int peerdist_discovery_reply ( char *data, size_t len,
+ struct peerdist_discovery_reply *reply ) {
+ static const struct peerdist_discovery_block_count zcount = {
+ .hex = "00000000",
+ };
+ struct peerdist_discovery_block_count *count;
+ unsigned int max;
+ unsigned int i;
+ char *scopes;
+ char *xaddrs;
+ char *blockcount;
+ char *in;
+ char *out;
+ size_t skip;
+
+ /* Find <wsd:Scopes> tag */
+ scopes = peerdist_discovery_reply_values ( data, len, "wsd:Scopes" );
+ if ( ! scopes ) {
+ DBGC ( reply, "PCCRD %p missing <wsd:Scopes> tag\n", reply );
+ return -ENOENT;
+ }
+
+ /* Find <wsd:XAddrs> tag */
+ xaddrs = peerdist_discovery_reply_values ( data, len, "wsd:XAddrs" );
+ if ( ! xaddrs ) {
+ DBGC ( reply, "PCCRD %p missing <wsd:XAddrs> tag\n", reply );
+ return -ENOENT;
+ }
+
+ /* Find <PeerDist:BlockCount> tag */
+ blockcount = peerdist_discovery_reply_values ( data, len,
+ "PeerDist:BlockCount" );
+ if ( ! blockcount ) {
+ DBGC ( reply, "PCCRD %p missing <PeerDist:BlockCount> tag\n",
+ reply );
+ return -ENOENT;
+ }
+
+ /* Determine maximum number of segments (according to number
+ * of entries in the block count list).
+ */
+ max = ( strlen ( blockcount ) / sizeof ( *count ) );
+ count = container_of ( blockcount,
+ struct peerdist_discovery_block_count, hex[0] );
+
+ /* Eliminate any segments with a zero block count */
+ for ( i = 0, in = scopes, out = scopes ; *in ; i++, in += skip ) {
+
+ /* Fail if we have overrun the maximum number of segments */
+ if ( i >= max ) {
+ DBGC ( reply, "PCCRD %p too many segment IDs\n",
+ reply );
+ return -EPROTO;
+ }
+
+ /* Delete segment if block count is zero */
+ skip = ( strlen ( in ) + 1 /* NUL */ );
+ if ( memcmp ( count[i].hex, zcount.hex,
+ sizeof ( zcount.hex ) ) == 0 )
+ continue;
+ strcpy ( out, in );
+ out += skip;
+ }
+ out[0] = '\0'; /* Ensure list is terminated with a zero-length string */
+
+ /* Fill in discovery reply */
+ reply->ids = scopes;
+ reply->locations = xaddrs;
+
+ return 0;
+}
diff --git a/roms/ipxe/src/net/peerblk.c b/roms/ipxe/src/net/peerblk.c
new file mode 100644
index 000000000..fd7ea0893
--- /dev/null
+++ b/roms/ipxe/src/net/peerblk.c
@@ -0,0 +1,1366 @@
+/*
+ * Copyright (C) 2015 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ipxe/http.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/xfer.h>
+#include <ipxe/uri.h>
+#include <ipxe/timer.h>
+#include <ipxe/profile.h>
+#include <ipxe/fault.h>
+#include <ipxe/pccrr.h>
+#include <ipxe/peerblk.h>
+
+/** @file
+ *
+ * Peer Content Caching and Retrieval (PeerDist) protocol block downloads
+ *
+ */
+
+/** PeerDist decryption chunksize
+ *
+ * This is a policy decision.
+ */
+#define PEERBLK_DECRYPT_CHUNKSIZE 2048
+
+/** PeerDist raw block download attempt initial progress timeout
+ *
+ * This is a policy decision.
+ */
+#define PEERBLK_RAW_OPEN_TIMEOUT ( 10 * TICKS_PER_SEC )
+
+/** PeerDist raw block download attempt ongoing progress timeout
+ *
+ * This is a policy decision.
+ */
+#define PEERBLK_RAW_RX_TIMEOUT ( 15 * TICKS_PER_SEC )
+
+/** PeerDist retrieval protocol block download attempt initial progress timeout
+ *
+ * This is a policy decision.
+ */
+#define PEERBLK_RETRIEVAL_OPEN_TIMEOUT ( 3 * TICKS_PER_SEC )
+
+/** PeerDist retrieval protocol block download attempt ongoing progress timeout
+ *
+ * This is a policy decision.
+ */
+#define PEERBLK_RETRIEVAL_RX_TIMEOUT ( 5 * TICKS_PER_SEC )
+
+/** PeerDist maximum number of full download attempt cycles
+ *
+ * This is the maximum number of times that we will try a full cycle
+ * of download attempts (i.e. a retrieval protocol download attempt
+ * from each discovered peer plus a raw download attempt from the
+ * origin server).
+ *
+ * This is a policy decision.
+ */
+#define PEERBLK_MAX_ATTEMPT_CYCLES 4
+
+/** PeerDist block download profiler */
+static struct profiler peerblk_download_profiler __profiler =
+ { .name = "peerblk.download" };
+
+/** PeerDist block download attempt success profiler */
+static struct profiler peerblk_attempt_success_profiler __profiler =
+ { .name = "peerblk.attempt.success" };
+
+/** PeerDist block download attempt failure profiler */
+static struct profiler peerblk_attempt_failure_profiler __profiler =
+ { .name = "peerblk.attempt.failure" };
+
+/** PeerDist block download attempt timeout profiler */
+static struct profiler peerblk_attempt_timeout_profiler __profiler =
+ { .name = "peerblk.attempt.timeout" };
+
+/** PeerDist block download discovery success profiler */
+static struct profiler peerblk_discovery_success_profiler __profiler =
+ { .name = "peerblk.discovery.success" };
+
+/** PeerDist block download discovery timeout profiler */
+static struct profiler peerblk_discovery_timeout_profiler __profiler =
+ { .name = "peerblk.discovery.timeout" };
+
+/**
+ * Get profiling timestamp
+ *
+ * @ret timestamp Timestamp
+ */
+static inline __attribute__ (( always_inline )) unsigned long
+peerblk_timestamp ( void ) {
+
+ if ( PROFILING ) {
+ return currticks();
+ } else {
+ return 0;
+ }
+}
+
+/**
+ * Free PeerDist block download
+ *
+ * @v refcnt Reference count
+ */
+static void peerblk_free ( struct refcnt *refcnt ) {
+ struct peerdist_block *peerblk =
+ container_of ( refcnt, struct peerdist_block, refcnt );
+
+ uri_put ( peerblk->uri );
+ free ( peerblk->cipherctx );
+ free ( peerblk );
+}
+
+/**
+ * Reset PeerDist block download attempt
+ *
+ * @v peerblk PeerDist block download
+ * @v rc Reason for reset
+ */
+static void peerblk_reset ( struct peerdist_block *peerblk, int rc ) {
+
+ /* Stop decryption process */
+ process_del ( &peerblk->process );
+
+ /* Stop timer */
+ stop_timer ( &peerblk->timer );
+
+ /* Abort any current download attempt */
+ intf_restart ( &peerblk->raw, rc );
+ intf_restart ( &peerblk->retrieval, rc );
+
+ /* Empty received data buffer */
+ xferbuf_free ( &peerblk->buffer );
+ peerblk->pos = 0;
+
+ /* Reset digest and free cipher context */
+ digest_init ( peerblk->digest, peerblk->digestctx );
+ free ( peerblk->cipherctx );
+ peerblk->cipherctx = NULL;
+ peerblk->cipher = NULL;
+
+ /* Reset trim thresholds */
+ peerblk->start = ( peerblk->trim.start - peerblk->range.start );
+ peerblk->end = ( peerblk->trim.end - peerblk->range.start );
+ assert ( peerblk->start <= peerblk->end );
+}
+
+/**
+ * Close PeerDist block download
+ *
+ * @v peerblk PeerDist block download
+ * @v rc Reason for close
+ */
+static void peerblk_close ( struct peerdist_block *peerblk, int rc ) {
+ unsigned long now = peerblk_timestamp();
+
+ /* Profile overall block download */
+ profile_custom ( &peerblk_download_profiler,
+ ( now - peerblk->started ) );
+
+ /* Reset download attempt */
+ peerblk_reset ( peerblk, rc );
+
+ /* Close discovery */
+ peerdisc_close ( &peerblk->discovery );
+
+ /* Shut down all interfaces */
+ intf_shutdown ( &peerblk->retrieval, rc );
+ intf_shutdown ( &peerblk->raw, rc );
+ intf_shutdown ( &peerblk->xfer, rc );
+}
+
+/**
+ * Calculate offset within overall download
+ *
+ * @v peerblk PeerDist block download
+ * @v pos Position within incoming data stream
+ * @ret offset Offset within overall download
+ */
+static inline __attribute__ (( always_inline )) size_t
+peerblk_offset ( struct peerdist_block *peerblk, size_t pos ) {
+
+ return ( ( pos - peerblk->start ) + peerblk->offset );
+}
+
+/**
+ * Deliver download attempt data block
+ *
+ * @v peerblk PeerDist block download
+ * @v iobuf I/O buffer
+ * @v meta Original data transfer metadata
+ * @v pos Position within incoming data stream
+ * @ret rc Return status code
+ */
+static int peerblk_deliver ( struct peerdist_block *peerblk,
+ struct io_buffer *iobuf,
+ struct xfer_metadata *meta, size_t pos ) {
+ struct xfer_metadata xfer_meta;
+ size_t len = iob_len ( iobuf );
+ size_t start = pos;
+ size_t end = ( pos + len );
+ int rc;
+
+ /* Discard zero-length packets and packets which lie entirely
+ * outside the trimmed range.
+ */
+ if ( ( start >= peerblk->end ) || ( end <= peerblk->start ) ||
+ ( len == 0 ) ) {
+ free_iob ( iobuf );
+ return 0;
+ }
+
+ /* Truncate data to within trimmed range */
+ if ( start < peerblk->start ) {
+ iob_pull ( iobuf, ( peerblk->start - start ) );
+ start = peerblk->start;
+ }
+ if ( end > peerblk->end ) {
+ iob_unput ( iobuf, ( end - peerblk->end ) );
+ end = peerblk->end;
+ }
+
+ /* Construct metadata */
+ memcpy ( &xfer_meta, meta, sizeof ( xfer_meta ) );
+ xfer_meta.flags |= XFER_FL_ABS_OFFSET;
+ xfer_meta.offset = peerblk_offset ( peerblk, start );
+
+ /* Deliver data */
+ if ( ( rc = xfer_deliver ( &peerblk->xfer, iob_disown ( iobuf ),
+ &xfer_meta ) ) != 0 ) {
+ DBGC ( peerblk, "PEERBLK %p %d.%d could not deliver data: %s\n",
+ peerblk, peerblk->segment, peerblk->block,
+ strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Finish PeerDist block download attempt
+ *
+ * @v peerblk PeerDist block download
+ * @v rc Reason for close
+ */
+static void peerblk_done ( struct peerdist_block *peerblk, int rc ) {
+ struct digest_algorithm *digest = peerblk->digest;
+ uint8_t hash[digest->digestsize];
+ unsigned long now = peerblk_timestamp();
+
+ /* Check for errors on completion */
+ if ( rc != 0 ) {
+ DBGC ( peerblk, "PEERBLK %p %d.%d attempt failed: %s\n",
+ peerblk, peerblk->segment, peerblk->block,
+ strerror ( rc ) );
+ goto err;
+ }
+
+ /* Check digest */
+ digest_final ( digest, peerblk->digestctx, hash );
+ if ( memcmp ( hash, peerblk->hash, peerblk->digestsize ) != 0 ) {
+ DBGC ( peerblk, "PEERBLK %p %d.%d digest mismatch:\n",
+ peerblk, peerblk->segment, peerblk->block );
+ DBGC_HDA ( peerblk, 0, hash, peerblk->digestsize );
+ DBGC_HDA ( peerblk, 0, peerblk->hash, peerblk->digestsize );
+ rc = -EIO;
+ goto err;
+ }
+
+ /* Profile successful attempt */
+ profile_custom ( &peerblk_attempt_success_profiler,
+ ( now - peerblk->attempted ) );
+
+ /* Close download */
+ peerblk_close ( peerblk, 0 );
+ return;
+
+ err:
+ /* Record failure reason and schedule a retry attempt */
+ profile_custom ( &peerblk_attempt_failure_profiler,
+ ( now - peerblk->attempted ) );
+ peerblk_reset ( peerblk, rc );
+ peerblk->rc = rc;
+ start_timer_nodelay ( &peerblk->timer );
+}
+
+/******************************************************************************
+ *
+ * Raw block download attempts (using an HTTP range request)
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Open PeerDist raw block download attempt
+ *
+ * @v peerblk PeerDist block download
+ * @ret rc Return status code
+ */
+static int peerblk_raw_open ( struct peerdist_block *peerblk ) {
+ struct http_request_range range;
+ int rc;
+
+ DBGC2 ( peerblk, "PEERBLK %p %d.%d attempting raw range request\n",
+ peerblk, peerblk->segment, peerblk->block );
+
+ /* Construct HTTP range */
+ memset ( &range, 0, sizeof ( range ) );
+ range.start = peerblk->range.start;
+ range.len = ( peerblk->range.end - peerblk->range.start );
+
+ /* Initiate range request to retrieve block */
+ if ( ( rc = http_open ( &peerblk->raw, &http_get, peerblk->uri,
+ &range, NULL ) ) != 0 ) {
+ DBGC ( peerblk, "PEERBLK %p %d.%d could not create range "
+ "request: %s\n", peerblk, peerblk->segment,
+ peerblk->block, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Annul HTTP connection (for testing) if applicable. Do not
+ * report as an immediate error, in order to test our ability
+ * to recover from a totally unresponsive HTTP server.
+ */
+ if ( inject_fault ( PEERBLK_ANNUL_RATE ) )
+ intf_restart ( &peerblk->raw, 0 );
+
+ return 0;
+}
+
+/**
+ * Receive PeerDist raw data
+ *
+ * @v peerblk PeerDist block download
+ * @v iobuf I/O buffer
+ * @v meta Data transfer metadata
+ * @ret rc Return status code
+ */
+static int peerblk_raw_rx ( struct peerdist_block *peerblk,
+ struct io_buffer *iobuf,
+ struct xfer_metadata *meta ) {
+ size_t len = iob_len ( iobuf );
+ size_t pos = peerblk->pos;
+ size_t mid = ( ( peerblk->range.end - peerblk->range.start ) / 2 );
+ int rc;
+
+ /* Corrupt received data (for testing) if applicable */
+ inject_corruption ( PEERBLK_CORRUPT_RATE, iobuf->data, len );
+
+ /* Fail if data is delivered out of order, since the streaming
+ * digest requires strict ordering.
+ */
+ if ( ( rc = xfer_check_order ( meta, &peerblk->pos, len ) ) != 0 )
+ goto err;
+
+ /* Add data to digest */
+ digest_update ( peerblk->digest, peerblk->digestctx, iobuf->data, len );
+
+ /* Deliver data */
+ if ( ( rc = peerblk_deliver ( peerblk, iob_disown ( iobuf ), meta,
+ pos ) ) != 0 )
+ goto err;
+
+ /* Extend download attempt timer */
+ start_timer_fixed ( &peerblk->timer, PEERBLK_RAW_RX_TIMEOUT );
+
+ /* Stall download attempt (for testing) if applicable */
+ if ( ( pos < mid ) && ( ( pos + len ) >= mid ) &&
+ ( ( rc = inject_fault ( PEERBLK_STALL_RATE ) ) != 0 ) ) {
+ intf_restart ( &peerblk->raw, rc );
+ }
+
+ return 0;
+
+ err:
+ free_iob ( iobuf );
+ peerblk_done ( peerblk, rc );
+ return rc;
+}
+
+/**
+ * Close PeerDist raw block download attempt
+ *
+ * @v peerblk PeerDist block download
+ * @v rc Reason for close
+ */
+static void peerblk_raw_close ( struct peerdist_block *peerblk, int rc ) {
+
+ /* Restart interface */
+ intf_restart ( &peerblk->raw, rc );
+
+ /* Fail immediately if we have an error */
+ if ( rc != 0 )
+ goto done;
+
+ /* Abort download attempt (for testing) if applicable */
+ if ( ( rc = inject_fault ( PEERBLK_ABORT_RATE ) ) != 0 )
+ goto done;
+
+ done:
+ /* Complete download attempt */
+ peerblk_done ( peerblk, rc );
+}
+
+/******************************************************************************
+ *
+ * Retrieval protocol block download attempts (using HTTP POST)
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Construct PeerDist retrieval protocol URI
+ *
+ * @v location Peer location
+ * @ret uri Retrieval URI, or NULL on error
+ */
+static struct uri * peerblk_retrieval_uri ( const char *location ) {
+ char uri_string[ 7 /* "http://" */ + strlen ( location ) +
+ sizeof ( PEERDIST_MAGIC_PATH /* includes NUL */ ) ];
+
+ /* Construct URI string */
+ snprintf ( uri_string, sizeof ( uri_string ),
+ ( "http://%s" PEERDIST_MAGIC_PATH ), location );
+
+ /* Parse URI string */
+ return parse_uri ( uri_string );
+}
+
+/**
+ * Open PeerDist retrieval protocol block download attempt
+ *
+ * @v peerblk PeerDist block download
+ * @v location Peer location
+ * @ret rc Return status code
+ */
+static int peerblk_retrieval_open ( struct peerdist_block *peerblk,
+ const char *location ) {
+ size_t digestsize = peerblk->digestsize;
+ peerdist_msg_getblks_t ( digestsize, 1, 0 ) req;
+ peerblk_msg_blk_t ( digestsize, 0, 0, 0 ) *rsp;
+ struct http_request_content content;
+ struct uri *uri;
+ int rc;
+
+ DBGC2 ( peerblk, "PEERBLK %p %d.%d attempting retrieval from %s\n",
+ peerblk, peerblk->segment, peerblk->block, location );
+
+ /* Construct block fetch request */
+ memset ( &req, 0, sizeof ( req ) );
+ req.getblks.hdr.version.raw = htonl ( PEERDIST_MSG_GETBLKS_VERSION );
+ req.getblks.hdr.type = htonl ( PEERDIST_MSG_GETBLKS_TYPE );
+ req.getblks.hdr.len = htonl ( sizeof ( req ) );
+ req.getblks.hdr.algorithm = htonl ( PEERDIST_MSG_AES_128_CBC );
+ req.segment.segment.digestsize = htonl ( digestsize );
+ memcpy ( req.segment.id, peerblk->id, digestsize );
+ req.ranges.ranges.count = htonl ( 1 );
+ req.ranges.range[0].first = htonl ( peerblk->block );
+ req.ranges.range[0].count = htonl ( 1 );
+
+ /* Construct POST request content */
+ memset ( &content, 0, sizeof ( content ) );
+ content.data = &req;
+ content.len = sizeof ( req );
+
+ /* Construct URI */
+ if ( ( uri = peerblk_retrieval_uri ( location ) ) == NULL ) {
+ rc = -ENOMEM;
+ goto err_uri;
+ }
+
+ /* Update trim thresholds */
+ peerblk->start += offsetof ( typeof ( *rsp ), msg.vrf );
+ peerblk->end += offsetof ( typeof ( *rsp ), msg.vrf );
+
+ /* Initiate HTTP POST to retrieve block */
+ if ( ( rc = http_open ( &peerblk->retrieval, &http_post, uri,
+ NULL, &content ) ) != 0 ) {
+ DBGC ( peerblk, "PEERBLK %p %d.%d could not create retrieval "
+ "request: %s\n", peerblk, peerblk->segment,
+ peerblk->block, strerror ( rc ) );
+ goto err_open;
+ }
+
+ /* Annul HTTP connection (for testing) if applicable. Do not
+ * report as an immediate error, in order to test our ability
+ * to recover from a totally unresponsive HTTP server.
+ */
+ if ( inject_fault ( PEERBLK_ANNUL_RATE ) )
+ intf_restart ( &peerblk->retrieval, 0 );
+
+ err_open:
+ uri_put ( uri );
+ err_uri:
+ return rc;
+}
+
+/**
+ * Receive PeerDist retrieval protocol data
+ *
+ * @v peerblk PeerDist block download
+ * @v iobuf I/O buffer
+ * @v meta Data transfer metadata
+ * @ret rc Return status code
+ */
+static int peerblk_retrieval_rx ( struct peerdist_block *peerblk,
+ struct io_buffer *iobuf,
+ struct xfer_metadata *meta ) {
+ size_t len = iob_len ( iobuf );
+ size_t start;
+ size_t end;
+ size_t before;
+ size_t after;
+ size_t cut;
+ int rc;
+
+ /* Some genius at Microsoft thought it would be a great idea
+ * to place the AES-CBC initialisation vector *after* the
+ * encrypted data, thereby making it logically impossible to
+ * decrypt each packet as it arrives.
+ *
+ * To work around this mindless stupidity, we deliver the
+ * ciphertext as-is and later use xfer_buffer() to obtain
+ * access to the underlying data transfer buffer in order to
+ * perform the decryption.
+ *
+ * There will be some data both before and after the bytes
+ * corresponding to the trimmed plaintext: a MSG_BLK
+ * header/footer, some block padding for the AES-CBC cipher,
+ * and a possibly large quantity of unwanted ciphertext which
+ * is excluded from the trimmed content range. We store this
+ * data in a local data transfer buffer. If the amount of
+ * data to be stored is too large, we will fail allocation and
+ * so eventually fall back to using a range request (which
+ * does not require this kind of temporary storage
+ * allocation).
+ */
+
+ /* Corrupt received data (for testing) if applicable */
+ inject_corruption ( PEERBLK_CORRUPT_RATE, iobuf->data, len );
+
+ /* Calculate start and end positions of this buffer */
+ start = peerblk->pos;
+ if ( meta->flags & XFER_FL_ABS_OFFSET )
+ start = 0;
+ start += meta->offset;
+ end = ( start + len );
+
+ /* Buffer any data before the trimmed content */
+ if ( ( start < peerblk->start ) && ( len > 0 ) ) {
+
+ /* Calculate length of data before the trimmed content */
+ before = ( peerblk->start - start );
+ if ( before > len )
+ before = len;
+
+ /* Buffer data before the trimmed content */
+ if ( ( rc = xferbuf_write ( &peerblk->buffer, start,
+ iobuf->data, before ) ) != 0 ) {
+ DBGC ( peerblk, "PEERBLK %p %d.%d could not buffer "
+ "data: %s\n", peerblk, peerblk->segment,
+ peerblk->block, strerror ( rc ) );
+ goto err;
+ }
+ }
+
+ /* Buffer any data after the trimmed content */
+ if ( ( end > peerblk->end ) && ( len > 0 ) ) {
+
+ /* Calculate length of data after the trimmed content */
+ after = ( end - peerblk->end );
+ if ( after > len )
+ after = len;
+
+ /* Buffer data after the trimmed content */
+ cut = ( peerblk->end - peerblk->start );
+ if ( ( rc = xferbuf_write ( &peerblk->buffer,
+ ( end - after - cut ),
+ ( iobuf->data + len - after ),
+ after ) ) != 0 ) {
+ DBGC ( peerblk, "PEERBLK %p %d.%d could not buffer "
+ "data: %s\n", peerblk, peerblk->segment,
+ peerblk->block, strerror ( rc ) );
+ goto err;
+ }
+ }
+
+ /* Deliver any remaining data */
+ if ( ( rc = peerblk_deliver ( peerblk, iob_disown ( iobuf ), meta,
+ start ) ) != 0 )
+ goto err;
+
+ /* Update position */
+ peerblk->pos = end;
+
+ /* Extend download attempt timer */
+ start_timer_fixed ( &peerblk->timer, PEERBLK_RETRIEVAL_RX_TIMEOUT );
+
+ /* Stall download attempt (for testing) if applicable */
+ if ( ( start < peerblk->end ) && ( end >= peerblk->end ) &&
+ ( ( rc = inject_fault ( PEERBLK_STALL_RATE ) ) != 0 ) ) {
+ intf_restart ( &peerblk->retrieval, rc );
+ }
+
+ return 0;
+
+ err:
+ free_iob ( iobuf );
+ peerblk_done ( peerblk, rc );
+ return rc;
+}
+
+/**
+ * Parse retrieval protocol message header
+ *
+ * @v peerblk PeerDist block download
+ * @ret rc Return status code
+ */
+static int peerblk_parse_header ( struct peerdist_block *peerblk ) {
+ struct {
+ struct peerdist_msg_transport_header hdr;
+ struct peerdist_msg_header msg;
+ } __attribute__ (( packed )) *msg = peerblk->buffer.data;
+ struct cipher_algorithm *cipher;
+ size_t len = peerblk->buffer.len;
+ size_t keylen = 0;
+ int rc;
+
+ /* Check message length */
+ if ( len < sizeof ( *msg ) ) {
+ DBGC ( peerblk, "PEERBLK %p %d.%d message too short for header "
+ "(%zd bytes)\n", peerblk, peerblk->segment,
+ peerblk->block, len );
+ return -ERANGE;
+ }
+
+ /* Check message type */
+ if ( msg->msg.type != htonl ( PEERDIST_MSG_BLK_TYPE ) ) {
+ DBGC ( peerblk, "PEERBLK %p %d.%d unexpected message type "
+ "%#08x\n", peerblk, peerblk->segment, peerblk->block,
+ ntohl ( msg->msg.type ) );
+ return -EPROTO;
+ }
+
+ /* Determine cipher algorithm and key length */
+ cipher = &aes_cbc_algorithm;
+ switch ( msg->msg.algorithm ) {
+ case htonl ( PEERDIST_MSG_PLAINTEXT ) :
+ cipher = NULL;
+ break;
+ case htonl ( PEERDIST_MSG_AES_128_CBC ) :
+ keylen = ( 128 / 8 );
+ break;
+ case htonl ( PEERDIST_MSG_AES_192_CBC ) :
+ keylen = ( 192 / 8 );
+ break;
+ case htonl ( PEERDIST_MSG_AES_256_CBC ) :
+ keylen = ( 256 / 8 );
+ break;
+ default:
+ DBGC ( peerblk, "PEERBLK %p %d.%d unrecognised algorithm "
+ "%#08x\n", peerblk, peerblk->segment, peerblk->block,
+ ntohl ( msg->msg.algorithm ) );
+ return -ENOTSUP;
+ }
+ DBGC2 ( peerblk, "PEERBLK %p %d.%d using %s with %zd-bit key\n",
+ peerblk, peerblk->segment, peerblk->block,
+ ( cipher ? cipher->name : "plaintext" ), ( 8 * keylen ) );
+
+ /* Sanity check key length against maximum secret length */
+ if ( keylen > peerblk->digestsize ) {
+ DBGC ( peerblk, "PEERBLK %p %d.%d %zd-byte secret too short "
+ "for %zd-bit key\n", peerblk, peerblk->segment,
+ peerblk->block, peerblk->digestsize, ( 8 * keylen ) );
+ return -EPROTO;
+ }
+
+ /* Allocate cipher context. Freeing the cipher context (on
+ * error or otherwise) is handled by peerblk_reset().
+ */
+ peerblk->cipher = cipher;
+ assert ( peerblk->cipherctx == NULL );
+ peerblk->cipherctx = malloc ( cipher->ctxsize );
+ if ( ! peerblk->cipherctx )
+ return -ENOMEM;
+
+ /* Initialise cipher */
+ if ( ( rc = cipher_setkey ( cipher, peerblk->cipherctx, peerblk->secret,
+ keylen ) ) != 0 ) {
+ DBGC ( peerblk, "PEERBLK %p %d.%d could not set key: %s\n",
+ peerblk, peerblk->segment, peerblk->block,
+ strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Parse retrieval protocol message segment and block details
+ *
+ * @v peerblk PeerDist block download
+ * @v buf_len Length of buffered data to fill in
+ * @ret rc Return status code
+ */
+static int peerblk_parse_block ( struct peerdist_block *peerblk,
+ size_t *buf_len ) {
+ size_t digestsize = peerblk->digestsize;
+ peerblk_msg_blk_t ( digestsize, 0, 0, 0 ) *msg = peerblk->buffer.data;
+ size_t len = peerblk->buffer.len;
+ size_t data_len;
+ size_t total;
+
+ /* Check message length */
+ if ( len < offsetof ( typeof ( *msg ), msg.block.data ) ) {
+ DBGC ( peerblk, "PEERBLK %p %d.%d message too short for "
+ "zero-length data (%zd bytes)\n", peerblk,
+ peerblk->segment, peerblk->block, len );
+ return -ERANGE;
+ }
+
+ /* Check digest size */
+ if ( ntohl ( msg->msg.segment.segment.digestsize ) != digestsize ) {
+ DBGC ( peerblk, "PEERBLK %p %d.%d incorrect digest size %d\n",
+ peerblk, peerblk->segment, peerblk->block,
+ ntohl ( msg->msg.segment.segment.digestsize ) );
+ return -EPROTO;
+ }
+
+ /* Check segment ID */
+ if ( memcmp ( msg->msg.segment.id, peerblk->id, digestsize ) != 0 ) {
+ DBGC ( peerblk, "PEERBLK %p %d.%d segment ID mismatch\n",
+ peerblk, peerblk->segment, peerblk->block );
+ return -EPROTO;
+ }
+
+ /* Check block ID */
+ if ( ntohl ( msg->msg.index ) != peerblk->block ) {
+ DBGC ( peerblk, "PEERBLK %p %d.%d block ID mismatch (got %d)\n",
+ peerblk, peerblk->segment, peerblk->block,
+ ntohl ( msg->msg.index ) );
+ return -EPROTO;
+ }
+
+ /* Check for missing blocks */
+ data_len = be32_to_cpu ( msg->msg.block.block.len );
+ if ( ! data_len ) {
+ DBGC ( peerblk, "PEERBLK %p %d.%d block not found\n",
+ peerblk, peerblk->segment, peerblk->block );
+ return -ENOENT;
+ }
+
+ /* Check for underlength blocks */
+ if ( data_len < ( peerblk->range.end - peerblk->range.start ) ) {
+ DBGC ( peerblk, "PEERBLK %p %d.%d underlength block (%zd "
+ "bytes)\n", peerblk, peerblk->segment, peerblk->block,
+ data_len );
+ return -ERANGE;
+ }
+
+ /* Calculate buffered data length (i.e. excluding data which
+ * was delivered to the final data transfer buffer).
+ */
+ *buf_len = ( data_len - ( peerblk->end - peerblk->start ) );
+
+ /* Describe data before the trimmed content */
+ peerblk->decrypt[PEERBLK_BEFORE].xferbuf = &peerblk->buffer;
+ peerblk->decrypt[PEERBLK_BEFORE].offset =
+ offsetof ( typeof ( *msg ), msg.block.data );
+ peerblk->decrypt[PEERBLK_BEFORE].len =
+ ( peerblk->start -
+ offsetof ( typeof ( *msg ), msg.block.data ) );
+ total = peerblk->decrypt[PEERBLK_BEFORE].len;
+
+ /* Describe data within the trimmed content */
+ peerblk->decrypt[PEERBLK_DURING].offset =
+ peerblk_offset ( peerblk, peerblk->start );
+ peerblk->decrypt[PEERBLK_DURING].len =
+ ( peerblk->end - peerblk->start );
+ total += peerblk->decrypt[PEERBLK_DURING].len;
+
+ /* Describe data after the trimmed content */
+ peerblk->decrypt[PEERBLK_AFTER].xferbuf = &peerblk->buffer;
+ peerblk->decrypt[PEERBLK_AFTER].offset = peerblk->start;
+ peerblk->decrypt[PEERBLK_AFTER].len =
+ ( offsetof ( typeof ( *msg ), msg.block.data )
+ + *buf_len - peerblk->start );
+ total += peerblk->decrypt[PEERBLK_AFTER].len;
+
+ /* Sanity check */
+ assert ( total == be32_to_cpu ( msg->msg.block.block.len ) );
+
+ /* Initialise cipher and digest lengths */
+ peerblk->cipher_remaining = total;
+ peerblk->digest_remaining =
+ ( peerblk->range.end - peerblk->range.start );
+ assert ( peerblk->cipher_remaining >= peerblk->digest_remaining );
+
+ return 0;
+}
+
+/**
+ * Parse retrieval protocol message useless details
+ *
+ * @v peerblk PeerDist block download
+ * @v buf_len Length of buffered data
+ * @v vrf_len Length of uselessness to fill in
+ * @ret rc Return status code
+ */
+static int peerblk_parse_useless ( struct peerdist_block *peerblk,
+ size_t buf_len, size_t *vrf_len ) {
+ size_t digestsize = peerblk->digestsize;
+ peerblk_msg_blk_t ( digestsize, buf_len, 0, 0 ) *msg =
+ peerblk->buffer.data;
+ size_t len = peerblk->buffer.len;
+
+ /* Check message length */
+ if ( len < offsetof ( typeof ( *msg ), msg.vrf.data ) ) {
+ DBGC ( peerblk, "PEERBLK %p %d.%d message too short for "
+ "zero-length uselessness (%zd bytes)\n", peerblk,
+ peerblk->segment, peerblk->block, len );
+ return -ERANGE;
+ }
+
+ /* Extract length of uselessness */
+ *vrf_len = be32_to_cpu ( msg->msg.vrf.vrf.len );
+
+ return 0;
+}
+
+/**
+ * Parse retrieval protocol message initialisation vector details
+ *
+ * @v peerblk PeerDist block download
+ * @v buf_len Length of buffered data
+ * @v vrf_len Length of uselessness
+ * @ret rc Return status code
+ */
+static int peerblk_parse_iv ( struct peerdist_block *peerblk, size_t buf_len,
+ size_t vrf_len ) {
+ size_t digestsize = peerblk->digestsize;
+ size_t blksize = peerblk->cipher->blocksize;
+ peerblk_msg_blk_t ( digestsize, buf_len, vrf_len, blksize ) *msg =
+ peerblk->buffer.data;
+ size_t len = peerblk->buffer.len;
+
+ /* Check message length */
+ if ( len < sizeof ( *msg ) ) {
+ DBGC ( peerblk, "PEERBLK %p %d.%d message too short for "
+ "initialisation vector (%zd bytes)\n", peerblk,
+ peerblk->segment, peerblk->block, len );
+ return -ERANGE;
+ }
+
+ /* Check initialisation vector size */
+ if ( ntohl ( msg->msg.iv.iv.blksize ) != blksize ) {
+ DBGC ( peerblk, "PEERBLK %p %d.%d incorrect IV size %d\n",
+ peerblk, peerblk->segment, peerblk->block,
+ ntohl ( msg->msg.iv.iv.blksize ) );
+ return -EPROTO;
+ }
+
+ /* Set initialisation vector */
+ cipher_setiv ( peerblk->cipher, peerblk->cipherctx, msg->msg.iv.data );
+
+ return 0;
+}
+
+/**
+ * Read from decryption buffers
+ *
+ * @v peerblk PeerDist block download
+ * @v data Data buffer
+ * @v len Length to read
+ * @ret rc Return status code
+ */
+static int peerblk_decrypt_read ( struct peerdist_block *peerblk,
+ void *data, size_t len ) {
+ struct peerdist_block_decrypt *decrypt = peerblk->decrypt;
+ size_t frag_len;
+ int rc;
+
+ /* Read from each decryption buffer in turn */
+ for ( ; len ; decrypt++, data += frag_len, len -= frag_len ) {
+
+ /* Calculate length to use from this buffer */
+ frag_len = decrypt->len;
+ if ( frag_len > len )
+ frag_len = len;
+ if ( ! frag_len )
+ continue;
+
+ /* Read from this buffer */
+ if ( ( rc = xferbuf_read ( decrypt->xferbuf, decrypt->offset,
+ data, frag_len ) ) != 0 )
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Write to decryption buffers and update offsets and lengths
+ *
+ * @v peerblk PeerDist block download
+ * @v data Data buffer
+ * @v len Length to read
+ * @ret rc Return status code
+ */
+static int peerblk_decrypt_write ( struct peerdist_block *peerblk,
+ const void *data, size_t len ) {
+ struct peerdist_block_decrypt *decrypt = peerblk->decrypt;
+ size_t frag_len;
+ int rc;
+
+ /* Write to each decryption buffer in turn */
+ for ( ; len ; decrypt++, data += frag_len, len -= frag_len ) {
+
+ /* Calculate length to use from this buffer */
+ frag_len = decrypt->len;
+ if ( frag_len > len )
+ frag_len = len;
+ if ( ! frag_len )
+ continue;
+
+ /* Write to this buffer */
+ if ( ( rc = xferbuf_write ( decrypt->xferbuf, decrypt->offset,
+ data, frag_len ) ) != 0 )
+ return rc;
+
+ /* Update offset and length */
+ decrypt->offset += frag_len;
+ decrypt->len -= frag_len;
+ }
+
+ return 0;
+}
+
+/**
+ * Decrypt one chunk of PeerDist retrieval protocol data
+ *
+ * @v peerblk PeerDist block download
+ */
+static void peerblk_decrypt ( struct peerdist_block *peerblk ) {
+ struct cipher_algorithm *cipher = peerblk->cipher;
+ struct digest_algorithm *digest = peerblk->digest;
+ struct xfer_buffer *xferbuf;
+ size_t cipher_len;
+ size_t digest_len;
+ void *data;
+ int rc;
+
+ /* Sanity check */
+ assert ( ( PEERBLK_DECRYPT_CHUNKSIZE % cipher->blocksize ) == 0 );
+
+ /* Get the underlying data transfer buffer */
+ xferbuf = xfer_buffer ( &peerblk->xfer );
+ if ( ! xferbuf ) {
+ DBGC ( peerblk, "PEERBLK %p %d.%d has no underlying data "
+ "transfer buffer\n", peerblk, peerblk->segment,
+ peerblk->block );
+ rc = -ENOTSUP;
+ goto err_xfer_buffer;
+ }
+ peerblk->decrypt[PEERBLK_DURING].xferbuf = xferbuf;
+
+ /* Calculate cipher and digest lengths */
+ cipher_len = PEERBLK_DECRYPT_CHUNKSIZE;
+ if ( cipher_len > peerblk->cipher_remaining )
+ cipher_len = peerblk->cipher_remaining;
+ digest_len = cipher_len;
+ if ( digest_len > peerblk->digest_remaining )
+ digest_len = peerblk->digest_remaining;
+ assert ( ( cipher_len & ( cipher->blocksize - 1 ) ) == 0 );
+
+ /* Allocate temporary data buffer */
+ data = malloc ( cipher_len );
+ if ( ! data ) {
+ rc = -ENOMEM;
+ goto err_alloc_data;
+ }
+
+ /* Read ciphertext */
+ if ( ( rc = peerblk_decrypt_read ( peerblk, data, cipher_len ) ) != 0 ){
+ DBGC ( peerblk, "PEERBLK %p %d.%d could not read ciphertext: "
+ "%s\n", peerblk, peerblk->segment, peerblk->block,
+ strerror ( rc ) );
+ goto err_read;
+ }
+
+ /* Decrypt data */
+ cipher_decrypt ( cipher, peerblk->cipherctx, data, data, cipher_len );
+
+ /* Add data to digest */
+ digest_update ( digest, peerblk->digestctx, data, digest_len );
+
+ /* Write plaintext */
+ if ( ( rc = peerblk_decrypt_write ( peerblk, data, cipher_len ) ) != 0){
+ DBGC ( peerblk, "PEERBLK %p %d.%d could not write plaintext: "
+ "%s\n", peerblk, peerblk->segment, peerblk->block,
+ strerror ( rc ) );
+ goto err_write;
+ }
+
+ /* Consume input */
+ peerblk->cipher_remaining -= cipher_len;
+ peerblk->digest_remaining -= digest_len;
+
+ /* Free temporary data buffer */
+ free ( data );
+
+ /* Continue processing until all input is consumed */
+ if ( peerblk->cipher_remaining )
+ return;
+
+ /* Complete download attempt */
+ peerblk_done ( peerblk, 0 );
+ return;
+
+ err_write:
+ err_read:
+ free ( data );
+ err_alloc_data:
+ err_xfer_buffer:
+ peerblk_done ( peerblk, rc );
+}
+
+/**
+ * Close PeerDist retrieval protocol block download attempt
+ *
+ * @v peerblk PeerDist block download
+ * @v rc Reason for close
+ */
+static void peerblk_retrieval_close ( struct peerdist_block *peerblk, int rc ) {
+ size_t buf_len;
+ size_t vrf_len;
+
+ /* Restart interface */
+ intf_restart ( &peerblk->retrieval, rc );
+
+ /* Fail immediately if we have an error */
+ if ( rc != 0 )
+ goto done;
+
+ /* Abort download attempt (for testing) if applicable */
+ if ( ( rc = inject_fault ( PEERBLK_ABORT_RATE ) ) != 0 )
+ goto done;
+
+ /* Parse message header */
+ if ( ( rc = peerblk_parse_header ( peerblk ) ) != 0 )
+ goto done;
+
+ /* Parse message segment and block details */
+ if ( ( rc = peerblk_parse_block ( peerblk, &buf_len ) ) != 0 )
+ goto done;
+
+ /* If the block was plaintext, then there is nothing more to do */
+ if ( ! peerblk->cipher )
+ goto done;
+
+ /* Parse message useless details */
+ if ( ( rc = peerblk_parse_useless ( peerblk, buf_len, &vrf_len ) ) != 0)
+ goto done;
+
+ /* Parse message initialisation vector details */
+ if ( ( rc = peerblk_parse_iv ( peerblk, buf_len, vrf_len ) ) != 0 )
+ goto done;
+
+ /* Fail if decryption length is not aligned to the cipher block size */
+ if ( peerblk->cipher_remaining & ( peerblk->cipher->blocksize - 1 ) ) {
+ DBGC ( peerblk, "PEERBLK %p %d.%d unaligned data length %zd\n",
+ peerblk, peerblk->segment, peerblk->block,
+ peerblk->cipher_remaining );
+ rc = -EPROTO;
+ goto done;
+ }
+
+ /* Stop the download attempt timer: there is no point in
+ * timing out while decrypting.
+ */
+ stop_timer ( &peerblk->timer );
+
+ /* Start decryption process */
+ process_add ( &peerblk->process );
+ return;
+
+ done:
+ /* Complete download attempt */
+ peerblk_done ( peerblk, rc );
+}
+
+/******************************************************************************
+ *
+ * Retry policy
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Handle PeerDist retry timer expiry
+ *
+ * @v timer Retry timer
+ * @v over Failure indicator
+ */
+static void peerblk_expired ( struct retry_timer *timer, int over __unused ) {
+ struct peerdist_block *peerblk =
+ container_of ( timer, struct peerdist_block, timer );
+ struct peerdisc_segment *segment = peerblk->discovery.segment;
+ struct peerdisc_peer *head;
+ unsigned long now = peerblk_timestamp();
+ const char *location;
+ int rc;
+
+ /* Profile discovery timeout, if applicable */
+ if ( ( peerblk->peer == NULL ) && ( timer->timeout != 0 ) ) {
+ profile_custom ( &peerblk_discovery_timeout_profiler,
+ ( now - peerblk->started ) );
+ DBGC ( peerblk, "PEERBLK %p %d.%d discovery timed out after "
+ "%ld ticks\n", peerblk, peerblk->segment,
+ peerblk->block, timer->timeout );
+ }
+
+ /* Profile download timeout, if applicable */
+ if ( ( peerblk->peer != NULL ) && ( timer->timeout != 0 ) ) {
+ profile_custom ( &peerblk_attempt_timeout_profiler,
+ ( now - peerblk->attempted ) );
+ DBGC ( peerblk, "PEERBLK %p %d.%d timed out after %ld ticks\n",
+ peerblk, peerblk->segment, peerblk->block,
+ timer->timeout );
+ }
+
+ /* Abort any current download attempt */
+ peerblk_reset ( peerblk, -ETIMEDOUT );
+
+ /* Record attempt start time */
+ peerblk->attempted = now;
+
+ /* If we have exceeded our maximum number of attempt cycles
+ * (each cycle comprising a retrieval protocol download from
+ * each peer in the list followed by a raw download from the
+ * origin server), then abort the overall download.
+ */
+ head = list_entry ( &segment->peers, struct peerdisc_peer, list );
+ if ( ( peerblk->peer == head ) &&
+ ( ++peerblk->cycles >= PEERBLK_MAX_ATTEMPT_CYCLES ) ) {
+ rc = peerblk->rc;
+ assert ( rc != 0 );
+ goto err;
+ }
+
+ /* If we have not yet made any download attempts, then move to
+ * the start of the peer list.
+ */
+ if ( peerblk->peer == NULL )
+ peerblk->peer = head;
+
+ /* Attempt retrieval protocol download from next usable peer */
+ list_for_each_entry_continue ( peerblk->peer, &segment->peers, list ) {
+
+ /* Attempt retrieval protocol download from this peer */
+ location = peerblk->peer->location;
+ if ( ( rc = peerblk_retrieval_open ( peerblk,
+ location ) ) != 0 ) {
+ /* Non-fatal: continue to try next peer */
+ continue;
+ }
+
+ /* Start download attempt timer */
+ peerblk->rc = -ETIMEDOUT;
+ start_timer_fixed ( &peerblk->timer,
+ PEERBLK_RETRIEVAL_OPEN_TIMEOUT );
+ return;
+ }
+
+ /* Attempt raw download */
+ if ( ( rc = peerblk_raw_open ( peerblk ) ) != 0 )
+ goto err;
+
+ /* Start download attempt timer */
+ peerblk->rc = -ETIMEDOUT;
+ start_timer_fixed ( &peerblk->timer, PEERBLK_RAW_OPEN_TIMEOUT );
+ return;
+
+ err:
+ peerblk_close ( peerblk, rc );
+}
+
+/**
+ * Handle PeerDist peer discovery
+ *
+ * @v discovery PeerDist discovery client
+ */
+static void peerblk_discovered ( struct peerdisc_client *discovery ) {
+ struct peerdist_block *peerblk =
+ container_of ( discovery, struct peerdist_block, discovery );
+ unsigned long now = peerblk_timestamp();
+
+ /* Do nothing unless we are still waiting for the initial
+ * discovery timeout.
+ */
+ if ( ( peerblk->peer != NULL ) || ( peerblk->timer.timeout == 0 ) )
+ return;
+
+ /* Schedule an immediate retry */
+ start_timer_nodelay ( &peerblk->timer );
+
+ /* Profile discovery success */
+ profile_custom ( &peerblk_discovery_success_profiler,
+ ( now - peerblk->started ) );
+}
+
+/******************************************************************************
+ *
+ * Opener
+ *
+ ******************************************************************************
+ */
+
+/** PeerDist block download data transfer interface operations */
+static struct interface_operation peerblk_xfer_operations[] = {
+ INTF_OP ( intf_close, struct peerdist_block *, peerblk_close ),
+};
+
+/** PeerDist block download data transfer interface descriptor */
+static struct interface_descriptor peerblk_xfer_desc =
+ INTF_DESC ( struct peerdist_block, xfer, peerblk_xfer_operations );
+
+/** PeerDist block download raw data interface operations */
+static struct interface_operation peerblk_raw_operations[] = {
+ INTF_OP ( xfer_deliver, struct peerdist_block *, peerblk_raw_rx ),
+ INTF_OP ( intf_close, struct peerdist_block *, peerblk_raw_close ),
+};
+
+/** PeerDist block download raw data interface descriptor */
+static struct interface_descriptor peerblk_raw_desc =
+ INTF_DESC ( struct peerdist_block, raw, peerblk_raw_operations );
+
+/** PeerDist block download retrieval protocol interface operations */
+static struct interface_operation peerblk_retrieval_operations[] = {
+ INTF_OP ( xfer_deliver, struct peerdist_block *, peerblk_retrieval_rx ),
+ INTF_OP ( intf_close, struct peerdist_block *, peerblk_retrieval_close),
+};
+
+/** PeerDist block download retrieval protocol interface descriptor */
+static struct interface_descriptor peerblk_retrieval_desc =
+ INTF_DESC ( struct peerdist_block, retrieval,
+ peerblk_retrieval_operations );
+
+/** PeerDist block download decryption process descriptor */
+static struct process_descriptor peerblk_process_desc =
+ PROC_DESC ( struct peerdist_block, process, peerblk_decrypt );
+
+/** PeerDist block download discovery operations */
+static struct peerdisc_client_operations peerblk_discovery_operations = {
+ .discovered = peerblk_discovered,
+};
+
+/**
+ * Open PeerDist block download
+ *
+ * @v xfer Data transfer interface
+ * @v uri Original URI
+ * @v info Content information block
+ * @ret rc Return status code
+ */
+int peerblk_open ( struct interface *xfer, struct uri *uri,
+ struct peerdist_info_block *block ) {
+ const struct peerdist_info_segment *segment = block->segment;
+ const struct peerdist_info *info = segment->info;
+ struct digest_algorithm *digest = info->digest;
+ struct peerdist_block *peerblk;
+ unsigned long timeout;
+ size_t digestsize;
+ int rc;
+
+ /* Allocate and initialise structure */
+ peerblk = zalloc ( sizeof ( *peerblk ) + digest->ctxsize );
+ if ( ! peerblk ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ ref_init ( &peerblk->refcnt, peerblk_free );
+ intf_init ( &peerblk->xfer, &peerblk_xfer_desc, &peerblk->refcnt );
+ intf_init ( &peerblk->raw, &peerblk_raw_desc, &peerblk->refcnt );
+ intf_init ( &peerblk->retrieval, &peerblk_retrieval_desc,
+ &peerblk->refcnt );
+ peerblk->uri = uri_get ( uri );
+ memcpy ( &peerblk->range, &block->range, sizeof ( peerblk->range ) );
+ memcpy ( &peerblk->trim, &block->trim, sizeof ( peerblk->trim ) );
+ peerblk->offset = ( block->trim.start - info->trim.start );
+ peerblk->digest = info->digest;
+ peerblk->digestsize = digestsize = info->digestsize;
+ peerblk->digestctx = ( ( ( void * ) peerblk ) + sizeof ( *peerblk ) );
+ peerblk->segment = segment->index;
+ memcpy ( peerblk->id, segment->id, sizeof ( peerblk->id ) );
+ memcpy ( peerblk->secret, segment->secret, sizeof ( peerblk->secret ) );
+ peerblk->block = block->index;
+ memcpy ( peerblk->hash, block->hash, sizeof ( peerblk->hash ) );
+ xferbuf_malloc_init ( &peerblk->buffer );
+ process_init_stopped ( &peerblk->process, &peerblk_process_desc,
+ &peerblk->refcnt );
+ peerdisc_init ( &peerblk->discovery, &peerblk_discovery_operations );
+ timer_init ( &peerblk->timer, peerblk_expired, &peerblk->refcnt );
+ DBGC2 ( peerblk, "PEERBLK %p %d.%d id %02x%02x%02x%02x%02x..."
+ "%02x%02x%02x [%08zx,%08zx)", peerblk, peerblk->segment,
+ peerblk->block, peerblk->id[0], peerblk->id[1], peerblk->id[2],
+ peerblk->id[3], peerblk->id[4], peerblk->id[ digestsize - 3 ],
+ peerblk->id[ digestsize - 2 ], peerblk->id[ digestsize - 1 ],
+ peerblk->range.start, peerblk->range.end );
+ if ( ( peerblk->trim.start != peerblk->range.start ) ||
+ ( peerblk->trim.end != peerblk->range.end ) ) {
+ DBGC2 ( peerblk, " covers [%08zx,%08zx)",
+ peerblk->trim.start, peerblk->trim.end );
+ }
+ DBGC2 ( peerblk, "\n" );
+
+ /* Open discovery */
+ if ( ( rc = peerdisc_open ( &peerblk->discovery, peerblk->id,
+ peerblk->digestsize ) ) != 0 )
+ goto err_open_discovery;
+
+ /* Schedule a retry attempt either immediately (if we already
+ * have some peers) or after the discovery timeout.
+ */
+ timeout = ( list_empty ( &peerblk->discovery.segment->peers ) ?
+ ( peerdisc_timeout_secs * TICKS_PER_SEC ) : 0 );
+ start_timer_fixed ( &peerblk->timer, timeout );
+
+ /* Record start time */
+ peerblk->started = peerblk_timestamp();
+
+ /* Attach to parent interface, mortalise self, and return */
+ intf_plug_plug ( xfer, &peerblk->xfer );
+ ref_put ( &peerblk->refcnt );
+ return 0;
+
+ err_open_discovery:
+ peerblk_close ( peerblk, rc );
+ err_alloc:
+ return rc;
+}
diff --git a/roms/ipxe/src/net/peerdisc.c b/roms/ipxe/src/net/peerdisc.c
new file mode 100644
index 000000000..5b0e98911
--- /dev/null
+++ b/roms/ipxe/src/net/peerdisc.c
@@ -0,0 +1,551 @@
+/*
+ * Copyright (C) 2015 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <assert.h>
+#include <ipxe/xfer.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/open.h>
+#include <ipxe/tcpip.h>
+#include <ipxe/uuid.h>
+#include <ipxe/base16.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/timer.h>
+#include <ipxe/fault.h>
+#include <ipxe/pccrd.h>
+#include <ipxe/peerdisc.h>
+
+/** @file
+ *
+ * Peer Content Caching and Retrieval (PeerDist) protocol peer discovery
+ *
+ */
+
+/** List of discovery segments */
+static LIST_HEAD ( peerdisc_segments );
+
+/** Number of repeated discovery attempts */
+#define PEERDISC_REPEAT_COUNT 2
+
+/** Time between repeated discovery attempts */
+#define PEERDISC_REPEAT_TIMEOUT ( 1 * TICKS_PER_SEC )
+
+/** Default discovery timeout (in seconds) */
+#define PEERDISC_DEFAULT_TIMEOUT_SECS 2
+
+/** Recommended discovery timeout (in seconds)
+ *
+ * We reduce the recommended discovery timeout whenever a segment
+ * fails to discover any peers, and restore the default value whenever
+ * a valid discovery reply is received. We continue to send discovery
+ * requests even if the recommended timeout is reduced to zero.
+ *
+ * This strategy is intended to minimise discovery delays when no
+ * peers are available on the network, while allowing downloads to
+ * quickly switch back to using PeerDist acceleration if new peers
+ * become available.
+ */
+unsigned int peerdisc_timeout_secs = PEERDISC_DEFAULT_TIMEOUT_SECS;
+
+static struct peerdisc_segment * peerdisc_find ( const char *id );
+static int peerdisc_discovered ( struct peerdisc_segment *segment,
+ const char *location );
+
+/******************************************************************************
+ *
+ * Discovery sockets
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Open all PeerDist discovery sockets
+ *
+ * @ret rc Return status code
+ */
+static int peerdisc_socket_open ( void ) {
+ struct peerdisc_socket *socket;
+ int rc;
+
+ /* Open each socket */
+ for_each_table_entry ( socket, PEERDISC_SOCKETS ) {
+ if ( ( rc = xfer_open_socket ( &socket->xfer, SOCK_DGRAM,
+ &socket->address.sa,
+ NULL ) ) != 0 ) {
+ DBGC ( socket, "PEERDISC %s could not open socket: "
+ "%s\n", socket->name, strerror ( rc ) );
+ goto err;
+ }
+ }
+
+ return 0;
+
+ err:
+ for_each_table_entry_continue_reverse ( socket, PEERDISC_SOCKETS )
+ intf_restart ( &socket->xfer, rc );
+ return rc;
+}
+
+/**
+ * Attempt to transmit PeerDist discovery requests on all sockets
+ *
+ * @v uuid Message UUID string
+ * @v id Segment identifier string
+ */
+static void peerdisc_socket_tx ( const char *uuid, const char *id ) {
+ struct peerdisc_socket *socket;
+ struct net_device *netdev;
+ struct xfer_metadata meta;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_tcpip st;
+ } address;
+ char *request;
+ size_t len;
+ int rc;
+
+ /* Construct discovery request */
+ request = peerdist_discovery_request ( uuid, id );
+ if ( ! request )
+ goto err_request;
+ len = strlen ( request );
+
+ /* Initialise data transfer metadata */
+ memset ( &meta, 0, sizeof ( meta ) );
+ meta.dest = &address.sa;
+
+ /* Send message on each socket */
+ for_each_table_entry ( socket, PEERDISC_SOCKETS ) {
+
+ /* Initialise socket address */
+ memcpy ( &address.sa, &socket->address.sa,
+ sizeof ( address.sa ) );
+
+ /* Send message on each open network device */
+ for_each_netdev ( netdev ) {
+
+ /* Skip unopened network devices */
+ if ( ! netdev_is_open ( netdev ) )
+ continue;
+ address.st.st_scope_id = netdev->index;
+
+ /* Discard request (for test purposes) if applicable */
+ if ( inject_fault ( PEERDISC_DISCARD_RATE ) )
+ continue;
+
+ /* Transmit request */
+ if ( ( rc = xfer_deliver_raw_meta ( &socket->xfer,
+ request, len,
+ &meta ) ) != 0 ) {
+ DBGC ( socket, "PEERDISC %s could not transmit "
+ "via %s: %s\n", socket->name,
+ netdev->name, strerror ( rc ) );
+ /* Contine to try other net devices/sockets */
+ continue;
+ }
+ }
+ }
+
+ free ( request );
+ err_request:
+ return;
+}
+
+/**
+ * Handle received PeerDist discovery reply
+ *
+ * @v socket PeerDist discovery socket
+ * @v iobuf I/O buffer
+ * @v meta Data transfer metadata
+ * @ret rc Return status code
+ */
+static int peerdisc_socket_rx ( struct peerdisc_socket *socket,
+ struct io_buffer *iobuf,
+ struct xfer_metadata *meta __unused ) {
+ struct peerdist_discovery_reply reply;
+ struct peerdisc_segment *segment;
+ char *id;
+ char *location;
+ int rc;
+
+ /* Discard reply (for test purposes) if applicable */
+ if ( ( rc = inject_fault ( PEERDISC_DISCARD_RATE ) ) != 0 )
+ goto err;
+
+ /* Parse reply */
+ if ( ( rc = peerdist_discovery_reply ( iobuf->data, iob_len ( iobuf ),
+ &reply ) ) != 0 ) {
+ DBGC ( socket, "PEERDISC %s could not parse reply: %s\n",
+ socket->name, strerror ( rc ) );
+ DBGC_HDA ( socket, 0, iobuf->data, iob_len ( iobuf ) );
+ goto err;
+ }
+
+ /* Any kind of discovery reply indicates that there are active
+ * peers on a local network, so restore the recommended
+ * discovery timeout to its default value for future requests.
+ */
+ if ( peerdisc_timeout_secs != PEERDISC_DEFAULT_TIMEOUT_SECS ) {
+ DBGC ( socket, "PEERDISC %s restoring timeout to %d seconds\n",
+ socket->name, PEERDISC_DEFAULT_TIMEOUT_SECS );
+ }
+ peerdisc_timeout_secs = PEERDISC_DEFAULT_TIMEOUT_SECS;
+
+ /* Iterate over segment IDs */
+ for ( id = reply.ids ; *id ; id += ( strlen ( id ) + 1 /* NUL */ ) ) {
+
+ /* Find corresponding segment */
+ segment = peerdisc_find ( id );
+ if ( ! segment ) {
+ DBGC ( socket, "PEERDISC %s ignoring reply for %s\n",
+ socket->name, id );
+ continue;
+ }
+
+ /* Report all discovered peer locations */
+ for ( location = reply.locations ; *location ;
+ location += ( strlen ( location ) + 1 /* NUL */ ) ) {
+
+ /* Report discovered peer location */
+ if ( ( rc = peerdisc_discovered ( segment,
+ location ) ) != 0 )
+ goto err;
+ }
+ }
+
+ err:
+ free_iob ( iobuf );
+ return rc;
+}
+
+/**
+ * Close all PeerDist discovery sockets
+ *
+ * @v rc Reason for close
+ */
+static void peerdisc_socket_close ( int rc ) {
+ struct peerdisc_socket *socket;
+
+ /* Close all sockets */
+ for_each_table_entry ( socket, PEERDISC_SOCKETS )
+ intf_restart ( &socket->xfer, rc );
+}
+
+/** PeerDist discovery socket interface operations */
+static struct interface_operation peerdisc_socket_operations[] = {
+ INTF_OP ( xfer_deliver, struct peerdisc_socket *, peerdisc_socket_rx ),
+};
+
+/** PeerDist discovery socket interface descriptor */
+static struct interface_descriptor peerdisc_socket_desc =
+ INTF_DESC ( struct peerdisc_socket, xfer, peerdisc_socket_operations );
+
+/** PeerDist discovery IPv4 socket */
+struct peerdisc_socket peerdisc_socket_ipv4 __peerdisc_socket = {
+ .name = "IPv4",
+ .address = {
+ .sin = {
+ .sin_family = AF_INET,
+ .sin_port = htons ( PEERDIST_DISCOVERY_PORT ),
+ .sin_addr.s_addr = htonl ( PEERDIST_DISCOVERY_IPV4 ),
+ },
+ },
+ .xfer = INTF_INIT ( peerdisc_socket_desc ),
+};
+
+/** PeerDist discovery IPv6 socket */
+struct peerdisc_socket peerdisc_socket_ipv6 __peerdisc_socket = {
+ .name = "IPv6",
+ .address = {
+ .sin6 = {
+ .sin6_family = AF_INET6,
+ .sin6_port = htons ( PEERDIST_DISCOVERY_PORT ),
+ .sin6_addr.s6_addr = PEERDIST_DISCOVERY_IPV6,
+ },
+ },
+ .xfer = INTF_INIT ( peerdisc_socket_desc ),
+};
+
+/******************************************************************************
+ *
+ * Discovery segments
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Free PeerDist discovery segment
+ *
+ * @v refcnt Reference count
+ */
+static void peerdisc_free ( struct refcnt *refcnt ) {
+ struct peerdisc_segment *segment =
+ container_of ( refcnt, struct peerdisc_segment, refcnt );
+ struct peerdisc_peer *peer;
+ struct peerdisc_peer *tmp;
+
+ /* Free all discovered peers */
+ list_for_each_entry_safe ( peer, tmp, &segment->peers, list ) {
+ list_del ( &peer->list );
+ free ( peer );
+ }
+
+ /* Free segment */
+ free ( segment );
+}
+
+/**
+ * Find PeerDist discovery segment
+ *
+ * @v id Segment ID
+ * @ret segment PeerDist discovery segment, or NULL if not found
+ */
+static struct peerdisc_segment * peerdisc_find ( const char *id ) {
+ struct peerdisc_segment *segment;
+
+ /* Look for a matching segment */
+ list_for_each_entry ( segment, &peerdisc_segments, list ) {
+ if ( strcmp ( id, segment->id ) == 0 )
+ return segment;
+ }
+
+ return NULL;
+}
+
+/**
+ * Add discovered PeerDist peer
+ *
+ * @v segment PeerDist discovery segment
+ * @v location Peer location
+ * @ret rc Return status code
+ */
+static int peerdisc_discovered ( struct peerdisc_segment *segment,
+ const char *location ) {
+ struct peerdisc_peer *peer;
+ struct peerdisc_client *peerdisc;
+ struct peerdisc_client *tmp;
+
+ /* Ignore duplicate peers */
+ list_for_each_entry ( peer, &segment->peers, list ) {
+ if ( strcmp ( peer->location, location ) == 0 ) {
+ DBGC2 ( segment, "PEERDISC %p duplicate %s\n",
+ segment, location );
+ return 0;
+ }
+ }
+ DBGC2 ( segment, "PEERDISC %p discovered %s\n", segment, location );
+
+ /* Allocate and initialise structure */
+ peer = zalloc ( sizeof ( *peer ) + strlen ( location ) + 1 /* NUL */ );
+ if ( ! peer )
+ return -ENOMEM;
+ strcpy ( peer->location, location );
+
+ /* Add to end of list of peers */
+ list_add_tail ( &peer->list, &segment->peers );
+
+ /* Notify all clients */
+ list_for_each_entry_safe ( peerdisc, tmp, &segment->clients, list )
+ peerdisc->op->discovered ( peerdisc );
+
+ return 0;
+}
+
+/**
+ * Handle discovery timer expiry
+ *
+ * @v timer Discovery timer
+ * @v over Failure indicator
+ */
+static void peerdisc_expired ( struct retry_timer *timer, int over __unused ) {
+ struct peerdisc_segment *segment =
+ container_of ( timer, struct peerdisc_segment, timer );
+
+ /* Attempt to transmit discovery requests */
+ peerdisc_socket_tx ( segment->uuid, segment->id );
+
+ /* Schedule next transmission, if applicable */
+ if ( timer->count < PEERDISC_REPEAT_COUNT )
+ start_timer_fixed ( &segment->timer, PEERDISC_REPEAT_TIMEOUT );
+}
+
+/**
+ * Create PeerDist discovery segment
+ *
+ * @v id Segment ID
+ * @ret segment PeerDist discovery segment, or NULL on error
+ */
+static struct peerdisc_segment * peerdisc_create ( const char *id ) {
+ struct peerdisc_segment *segment;
+ union {
+ union uuid uuid;
+ uint32_t dword[ sizeof ( union uuid ) / sizeof ( uint32_t ) ];
+ } random_uuid;
+ size_t uuid_len;
+ size_t id_len;
+ char *uuid;
+ char *uuid_copy;
+ char *id_copy;
+ unsigned int i;
+
+ /* Generate a random message UUID. This does not require high
+ * quality randomness.
+ */
+ for ( i = 0 ; i < ( sizeof ( random_uuid.dword ) /
+ sizeof ( random_uuid.dword[0] ) ) ; i++ )
+ random_uuid.dword[i] = random();
+ uuid = uuid_ntoa ( &random_uuid.uuid );
+
+ /* Calculate string lengths */
+ id_len = ( strlen ( id ) + 1 /* NUL */ );
+ uuid_len = ( strlen ( uuid ) + 1 /* NUL */ );
+
+ /* Allocate and initialise structure */
+ segment = zalloc ( sizeof ( *segment ) + id_len + uuid_len );
+ if ( ! segment )
+ return NULL;
+ id_copy = ( ( ( void * ) segment ) + sizeof ( *segment ) );
+ memcpy ( id_copy, id, id_len );
+ uuid_copy = ( ( ( void * ) id_copy ) + id_len );
+ memcpy ( uuid_copy, uuid, uuid_len );
+ ref_init ( &segment->refcnt, peerdisc_free );
+ segment->id = id_copy;
+ segment->uuid = uuid_copy;
+ INIT_LIST_HEAD ( &segment->peers );
+ INIT_LIST_HEAD ( &segment->clients );
+ timer_init ( &segment->timer, peerdisc_expired, &segment->refcnt );
+ DBGC2 ( segment, "PEERDISC %p discovering %s\n", segment, segment->id );
+
+ /* Start discovery timer */
+ start_timer_nodelay ( &segment->timer );
+
+ /* Add to list of segments, transfer reference to list, and return */
+ list_add_tail ( &segment->list, &peerdisc_segments );
+ return segment;
+}
+
+/**
+ * Destroy PeerDist discovery segment
+ *
+ * @v segment PeerDist discovery segment
+ */
+static void peerdisc_destroy ( struct peerdisc_segment *segment ) {
+
+ /* Sanity check */
+ assert ( list_empty ( &segment->clients ) );
+
+ /* Stop timer */
+ stop_timer ( &segment->timer );
+
+ /* Remove from list of segments and drop list's reference */
+ list_del ( &segment->list );
+ ref_put ( &segment->refcnt );
+}
+
+/******************************************************************************
+ *
+ * Discovery clients
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Open PeerDist discovery client
+ *
+ * @v peerdisc PeerDist discovery client
+ * @v id Segment ID
+ * @v len Length of segment ID
+ * @ret rc Return status code
+ */
+int peerdisc_open ( struct peerdisc_client *peerdisc, const void *id,
+ size_t len ) {
+ struct peerdisc_segment *segment;
+ char id_string[ base16_encoded_len ( len ) + 1 /* NUL */ ];
+ char *id_chr;
+ int rc;
+
+ /* Construct ID string */
+ base16_encode ( id, len, id_string, sizeof ( id_string ) );
+ for ( id_chr = id_string ; *id_chr ; id_chr++ )
+ *id_chr = toupper ( *id_chr );
+
+ /* Sanity check */
+ assert ( peerdisc->segment == NULL );
+
+ /* Open socket if this is the first segment */
+ if ( list_empty ( &peerdisc_segments ) &&
+ ( ( rc = peerdisc_socket_open() ) != 0 ) )
+ return rc;
+
+ /* Find or create segment */
+ if ( ! ( ( segment = peerdisc_find ( id_string ) ) ||
+ ( segment = peerdisc_create ( id_string ) ) ) )
+ return -ENOMEM;
+
+ /* Add to list of clients */
+ ref_get ( &segment->refcnt );
+ peerdisc->segment = segment;
+ list_add_tail ( &peerdisc->list, &segment->clients );
+
+ return 0;
+}
+
+/**
+ * Close PeerDist discovery client
+ *
+ * @v peerdisc PeerDist discovery client
+ */
+void peerdisc_close ( struct peerdisc_client *peerdisc ) {
+ struct peerdisc_segment *segment = peerdisc->segment;
+
+ /* Ignore if discovery is already closed */
+ if ( ! segment )
+ return;
+
+ /* If no peers were discovered, reduce the recommended
+ * discovery timeout to minimise delays on future requests.
+ */
+ if ( list_empty ( &segment->peers ) && peerdisc_timeout_secs ) {
+ peerdisc_timeout_secs--;
+ DBGC ( segment, "PEERDISC %p reducing timeout to %d "
+ "seconds\n", peerdisc, peerdisc_timeout_secs );
+ }
+
+ /* Remove from list of clients */
+ peerdisc->segment = NULL;
+ list_del ( &peerdisc->list );
+ ref_put ( &segment->refcnt );
+
+ /* If this was the last clients, destroy the segment */
+ if ( list_empty ( &segment->clients ) )
+ peerdisc_destroy ( segment );
+
+ /* If there are no more segments, close the socket */
+ if ( list_empty ( &peerdisc_segments ) )
+ peerdisc_socket_close ( 0 );
+}
diff --git a/roms/ipxe/src/net/peerdist.c b/roms/ipxe/src/net/peerdist.c
new file mode 100644
index 000000000..48933f951
--- /dev/null
+++ b/roms/ipxe/src/net/peerdist.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2015 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdio.h>
+#include <ipxe/http.h>
+#include <ipxe/peermux.h>
+
+/** @file
+ *
+ * Peer Content Caching and Retrieval (PeerDist) protocol
+ *
+ * This is quite possibly the ugliest protocol I have ever had the
+ * misfortune to encounter, and I've encountered multicast TFTP.
+ */
+
+/**
+ * Check whether or not to support PeerDist encoding for this request
+ *
+ * @v http HTTP transaction
+ * @ret supported PeerDist encoding is supported for this request
+ */
+static int http_peerdist_supported ( struct http_transaction *http ) {
+
+ /* Support PeerDist encoding only if we can directly access an
+ * underlying data transfer buffer. Direct access is required
+ * in order to support decryption of data received via the
+ * retrieval protocol (which provides the AES initialisation
+ * vector only after all of the encrypted data has been
+ * received).
+ *
+ * This test simultaneously ensures that we do not attempt to
+ * use PeerDist encoding on a request which is itself a
+ * PeerDist individual block download, since the individual
+ * block downloads do not themselves provide direct access to
+ * an underlying data transfer buffer.
+ */
+ return ( xfer_buffer ( &http->xfer ) != NULL );
+}
+
+/**
+ * Format HTTP "X-P2P-PeerDist" header
+ *
+ * @v http HTTP transaction
+ * @v buf Buffer
+ * @v len Length of buffer
+ * @ret len Length of header value, or negative error
+ */
+static int http_format_p2p_peerdist ( struct http_transaction *http,
+ char *buf, size_t len ) {
+ int supported = http_peerdist_supported ( http );
+ int missing;
+
+ /* PeerDist wants us to inform the server whenever we make a
+ * request for data that was missing from local peers
+ * (presumably for statistical purposes only). We use the
+ * heuristic of assuming that the combination of "this request
+ * may not itself use PeerDist content encoding" and "this is
+ * a range request" probably indicates that we are making a
+ * PeerDist block raw range request for missing data.
+ */
+ missing = ( http->request.range.len && ( ! supported ) );
+
+ /* Omit header if PeerDist encoding is not supported and we
+ * are not reporting a missing data request.
+ */
+ if ( ! ( supported || missing ) )
+ return 0;
+
+ /* Construct header */
+ return snprintf ( buf, len, "Version=1.1%s",
+ ( missing ? ", MissingDataRequest=true" : "" ) );
+}
+
+/** HTTP "X-P2P-PeerDist" header */
+struct http_request_header http_request_p2p_peerdist __http_request_header = {
+ .name = "X-P2P-PeerDist",
+ .format = http_format_p2p_peerdist,
+};
+
+/**
+ * Format HTTP "X-P2P-PeerDistEx" header
+ *
+ * @v http HTTP transaction
+ * @v buf Buffer
+ * @v len Length of buffer
+ * @ret len Length of header value, or negative error
+ */
+static int http_format_p2p_peerdistex ( struct http_transaction *http,
+ char *buf, size_t len ) {
+ int supported = http_peerdist_supported ( http );
+
+ /* Omit header if PeerDist encoding is not supported */
+ if ( ! supported )
+ return 0;
+
+ /* Construct header */
+ return snprintf ( buf, len, ( "MinContentInformation=1.0, "
+ "MaxContentInformation=2.0" ) );
+}
+
+/** HTTP "X-P2P-PeerDist" header */
+struct http_request_header http_request_p2p_peerdistex __http_request_header = {
+ .name = "X-P2P-PeerDistEx",
+ .format = http_format_p2p_peerdistex,
+};
+
+/**
+ * Initialise PeerDist content encoding
+ *
+ * @v http HTTP transaction
+ * @ret rc Return status code
+ */
+static int http_peerdist_init ( struct http_transaction *http ) {
+
+ return peermux_filter ( &http->content, &http->transfer, http->uri );
+}
+
+/** PeerDist HTTP content encoding */
+struct http_content_encoding peerdist_encoding __http_content_encoding = {
+ .name = "peerdist",
+ .supported = http_peerdist_supported,
+ .init = http_peerdist_init,
+};
diff --git a/roms/ipxe/src/net/peermux.c b/roms/ipxe/src/net/peermux.c
new file mode 100644
index 000000000..634c69992
--- /dev/null
+++ b/roms/ipxe/src/net/peermux.c
@@ -0,0 +1,387 @@
+/*
+ * Copyright (C) 2015 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdlib.h>
+#include <errno.h>
+#include <ipxe/uri.h>
+#include <ipxe/xferbuf.h>
+#include <ipxe/peerblk.h>
+#include <ipxe/peermux.h>
+
+/** @file
+ *
+ * Peer Content Caching and Retrieval (PeerDist) protocol multiplexer
+ *
+ */
+
+/**
+ * Free PeerDist download multiplexer
+ *
+ * @v refcnt Reference count
+ */
+static void peermux_free ( struct refcnt *refcnt ) {
+ struct peerdist_multiplexer *peermux =
+ container_of ( refcnt, struct peerdist_multiplexer, refcnt );
+
+ uri_put ( peermux->uri );
+ xferbuf_free ( &peermux->buffer );
+ free ( peermux );
+}
+
+/**
+ * Close PeerDist download multiplexer
+ *
+ * @v peermux PeerDist download multiplexer
+ * @v rc Reason for close
+ */
+static void peermux_close ( struct peerdist_multiplexer *peermux, int rc ) {
+ unsigned int i;
+
+ /* Stop block download initiation process */
+ process_del ( &peermux->process );
+
+ /* Shut down all block downloads */
+ for ( i = 0 ; i < PEERMUX_MAX_BLOCKS ; i++ )
+ intf_shutdown ( &peermux->block[i].xfer, rc );
+
+ /* Shut down all other interfaces (which may be connected to
+ * the same object).
+ */
+ intf_nullify ( &peermux->info ); /* avoid potential loops */
+ intf_shutdown ( &peermux->xfer, rc );
+ intf_shutdown ( &peermux->info, rc );
+}
+
+/**
+ * Receive content information
+ *
+ * @v peermux PeerDist download multiplexer
+ * @v iobuf I/O buffer
+ * @v meta Data transfer metadata
+ * @ret rc Return status code
+ */
+static int peermux_info_deliver ( struct peerdist_multiplexer *peermux,
+ struct io_buffer *iobuf,
+ struct xfer_metadata *meta ) {
+ int rc;
+
+ /* Add data to buffer */
+ if ( ( rc = xferbuf_deliver ( &peermux->buffer, iobuf, meta ) ) != 0 )
+ goto err;
+
+ return 0;
+
+ err:
+ peermux_close ( peermux, rc );
+ return rc;
+}
+
+/**
+ * Close content information interface
+ *
+ * @v peermux PeerDist download multiplexer
+ * @v rc Reason for close
+ */
+static void peermux_info_close ( struct peerdist_multiplexer *peermux, int rc ){
+ struct peerdist_info *info = &peermux->cache.info;
+ size_t len;
+
+ /* Terminate download on error */
+ if ( rc != 0 )
+ goto err;
+
+ /* Successfully closing the content information interface
+ * indicates that the content information has been fully
+ * received, and initiates the actual PeerDist download.
+ */
+
+ /* Shut down content information interface */
+ intf_shutdown ( &peermux->info, rc );
+
+ /* Parse content information */
+ if ( ( rc = peerdist_info ( info->raw.data, peermux->buffer.len,
+ info ) ) != 0 ) {
+ DBGC ( peermux, "PEERMUX %p could not parse content info: %s\n",
+ peermux, strerror ( rc ) );
+ goto err;
+ }
+
+ /* Notify recipient of total download size */
+ len = ( info->trim.end - info->trim.start );
+ if ( ( rc = xfer_seek ( &peermux->xfer, len ) ) != 0 ) {
+ DBGC ( peermux, "PEERMUX %p could not presize buffer: %s\n",
+ peermux, strerror ( rc ) );
+ goto err;
+ }
+ xfer_seek ( &peermux->xfer, 0 );
+
+ /* Start block download process */
+ process_add ( &peermux->process );
+
+ return;
+
+ err:
+ peermux_close ( peermux, rc );
+}
+
+/**
+ * Initiate multiplexed block download
+ *
+ * @v peermux PeerDist download multiplexer
+ */
+static void peermux_step ( struct peerdist_multiplexer *peermux ) {
+ struct peerdist_info *info = &peermux->cache.info;
+ struct peerdist_info_segment *segment = &peermux->cache.segment;
+ struct peerdist_info_block *block = &peermux->cache.block;
+ struct peerdist_multiplexed_block *peermblk;
+ unsigned int next_segment;
+ unsigned int next_block;
+ int rc;
+
+ /* Stop initiation process if all block downloads are busy */
+ peermblk = list_first_entry ( &peermux->idle,
+ struct peerdist_multiplexed_block, list );
+ if ( ! peermblk ) {
+ process_del ( &peermux->process );
+ return;
+ }
+
+ /* Increment block index */
+ next_block = ( block->index + 1 );
+
+ /* Move to first/next segment, if applicable */
+ if ( next_block >= segment->blocks ) {
+
+ /* Reset block index */
+ next_block = 0;
+
+ /* Calculate segment index */
+ next_segment = ( segment->info ? ( segment->index + 1 ) : 0 );
+
+ /* If we have finished all segments and have no
+ * remaining block downloads, then we are finished.
+ */
+ if ( next_segment >= info->segments ) {
+ process_del ( &peermux->process );
+ if ( list_empty ( &peermux->busy ) )
+ peermux_close ( peermux, 0 );
+ return;
+ }
+
+ /* Get content information segment */
+ if ( ( rc = peerdist_info_segment ( info, segment,
+ next_segment ) ) != 0 ) {
+ DBGC ( peermux, "PEERMUX %p could not get segment %d "
+ "information: %s\n", peermux, next_segment,
+ strerror ( rc ) );
+ goto err;
+ }
+ }
+
+ /* Get content information block */
+ if ( ( rc = peerdist_info_block ( segment, block, next_block ) ) != 0 ){
+ DBGC ( peermux, "PEERMUX %p could not get segment %d block "
+ "%d information: %s\n", peermux, segment->index,
+ next_block, strerror ( rc ) );
+ goto err;
+ }
+
+ /* Ignore block if it lies entirely outside the trimmed range */
+ if ( block->trim.start == block->trim.end ) {
+ DBGC ( peermux, "PEERMUX %p skipping segment %d block %d\n",
+ peermux, segment->index, block->index );
+ return;
+ }
+
+ /* Start downloading this block */
+ if ( ( rc = peerblk_open ( &peermblk->xfer, peermux->uri,
+ block ) ) != 0 ) {
+ DBGC ( peermux, "PEERMUX %p could not start download for "
+ "segment %d block %d: %s\n", peermux, segment->index,
+ block->index, strerror ( rc ) );
+ goto err;
+ }
+
+ /* Move to list of busy block downloads */
+ list_del ( &peermblk->list );
+ list_add_tail ( &peermblk->list, &peermux->busy );
+
+ return;
+
+ err:
+ peermux_close ( peermux, rc );
+}
+
+/**
+ * Receive data from multiplexed block download
+ *
+ * @v peermblk PeerDist multiplexed block download
+ * @v iobuf I/O buffer
+ * @v meta Data transfer metadata
+ * @ret rc Return status code
+ */
+static int peermux_block_deliver ( struct peerdist_multiplexed_block *peermblk,
+ struct io_buffer *iobuf,
+ struct xfer_metadata *meta ) {
+ struct peerdist_multiplexer *peermux = peermblk->peermux;
+
+ /* Sanity check: all block downloads must use absolute
+ * positions for all deliveries, since they run concurrently.
+ */
+ assert ( meta->flags & XFER_FL_ABS_OFFSET );
+
+ /* We can't use a simple passthrough interface descriptor,
+ * since there are multiple block download interfaces.
+ */
+ return xfer_deliver ( &peermux->xfer, iob_disown ( iobuf ), meta );
+}
+
+/**
+ * Get multiplexed block download underlying data transfer buffer
+ *
+ * @v peermblk PeerDist multiplexed download block
+ * @ret xferbuf Data transfer buffer, or NULL on error
+ */
+static struct xfer_buffer *
+peermux_block_buffer ( struct peerdist_multiplexed_block *peermblk ) {
+ struct peerdist_multiplexer *peermux = peermblk->peermux;
+
+ /* We can't use a simple passthrough interface descriptor,
+ * since there are multiple block download interfaces.
+ */
+ return xfer_buffer ( &peermux->xfer );
+}
+
+/**
+ * Close multiplexed block download
+ *
+ * @v peermblk PeerDist multiplexed block download
+ * @v rc Reason for close
+ */
+static void peermux_block_close ( struct peerdist_multiplexed_block *peermblk,
+ int rc ) {
+ struct peerdist_multiplexer *peermux = peermblk->peermux;
+
+ /* Move to list of idle downloads */
+ list_del ( &peermblk->list );
+ list_add_tail ( &peermblk->list, &peermux->idle );
+
+ /* If any error occurred, terminate the whole multiplexer */
+ if ( rc != 0 ) {
+ peermux_close ( peermux, rc );
+ return;
+ }
+
+ /* Restart data transfer interface */
+ intf_restart ( &peermblk->xfer, rc );
+
+ /* Restart block download initiation process */
+ process_add ( &peermux->process );
+}
+
+/** Data transfer interface operations */
+static struct interface_operation peermux_xfer_operations[] = {
+ INTF_OP ( intf_close, struct peerdist_multiplexer *, peermux_close ),
+};
+
+/** Data transfer interface descriptor */
+static struct interface_descriptor peermux_xfer_desc =
+ INTF_DESC_PASSTHRU ( struct peerdist_multiplexer, xfer,
+ peermux_xfer_operations, info );
+
+/** Content information interface operations */
+static struct interface_operation peermux_info_operations[] = {
+ INTF_OP ( xfer_deliver, struct peerdist_multiplexer *,
+ peermux_info_deliver ),
+ INTF_OP ( intf_close, struct peerdist_multiplexer *,
+ peermux_info_close ),
+};
+
+/** Content information interface descriptor */
+static struct interface_descriptor peermux_info_desc =
+ INTF_DESC_PASSTHRU ( struct peerdist_multiplexer, info,
+ peermux_info_operations, xfer );
+
+/** Block download data transfer interface operations */
+static struct interface_operation peermux_block_operations[] = {
+ INTF_OP ( xfer_deliver, struct peerdist_multiplexed_block *,
+ peermux_block_deliver ),
+ INTF_OP ( xfer_buffer, struct peerdist_multiplexed_block *,
+ peermux_block_buffer ),
+ INTF_OP ( intf_close, struct peerdist_multiplexed_block *,
+ peermux_block_close ),
+};
+
+/** Block download data transfer interface descriptor */
+static struct interface_descriptor peermux_block_desc =
+ INTF_DESC ( struct peerdist_multiplexed_block, xfer,
+ peermux_block_operations );
+
+/** Block download initiation process descriptor */
+static struct process_descriptor peermux_process_desc =
+ PROC_DESC ( struct peerdist_multiplexer, process, peermux_step );
+
+/**
+ * Add PeerDist content-encoding filter
+ *
+ * @v xfer Data transfer interface
+ * @v info Content information interface
+ * @v uri Original URI
+ * @ret rc Return status code
+ */
+int peermux_filter ( struct interface *xfer, struct interface *info,
+ struct uri *uri ) {
+ struct peerdist_multiplexer *peermux;
+ struct peerdist_multiplexed_block *peermblk;
+ unsigned int i;
+
+ /* Allocate and initialise structure */
+ peermux = zalloc ( sizeof ( *peermux ) );
+ if ( ! peermux )
+ return -ENOMEM;
+ ref_init ( &peermux->refcnt, peermux_free );
+ intf_init ( &peermux->xfer, &peermux_xfer_desc, &peermux->refcnt );
+ intf_init ( &peermux->info, &peermux_info_desc, &peermux->refcnt );
+ peermux->uri = uri_get ( uri );
+ xferbuf_umalloc_init ( &peermux->buffer,
+ &peermux->cache.info.raw.data );
+ process_init_stopped ( &peermux->process, &peermux_process_desc,
+ &peermux->refcnt );
+ INIT_LIST_HEAD ( &peermux->busy );
+ INIT_LIST_HEAD ( &peermux->idle );
+ for ( i = 0 ; i < PEERMUX_MAX_BLOCKS ; i++ ) {
+ peermblk = &peermux->block[i];
+ peermblk->peermux = peermux;
+ list_add_tail ( &peermblk->list, &peermux->idle );
+ intf_init ( &peermblk->xfer, &peermux_block_desc,
+ &peermux->refcnt );
+ }
+
+ /* Attach to parent interfaces, mortalise self, and return */
+ intf_plug_plug ( &peermux->xfer, xfer );
+ intf_plug_plug ( &peermux->info, info );
+ ref_put ( &peermux->refcnt );
+ return 0;
+}
diff --git a/roms/ipxe/src/net/ping.c b/roms/ipxe/src/net/ping.c
index d9da87ade..3f4fa5c11 100644
--- a/roms/ipxe/src/net/ping.c
+++ b/roms/ipxe/src/net/ping.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdlib.h>
#include <string.h>
diff --git a/roms/ipxe/src/net/rarp.c b/roms/ipxe/src/net/rarp.c
index 371145015..c194a404f 100644
--- a/roms/ipxe/src/net/rarp.c
+++ b/roms/ipxe/src/net/rarp.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <byteswap.h>
diff --git a/roms/ipxe/src/net/retry.c b/roms/ipxe/src/net/retry.c
index 8f210bdcc..734567be5 100644
--- a/roms/ipxe/src/net/retry.c
+++ b/roms/ipxe/src/net/retry.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <ipxe/timer.h>
@@ -35,7 +39,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
* This implementation of the timer is designed to satisfy RFC 2988
* and therefore be usable as a TCP retransmission timer.
- *
*
*/
@@ -49,47 +52,59 @@ FILE_LICENCE ( GPL2_OR_LATER );
static LIST_HEAD ( timers );
/**
- * Start timer
+ * Start timer with a specified timeout
*
* @v timer Retry timer
+ * @v timeout Timeout, in ticks
*
- * This starts the timer running with the current timeout value. If
+ * This starts the timer running with the specified timeout value. If
* stop_timer() is not called before the timer expires, the timer will
* be stopped and the timer's callback function will be called.
*/
-void start_timer ( struct retry_timer *timer ) {
+void start_timer_fixed ( struct retry_timer *timer, unsigned long timeout ) {
+
+ /* Add to list of running timers (if applicable) */
if ( ! timer->running ) {
list_add ( &timer->list, &timers );
ref_get ( timer->refcnt );
+ timer->running = 1;
}
+
+ /* Record start time */
timer->start = currticks();
- timer->running = 1;
-
- /* 0 means "use default timeout" */
- if ( timer->min_timeout == 0 )
- timer->min_timeout = DEFAULT_MIN_TIMEOUT;
- /* We must never be less than MIN_TIMEOUT under any circumstances */
- if ( timer->min_timeout < MIN_TIMEOUT )
- timer->min_timeout = MIN_TIMEOUT;
- /* Honor user-specified minimum timeout */
- if ( timer->timeout < timer->min_timeout )
- timer->timeout = timer->min_timeout;
-
- DBG2 ( "Timer %p started at time %ld (expires at %ld)\n",
- timer, timer->start, ( timer->start + timer->timeout ) );
+
+ /* Record timeout */
+ timer->timeout = timeout;
+
+ DBGC2 ( timer, "Timer %p started at time %ld (expires at %ld)\n",
+ timer, timer->start, ( timer->start + timer->timeout ) );
}
/**
- * Start timer with a specified fixed timeout
+ * Start timer
*
* @v timer Retry timer
- * @v timeout Timeout, in ticks
+ *
+ * This starts the timer running with the current timeout value
+ * (rounded up to the minimum timeout value). If stop_timer() is not
+ * called before the timer expires, the timer will be stopped and the
+ * timer's callback function will be called.
*/
-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 ) );
+void start_timer ( struct retry_timer *timer ) {
+ unsigned long timeout = timer->timeout;
+ unsigned long min;
+
+ /* Calculate minimum timeout */
+ min = ( timer->min ? timer->min : DEFAULT_MIN_TIMEOUT );
+ if ( min < MIN_TIMEOUT )
+ min = MIN_TIMEOUT;
+
+ /* Ensure timeout is at least the minimum */
+ if ( timeout < min )
+ timeout = min;
+
+ /* Start timer with this timeout */
+ start_timer_fixed ( timer, timeout );
}
/**
@@ -111,8 +126,8 @@ void stop_timer ( struct retry_timer *timer ) {
list_del ( &timer->list );
runtime = ( now - timer->start );
timer->running = 0;
- DBG2 ( "Timer %p stopped at time %ld (ran for %ld)\n",
- timer, now, runtime );
+ DBGC2 ( timer, "Timer %p stopped at time %ld (ran for %ld)\n",
+ timer, now, runtime );
/* Update timer. Variables are:
*
@@ -135,8 +150,8 @@ void stop_timer ( struct retry_timer *timer ) {
timer->timeout -= ( timer->timeout >> 3 );
timer->timeout += ( runtime >> 1 );
if ( timer->timeout != old_timeout ) {
- DBG ( "Timer %p timeout updated to %ld\n",
- timer, timer->timeout );
+ DBGC ( timer, "Timer %p timeout updated to %ld\n",
+ timer, timer->timeout );
}
}
@@ -150,11 +165,12 @@ void stop_timer ( struct retry_timer *timer ) {
*/
static void timer_expired ( struct retry_timer *timer ) {
struct refcnt *refcnt = timer->refcnt;
+ unsigned long max = ( timer->max ? timer->max : DEFAULT_MAX_TIMEOUT );
int fail;
/* Stop timer without performing RTT calculations */
- DBG2 ( "Timer %p stopped at time %ld on expiry\n",
- timer, currticks() );
+ DBGC2 ( timer, "Timer %p stopped at time %ld on expiry\n",
+ timer, currticks() );
assert ( timer->running );
list_del ( &timer->list );
timer->running = 0;
@@ -162,12 +178,10 @@ static void timer_expired ( struct retry_timer *timer ) {
/* Back off the timeout value */
timer->timeout <<= 1;
- if ( timer->max_timeout == 0 ) /* 0 means "use default timeout" */
- timer->max_timeout = DEFAULT_MAX_TIMEOUT;
- if ( ( fail = ( timer->timeout > timer->max_timeout ) ) )
- timer->timeout = timer->max_timeout;
- DBG ( "Timer %p timeout backed off to %ld\n",
- timer, timer->timeout );
+ if ( ( fail = ( timer->timeout > max ) ) )
+ timer->timeout = max;
+ DBGC ( timer, "Timer %p timeout backed off to %ld\n",
+ timer, timer->timeout );
/* Call expiry callback */
timer->expired ( timer, fail );
diff --git a/roms/ipxe/src/net/rndis.c b/roms/ipxe/src/net/rndis.c
new file mode 100644
index 000000000..8c4fe8b30
--- /dev/null
+++ b/roms/ipxe/src/net/rndis.c
@@ -0,0 +1,1052 @@
+/*
+ * Copyright (C) 2014 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/** @file
+ *
+ * Remote Network Driver Interface Specification
+ *
+ */
+
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/device.h>
+#include <ipxe/rndis.h>
+
+/**
+ * Allocate I/O buffer
+ *
+ * @v len Length
+ * @ret iobuf I/O buffer, or NULL
+ */
+static struct io_buffer * rndis_alloc_iob ( size_t len ) {
+ struct rndis_header *header;
+ struct io_buffer *iobuf;
+
+ /* Allocate I/O buffer and reserve space */
+ iobuf = alloc_iob ( sizeof ( *header ) + len );
+ if ( iobuf )
+ iob_reserve ( iobuf, sizeof ( *header ) );
+
+ return iobuf;
+}
+
+/**
+ * Wait for completion
+ *
+ * @v rndis RNDIS device
+ * @v wait_id Request ID
+ * @ret rc Return status code
+ */
+static int rndis_wait ( struct rndis_device *rndis, unsigned int wait_id ) {
+ unsigned int i;
+
+ /* Record query ID */
+ rndis->wait_id = wait_id;
+
+ /* Wait for operation to complete */
+ for ( i = 0 ; i < RNDIS_MAX_WAIT_MS ; i++ ) {
+
+ /* Check for completion */
+ if ( ! rndis->wait_id )
+ return rndis->wait_rc;
+
+ /* Poll RNDIS device */
+ rndis->op->poll ( rndis );
+
+ /* Delay for 1ms */
+ mdelay ( 1 );
+ }
+
+ DBGC ( rndis, "RNDIS %s timed out waiting for ID %#08x\n",
+ rndis->name, wait_id );
+ return -ETIMEDOUT;
+}
+
+/**
+ * Transmit message
+ *
+ * @v rndis RNDIS device
+ * @v iobuf I/O buffer
+ * @v type Message type
+ * @ret rc Return status code
+ */
+static int rndis_tx_message ( struct rndis_device *rndis,
+ struct io_buffer *iobuf, unsigned int type ) {
+ struct rndis_header *header;
+ int rc;
+
+ /* Prepend RNDIS header */
+ header = iob_push ( iobuf, sizeof ( *header ) );
+ header->type = cpu_to_le32 ( type );
+ header->len = cpu_to_le32 ( iob_len ( iobuf ) );
+
+ /* Transmit message */
+ if ( ( rc = rndis->op->transmit ( rndis, iobuf ) ) != 0 ) {
+ DBGC ( rndis, "RNDIS %s could not transmit: %s\n",
+ rndis->name, strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Complete message transmission
+ *
+ * @v rndis RNDIS device
+ * @v iobuf I/O buffer
+ * @v rc Packet status code
+ */
+void rndis_tx_complete_err ( struct rndis_device *rndis,
+ struct io_buffer *iobuf, int rc ) {
+ struct net_device *netdev = rndis->netdev;
+ struct rndis_header *header;
+ size_t len = iob_len ( iobuf );
+
+ /* Sanity check */
+ if ( len < sizeof ( *header ) ) {
+ DBGC ( rndis, "RNDIS %s completed underlength transmission:\n",
+ rndis->name );
+ DBGC_HDA ( rndis, 0, iobuf->data, len );
+ netdev_tx_err ( netdev, NULL, -EINVAL );
+ return;
+ }
+ header = iobuf->data;
+
+ /* Complete buffer */
+ if ( header->type == cpu_to_le32 ( RNDIS_PACKET_MSG ) ) {
+ netdev_tx_complete_err ( netdev, iobuf, rc );
+ } else {
+ free_iob ( iobuf );
+ }
+}
+
+/**
+ * Transmit data packet
+ *
+ * @v rndis RNDIS device
+ * @v iobuf I/O buffer
+ * @ret rc Return status code
+ */
+static int rndis_tx_data ( struct rndis_device *rndis,
+ struct io_buffer *iobuf ) {
+ struct rndis_packet_message *msg;
+ size_t len = iob_len ( iobuf );
+ int rc;
+
+ /* Prepend packet message header */
+ msg = iob_push ( iobuf, sizeof ( *msg ) );
+ memset ( msg, 0, sizeof ( *msg ) );
+ msg->data.offset = cpu_to_le32 ( sizeof ( *msg ) );
+ msg->data.len = cpu_to_le32 ( len );
+
+ /* Transmit message */
+ if ( ( rc = rndis_tx_message ( rndis, iobuf, RNDIS_PACKET_MSG ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/**
+ * Defer transmitted packet
+ *
+ * @v rndis RNDIS device
+ * @v iobuf I/O buffer
+ * @ret rc Return status code
+ *
+ * As with netdev_tx_defer(), the caller must ensure that space in the
+ * transmit descriptor ring is freed up before calling
+ * rndis_tx_complete().
+ *
+ * Unlike netdev_tx_defer(), this call may fail.
+ */
+int rndis_tx_defer ( struct rndis_device *rndis, struct io_buffer *iobuf ) {
+ struct net_device *netdev = rndis->netdev;
+ struct rndis_header *header;
+ struct rndis_packet_message *msg;
+
+ /* Fail unless this was a packet message. Only packet
+ * messages correspond to I/O buffers in the network device's
+ * TX queue; other messages cannot be deferred in this way.
+ */
+ assert ( iob_len ( iobuf ) >= sizeof ( *header ) );
+ header = iobuf->data;
+ if ( header->type != cpu_to_le32 ( RNDIS_PACKET_MSG ) )
+ return -ENOTSUP;
+
+ /* Strip RNDIS header and packet message header, to return
+ * this packet to the state in which we received it.
+ */
+ iob_pull ( iobuf, ( sizeof ( *header ) + sizeof ( *msg ) ) );
+
+ /* Defer packet */
+ netdev_tx_defer ( netdev, iobuf );
+
+ return 0;
+}
+
+/**
+ * Receive data packet
+ *
+ * @v rndis RNDIS device
+ * @v iobuf I/O buffer
+ */
+static void rndis_rx_data ( struct rndis_device *rndis,
+ struct io_buffer *iobuf ) {
+ struct net_device *netdev = rndis->netdev;
+ struct rndis_packet_message *msg;
+ size_t len = iob_len ( iobuf );
+ size_t data_offset;
+ size_t data_len;
+ int rc;
+
+ /* Sanity check */
+ if ( len < sizeof ( *msg ) ) {
+ DBGC ( rndis, "RNDIS %s received underlength data packet:\n",
+ rndis->name );
+ DBGC_HDA ( rndis, 0, iobuf->data, len );
+ rc = -EINVAL;
+ goto err_len;
+ }
+ msg = iobuf->data;
+
+ /* Locate and sanity check data buffer */
+ data_offset = le32_to_cpu ( msg->data.offset );
+ data_len = le32_to_cpu ( msg->data.len );
+ if ( ( data_offset > len ) || ( data_len > ( len - data_offset ) ) ) {
+ DBGC ( rndis, "RNDIS %s data packet data exceeds packet:\n",
+ rndis->name );
+ DBGC_HDA ( rndis, 0, iobuf->data, len );
+ rc = -EINVAL;
+ goto err_data;
+ }
+
+ /* Strip non-data portions */
+ iob_pull ( iobuf, data_offset );
+ iob_unput ( iobuf, ( iob_len ( iobuf ) - data_len ) );
+
+ /* Hand off to network stack */
+ netdev_rx ( netdev, iob_disown ( iobuf ) );
+
+ return;
+
+ err_data:
+ err_len:
+ /* Report error to network stack */
+ netdev_rx_err ( netdev, iob_disown ( iobuf ), rc );
+}
+
+/**
+ * Transmit initialisation message
+ *
+ * @v rndis RNDIS device
+ * @v id Request ID
+ * @ret rc Return status code
+ */
+static int rndis_tx_initialise ( struct rndis_device *rndis, unsigned int id ) {
+ struct io_buffer *iobuf;
+ struct rndis_initialise_message *msg;
+ int rc;
+
+ /* Allocate I/O buffer */
+ iobuf = rndis_alloc_iob ( sizeof ( *msg ) );
+ if ( ! iobuf ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+
+ /* Construct message */
+ msg = iob_put ( iobuf, sizeof ( *msg ) );
+ memset ( msg, 0, sizeof ( *msg ) );
+ msg->id = id; /* Non-endian */
+ msg->major = cpu_to_le32 ( RNDIS_VERSION_MAJOR );
+ msg->minor = cpu_to_le32 ( RNDIS_VERSION_MINOR );
+ msg->mtu = cpu_to_le32 ( RNDIS_MTU );
+
+ /* Transmit message */
+ if ( ( rc = rndis_tx_message ( rndis, iobuf,
+ RNDIS_INITIALISE_MSG ) ) != 0 )
+ goto err_tx;
+
+ return 0;
+
+ err_tx:
+ free_iob ( iobuf );
+ err_alloc:
+ return rc;
+}
+
+/**
+ * Receive initialisation completion
+ *
+ * @v rndis RNDIS device
+ * @v iobuf I/O buffer
+ */
+static void rndis_rx_initialise ( struct rndis_device *rndis,
+ struct io_buffer *iobuf ) {
+ struct rndis_initialise_completion *cmplt;
+ size_t len = iob_len ( iobuf );
+ unsigned int id;
+ int rc;
+
+ /* Sanity check */
+ if ( len < sizeof ( *cmplt ) ) {
+ DBGC ( rndis, "RNDIS %s received underlength initialisation "
+ "completion:\n", rndis->name );
+ DBGC_HDA ( rndis, 0, iobuf->data, len );
+ rc = -EINVAL;
+ goto err_len;
+ }
+ cmplt = iobuf->data;
+
+ /* Extract request ID */
+ id = cmplt->id; /* Non-endian */
+
+ /* Check status */
+ if ( cmplt->status ) {
+ DBGC ( rndis, "RNDIS %s received initialisation completion "
+ "failure %#08x\n", rndis->name,
+ le32_to_cpu ( cmplt->status ) );
+ rc = -EIO;
+ goto err_status;
+ }
+
+ /* Success */
+ rc = 0;
+
+ err_status:
+ /* Record completion result if applicable */
+ if ( id == rndis->wait_id ) {
+ rndis->wait_id = 0;
+ rndis->wait_rc = rc;
+ }
+ err_len:
+ free_iob ( iobuf );
+}
+
+/**
+ * Initialise RNDIS
+ *
+ * @v rndis RNDIS device
+ * @ret rc Return status code
+ */
+static int rndis_initialise ( struct rndis_device *rndis ) {
+ int rc;
+
+ /* Transmit initialisation message */
+ if ( ( rc = rndis_tx_initialise ( rndis, RNDIS_INIT_ID ) ) != 0 )
+ return rc;
+
+ /* Wait for response */
+ if ( ( rc = rndis_wait ( rndis, RNDIS_INIT_ID ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/**
+ * Transmit halt message
+ *
+ * @v rndis RNDIS device
+ * @ret rc Return status code
+ */
+static int rndis_tx_halt ( struct rndis_device *rndis ) {
+ struct io_buffer *iobuf;
+ struct rndis_halt_message *msg;
+ int rc;
+
+ /* Allocate I/O buffer */
+ iobuf = rndis_alloc_iob ( sizeof ( *msg ) );
+ if ( ! iobuf ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+
+ /* Construct message */
+ msg = iob_put ( iobuf, sizeof ( *msg ) );
+ memset ( msg, 0, sizeof ( *msg ) );
+
+ /* Transmit message */
+ if ( ( rc = rndis_tx_message ( rndis, iobuf, RNDIS_HALT_MSG ) ) != 0 )
+ goto err_tx;
+
+ return 0;
+
+ err_tx:
+ free_iob ( iobuf );
+ err_alloc:
+ return rc;
+}
+
+/**
+ * Halt RNDIS
+ *
+ * @v rndis RNDIS device
+ * @ret rc Return status code
+ */
+static int rndis_halt ( struct rndis_device *rndis ) {
+ int rc;
+
+ /* Transmit halt message */
+ if ( ( rc = rndis_tx_halt ( rndis ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/**
+ * Transmit OID message
+ *
+ * @v rndis RNDIS device
+ * @v oid Object ID
+ * @v data New OID value (or NULL to query current value)
+ * @v len Length of new OID value
+ * @ret rc Return status code
+ */
+static int rndis_tx_oid ( struct rndis_device *rndis, unsigned int oid,
+ const void *data, size_t len ) {
+ struct io_buffer *iobuf;
+ struct rndis_oid_message *msg;
+ unsigned int type;
+ int rc;
+
+ /* Allocate I/O buffer */
+ iobuf = rndis_alloc_iob ( sizeof ( *msg ) + len );
+ if ( ! iobuf ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+
+ /* Construct message. We use the OID as the request ID. */
+ msg = iob_put ( iobuf, sizeof ( *msg ) );
+ memset ( msg, 0, sizeof ( *msg ) );
+ msg->id = oid; /* Non-endian */
+ msg->oid = cpu_to_le32 ( oid );
+ msg->offset = cpu_to_le32 ( sizeof ( *msg ) );
+ msg->len = cpu_to_le32 ( len );
+ memcpy ( iob_put ( iobuf, len ), data, len );
+
+ /* Transmit message */
+ type = ( data ? RNDIS_SET_MSG : RNDIS_QUERY_MSG );
+ if ( ( rc = rndis_tx_message ( rndis, iobuf, type ) ) != 0 )
+ goto err_tx;
+
+ return 0;
+
+ err_tx:
+ free_iob ( iobuf );
+ err_alloc:
+ return rc;
+}
+
+/**
+ * Receive query OID completion
+ *
+ * @v rndis RNDIS device
+ * @v iobuf I/O buffer
+ */
+static void rndis_rx_query_oid ( struct rndis_device *rndis,
+ struct io_buffer *iobuf ) {
+ struct net_device *netdev = rndis->netdev;
+ struct rndis_query_completion *cmplt;
+ size_t len = iob_len ( iobuf );
+ size_t info_offset;
+ size_t info_len;
+ unsigned int id;
+ void *info;
+ uint32_t *link_status;
+ int rc;
+
+ /* Sanity check */
+ if ( len < sizeof ( *cmplt ) ) {
+ DBGC ( rndis, "RNDIS %s received underlength query "
+ "completion:\n", rndis->name );
+ DBGC_HDA ( rndis, 0, iobuf->data, len );
+ rc = -EINVAL;
+ goto err_len;
+ }
+ cmplt = iobuf->data;
+
+ /* Extract request ID */
+ id = cmplt->id; /* Non-endian */
+
+ /* Check status */
+ if ( cmplt->status ) {
+ DBGC ( rndis, "RNDIS %s received query completion failure "
+ "%#08x\n", rndis->name, le32_to_cpu ( cmplt->status ) );
+ DBGC_HDA ( rndis, 0, iobuf->data, len );
+ rc = -EIO;
+ goto err_status;
+ }
+
+ /* Locate and sanity check information buffer */
+ info_offset = le32_to_cpu ( cmplt->offset );
+ info_len = le32_to_cpu ( cmplt->len );
+ if ( ( info_offset > len ) || ( info_len > ( len - info_offset ) ) ) {
+ DBGC ( rndis, "RNDIS %s query completion information exceeds "
+ "packet:\n", rndis->name );
+ DBGC_HDA ( rndis, 0, iobuf->data, len );
+ rc = -EINVAL;
+ goto err_info;
+ }
+ info = ( ( ( void * ) cmplt ) + info_offset );
+
+ /* Handle OID */
+ switch ( id ) {
+
+ case RNDIS_OID_802_3_PERMANENT_ADDRESS:
+ if ( info_len > sizeof ( netdev->hw_addr ) )
+ info_len = sizeof ( netdev->hw_addr );
+ memcpy ( netdev->hw_addr, info, info_len );
+ break;
+
+ case RNDIS_OID_802_3_CURRENT_ADDRESS:
+ if ( info_len > sizeof ( netdev->ll_addr ) )
+ info_len = sizeof ( netdev->ll_addr );
+ memcpy ( netdev->ll_addr, info, info_len );
+ break;
+
+ case RNDIS_OID_GEN_MEDIA_CONNECT_STATUS:
+ if ( info_len != sizeof ( *link_status ) ) {
+ DBGC ( rndis, "RNDIS %s invalid link status:\n",
+ rndis->name );
+ DBGC_HDA ( rndis, 0, iobuf->data, len );
+ rc = -EPROTO;
+ goto err_link_status;
+ }
+ link_status = info;
+ if ( *link_status == 0 ) {
+ DBGC ( rndis, "RNDIS %s link is up\n", rndis->name );
+ netdev_link_up ( netdev );
+ } else {
+ DBGC ( rndis, "RNDIS %s link is down: %#08x\n",
+ rndis->name, le32_to_cpu ( *link_status ) );
+ netdev_link_down ( netdev );
+ }
+ break;
+
+ default:
+ DBGC ( rndis, "RNDIS %s unexpected query completion ID %#08x\n",
+ rndis->name, id );
+ DBGC_HDA ( rndis, 0, iobuf->data, len );
+ rc = -EPROTO;
+ goto err_id;
+ }
+
+ /* Success */
+ rc = 0;
+
+ err_id:
+ err_link_status:
+ err_info:
+ err_status:
+ /* Record completion result if applicable */
+ if ( id == rndis->wait_id ) {
+ rndis->wait_id = 0;
+ rndis->wait_rc = rc;
+ }
+ err_len:
+ /* Free I/O buffer */
+ free_iob ( iobuf );
+}
+
+/**
+ * Receive set OID completion
+ *
+ * @v rndis RNDIS device
+ * @v iobuf I/O buffer
+ */
+static void rndis_rx_set_oid ( struct rndis_device *rndis,
+ struct io_buffer *iobuf ) {
+ struct rndis_set_completion *cmplt;
+ size_t len = iob_len ( iobuf );
+ unsigned int id;
+ int rc;
+
+ /* Sanity check */
+ if ( len < sizeof ( *cmplt ) ) {
+ DBGC ( rndis, "RNDIS %s received underlength set completion:\n",
+ rndis->name );
+ DBGC_HDA ( rndis, 0, iobuf->data, len );
+ rc = -EINVAL;
+ goto err_len;
+ }
+ cmplt = iobuf->data;
+
+ /* Extract request ID */
+ id = cmplt->id; /* Non-endian */
+
+ /* Check status */
+ if ( cmplt->status ) {
+ DBGC ( rndis, "RNDIS %s received set completion failure "
+ "%#08x\n", rndis->name, le32_to_cpu ( cmplt->status ) );
+ DBGC_HDA ( rndis, 0, iobuf->data, len );
+ rc = -EIO;
+ goto err_status;
+ }
+
+ /* Success */
+ rc = 0;
+
+ err_status:
+ /* Record completion result if applicable */
+ if ( id == rndis->wait_id ) {
+ rndis->wait_id = 0;
+ rndis->wait_rc = rc;
+ }
+ err_len:
+ /* Free I/O buffer */
+ free_iob ( iobuf );
+}
+
+/**
+ * Query or set OID
+ *
+ * @v rndis RNDIS device
+ * @v oid Object ID
+ * @v data New OID value (or NULL to query current value)
+ * @v len Length of new OID value
+ * @ret rc Return status code
+ */
+static int rndis_oid ( struct rndis_device *rndis, unsigned int oid,
+ const void *data, size_t len ) {
+ int rc;
+
+ /* Transmit query */
+ if ( ( rc = rndis_tx_oid ( rndis, oid, data, len ) ) != 0 )
+ return rc;
+
+ /* Wait for response */
+ if ( ( rc = rndis_wait ( rndis, oid ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/**
+ * Receive indicate status message
+ *
+ * @v rndis RNDIS device
+ * @v iobuf I/O buffer
+ */
+static void rndis_rx_status ( struct rndis_device *rndis,
+ struct io_buffer *iobuf ) {
+ struct net_device *netdev = rndis->netdev;
+ struct rndis_indicate_status_message *msg;
+ size_t len = iob_len ( iobuf );
+ unsigned int status;
+ int rc;
+
+ /* Sanity check */
+ if ( len < sizeof ( *msg ) ) {
+ DBGC ( rndis, "RNDIS %s received underlength status message:\n",
+ rndis->name );
+ DBGC_HDA ( rndis, 0, iobuf->data, len );
+ rc = -EINVAL;
+ goto err_len;
+ }
+ msg = iobuf->data;
+
+ /* Extract status */
+ status = le32_to_cpu ( msg->status );
+
+ /* Handle status */
+ switch ( msg->status ) {
+
+ case RNDIS_STATUS_MEDIA_CONNECT:
+ DBGC ( rndis, "RNDIS %s link is up\n", rndis->name );
+ netdev_link_up ( netdev );
+ break;
+
+ case RNDIS_STATUS_MEDIA_DISCONNECT:
+ DBGC ( rndis, "RNDIS %s link is down\n", rndis->name );
+ netdev_link_down ( netdev );
+ break;
+
+ case RNDIS_STATUS_WTF_WORLD:
+ /* Ignore */
+ break;
+
+ default:
+ DBGC ( rndis, "RNDIS %s unexpected status %#08x:\n",
+ rndis->name, status );
+ DBGC_HDA ( rndis, 0, iobuf->data, len );
+ rc = -ENOTSUP;
+ goto err_status;
+ }
+
+ /* Free I/O buffer */
+ free_iob ( iobuf );
+
+ return;
+
+ err_status:
+ err_len:
+ /* Report error via network device statistics */
+ netdev_rx_err ( netdev, iobuf, rc );
+}
+
+/**
+ * Receive RNDIS message
+ *
+ * @v rndis RNDIS device
+ * @v iobuf I/O buffer
+ * @v type Message type
+ */
+static void rndis_rx_message ( struct rndis_device *rndis,
+ struct io_buffer *iobuf, unsigned int type ) {
+ struct net_device *netdev = rndis->netdev;
+ int rc;
+
+ /* Handle packet */
+ switch ( type ) {
+
+ case RNDIS_PACKET_MSG:
+ rndis_rx_data ( rndis, iob_disown ( iobuf ) );
+ break;
+
+ case RNDIS_INITIALISE_CMPLT:
+ rndis_rx_initialise ( rndis, iob_disown ( iobuf ) );
+ break;
+
+ case RNDIS_QUERY_CMPLT:
+ rndis_rx_query_oid ( rndis, iob_disown ( iobuf ) );
+ break;
+
+ case RNDIS_SET_CMPLT:
+ rndis_rx_set_oid ( rndis, iob_disown ( iobuf ) );
+ break;
+
+ case RNDIS_INDICATE_STATUS_MSG:
+ rndis_rx_status ( rndis, iob_disown ( iobuf ) );
+ break;
+
+ default:
+ DBGC ( rndis, "RNDIS %s received unexpected type %#08x\n",
+ rndis->name, type );
+ DBGC_HDA ( rndis, 0, iobuf->data, iob_len ( iobuf ) );
+ rc = -EPROTO;
+ goto err_type;
+ }
+
+ return;
+
+ err_type:
+ /* Report error via network device statistics */
+ netdev_rx_err ( netdev, iobuf, rc );
+}
+
+/**
+ * Receive packet from underlying transport layer
+ *
+ * @v rndis RNDIS device
+ * @v iobuf I/O buffer
+ */
+void rndis_rx ( struct rndis_device *rndis, struct io_buffer *iobuf ) {
+ struct net_device *netdev = rndis->netdev;
+ struct rndis_header *header;
+ unsigned int type;
+ int rc;
+
+ /* Sanity check */
+ if ( iob_len ( iobuf ) < sizeof ( *header ) ) {
+ DBGC ( rndis, "RNDIS %s received underlength packet:\n",
+ rndis->name );
+ DBGC_HDA ( rndis, 0, iobuf->data, iob_len ( iobuf ) );
+ rc = -EINVAL;
+ goto drop;
+ }
+ header = iobuf->data;
+
+ /* Parse and strip header */
+ type = le32_to_cpu ( header->type );
+ iob_pull ( iobuf, sizeof ( *header ) );
+
+ /* Handle message */
+ rndis_rx_message ( rndis, iob_disown ( iobuf ), type );
+
+ return;
+
+ drop:
+ /* Record error */
+ netdev_rx_err ( netdev, iob_disown ( iobuf ), rc );
+}
+
+/**
+ * Discard packet from underlying transport layer
+ *
+ * @v rndis RNDIS device
+ * @v iobuf I/O buffer
+ * @v rc Packet status code
+ */
+void rndis_rx_err ( struct rndis_device *rndis, struct io_buffer *iobuf,
+ int rc ) {
+ struct net_device *netdev = rndis->netdev;
+
+ /* Record error */
+ netdev_rx_err ( netdev, iob_disown ( iobuf ), rc );
+}
+
+/**
+ * Set receive filter
+ *
+ * @v rndis RNDIS device
+ * @v filter Receive filter
+ * @ret rc Return status code
+ */
+static int rndis_filter ( struct rndis_device *rndis, unsigned int filter ) {
+ uint32_t value = cpu_to_le32 ( filter );
+ int rc;
+
+ /* Set receive filter */
+ if ( ( rc = rndis_oid ( rndis, RNDIS_OID_GEN_CURRENT_PACKET_FILTER,
+ &value, sizeof ( value ) ) ) != 0 ) {
+ DBGC ( rndis, "RNDIS %s could not set receive filter to %#08x: "
+ "%s\n", rndis->name, filter, strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Open network device
+ *
+ * @v netdev Network device
+ * @ret rc Return status code
+ */
+static int rndis_open ( struct net_device *netdev ) {
+ struct rndis_device *rndis = netdev->priv;
+ int rc;
+
+ /* Open RNDIS device */
+ if ( ( rc = rndis->op->open ( rndis ) ) != 0 ) {
+ DBGC ( rndis, "RNDIS %s could not open: %s\n",
+ rndis->name, strerror ( rc ) );
+ goto err_open;
+ }
+
+ /* Initialise RNDIS */
+ if ( ( rc = rndis_initialise ( rndis ) ) != 0 )
+ goto err_initialise;
+
+ /* Set receive filter */
+ if ( ( rc = rndis_filter ( rndis, ( RNDIS_FILTER_UNICAST |
+ RNDIS_FILTER_MULTICAST |
+ RNDIS_FILTER_ALL_MULTICAST |
+ RNDIS_FILTER_BROADCAST |
+ RNDIS_FILTER_PROMISCUOUS ) ) ) != 0)
+ goto err_set_filter;
+
+ /* Update link status */
+ if ( ( rc = rndis_oid ( rndis, RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
+ NULL, 0 ) ) != 0 )
+ goto err_query_link;
+
+ return 0;
+
+ err_query_link:
+ err_set_filter:
+ rndis_halt ( rndis );
+ err_initialise:
+ rndis->op->close ( rndis );
+ err_open:
+ return rc;
+}
+
+/**
+ * Close network device
+ *
+ * @v netdev Network device
+ */
+static void rndis_close ( struct net_device *netdev ) {
+ struct rndis_device *rndis = netdev->priv;
+
+ /* Clear receive filter */
+ rndis_filter ( rndis, 0 );
+
+ /* Halt RNDIS device */
+ rndis_halt ( rndis );
+
+ /* Close RNDIS device */
+ rndis->op->close ( rndis );
+}
+
+/**
+ * Transmit packet
+ *
+ * @v netdev Network device
+ * @v iobuf I/O buffer
+ * @ret rc Return status code
+ */
+static int rndis_transmit ( struct net_device *netdev,
+ struct io_buffer *iobuf ) {
+ struct rndis_device *rndis = netdev->priv;
+
+ /* Transmit data packet */
+ return rndis_tx_data ( rndis, iobuf );
+}
+
+/**
+ * Poll for completed and received packets
+ *
+ * @v netdev Network device
+ */
+static void rndis_poll ( struct net_device *netdev ) {
+ struct rndis_device *rndis = netdev->priv;
+
+ /* Poll RNDIS device */
+ rndis->op->poll ( rndis );
+}
+
+/** Network device operations */
+static struct net_device_operations rndis_operations = {
+ .open = rndis_open,
+ .close = rndis_close,
+ .transmit = rndis_transmit,
+ .poll = rndis_poll,
+};
+
+/**
+ * Allocate RNDIS device
+ *
+ * @v priv_len Length of private data
+ * @ret rndis RNDIS device, or NULL on allocation failure
+ */
+struct rndis_device * alloc_rndis ( size_t priv_len ) {
+ struct net_device *netdev;
+ struct rndis_device *rndis;
+
+ /* Allocate and initialise structure */
+ netdev = alloc_etherdev ( sizeof ( *rndis ) + priv_len );
+ if ( ! netdev )
+ return NULL;
+ netdev_init ( netdev, &rndis_operations );
+ rndis = netdev->priv;
+ rndis->netdev = netdev;
+ rndis->priv = ( ( ( void * ) rndis ) + sizeof ( *rndis ) );
+
+ return rndis;
+}
+
+/**
+ * Register RNDIS device
+ *
+ * @v rndis RNDIS device
+ * @ret rc Return status code
+ *
+ * Note that this routine will open and use the RNDIS device in order
+ * to query the MAC address. The device must be immediately ready for
+ * use prior to registration.
+ */
+int register_rndis ( struct rndis_device *rndis ) {
+ struct net_device *netdev = rndis->netdev;
+ int rc;
+
+ /* Assign device name (for debugging) */
+ rndis->name = netdev->dev->name;
+
+ /* Register network device */
+ if ( ( rc = register_netdev ( netdev ) ) != 0 ) {
+ DBGC ( rndis, "RNDIS %s could not register: %s\n",
+ rndis->name, strerror ( rc ) );
+ goto err_register;
+ }
+
+ /* Open RNDIS device to read MAC addresses */
+ if ( ( rc = rndis->op->open ( rndis ) ) != 0 ) {
+ DBGC ( rndis, "RNDIS %s could not open: %s\n",
+ rndis->name, strerror ( rc ) );
+ goto err_open;
+ }
+
+ /* Initialise RNDIS */
+ if ( ( rc = rndis_initialise ( rndis ) ) != 0 )
+ goto err_initialise;
+
+ /* Query permanent MAC address */
+ if ( ( rc = rndis_oid ( rndis, RNDIS_OID_802_3_PERMANENT_ADDRESS,
+ NULL, 0 ) ) != 0 )
+ goto err_query_permanent;
+
+ /* Query current MAC address */
+ if ( ( rc = rndis_oid ( rndis, RNDIS_OID_802_3_CURRENT_ADDRESS,
+ NULL, 0 ) ) != 0 )
+ goto err_query_current;
+
+ /* Get link status */
+ if ( ( rc = rndis_oid ( rndis, RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
+ NULL, 0 ) ) != 0 )
+ goto err_query_link;
+
+ /* Halt RNDIS device */
+ rndis_halt ( rndis );
+
+ /* Close RNDIS device */
+ rndis->op->close ( rndis );
+
+ return 0;
+
+ err_query_link:
+ err_query_current:
+ err_query_permanent:
+ rndis_halt ( rndis );
+ err_initialise:
+ rndis->op->close ( rndis );
+ err_open:
+ unregister_netdev ( netdev );
+ err_register:
+ return rc;
+}
+
+/**
+ * Unregister RNDIS device
+ *
+ * @v rndis RNDIS device
+ */
+void unregister_rndis ( struct rndis_device *rndis ) {
+ struct net_device *netdev = rndis->netdev;
+
+ /* Unregister network device */
+ unregister_netdev ( netdev );
+}
+
+/**
+ * Free RNDIS device
+ *
+ * @v rndis RNDIS device
+ */
+void free_rndis ( struct rndis_device *rndis ) {
+ struct net_device *netdev = rndis->netdev;
+
+ /* Free network device */
+ netdev_nullify ( netdev );
+ netdev_put ( netdev );
+}
diff --git a/roms/ipxe/src/net/socket.c b/roms/ipxe/src/net/socket.c
index 24f6a0892..2009ab237 100644
--- a/roms/ipxe/src/net/socket.c
+++ b/roms/ipxe/src/net/socket.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <errno.h>
diff --git a/roms/ipxe/src/net/stp.c b/roms/ipxe/src/net/stp.c
new file mode 100644
index 000000000..d4e65a1a2
--- /dev/null
+++ b/roms/ipxe/src/net/stp.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2015 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/timer.h>
+#include <ipxe/stp.h>
+
+/** @file
+ *
+ * Spanning Tree Protocol (STP)
+ *
+ */
+
+/* Disambiguate the various error causes */
+#define ENOTSUP_PROTOCOL __einfo_error ( EINFO_ENOTSUP_PROTOCOL )
+#define EINFO_ENOTSUP_PROTOCOL \
+ __einfo_uniqify ( EINFO_ENOTSUP, 0x01, \
+ "Non-STP packet received" )
+#define ENOTSUP_VERSION __einfo_error ( EINFO_ENOTSUP_VERSION )
+#define EINFO_ENOTSUP_VERSION \
+ __einfo_uniqify ( EINFO_ENOTSUP, 0x01, \
+ "Legacy STP packet received" )
+#define ENOTSUP_TYPE __einfo_error ( EINFO_ENOTSUP_TYPE )
+#define EINFO_ENOTSUP_TYPE \
+ __einfo_uniqify ( EINFO_ENOTSUP, 0x01, \
+ "Non-RSTP packet received" )
+
+/**
+ * Process incoming STP packets
+ *
+ * @v iobuf I/O buffer
+ * @v netdev Network device
+ * @v ll_source Link-layer source address
+ * @v flags Packet flags
+ * @ret rc Return status code
+ */
+static int stp_rx ( struct io_buffer *iobuf, struct net_device *netdev,
+ const void *ll_dest __unused,
+ const void *ll_source __unused,
+ unsigned int flags __unused ) {
+ struct stp_bpdu *stp;
+ unsigned int hello;
+ int rc;
+
+ /* Sanity check */
+ if ( iob_len ( iobuf ) < sizeof ( *stp ) ) {
+ DBGC ( netdev, "STP %s received underlength packet (%zd "
+ "bytes):\n", netdev->name, iob_len ( iobuf ) );
+ DBGC_HDA ( netdev, 0, iobuf->data, iob_len ( iobuf ) );
+ rc = -EINVAL;
+ goto done;
+ }
+ stp = iobuf->data;
+
+ /* Ignore non-RSTP packets */
+ if ( stp->protocol != htons ( STP_PROTOCOL ) ) {
+ DBGC ( netdev, "STP %s ignoring non-STP packet (protocol "
+ "%#04x)\n", netdev->name, ntohs ( stp->protocol ) );
+ rc = -ENOTSUP_PROTOCOL;
+ goto done;
+ }
+ if ( stp->version < STP_VERSION_RSTP ) {
+ DBGC ( netdev, "STP %s received legacy STP packet (version "
+ "%#02x)\n", netdev->name, stp->version );
+ rc = -ENOTSUP_VERSION;
+ goto done;
+ }
+ if ( stp->type != STP_TYPE_RSTP ) {
+ DBGC ( netdev, "STP %s received non-RSTP packet (type %#02x)\n",
+ netdev->name, stp->type );
+ rc = -ENOTSUP_TYPE;
+ goto done;
+ }
+
+ /* Dump information */
+ DBGC2 ( netdev, "STP %s %s port %#04x flags %#02x hello %d delay %d\n",
+ netdev->name, eth_ntoa ( stp->sender.mac ), ntohs ( stp->port ),
+ stp->flags, ntohs ( stp->hello ), ntohs ( stp->delay ) );
+
+ /* Check if port is forwarding */
+ if ( ! ( stp->flags & STP_FL_FORWARDING ) ) {
+ /* Port is not forwarding: block link for two hello times */
+ DBGC ( netdev, "STP %s %s port %#04x flags %#02x is not "
+ "forwarding\n",
+ netdev->name, eth_ntoa ( stp->sender.mac ),
+ ntohs ( stp->port ), stp->flags );
+ hello = ( ( ntohs ( stp->hello ) * TICKS_PER_SEC ) / 256 );
+ netdev_link_block ( netdev, ( hello * 2 ) );
+ rc = -ENETUNREACH;
+ goto done;
+ }
+
+ /* Success */
+ if ( netdev_link_blocked ( netdev ) ) {
+ DBGC ( netdev, "STP %s %s port %#04x flags %#02x is "
+ "forwarding\n",
+ netdev->name, eth_ntoa ( stp->sender.mac ),
+ ntohs ( stp->port ), stp->flags );
+ }
+ netdev_link_unblock ( netdev );
+ rc = 0;
+
+ done:
+ free_iob ( iobuf );
+ return rc;
+}
+
+/**
+ * Transcribe STP address
+ *
+ * @v net_addr STP address
+ * @ret string "<STP>"
+ *
+ * This operation is meaningless for the STP protocol.
+ */
+static const char * stp_ntoa ( const void *net_addr __unused ) {
+ return "<STP>";
+}
+
+/** STP network protocol */
+struct net_protocol stp_protocol __net_protocol = {
+ .name = "STP",
+ .net_proto = htons ( ETH_P_STP ),
+ .rx = stp_rx,
+ .ntoa = stp_ntoa,
+};
diff --git a/roms/ipxe/src/net/tcp.c b/roms/ipxe/src/net/tcp.c
index 987cb63e1..c69c83b85 100644
--- a/roms/ipxe/src/net/tcp.c
+++ b/roms/ipxe/src/net/tcp.c
@@ -26,7 +26,7 @@
*
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** A TCP connection */
struct tcp_connection {
@@ -101,8 +101,9 @@ struct tcp_connection {
* Equivalent to Rcv.Wind.Scale in RFC 1323 terminology
*/
uint8_t rcv_win_scale;
- /** Maximum receive window */
- uint32_t max_rcv_win;
+
+ /** Selective acknowledgement list (in host-endian order) */
+ struct tcp_sack_block sack[TCP_SACK_MAX];
/** Transmit queue */
struct list_head tx_queue;
@@ -129,6 +130,8 @@ enum tcp_flags {
TCP_TS_ENABLED = 0x0002,
/** TCP acknowledgement is pending */
TCP_ACK_PENDING = 0x0004,
+ /** TCP selective acknowledgement is enabled */
+ TCP_SACK_ENABLED = 0x0008,
};
/** TCP internal header
@@ -143,6 +146,8 @@ struct tcp_rx_queued_header {
* enqueued, and so excludes the SYN, if present.
*/
uint32_t seq;
+ /** Next SEQ value, in host-endian order */
+ uint32_t nxt;
/** Flags
*
* Only FIN is valid within this flags byte; all other flags
@@ -284,7 +289,6 @@ static int tcp_open ( struct interface *xfer, struct sockaddr *peer,
tcp->tcp_state = TCP_STATE_SENT ( TCP_SYN );
tcp_dump_state ( tcp );
tcp->snd_seq = random();
- tcp->max_rcv_win = TCP_MAX_WINDOW_SIZE;
INIT_LIST_HEAD ( &tcp->tx_queue );
INIT_LIST_HEAD ( &tcp->rx_queue );
memcpy ( &tcp->peer, st_peer, sizeof ( tcp->peer ) );
@@ -396,6 +400,7 @@ static void tcp_close ( struct tcp_connection *tcp, int rc ) {
tcp->tcp_state |= TCP_STATE_SENT ( TCP_FIN );
tcp_dump_state ( tcp );
+ process_add ( &tcp->process );
/* Add a pending operation for the FIN */
pending_get ( &tcp->pending_flags );
@@ -450,6 +455,94 @@ static size_t tcp_xfer_window ( struct tcp_connection *tcp ) {
}
/**
+ * Find selective acknowledgement block
+ *
+ * @v tcp TCP connection
+ * @v seq SEQ value in SACK block (in host-endian order)
+ * @v sack SACK block to fill in (in host-endian order)
+ * @ret len Length of SACK block
+ */
+static uint32_t tcp_sack_block ( struct tcp_connection *tcp, uint32_t seq,
+ struct tcp_sack_block *sack ) {
+ struct io_buffer *iobuf;
+ struct tcp_rx_queued_header *tcpqhdr;
+ uint32_t left = tcp->rcv_ack;
+ uint32_t right = left;
+
+ /* Find highest block which does not start after SEQ */
+ list_for_each_entry ( iobuf, &tcp->rx_queue, list ) {
+ tcpqhdr = iobuf->data;
+ if ( tcp_cmp ( tcpqhdr->seq, right ) > 0 ) {
+ if ( tcp_cmp ( tcpqhdr->seq, seq ) > 0 )
+ break;
+ left = tcpqhdr->seq;
+ }
+ if ( tcp_cmp ( tcpqhdr->nxt, right ) > 0 )
+ right = tcpqhdr->nxt;
+ }
+
+ /* Fail if this block does not contain SEQ */
+ if ( tcp_cmp ( right, seq ) < 0 )
+ return 0;
+
+ /* Populate SACK block */
+ sack->left = left;
+ sack->right = right;
+ return ( right - left );
+}
+
+/**
+ * Update TCP selective acknowledgement list
+ *
+ * @v tcp TCP connection
+ * @v seq SEQ value in first SACK block (in host-endian order)
+ * @ret count Number of SACK blocks
+ */
+static unsigned int tcp_sack ( struct tcp_connection *tcp, uint32_t seq ) {
+ struct tcp_sack_block sack[TCP_SACK_MAX];
+ unsigned int old = 0;
+ unsigned int new = 0;
+ unsigned int i;
+ uint32_t len;
+
+ /* Populate first new SACK block */
+ len = tcp_sack_block ( tcp, seq, &sack[0] );
+ if ( len )
+ new++;
+
+ /* Populate remaining new SACK blocks based on old SACK blocks */
+ for ( old = 0 ; old < TCP_SACK_MAX ; old++ ) {
+
+ /* Stop if we run out of space in the new list */
+ if ( new == TCP_SACK_MAX )
+ break;
+
+ /* Skip empty old SACK blocks */
+ if ( tcp->sack[old].left == tcp->sack[old].right )
+ continue;
+
+ /* Populate new SACK block */
+ len = tcp_sack_block ( tcp, tcp->sack[old].left, &sack[new] );
+ if ( len == 0 )
+ continue;
+
+ /* Eliminate duplicates */
+ for ( i = 0 ; i < new ; i++ ) {
+ if ( sack[i].left == sack[new].left ) {
+ new--;
+ break;
+ }
+ }
+ new++;
+ }
+
+ /* Update SACK list */
+ memset ( tcp->sack, 0, sizeof ( tcp->sack ) );
+ memcpy ( tcp->sack, sack, ( new * sizeof ( tcp->sack[0] ) ) );
+ return new;
+}
+
+/**
* Process TCP transmit queue
*
* @v tcp TCP connection
@@ -493,9 +586,10 @@ static size_t tcp_process_tx_queue ( struct tcp_connection *tcp, size_t max_len,
}
/**
- * Transmit any outstanding data
+ * Transmit any outstanding data (with selective acknowledgement)
*
* @v tcp TCP connection
+ * @v sack_seq SEQ for first selective acknowledgement (if any)
*
* Transmits any outstanding data on the connection.
*
@@ -503,17 +597,22 @@ static size_t tcp_process_tx_queue ( struct tcp_connection *tcp, size_t max_len,
* will have been started if necessary, and so the stack will
* eventually attempt to retransmit the failed packet.
*/
-static void tcp_xmit ( struct tcp_connection *tcp ) {
+static void tcp_xmit_sack ( struct tcp_connection *tcp, uint32_t sack_seq ) {
struct io_buffer *iobuf;
struct tcp_header *tcphdr;
struct tcp_mss_option *mssopt;
struct tcp_window_scale_padded_option *wsopt;
struct tcp_timestamp_padded_option *tsopt;
+ struct tcp_sack_permitted_padded_option *spopt;
+ struct tcp_sack_padded_option *sackopt;
+ struct tcp_sack_block *sack;
void *payload;
unsigned int flags;
+ unsigned int sack_count;
+ unsigned int i;
size_t len = 0;
+ size_t sack_len;
uint32_t seq_len;
- uint32_t app_win;
uint32_t max_rcv_win;
uint32_t max_representable_win;
int rc;
@@ -567,10 +666,9 @@ static void tcp_xmit ( struct tcp_connection *tcp ) {
tcp_process_tx_queue ( tcp, len, iobuf, 0 );
/* Expand receive window if possible */
- max_rcv_win = tcp->max_rcv_win;
- app_win = xfer_window ( &tcp->xfer );
- if ( max_rcv_win > app_win )
- max_rcv_win = app_win;
+ max_rcv_win = xfer_window ( &tcp->xfer );
+ if ( max_rcv_win > TCP_MAX_WINDOW_SIZE )
+ max_rcv_win = TCP_MAX_WINDOW_SIZE;
max_representable_win = ( 0xffff << tcp->rcv_win_scale );
if ( max_rcv_win > max_representable_win )
max_rcv_win = max_representable_win;
@@ -590,6 +688,10 @@ static void tcp_xmit ( struct tcp_connection *tcp ) {
wsopt->wsopt.kind = TCP_OPTION_WS;
wsopt->wsopt.length = sizeof ( wsopt->wsopt );
wsopt->wsopt.scale = TCP_RX_WINDOW_SCALE;
+ spopt = iob_push ( iobuf, sizeof ( *spopt ) );
+ memset ( spopt->nop, TCP_OPTION_NOP, sizeof ( spopt ) );
+ spopt->spopt.kind = TCP_OPTION_SACK_PERMITTED;
+ spopt->spopt.length = sizeof ( spopt->spopt );
}
if ( ( flags & TCP_SYN ) || ( tcp->flags & TCP_TS_ENABLED ) ) {
tsopt = iob_push ( iobuf, sizeof ( *tsopt ) );
@@ -599,6 +701,21 @@ static void tcp_xmit ( struct tcp_connection *tcp ) {
tsopt->tsopt.tsval = htonl ( currticks() );
tsopt->tsopt.tsecr = htonl ( tcp->ts_recent );
}
+ if ( ( tcp->flags & TCP_SACK_ENABLED ) &&
+ ( ! list_empty ( &tcp->rx_queue ) ) &&
+ ( ( sack_count = tcp_sack ( tcp, sack_seq ) ) != 0 ) ) {
+ sack_len = ( sack_count * sizeof ( *sack ) );
+ sackopt = iob_push ( iobuf, ( sizeof ( *sackopt ) + sack_len ));
+ memset ( sackopt->nop, TCP_OPTION_NOP, sizeof ( sackopt->nop ));
+ sackopt->sackopt.kind = TCP_OPTION_SACK;
+ sackopt->sackopt.length =
+ ( sizeof ( sackopt->sackopt ) + sack_len );
+ sack = ( ( ( void * ) sackopt ) + sizeof ( *sackopt ) );
+ for ( i = 0 ; i < sack_count ; i++, sack++ ) {
+ sack->left = htonl ( tcp->sack[i].left );
+ sack->right = htonl ( tcp->sack[i].right );
+ }
+ }
if ( len != 0 )
flags |= TCP_PSH;
tcphdr = iob_push ( iobuf, sizeof ( *tcphdr ) );
@@ -635,6 +752,17 @@ static void tcp_xmit ( struct tcp_connection *tcp ) {
profile_stop ( &tcp_tx_profiler );
}
+/**
+ * Transmit any outstanding data
+ *
+ * @v tcp TCP connection
+ */
+static void tcp_xmit ( struct tcp_connection *tcp ) {
+
+ /* Transmit without an explicit first SACK */
+ tcp_xmit_sack ( tcp, tcp->rcv_ack );
+}
+
/** TCP process descriptor */
static struct process_descriptor tcp_process_desc =
PROC_DESC_ONCE ( struct tcp_connection, process, tcp_xmit );
@@ -804,6 +932,12 @@ static void tcp_rx_opts ( struct tcp_connection *tcp, const void *data,
case TCP_OPTION_WS:
options->wsopt = data;
break;
+ case TCP_OPTION_SACK_PERMITTED:
+ options->spopt = data;
+ break;
+ case TCP_OPTION_SACK:
+ /* Ignore received SACKs */
+ break;
case TCP_OPTION_TS:
options->tsopt = data;
break;
@@ -823,6 +957,7 @@ static void tcp_rx_opts ( struct tcp_connection *tcp, const void *data,
* @v seq_len Sequence space length to consume
*/
static void tcp_rx_seq ( struct tcp_connection *tcp, uint32_t seq_len ) {
+ unsigned int sack;
/* Sanity check */
assert ( seq_len > 0 );
@@ -840,6 +975,16 @@ static void tcp_rx_seq ( struct tcp_connection *tcp, uint32_t seq_len ) {
/* Update timestamp */
tcp->ts_recent = tcp->ts_val;
+ /* Update SACK list */
+ for ( sack = 0 ; sack < TCP_SACK_MAX ; sack++ ) {
+ if ( tcp->sack[sack].left == tcp->sack[sack].right )
+ continue;
+ if ( tcp_cmp ( tcp->sack[sack].left, tcp->rcv_ack ) < 0 )
+ tcp->sack[sack].left = tcp->rcv_ack;
+ if ( tcp_cmp ( tcp->sack[sack].right, tcp->rcv_ack ) < 0 )
+ tcp->sack[sack].right = tcp->rcv_ack;
+ }
+
/* Mark ACK as pending */
tcp->flags |= TCP_ACK_PENDING;
}
@@ -860,6 +1005,8 @@ static int tcp_rx_syn ( struct tcp_connection *tcp, uint32_t seq,
tcp->rcv_ack = seq;
if ( options->tsopt )
tcp->flags |= TCP_TS_ENABLED;
+ if ( options->spopt )
+ tcp->flags |= TCP_SACK_ENABLED;
if ( options->wsopt ) {
tcp->snd_win_scale = options->wsopt->scale;
tcp->rcv_win_scale = TCP_RX_WINDOW_SCALE;
@@ -1070,6 +1217,7 @@ static void tcp_rx_enqueue ( struct tcp_connection *tcp, uint32_t seq,
struct io_buffer *queued;
size_t len;
uint32_t seq_len;
+ uint32_t nxt;
/* Calculate remaining flags and sequence length. Note that
* SYN, if present, has already been processed by this point.
@@ -1077,6 +1225,7 @@ static void tcp_rx_enqueue ( struct tcp_connection *tcp, uint32_t seq,
flags &= TCP_FIN;
len = iob_len ( iobuf );
seq_len = ( len + ( flags ? 1 : 0 ) );
+ nxt = ( seq + seq_len );
/* Discard immediately (to save memory) if:
*
@@ -1087,7 +1236,7 @@ static void tcp_rx_enqueue ( struct tcp_connection *tcp, uint32_t seq,
*/
if ( ( ! ( tcp->tcp_state & TCP_STATE_RCVD ( TCP_SYN ) ) ) ||
( tcp_cmp ( seq, tcp->rcv_ack + tcp->rcv_win ) >= 0 ) ||
- ( tcp_cmp ( seq + seq_len, tcp->rcv_ack ) < 0 ) ||
+ ( tcp_cmp ( nxt, tcp->rcv_ack ) < 0 ) ||
( seq_len == 0 ) ) {
free_iob ( iobuf );
return;
@@ -1096,6 +1245,7 @@ static void tcp_rx_enqueue ( struct tcp_connection *tcp, uint32_t seq,
/* Add internal header */
tcpqhdr = iob_push ( iobuf, sizeof ( *tcpqhdr ) );
tcpqhdr->seq = seq;
+ tcpqhdr->nxt = nxt;
tcpqhdr->flags = flags;
/* Add to RX queue */
@@ -1289,7 +1439,7 @@ static int tcp_rx ( struct io_buffer *iobuf,
if ( list_empty ( &tcp->rx_queue ) ) {
process_add ( &tcp->process );
} else {
- tcp_xmit ( tcp );
+ tcp_xmit_sack ( tcp, seq );
}
/* If this packet was the last we expect to receive, set up
@@ -1328,24 +1478,12 @@ struct tcpip_protocol tcp_protocol __tcpip_protocol = {
static unsigned int tcp_discard ( void ) {
struct tcp_connection *tcp;
struct io_buffer *iobuf;
- struct tcp_rx_queued_header *tcpqhdr;
- uint32_t max_win;
unsigned int discarded = 0;
/* Try to drop one queued RX packet from each connection */
list_for_each_entry ( tcp, &tcp_conns, list ) {
list_for_each_entry_reverse ( iobuf, &tcp->rx_queue, list ) {
- /* Limit window to prevent future discards */
- tcpqhdr = iobuf->data;
- max_win = ( tcpqhdr->seq - tcp->rcv_ack );
- if ( max_win < tcp->max_rcv_win ) {
- DBGC ( tcp, "TCP %p reducing maximum window "
- "from %d to %d\n",
- tcp, tcp->max_rcv_win, max_win );
- tcp->max_rcv_win = max_win;
- }
-
/* Remove packet from queue */
list_del ( &iobuf->list );
free_iob ( iobuf );
@@ -1365,12 +1503,67 @@ struct cache_discarder tcp_discarder __cache_discarder ( CACHE_NORMAL ) = {
};
/**
+ * Find first TCP connection that has not yet been closed
+ *
+ * @ret tcp First unclosed connection, or NULL
+ */
+static struct tcp_connection * tcp_first_unclosed ( void ) {
+ struct tcp_connection *tcp;
+
+ /* Find first connection which has not yet been closed */
+ list_for_each_entry ( tcp, &tcp_conns, list ) {
+ if ( ! ( tcp->flags & TCP_XFER_CLOSED ) )
+ return tcp;
+ }
+ return NULL;
+}
+
+/**
+ * Find first TCP connection that has not yet finished all operations
+ *
+ * @ret tcp First unfinished connection, or NULL
+ */
+static struct tcp_connection * tcp_first_unfinished ( void ) {
+ struct tcp_connection *tcp;
+
+ /* Find first connection which has not yet closed gracefully,
+ * or which still has a pending transmission (e.g. to ACK the
+ * received FIN).
+ */
+ list_for_each_entry ( tcp, &tcp_conns, list ) {
+ if ( ( ! TCP_CLOSED_GRACEFULLY ( tcp->tcp_state ) ) ||
+ process_running ( &tcp->process ) ) {
+ return tcp;
+ }
+ }
+ return NULL;
+}
+
+/**
* Shut down all TCP connections
*
*/
static void tcp_shutdown ( int booting __unused ) {
struct tcp_connection *tcp;
+ unsigned long start;
+ unsigned long elapsed;
+
+ /* Initiate a graceful close of all connections, allowing for
+ * the fact that the connection list may change as we do so.
+ */
+ while ( ( tcp = tcp_first_unclosed() ) ) {
+ DBGC ( tcp, "TCP %p closing for shutdown\n", tcp );
+ tcp_close ( tcp, -ECANCELED );
+ }
+
+ /* Wait for all connections to finish closing gracefully */
+ start = currticks();
+ while ( ( tcp = tcp_first_unfinished() ) &&
+ ( ( elapsed = ( currticks() - start ) ) < TCP_FINISH_TIMEOUT )){
+ step();
+ }
+ /* Forcibly close any remaining connections */
while ( ( tcp = list_first_entry ( &tcp_conns, struct tcp_connection,
list ) ) != NULL ) {
tcp->tcp_state = TCP_CLOSED;
@@ -1380,7 +1573,7 @@ static void tcp_shutdown ( int booting __unused ) {
}
/** TCP shutdown function */
-struct startup_fn tcp_startup_fn __startup_fn ( STARTUP_EARLY ) = {
+struct startup_fn tcp_startup_fn __startup_fn ( STARTUP_LATE ) = {
.shutdown = tcp_shutdown,
};
diff --git a/roms/ipxe/src/net/tcp/http.c b/roms/ipxe/src/net/tcp/http.c
index 90bae9d7a..b000ed80f 100644
--- a/roms/ipxe/src/net/tcp/http.c
+++ b/roms/ipxe/src/net/tcp/http.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @file
@@ -26,26 +30,20 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
*/
-#include <stddef.h>
#include <ipxe/open.h>
#include <ipxe/http.h>
#include <ipxe/features.h>
FEATURE ( FEATURE_PROTOCOL, "HTTP", DHCP_EB_FEATURE_HTTP, 1 );
-/**
- * Initiate an HTTP connection
- *
- * @v xfer Data transfer interface
- * @v uri Uniform Resource Identifier
- * @ret rc Return status code
- */
-static int http_open ( struct interface *xfer, struct uri *uri ) {
- return http_open_filter ( xfer, uri, HTTP_PORT, NULL );
-}
-
/** HTTP URI opener */
struct uri_opener http_uri_opener __uri_opener = {
.scheme = "http",
- .open = http_open,
+ .open = http_open_uri,
+};
+
+/** HTTP URI scheme */
+struct http_scheme http_scheme __http_scheme = {
+ .name = "http",
+ .port = HTTP_PORT,
};
diff --git a/roms/ipxe/src/net/tcp/httpauth.c b/roms/ipxe/src/net/tcp/httpauth.c
new file mode 100644
index 000000000..fb6dcd035
--- /dev/null
+++ b/roms/ipxe/src/net/tcp/httpauth.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/**
+ * @file
+ *
+ * Hyper Text Transfer Protocol (HTTP) authentication
+ *
+ */
+
+#include <stdio.h>
+#include <strings.h>
+#include <errno.h>
+#include <ipxe/http.h>
+
+/**
+ * Identify authentication scheme
+ *
+ * @v http HTTP transaction
+ * @v name Scheme name
+ * @ret auth Authentication scheme, or NULL
+ */
+static struct http_authentication * http_authentication ( const char *name ) {
+ struct http_authentication *auth;
+
+ /* Identify authentication scheme */
+ for_each_table_entry ( auth, HTTP_AUTHENTICATIONS ) {
+ if ( strcasecmp ( name, auth->name ) == 0 )
+ return auth;
+ }
+
+ return NULL;
+}
+
+/** An HTTP "WWW-Authenticate" response field */
+struct http_www_authenticate_field {
+ /** Name */
+ const char *name;
+ /** Offset */
+ size_t offset;
+};
+
+/** Define an HTTP "WWW-Authenticate" response field */
+#define HTTP_WWW_AUTHENTICATE_FIELD( _name ) { \
+ .name = #_name, \
+ .offset = offsetof ( struct http_transaction, \
+ response.auth._name ), \
+ }
+
+/**
+ * Set HTTP "WWW-Authenticate" response field value
+ *
+ * @v http HTTP transaction
+ * @v field Response field
+ * @v value Field value
+ */
+static inline void
+http_www_auth_field ( struct http_transaction *http,
+ struct http_www_authenticate_field *field, char *value ) {
+ char **ptr;
+
+ ptr = ( ( ( void * ) http ) + field->offset );
+ *ptr = value;
+}
+
+/** HTTP "WWW-Authenticate" fields */
+static struct http_www_authenticate_field http_www_auth_fields[] = {
+ HTTP_WWW_AUTHENTICATE_FIELD ( realm ),
+ HTTP_WWW_AUTHENTICATE_FIELD ( qop ),
+ HTTP_WWW_AUTHENTICATE_FIELD ( algorithm ),
+ HTTP_WWW_AUTHENTICATE_FIELD ( nonce ),
+ HTTP_WWW_AUTHENTICATE_FIELD ( opaque ),
+};
+
+/**
+ * Parse HTTP "WWW-Authenticate" header
+ *
+ * @v http HTTP transaction
+ * @v line Remaining header line
+ * @ret rc Return status code
+ */
+static int http_parse_www_authenticate ( struct http_transaction *http,
+ char *line ) {
+ struct http_www_authenticate_field *field;
+ char *name;
+ char *key;
+ char *value;
+ unsigned int i;
+
+ /* Get scheme name */
+ name = http_token ( &line, NULL );
+ if ( ! name ) {
+ DBGC ( http, "HTTP %p malformed WWW-Authenticate \"%s\"\n",
+ http, value );
+ return -EPROTO;
+ }
+
+ /* Identify scheme */
+ http->response.auth.auth = http_authentication ( name );
+ if ( ! http->response.auth.auth ) {
+ DBGC ( http, "HTTP %p unrecognised authentication scheme "
+ "\"%s\"\n", http, name );
+ return -ENOTSUP;
+ }
+
+ /* Process fields */
+ while ( ( key = http_token ( &line, &value ) ) ) {
+ for ( i = 0 ; i < ( sizeof ( http_www_auth_fields ) /
+ sizeof ( http_www_auth_fields[0] ) ) ; i++){
+ field = &http_www_auth_fields[i];
+ if ( strcasecmp ( key, field->name ) == 0 )
+ http_www_auth_field ( http, field, value );
+ }
+ }
+
+ /* Allow HTTP request to be retried if the request had not
+ * already tried authentication.
+ */
+ if ( ! http->request.auth.auth )
+ http->response.flags |= HTTP_RESPONSE_RETRY;
+
+ return 0;
+}
+
+/** HTTP "WWW-Authenticate" header */
+struct http_response_header
+http_response_www_authenticate __http_response_header = {
+ .name = "WWW-Authenticate",
+ .parse = http_parse_www_authenticate,
+};
+
+/**
+ * Construct HTTP "Authorization" header
+ *
+ * @v http HTTP transaction
+ * @v buf Buffer
+ * @v len Length of buffer
+ * @ret len Length of header value, or negative error
+ */
+static int http_format_authorization ( struct http_transaction *http,
+ char *buf, size_t len ) {
+ struct http_authentication *auth = http->request.auth.auth;
+ size_t used;
+ int auth_len;
+ int rc;
+
+ /* Do nothing unless we have an authentication scheme */
+ if ( ! auth )
+ return 0;
+
+ /* Construct header */
+ used = snprintf ( buf, len, "%s ", auth->name );
+ auth_len = auth->format ( http, ( buf + used ),
+ ( ( used < len ) ? ( len - used ) : 0 ) );
+ if ( auth_len < 0 ) {
+ rc = auth_len;
+ return rc;
+ }
+ used += auth_len;
+
+ return used;
+}
+
+/** HTTP "Authorization" header */
+struct http_request_header http_request_authorization __http_request_header = {
+ .name = "Authorization",
+ .format = http_format_authorization,
+};
diff --git a/roms/ipxe/src/net/tcp/httpbasic.c b/roms/ipxe/src/net/tcp/httpbasic.c
new file mode 100644
index 000000000..7ed7de9e7
--- /dev/null
+++ b/roms/ipxe/src/net/tcp/httpbasic.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/**
+ * @file
+ *
+ * Hyper Text Transfer Protocol (HTTP) Basic authentication
+ *
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <ipxe/uri.h>
+#include <ipxe/base64.h>
+#include <ipxe/http.h>
+
+/* Disambiguate the various error causes */
+#define EACCES_USERNAME __einfo_error ( EINFO_EACCES_USERNAME )
+#define EINFO_EACCES_USERNAME \
+ __einfo_uniqify ( EINFO_EACCES, 0x01, \
+ "No username available for Basic authentication" )
+
+/**
+ * Perform HTTP Basic authentication
+ *
+ * @v http HTTP transaction
+ * @ret rc Return status code
+ */
+static int http_basic_authenticate ( struct http_transaction *http ) {
+ struct http_request_auth *req = &http->request.auth;
+
+ /* Record username and password */
+ if ( ! http->uri->user ) {
+ DBGC ( http, "HTTP %p has no username for Basic "
+ "authentication\n", http );
+ return -EACCES_USERNAME;
+ }
+ req->username = http->uri->user;
+ req->password = ( http->uri->password ? http->uri->password : "" );
+
+ return 0;
+}
+
+/**
+ * Construct HTTP "Authorization" header for Basic authentication
+ *
+ * @v http HTTP transaction
+ * @v buf Buffer
+ * @v len Length of buffer
+ * @ret len Length of header value, or negative error
+ */
+static int http_format_basic_auth ( struct http_transaction *http,
+ char *buf, size_t len ) {
+ struct http_request_auth *req = &http->request.auth;
+ size_t user_pw_len = ( strlen ( req->username ) + 1 /* ":" */ +
+ strlen ( req->password ) );
+ char user_pw[ user_pw_len + 1 /* NUL */ ];
+
+ /* Sanity checks */
+ assert ( req->username != NULL );
+ assert ( req->password != NULL );
+
+ /* Construct "user:password" string */
+ snprintf ( user_pw, sizeof ( user_pw ), "%s:%s",
+ req->username, req->password );
+
+ /* Construct response */
+ return base64_encode ( user_pw, user_pw_len, buf, len );
+}
+
+/** HTTP Basic authentication scheme */
+struct http_authentication http_basic_auth __http_authentication = {
+ .name = "Basic",
+ .authenticate = http_basic_authenticate,
+ .format = http_format_basic_auth,
+};
+
+/* Drag in HTTP authentication support */
+REQUIRING_SYMBOL ( http_basic_auth );
+REQUIRE_OBJECT ( httpauth );
diff --git a/roms/ipxe/src/net/tcp/httpblock.c b/roms/ipxe/src/net/tcp/httpblock.c
new file mode 100644
index 000000000..e124ad2d6
--- /dev/null
+++ b/roms/ipxe/src/net/tcp/httpblock.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/**
+ * @file
+ *
+ * Hyper Text Transfer Protocol (HTTP) block device
+ *
+ */
+
+#include <stdint.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/blocktrans.h>
+#include <ipxe/blockdev.h>
+#include <ipxe/acpi.h>
+#include <ipxe/http.h>
+
+/** Block size used for HTTP block device requests */
+#define HTTP_BLKSIZE 512
+
+/**
+ * Read from block device
+ *
+ * @v http HTTP transaction
+ * @v data Data interface
+ * @v lba Starting logical block address
+ * @v count Number of logical blocks
+ * @v buffer Data buffer
+ * @v len Length of data buffer
+ * @ret rc Return status code
+ */
+int http_block_read ( struct http_transaction *http, struct interface *data,
+ uint64_t lba, unsigned int count, userptr_t buffer,
+ size_t len ) {
+ struct http_request_range range;
+ int rc;
+
+ /* Sanity check */
+ assert ( len == ( count * HTTP_BLKSIZE ) );
+
+ /* Construct request range descriptor */
+ range.start = ( lba * HTTP_BLKSIZE );
+ range.len = len;
+
+ /* Start a range request to retrieve the block(s) */
+ if ( ( rc = http_open ( data, &http_get, http->uri, &range,
+ NULL ) ) != 0 )
+ goto err_open;
+
+ /* Insert block device translator */
+ if ( ( rc = block_translate ( data, buffer, len ) ) != 0 ) {
+ DBGC ( http, "HTTP %p could not insert block translator: %s\n",
+ http, strerror ( rc ) );
+ goto err_translate;
+ }
+
+ return 0;
+
+ err_translate:
+ intf_restart ( data, rc );
+ err_open:
+ return rc;
+}
+
+/**
+ * Read block device capacity
+ *
+ * @v control Control interface
+ * @v data Data interface
+ * @ret rc Return status code
+ */
+int http_block_read_capacity ( struct http_transaction *http,
+ struct interface *data ) {
+ int rc;
+
+ /* Start a HEAD request to retrieve the capacity */
+ if ( ( rc = http_open ( data, &http_head, http->uri, NULL,
+ NULL ) ) != 0 )
+ goto err_open;
+
+ /* Insert block device translator */
+ if ( ( rc = block_translate ( data, UNULL, HTTP_BLKSIZE ) ) != 0 ) {
+ DBGC ( http, "HTTP %p could not insert block translator: %s\n",
+ http, strerror ( rc ) );
+ goto err_translate;
+ }
+
+ return 0;
+
+ err_translate:
+ intf_restart ( data, rc );
+ err_open:
+ return rc;
+}
+
+/**
+ * Describe device in ACPI table
+ *
+ * @v http HTTP transaction
+ * @v acpi ACPI table
+ * @v len Length of ACPI table
+ * @ret rc Return status code
+ */
+int http_acpi_describe ( struct http_transaction *http,
+ struct acpi_description_header *acpi, size_t len ) {
+
+ DBGC ( http, "HTTP %p cannot yet describe device in an ACPI table\n",
+ http );
+ ( void ) acpi;
+ ( void ) len;
+ return 0;
+}
diff --git a/roms/ipxe/src/net/tcp/httpconn.c b/roms/ipxe/src/net/tcp/httpconn.c
new file mode 100644
index 000000000..7e4877b7b
--- /dev/null
+++ b/roms/ipxe/src/net/tcp/httpconn.c
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/**
+ * @file
+ *
+ * Hyper Text Transfer Protocol (HTTP) connection management
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/tcpip.h>
+#include <ipxe/uri.h>
+#include <ipxe/timer.h>
+#include <ipxe/xfer.h>
+#include <ipxe/open.h>
+#include <ipxe/pool.h>
+#include <ipxe/http.h>
+
+/** HTTP pooled connection expiry time */
+#define HTTP_CONN_EXPIRY ( 10 * TICKS_PER_SEC )
+
+/** HTTP connection pool */
+static LIST_HEAD ( http_connection_pool );
+
+/**
+ * Identify HTTP scheme
+ *
+ * @v uri URI
+ * @ret scheme HTTP scheme, or NULL
+ */
+static struct http_scheme * http_scheme ( struct uri *uri ) {
+ struct http_scheme *scheme;
+
+ /* Sanity check */
+ if ( ! uri->scheme )
+ return NULL;
+
+ /* Identify scheme */
+ for_each_table_entry ( scheme, HTTP_SCHEMES ) {
+ if ( strcmp ( uri->scheme, scheme->name ) == 0 )
+ return scheme;
+ }
+
+ return NULL;
+}
+
+/**
+ * Free HTTP connection
+ *
+ * @v refcnt Reference count
+ */
+static void http_conn_free ( struct refcnt *refcnt ) {
+ struct http_connection *conn =
+ container_of ( refcnt, struct http_connection, refcnt );
+
+ /* Free connection */
+ uri_put ( conn->uri );
+ free ( conn );
+}
+
+/**
+ * Close HTTP connection
+ *
+ * @v conn HTTP connection
+ * @v rc Reason for close
+ */
+static void http_conn_close ( struct http_connection *conn, int rc ) {
+
+ /* Remove from connection pool, if applicable */
+ pool_del ( &conn->pool );
+
+ /* Shut down interfaces */
+ intf_shutdown ( &conn->socket, rc );
+ intf_shutdown ( &conn->xfer, rc );
+ if ( rc == 0 ) {
+ DBGC2 ( conn, "HTTPCONN %p closed %s://%s\n",
+ conn, conn->scheme->name, conn->uri->host );
+ } else {
+ DBGC ( conn, "HTTPCONN %p closed %s://%s: %s\n",
+ conn, conn->scheme->name, conn->uri->host,
+ strerror ( rc ) );
+ }
+}
+
+/**
+ * Disconnect idle HTTP connection
+ *
+ * @v pool Pooled connection
+ */
+static void http_conn_expired ( struct pooled_connection *pool ) {
+ struct http_connection *conn =
+ container_of ( pool, struct http_connection, pool );
+
+ /* Close connection */
+ http_conn_close ( conn, 0 /* Not an error to close idle connection */ );
+}
+
+/**
+ * Receive data from transport layer interface
+ *
+ * @v http HTTP connection
+ * @v iobuf I/O buffer
+ * @v meta Transfer metadata
+ * @ret rc Return status code
+ */
+static int http_conn_socket_deliver ( struct http_connection *conn,
+ struct io_buffer *iobuf,
+ struct xfer_metadata *meta ) {
+
+ /* Mark connection as alive */
+ pool_alive ( &conn->pool );
+
+ /* Pass on to data transfer interface */
+ return xfer_deliver ( &conn->xfer, iobuf, meta );
+}
+
+/**
+ * Close HTTP connection transport layer interface
+ *
+ * @v http HTTP connection
+ * @v rc Reason for close
+ */
+static void http_conn_socket_close ( struct http_connection *conn, int rc ) {
+
+ /* If we are reopenable (i.e. we are a recycled connection
+ * from the connection pool, and we have received no data from
+ * the underlying socket since we were pooled), then suggest
+ * that the client should reopen the connection.
+ */
+ if ( pool_is_reopenable ( &conn->pool ) )
+ pool_reopen ( &conn->xfer );
+
+ /* Close the connection */
+ http_conn_close ( conn, rc );
+}
+
+/**
+ * Recycle this connection after closing
+ *
+ * @v http HTTP connection
+ */
+static void http_conn_xfer_recycle ( struct http_connection *conn ) {
+
+ /* Mark connection as recyclable */
+ pool_recyclable ( &conn->pool );
+ DBGC2 ( conn, "HTTPCONN %p keepalive enabled\n", conn );
+}
+
+/**
+ * Close HTTP connection data transfer interface
+ *
+ * @v conn HTTP connection
+ * @v rc Reason for close
+ */
+static void http_conn_xfer_close ( struct http_connection *conn, int rc ) {
+
+ /* Add to the connection pool if keepalive is enabled and no
+ * error occurred.
+ */
+ if ( ( rc == 0 ) && pool_is_recyclable ( &conn->pool ) ) {
+ intf_restart ( &conn->xfer, rc );
+ pool_add ( &conn->pool, &http_connection_pool,
+ HTTP_CONN_EXPIRY );
+ DBGC2 ( conn, "HTTPCONN %p pooled %s://%s\n",
+ conn, conn->scheme->name, conn->uri->host );
+ return;
+ }
+
+ /* Otherwise, close the connection */
+ http_conn_close ( conn, rc );
+}
+
+/** HTTP connection socket interface operations */
+static struct interface_operation http_conn_socket_operations[] = {
+ INTF_OP ( xfer_deliver, struct http_connection *,
+ http_conn_socket_deliver ),
+ INTF_OP ( intf_close, struct http_connection *,
+ http_conn_socket_close ),
+};
+
+/** HTTP connection socket interface descriptor */
+static struct interface_descriptor http_conn_socket_desc =
+ INTF_DESC_PASSTHRU ( struct http_connection, socket,
+ http_conn_socket_operations, xfer );
+
+/** HTTP connection data transfer interface operations */
+static struct interface_operation http_conn_xfer_operations[] = {
+ INTF_OP ( pool_recycle, struct http_connection *,
+ http_conn_xfer_recycle ),
+ INTF_OP ( intf_close, struct http_connection *,
+ http_conn_xfer_close ),
+};
+
+/** HTTP connection data transfer interface descriptor */
+static struct interface_descriptor http_conn_xfer_desc =
+ INTF_DESC_PASSTHRU ( struct http_connection, xfer,
+ http_conn_xfer_operations, socket );
+
+/**
+ * Connect to an HTTP server
+ *
+ * @v xfer Data transfer interface
+ * @v uri Connection URI
+ * @ret rc Return status code
+ *
+ * HTTP connections are pooled. The caller should be prepared to
+ * receive a pool_reopen() message.
+ */
+int http_connect ( struct interface *xfer, struct uri *uri ) {
+ struct http_connection *conn;
+ struct http_scheme *scheme;
+ struct sockaddr_tcpip server;
+ struct interface *socket;
+ int rc;
+
+ /* Identify scheme */
+ scheme = http_scheme ( uri );
+ if ( ! scheme )
+ return -ENOTSUP;
+
+ /* Sanity check */
+ if ( ! uri->host )
+ return -EINVAL;
+
+ /* Look for a reusable connection in the pool */
+ list_for_each_entry ( conn, &http_connection_pool, pool.list ) {
+
+ /* Sanity checks */
+ assert ( conn->uri != NULL );
+ assert ( conn->uri->host != NULL );
+
+ /* Reuse connection, if possible */
+ if ( ( scheme == conn->scheme ) &&
+ ( strcmp ( uri->host, conn->uri->host ) == 0 ) ) {
+
+ /* Remove from connection pool, stop timer,
+ * attach to parent interface, and return.
+ */
+ pool_del ( &conn->pool );
+ intf_plug_plug ( &conn->xfer, xfer );
+ DBGC2 ( conn, "HTTPCONN %p reused %s://%s\n",
+ conn, conn->scheme->name, conn->uri->host );
+ return 0;
+ }
+ }
+
+ /* Allocate and initialise structure */
+ conn = zalloc ( sizeof ( *conn ) );
+ ref_init ( &conn->refcnt, http_conn_free );
+ conn->uri = uri_get ( uri );
+ conn->scheme = scheme;
+ intf_init ( &conn->socket, &http_conn_socket_desc, &conn->refcnt );
+ intf_init ( &conn->xfer, &http_conn_xfer_desc, &conn->refcnt );
+ pool_init ( &conn->pool, http_conn_expired, &conn->refcnt );
+
+ /* Open socket */
+ memset ( &server, 0, sizeof ( server ) );
+ server.st_port = htons ( uri_port ( uri, scheme->port ) );
+ socket = &conn->socket;
+ if ( scheme->filter &&
+ ( ( rc = scheme->filter ( socket, uri->host, &socket ) ) != 0 ) )
+ goto err_filter;
+ if ( ( rc = xfer_open_named_socket ( socket, SOCK_STREAM,
+ ( struct sockaddr * ) &server,
+ uri->host, NULL ) ) != 0 )
+ goto err_open;
+
+ /* Attach to parent interface, mortalise self, and return */
+ intf_plug_plug ( &conn->xfer, xfer );
+ ref_put ( &conn->refcnt );
+
+ DBGC2 ( conn, "HTTPCONN %p created %s://%s:%d\n", conn,
+ conn->scheme->name, conn->uri->host, ntohs ( server.st_port ) );
+ return 0;
+
+ err_open:
+ err_filter:
+ DBGC2 ( conn, "HTTPCONN %p could not create %s://%s: %s\n",
+ conn, conn->scheme->name, conn->uri->host, strerror ( rc ) );
+ http_conn_close ( conn, rc );
+ ref_put ( &conn->refcnt );
+ return rc;
+}
diff --git a/roms/ipxe/src/net/tcp/httpcore.c b/roms/ipxe/src/net/tcp/httpcore.c
index 1d1953e61..af3ca9780 100644
--- a/roms/ipxe/src/net/tcp/httpcore.c
+++ b/roms/ipxe/src/net/tcp/httpcore.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
+ * Copyright (C) 2015 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
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @file
@@ -40,35 +44,26 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/iobuf.h>
#include <ipxe/xfer.h>
#include <ipxe/open.h>
-#include <ipxe/socket.h>
-#include <ipxe/tcpip.h>
#include <ipxe/process.h>
#include <ipxe/retry.h>
#include <ipxe/timer.h>
#include <ipxe/linebuf.h>
-#include <ipxe/base64.h>
-#include <ipxe/base16.h>
-#include <ipxe/md5.h>
+#include <ipxe/xferbuf.h>
#include <ipxe/blockdev.h>
#include <ipxe/acpi.h>
#include <ipxe/version.h>
#include <ipxe/params.h>
#include <ipxe/profile.h>
+#include <ipxe/vsprintf.h>
#include <ipxe/http.h>
/* Disambiguate the various error causes */
#define EACCES_401 __einfo_error ( EINFO_EACCES_401 )
#define EINFO_EACCES_401 \
__einfo_uniqify ( EINFO_EACCES, 0x01, "HTTP 401 Unauthorized" )
-#define EIO_OTHER __einfo_error ( EINFO_EIO_OTHER )
-#define EINFO_EIO_OTHER \
- __einfo_uniqify ( EINFO_EIO, 0x01, "Unrecognised HTTP response code" )
-#define EIO_CONTENT_LENGTH __einfo_error ( EINFO_EIO_CONTENT_LENGTH )
-#define EINFO_EIO_CONTENT_LENGTH \
- __einfo_uniqify ( EINFO_EIO, 0x02, "Content length mismatch" )
-#define EINVAL_RESPONSE __einfo_error ( EINFO_EINVAL_RESPONSE )
-#define EINFO_EINVAL_RESPONSE \
- __einfo_uniqify ( EINFO_EINVAL, 0x01, "Invalid content length" )
+#define EINVAL_STATUS __einfo_error ( EINFO_EINVAL_STATUS )
+#define EINFO_EINVAL_STATUS \
+ __einfo_uniqify ( EINFO_EINVAL, 0x01, "Invalid status line" )
#define EINVAL_HEADER __einfo_error ( EINFO_EINVAL_HEADER )
#define EINFO_EINVAL_HEADER \
__einfo_uniqify ( EINFO_EINVAL, 0x02, "Invalid header" )
@@ -78,9 +73,27 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define EINVAL_CHUNK_LENGTH __einfo_error ( EINFO_EINVAL_CHUNK_LENGTH )
#define EINFO_EINVAL_CHUNK_LENGTH \
__einfo_uniqify ( EINFO_EINVAL, 0x04, "Invalid chunk length" )
+#define EIO_OTHER __einfo_error ( EINFO_EIO_OTHER )
+#define EINFO_EIO_OTHER \
+ __einfo_uniqify ( EINFO_EIO, 0x01, "Unrecognised HTTP response code" )
+#define EIO_CONTENT_LENGTH __einfo_error ( EINFO_EIO_CONTENT_LENGTH )
+#define EINFO_EIO_CONTENT_LENGTH \
+ __einfo_uniqify ( EINFO_EIO, 0x02, "Content length mismatch" )
+#define EIO_4XX __einfo_error ( EINFO_EIO_4XX )
+#define EINFO_EIO_4XX \
+ __einfo_uniqify ( EINFO_EIO, 0x04, "HTTP 4xx Client Error" )
+#define EIO_5XX __einfo_error ( EINFO_EIO_5XX )
+#define EINFO_EIO_5XX \
+ __einfo_uniqify ( EINFO_EIO, 0x05, "HTTP 5xx Server Error" )
#define ENOENT_404 __einfo_error ( EINFO_ENOENT_404 )
#define EINFO_ENOENT_404 \
__einfo_uniqify ( EINFO_ENOENT, 0x01, "HTTP 404 Not Found" )
+#define ENOTSUP_CONNECTION __einfo_error ( EINFO_ENOTSUP_CONNECTION )
+#define EINFO_ENOTSUP_CONNECTION \
+ __einfo_uniqify ( EINFO_ENOTSUP, 0x01, "Unsupported connection header" )
+#define ENOTSUP_TRANSFER __einfo_error ( EINFO_ENOTSUP_TRANSFER )
+#define EINFO_ENOTSUP_TRANSFER \
+ __einfo_uniqify ( EINFO_ENOTSUP, 0x02, "Unsupported transfer encoding" )
#define EPERM_403 __einfo_error ( EINFO_EPERM_403 )
#define EINFO_EPERM_403 \
__einfo_uniqify ( EINFO_EPERM, 0x01, "HTTP 403 Forbidden" )
@@ -88,9 +101,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define EINFO_EPROTO_UNSOLICITED \
__einfo_uniqify ( EINFO_EPROTO, 0x01, "Unsolicited data" )
-/** Block size used for HTTP block device request */
-#define HTTP_BLKSIZE 512
-
/** Retry delay used when we cannot understand the Retry-After header */
#define HTTP_RETRY_SECONDS 5
@@ -100,1069 +110,1711 @@ static struct profiler http_rx_profiler __profiler = { .name = "http.rx" };
/** Data transfer profiler */
static struct profiler http_xfer_profiler __profiler = { .name = "http.xfer" };
-/** HTTP flags */
-enum http_flags {
- /** Request is waiting to be transmitted */
- HTTP_TX_PENDING = 0x0001,
- /** Fetch header only */
- HTTP_HEAD_ONLY = 0x0002,
- /** Client would like to keep connection alive */
- HTTP_CLIENT_KEEPALIVE = 0x0004,
- /** Server will keep connection alive */
- HTTP_SERVER_KEEPALIVE = 0x0008,
- /** Discard the current request and try again */
- HTTP_TRY_AGAIN = 0x0010,
- /** Provide Basic authentication details */
- HTTP_BASIC_AUTH = 0x0020,
- /** Provide Digest authentication details */
- HTTP_DIGEST_AUTH = 0x0040,
- /** Socket must be reopened */
- HTTP_REOPEN_SOCKET = 0x0080,
+static struct http_state http_request;
+static struct http_state http_headers;
+static struct http_state http_trailers;
+static struct http_transfer_encoding http_transfer_identity;
+
+/******************************************************************************
+ *
+ * Methods
+ *
+ ******************************************************************************
+ */
+
+/** HTTP HEAD method */
+struct http_method http_head = {
+ .name = "HEAD",
};
-/** HTTP receive state */
-enum http_rx_state {
- HTTP_RX_RESPONSE = 0,
- HTTP_RX_HEADER,
- HTTP_RX_CHUNK_LEN,
- /* In HTTP_RX_DATA, it is acceptable for the server to close
- * the connection (unless we are in the middle of a chunked
- * transfer).
- */
- HTTP_RX_DATA,
- /* In the following states, it is acceptable for the server to
- * close the connection.
- */
- HTTP_RX_TRAILER,
- HTTP_RX_IDLE,
- HTTP_RX_DEAD,
+/** HTTP GET method */
+struct http_method http_get = {
+ .name = "GET",
};
+/** HTTP POST method */
+struct http_method http_post = {
+ .name = "POST",
+};
+
+/******************************************************************************
+ *
+ * Utility functions
+ *
+ ******************************************************************************
+ */
+
/**
- * An HTTP request
+ * Handle received HTTP line-buffered data
*
+ * @v http HTTP transaction
+ * @v iobuf I/O buffer
+ * @v linebuf Line buffer
+ * @ret rc Return status code
*/
-struct http_request {
- /** Reference count */
- struct refcnt refcnt;
- /** Data transfer interface */
- struct interface xfer;
- /** Partial transfer interface */
- struct interface partial;
-
- /** URI being fetched */
- struct uri *uri;
- /** Default port */
- unsigned int default_port;
- /** Filter (if any) */
- int ( * filter ) ( struct interface *xfer,
- const char *name,
- struct interface **next );
- /** Transport layer interface */
- struct interface socket;
-
- /** Flags */
- unsigned int flags;
- /** Starting offset of partial transfer (if applicable) */
- size_t partial_start;
- /** Length of partial transfer (if applicable) */
- size_t partial_len;
-
- /** TX process */
- struct process process;
-
- /** RX state */
- enum http_rx_state rx_state;
- /** Response code */
- unsigned int code;
- /** Received length */
- size_t rx_len;
- /** Length remaining (or 0 if unknown) */
- size_t remaining;
- /** HTTP is using Transfer-Encoding: chunked */
- int chunked;
- /** Current chunk length remaining (if applicable) */
- size_t chunk_remaining;
- /** Line buffer for received header lines */
- struct line_buffer linebuf;
- /** Receive data buffer (if applicable) */
- userptr_t rx_buffer;
-
- /** Authentication realm (if any) */
- char *auth_realm;
- /** Authentication nonce (if any) */
- char *auth_nonce;
- /** Authentication opaque string (if any) */
- char *auth_opaque;
-
- /** Request retry timer */
- struct retry_timer timer;
- /** Retry delay (in timer ticks) */
- unsigned long retry_delay;
-};
+static int http_rx_linebuf ( struct http_transaction *http,
+ struct io_buffer *iobuf,
+ struct line_buffer *linebuf ) {
+ int consumed;
+ int rc;
+
+ /* Buffer received line */
+ consumed = line_buffer ( linebuf, iobuf->data, iob_len ( iobuf ) );
+ if ( consumed < 0 ) {
+ rc = consumed;
+ DBGC ( http, "HTTP %p could not buffer line: %s\n",
+ http, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Consume line */
+ iob_pull ( iobuf, consumed );
+
+ return 0;
+}
/**
- * Free HTTP request
+ * Get HTTP response token
*
- * @v refcnt Reference counter
+ * @v line Line position
+ * @v value Token value to fill in (if any)
+ * @ret token Token, or NULL
+ */
+char * http_token ( char **line, char **value ) {
+ char *token;
+ char quote = '\0';
+ char c;
+
+ /* Avoid returning uninitialised data */
+ if ( value )
+ *value = NULL;
+
+ /* Skip any initial whitespace */
+ while ( isspace ( **line ) )
+ (*line)++;
+
+ /* Check for end of line and record token position */
+ if ( ! **line )
+ return NULL;
+ token = *line;
+
+ /* Scan for end of token */
+ while ( ( c = **line ) ) {
+
+ /* Terminate if we hit an unquoted whitespace */
+ if ( isspace ( c ) && ! quote )
+ break;
+
+ /* Terminate if we hit a closing quote */
+ if ( c == quote )
+ break;
+
+ /* Check for value separator */
+ if ( value && ( ! *value ) && ( c == '=' ) ) {
+
+ /* Terminate key portion of token */
+ *((*line)++) = '\0';
+
+ /* Check for quote character */
+ c = **line;
+ if ( ( c == '"' ) || ( c == '\'' ) ) {
+ quote = c;
+ (*line)++;
+ }
+
+ /* Record value portion of token */
+ *value = *line;
+
+ } else {
+
+ /* Move to next character */
+ (*line)++;
+ }
+ }
+
+ /* Terminate token, if applicable */
+ if ( c )
+ *((*line)++) = '\0';
+
+ return token;
+}
+
+/******************************************************************************
+ *
+ * Transactions
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Free HTTP transaction
+ *
+ * @v refcnt Reference count
*/
static void http_free ( struct refcnt *refcnt ) {
- struct http_request *http =
- container_of ( refcnt, struct http_request, refcnt );
+ struct http_transaction *http =
+ container_of ( refcnt, struct http_transaction, refcnt );
- uri_put ( http->uri );
+ empty_line_buffer ( &http->response.headers );
empty_line_buffer ( &http->linebuf );
- free ( http->auth_realm );
- free ( http->auth_nonce );
- free ( http->auth_opaque );
+ uri_put ( http->uri );
free ( http );
-};
+}
/**
- * Close HTTP request
+ * Close HTTP transaction
*
- * @v http HTTP request
- * @v rc Return status code
+ * @v http HTTP transaction
+ * @v rc Reason for close
*/
-static void http_close ( struct http_request *http, int rc ) {
-
- /* Prevent further processing of any current packet */
- http->rx_state = HTTP_RX_DEAD;
+static void http_close ( struct http_transaction *http, int rc ) {
- /* Prevent reconnection */
- http->flags &= ~HTTP_CLIENT_KEEPALIVE;
-
- /* Remove process */
+ /* Stop process */
process_del ( &http->process );
- /* Close all data transfer interfaces */
- intf_shutdown ( &http->socket, rc );
- intf_shutdown ( &http->partial, rc );
+ /* Stop timer */
+ stop_timer ( &http->timer );
+
+ /* Close all interfaces, allowing for the fact that the
+ * content-decoded and transfer-decoded interfaces may be
+ * connected to the same object.
+ */
+ intf_shutdown ( &http->conn, rc );
+ intf_nullify ( &http->transfer );
+ intf_shutdown ( &http->content, rc );
+ intf_shutdown ( &http->transfer, rc );
intf_shutdown ( &http->xfer, rc );
}
/**
- * Open HTTP socket
+ * Close HTTP transaction with error (even if none specified)
*
- * @v http HTTP request
- * @ret rc Return status code
+ * @v http HTTP transaction
+ * @v rc Reason for close
*/
-static int http_socket_open ( struct http_request *http ) {
- struct uri *uri = http->uri;
- struct sockaddr_tcpip server;
- struct interface *socket;
+static void http_close_error ( struct http_transaction *http, int rc ) {
+
+ /* Treat any close as an error */
+ http_close ( http, ( rc ? rc : -EPIPE ) );
+}
+
+/**
+ * Reopen stale HTTP connection
+ *
+ * @v http HTTP transaction
+ */
+static void http_reopen ( struct http_transaction *http ) {
int rc;
- /* Open socket */
- memset ( &server, 0, sizeof ( server ) );
- server.st_port = htons ( uri_port ( uri, http->default_port ) );
- socket = &http->socket;
- if ( http->filter ) {
- if ( ( rc = http->filter ( socket, uri->host, &socket ) ) != 0 )
- return rc;
+ /* Close existing connection */
+ intf_restart ( &http->conn, -ECANCELED );
+
+ /* Reopen connection */
+ if ( ( rc = http_connect ( &http->conn, http->uri ) ) != 0 ) {
+ DBGC ( http, "HTTP %p could not reconnect: %s\n",
+ http, strerror ( rc ) );
+ goto err_connect;
}
- if ( ( rc = xfer_open_named_socket ( socket, SOCK_STREAM,
- ( struct sockaddr * ) &server,
- uri->host, NULL ) ) != 0 )
- return rc;
- return 0;
+ /* Reset state */
+ http->state = &http_request;
+
+ /* Reschedule transmission process */
+ process_add ( &http->process );
+
+ return;
+
+ err_connect:
+ http_close ( http, rc );
}
/**
- * Retry HTTP request
+ * Handle retry timer expiry
*
* @v timer Retry timer
- * @v fail Failure indicator
+ * @v over Failure indicator
+ */
+static void http_expired ( struct retry_timer *timer, int over __unused ) {
+ struct http_transaction *http =
+ container_of ( timer, struct http_transaction, timer );
+
+ /* Reopen connection */
+ http_reopen ( http );
+}
+
+/**
+ * HTTP transmit process
+ *
+ * @v http HTTP transaction
*/
-static void http_retry ( struct retry_timer *timer, int fail __unused ) {
- struct http_request *http =
- container_of ( timer, struct http_request, timer );
+static void http_step ( struct http_transaction *http ) {
int rc;
- /* Reopen socket if required */
- if ( http->flags & HTTP_REOPEN_SOCKET ) {
- http->flags &= ~HTTP_REOPEN_SOCKET;
- DBGC ( http, "HTTP %p reopening connection\n", http );
- if ( ( rc = http_socket_open ( http ) ) != 0 ) {
- http_close ( http, rc );
- return;
+ /* Do nothing if we have nothing to transmit */
+ if ( ! http->state->tx )
+ return;
+
+ /* Do nothing until connection is ready */
+ if ( ! xfer_window ( &http->conn ) )
+ return;
+
+ /* Do nothing until data transfer interface is ready */
+ if ( ! xfer_window ( &http->xfer ) )
+ return;
+
+ /* Transmit data */
+ if ( ( rc = http->state->tx ( http ) ) != 0 )
+ goto err;
+
+ return;
+
+ err:
+ http_close ( http, rc );
+}
+
+/**
+ * Handle received HTTP data
+ *
+ * @v http HTTP transaction
+ * @v iobuf I/O buffer
+ * @v meta Transfer metadata
+ * @ret rc Return status code
+ *
+ * This function takes ownership of the I/O buffer.
+ */
+static int http_conn_deliver ( struct http_transaction *http,
+ struct io_buffer *iobuf,
+ struct xfer_metadata *meta __unused ) {
+ int rc;
+
+ /* Handle received data */
+ profile_start ( &http_rx_profiler );
+ while ( iobuf && iob_len ( iobuf ) ) {
+
+ /* Sanity check */
+ if ( ( ! http->state ) || ( ! http->state->rx ) ) {
+ DBGC ( http, "HTTP %p unexpected data\n", http );
+ rc = -EPROTO_UNSOLICITED;
+ goto err;
}
- }
- /* Retry the request if applicable */
- if ( http->flags & HTTP_TRY_AGAIN ) {
- http->flags &= ~HTTP_TRY_AGAIN;
- DBGC ( http, "HTTP %p retrying request\n", http );
- http->flags |= HTTP_TX_PENDING;
- http->rx_state = HTTP_RX_RESPONSE;
- process_add ( &http->process );
+ /* Receive (some) data */
+ if ( ( rc = http->state->rx ( http, &iobuf ) ) != 0 )
+ goto err;
}
+
+ /* Free I/O buffer, if applicable */
+ free_iob ( iobuf );
+
+ profile_stop ( &http_rx_profiler );
+ return 0;
+
+ err:
+ free_iob ( iobuf );
+ http_close ( http, rc );
+ return rc;
}
/**
- * Mark HTTP request as completed successfully
+ * Handle server connection close
*
- * @v http HTTP request
+ * @v http HTTP transaction
+ * @v rc Reason for close
*/
-static void http_done ( struct http_request *http ) {
+static void http_conn_close ( struct http_transaction *http, int rc ) {
- /* If we are not at an appropriate stage of the protocol
- * (including being in the middle of a chunked transfer),
- * force an error.
- */
- if ( ( http->rx_state < HTTP_RX_DATA ) || ( http->chunked != 0 ) ) {
- DBGC ( http, "HTTP %p connection closed unexpectedly in state "
- "%d\n", http, http->rx_state );
- http_close ( http, -ECONNRESET );
- return;
- }
+ /* Sanity checks */
+ assert ( http->state != NULL );
+ assert ( http->state->close != NULL );
+
+ /* Restart server connection interface */
+ intf_restart ( &http->conn, rc );
+
+ /* Hand off to state-specific method */
+ http->state->close ( http, rc );
+}
- /* If we had a Content-Length, and the received content length
- * isn't correct, force an error
+/**
+ * Handle received content-decoded data
+ *
+ * @v http HTTP transaction
+ * @v iobuf I/O buffer
+ * @v meta Data transfer metadata
+ */
+static int http_content_deliver ( struct http_transaction *http,
+ struct io_buffer *iobuf,
+ struct xfer_metadata *meta ) {
+ int rc;
+
+ /* Ignore content if this is anything other than a successful
+ * transfer.
*/
- if ( http->remaining != 0 ) {
- DBGC ( http, "HTTP %p incorrect length %zd, should be %zd\n",
- http, http->rx_len, ( http->rx_len + http->remaining ) );
- http_close ( http, -EIO_CONTENT_LENGTH );
- return;
+ if ( http->response.rc != 0 ) {
+ free_iob ( iobuf );
+ return 0;
}
- /* Enter idle state */
- http->rx_state = HTTP_RX_IDLE;
- http->rx_len = 0;
- assert ( http->remaining == 0 );
- assert ( http->chunked == 0 );
- assert ( http->chunk_remaining == 0 );
+ /* Deliver to data transfer interface */
+ profile_start ( &http_xfer_profiler );
+ if ( ( rc = xfer_deliver ( &http->xfer, iob_disown ( iobuf ),
+ meta ) ) != 0 )
+ return rc;
+ profile_stop ( &http_xfer_profiler );
- /* Close partial transfer interface */
- if ( ! ( http->flags & HTTP_TRY_AGAIN ) )
- intf_restart ( &http->partial, 0 );
+ return 0;
+}
- /* Close everything unless we want to keep the connection alive */
- if ( ! ( http->flags & ( HTTP_CLIENT_KEEPALIVE | HTTP_TRY_AGAIN ) ) ) {
- http_close ( http, 0 );
- return;
- }
+/**
+ * Get underlying data transfer buffer
+ *
+ * @v http HTTP transaction
+ * @ret xferbuf Data transfer buffer, or NULL on error
+ */
+static struct xfer_buffer *
+http_content_buffer ( struct http_transaction *http ) {
- /* If the server is not intending to keep the connection
- * alive, then close the socket and mark it as requiring
- * reopening.
+ /* Deny access to the data transfer buffer if this is anything
+ * other than a successful transfer.
*/
- if ( ! ( http->flags & HTTP_SERVER_KEEPALIVE ) ) {
- intf_restart ( &http->socket, 0 );
- http->flags &= ~HTTP_SERVER_KEEPALIVE;
- http->flags |= HTTP_REOPEN_SOCKET;
- }
+ if ( http->response.rc != 0 )
+ return NULL;
- /* Start request retry timer */
- start_timer_fixed ( &http->timer, http->retry_delay );
- http->retry_delay = 0;
+ /* Hand off to data transfer interface */
+ return xfer_buffer ( &http->xfer );
}
/**
- * Convert HTTP response code to return status code
+ * Read from block device (when HTTP block device support is not present)
*
- * @v response HTTP response code
+ * @v http HTTP transaction
+ * @v data Data interface
+ * @v lba Starting logical block address
+ * @v count Number of logical blocks
+ * @v buffer Data buffer
+ * @v len Length of data buffer
* @ret rc Return status code
*/
-static int http_response_to_rc ( unsigned int response ) {
- switch ( response ) {
- case 200:
- case 206:
- case 301:
- case 302:
- case 303:
- return 0;
- case 404:
- return -ENOENT_404;
- case 403:
- return -EPERM_403;
- case 401:
- return -EACCES_401;
- default:
- return -EIO_OTHER;
- }
+__weak int http_block_read ( struct http_transaction *http __unused,
+ struct interface *data __unused,
+ uint64_t lba __unused, unsigned int count __unused,
+ userptr_t buffer __unused, size_t len __unused ) {
+
+ return -ENOTSUP;
}
/**
- * Handle HTTP response
+ * Read block device capacity (when HTTP block device support is not present)
*
- * @v http HTTP request
- * @v response HTTP response
+ * @v control Control interface
+ * @v data Data interface
* @ret rc Return status code
*/
-static int http_rx_response ( struct http_request *http, char *response ) {
- char *spc;
-
- DBGC ( http, "HTTP %p response \"%s\"\n", http, response );
+__weak int http_block_read_capacity ( struct http_transaction *http __unused,
+ struct interface *data __unused ) {
- /* Check response starts with "HTTP/" */
- if ( strncmp ( response, "HTTP/", 5 ) != 0 )
- return -EINVAL_RESPONSE;
+ return -ENOTSUP;
+}
- /* Locate and store response code */
- spc = strchr ( response, ' ' );
- if ( ! spc )
- return -EINVAL_RESPONSE;
- http->code = strtoul ( spc, NULL, 10 );
+/**
+ * Describe device in ACPI table (when HTTP block device support is not present)
+ *
+ * @v http HTTP transaction
+ * @v acpi ACPI table
+ * @v len Length of ACPI table
+ * @ret rc Return status code
+ */
+__weak int http_acpi_describe ( struct http_transaction *http __unused,
+ struct acpi_description_header *acpi __unused,
+ size_t len __unused ) {
- /* Move to receive headers */
- http->rx_state = ( ( http->flags & HTTP_HEAD_ONLY ) ?
- HTTP_RX_TRAILER : HTTP_RX_HEADER );
- return 0;
+ return -ENOTSUP;
}
+/** HTTP data transfer interface operations */
+static struct interface_operation http_xfer_operations[] = {
+ INTF_OP ( block_read, struct http_transaction *, http_block_read ),
+ INTF_OP ( block_read_capacity, struct http_transaction *,
+ http_block_read_capacity ),
+ INTF_OP ( acpi_describe, struct http_transaction *,
+ http_acpi_describe ),
+ INTF_OP ( xfer_window_changed, struct http_transaction *, http_step ),
+ INTF_OP ( intf_close, struct http_transaction *, http_close ),
+};
+
+/** HTTP data transfer interface descriptor */
+static struct interface_descriptor http_xfer_desc =
+ INTF_DESC_PASSTHRU ( struct http_transaction, xfer,
+ http_xfer_operations, content );
+
+/** HTTP content-decoded interface operations */
+static struct interface_operation http_content_operations[] = {
+ INTF_OP ( xfer_deliver, struct http_transaction *,
+ http_content_deliver ),
+ INTF_OP ( xfer_buffer, struct http_transaction *, http_content_buffer ),
+ INTF_OP ( intf_close, struct http_transaction *, http_close ),
+};
+
+/** HTTP content-decoded interface descriptor */
+static struct interface_descriptor http_content_desc =
+ INTF_DESC_PASSTHRU ( struct http_transaction, content,
+ http_content_operations, xfer );
+
+/** HTTP transfer-decoded interface operations */
+static struct interface_operation http_transfer_operations[] = {
+ INTF_OP ( intf_close, struct http_transaction *, http_close ),
+};
+
+/** HTTP transfer-decoded interface descriptor */
+static struct interface_descriptor http_transfer_desc =
+ INTF_DESC_PASSTHRU ( struct http_transaction, transfer,
+ http_transfer_operations, conn );
+
+/** HTTP server connection interface operations */
+static struct interface_operation http_conn_operations[] = {
+ INTF_OP ( xfer_deliver, struct http_transaction *, http_conn_deliver ),
+ INTF_OP ( xfer_window_changed, struct http_transaction *, http_step ),
+ INTF_OP ( pool_reopen, struct http_transaction *, http_reopen ),
+ INTF_OP ( intf_close, struct http_transaction *, http_conn_close ),
+};
+
+/** HTTP server connection interface descriptor */
+static struct interface_descriptor http_conn_desc =
+ INTF_DESC_PASSTHRU ( struct http_transaction, conn,
+ http_conn_operations, transfer );
+
+/** HTTP process descriptor */
+static struct process_descriptor http_process_desc =
+ PROC_DESC_ONCE ( struct http_transaction, process, http_step );
+
/**
- * Handle HTTP Location header
+ * Open HTTP transaction
*
- * @v http HTTP request
- * @v value HTTP header value
+ * @v xfer Data transfer interface
+ * @v method Request method
+ * @v uri Request URI
+ * @v range Content range (if any)
+ * @v content Request content (if any)
* @ret rc Return status code
*/
-static int http_rx_location ( struct http_request *http, char *value ) {
+int http_open ( struct interface *xfer, struct http_method *method,
+ struct uri *uri, struct http_request_range *range,
+ struct http_request_content *content ) {
+ struct http_transaction *http;
+ struct uri request_uri;
+ struct uri request_host;
+ size_t request_uri_len;
+ size_t request_host_len;
+ size_t content_len;
+ char *request_uri_string;
+ char *request_host_string;
+ void *content_data;
int rc;
- /* Redirect to new location */
- DBGC ( http, "HTTP %p redirecting to %s\n", http, value );
- if ( ( rc = xfer_redirect ( &http->xfer, LOCATION_URI_STRING,
- value ) ) != 0 ) {
- DBGC ( http, "HTTP %p could not redirect: %s\n",
+ /* Calculate request URI length */
+ memset ( &request_uri, 0, sizeof ( request_uri ) );
+ request_uri.path = ( uri->path ? uri->path : "/" );
+ request_uri.query = uri->query;
+ request_uri_len =
+ ( format_uri ( &request_uri, NULL, 0 ) + 1 /* NUL */);
+
+ /* Calculate host name length */
+ memset ( &request_host, 0, sizeof ( request_host ) );
+ request_host.host = uri->host;
+ request_host.port = uri->port;
+ request_host_len =
+ ( format_uri ( &request_host, NULL, 0 ) + 1 /* NUL */ );
+
+ /* Calculate request content length */
+ content_len = ( content ? content->len : 0 );
+
+ /* Allocate and initialise structure */
+ http = zalloc ( sizeof ( *http ) + request_uri_len + request_host_len +
+ content_len );
+ if ( ! http ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ request_uri_string = ( ( ( void * ) http ) + sizeof ( *http ) );
+ request_host_string = ( request_uri_string + request_uri_len );
+ content_data = ( request_host_string + request_host_len );
+ format_uri ( &request_uri, request_uri_string, request_uri_len );
+ format_uri ( &request_host, request_host_string, request_host_len );
+ ref_init ( &http->refcnt, http_free );
+ intf_init ( &http->xfer, &http_xfer_desc, &http->refcnt );
+ intf_init ( &http->content, &http_content_desc, &http->refcnt );
+ intf_init ( &http->transfer, &http_transfer_desc, &http->refcnt );
+ intf_init ( &http->conn, &http_conn_desc, &http->refcnt );
+ intf_plug_plug ( &http->transfer, &http->content );
+ process_init ( &http->process, &http_process_desc, &http->refcnt );
+ timer_init ( &http->timer, http_expired, &http->refcnt );
+ http->uri = uri_get ( uri );
+ http->request.method = method;
+ http->request.uri = request_uri_string;
+ http->request.host = request_host_string;
+ if ( range ) {
+ memcpy ( &http->request.range, range,
+ sizeof ( http->request.range ) );
+ }
+ if ( content ) {
+ http->request.content.type = content->type;
+ http->request.content.data = content_data;
+ http->request.content.len = content_len;
+ memcpy ( content_data, content->data, content_len );
+ }
+ http->state = &http_request;
+ DBGC2 ( http, "HTTP %p %s://%s%s\n", http, http->uri->scheme,
+ http->request.host, http->request.uri );
+
+ /* Open connection */
+ if ( ( rc = http_connect ( &http->conn, uri ) ) != 0 ) {
+ DBGC ( http, "HTTP %p could not connect: %s\n",
http, strerror ( rc ) );
- return rc;
+ goto err_connect;
}
+ /* Attach to parent interface, mortalise self, and return */
+ intf_plug_plug ( &http->xfer, xfer );
+ ref_put ( &http->refcnt );
return 0;
+
+ err_connect:
+ http_close ( http, rc );
+ ref_put ( &http->refcnt );
+ err_alloc:
+ return rc;
}
/**
- * Handle HTTP Content-Length header
+ * Handle successful transfer completion
*
- * @v http HTTP request
- * @v value HTTP header value
+ * @v http HTTP transaction
* @ret rc Return status code
*/
-static int http_rx_content_length ( struct http_request *http, char *value ) {
- struct block_device_capacity capacity;
- size_t content_len;
- char *endp;
+static int http_transfer_complete ( struct http_transaction *http ) {
+ struct http_authentication *auth;
+ const char *location;
+ int rc;
- /* Parse content length */
- content_len = strtoul ( value, &endp, 10 );
- if ( ! ( ( *endp == '\0' ) || isspace ( *endp ) ) ) {
- DBGC ( http, "HTTP %p invalid Content-Length \"%s\"\n",
- http, value );
- return -EINVAL_CONTENT_LENGTH;
+ /* Keep connection alive if applicable */
+ if ( http->response.flags & HTTP_RESPONSE_KEEPALIVE )
+ pool_recycle ( &http->conn );
+
+ /* Restart server connection interface */
+ intf_restart ( &http->conn, 0 );
+
+ /* No more data is expected */
+ http->state = NULL;
+
+ /* If transaction is successful, then close the
+ * transfer-decoded interface. The content encoding may
+ * choose whether or not to immediately terminate the
+ * transaction.
+ */
+ if ( http->response.rc == 0 ) {
+ intf_shutdown ( &http->transfer, 0 );
+ return 0;
}
- /* If we already have an expected content length, and this
- * isn't it, then complain
+ /* Perform redirection, if applicable */
+ if ( ( location = http->response.location ) ) {
+ DBGC2 ( http, "HTTP %p redirecting to \"%s\"\n",
+ http, location );
+ if ( ( rc = xfer_redirect ( &http->xfer, LOCATION_URI_STRING,
+ location ) ) != 0 ) {
+ DBGC ( http, "HTTP %p could not redirect: %s\n",
+ http, strerror ( rc ) );
+ return rc;
+ }
+ http_close ( http, 0 );
+ return 0;
+ }
+
+ /* Fail unless a retry is permitted */
+ if ( ! ( http->response.flags & HTTP_RESPONSE_RETRY ) )
+ return http->response.rc;
+
+ /* Perform authentication, if applicable */
+ if ( ( auth = http->response.auth.auth ) ) {
+ http->request.auth.auth = auth;
+ DBGC2 ( http, "HTTP %p performing %s authentication\n",
+ http, auth->name );
+ if ( ( rc = auth->authenticate ( http ) ) != 0 ) {
+ DBGC ( http, "HTTP %p could not authenticate: %s\n",
+ http, strerror ( rc ) );
+ return rc;
+ }
+ }
+
+ /* Restart content decoding interfaces (which may be attached
+ * to the same object).
*/
- if ( http->remaining && ( http->remaining != content_len ) ) {
- DBGC ( http, "HTTP %p incorrect Content-Length %zd (expected "
- "%zd)\n", http, content_len, http->remaining );
- return -EIO_CONTENT_LENGTH;
+ intf_nullify ( &http->content );
+ intf_nullify ( &http->transfer );
+ intf_restart ( &http->content, http->response.rc );
+ intf_restart ( &http->transfer, http->response.rc );
+ http->content.desc = &http_content_desc;
+ http->transfer.desc = &http_transfer_desc;
+ intf_plug_plug ( &http->transfer, &http->content );
+ http->len = 0;
+ assert ( http->remaining == 0 );
+
+ /* Start timer to initiate retry */
+ DBGC2 ( http, "HTTP %p retrying after %d seconds\n",
+ http, http->response.retry_after );
+ start_timer_fixed ( &http->timer,
+ ( http->response.retry_after * TICKS_PER_SEC ) );
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * Requests
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Construct HTTP request headers
+ *
+ * @v http HTTP transaction
+ * @v buf Buffer
+ * @v len Length of buffer
+ * @ret len Length, or negative error
+ */
+static int http_format_headers ( struct http_transaction *http, char *buf,
+ size_t len ) {
+ struct http_request_header *header;
+ size_t used;
+ size_t remaining;
+ char *line;
+ int value_len;
+ int rc;
+
+ /* Construct request line */
+ used = ssnprintf ( buf, len, "%s %s HTTP/1.1",
+ http->request.method->name, http->request.uri );
+ if ( used < len )
+ DBGC2 ( http, "HTTP %p TX %s\n", http, buf );
+ used += ssnprintf ( ( buf + used ), ( len - used ), "\r\n" );
+
+ /* Construct all headers */
+ for_each_table_entry ( header, HTTP_REQUEST_HEADERS ) {
+
+ /* Determine header value length */
+ value_len = header->format ( http, NULL, 0 );
+ if ( value_len < 0 ) {
+ rc = value_len;
+ return rc;
+ }
+
+ /* Skip zero-length headers */
+ if ( ! value_len )
+ continue;
+
+ /* Construct header */
+ line = ( buf + used );
+ used += ssnprintf ( ( buf + used ), ( len - used ), "%s: ",
+ header->name );
+ remaining = ( ( used < len ) ? ( len - used ) : 0 );
+ used += header->format ( http, ( buf + used ), remaining );
+ if ( used < len )
+ DBGC2 ( http, "HTTP %p TX %s\n", http, line );
+ used += ssnprintf ( ( buf + used ), ( len - used ), "\r\n" );
}
- if ( ! ( http->flags & HTTP_HEAD_ONLY ) )
- http->remaining = content_len;
- /* Do nothing more if we are retrying the request */
- if ( http->flags & HTTP_TRY_AGAIN )
+ /* Construct terminating newline */
+ used += ssnprintf ( ( buf + used ), ( len - used ), "\r\n" );
+
+ return used;
+}
+
+/**
+ * Construct HTTP "Host" header
+ *
+ * @v http HTTP transaction
+ * @v buf Buffer
+ * @v len Length of buffer
+ * @ret len Length of header value, or negative error
+ */
+static int http_format_host ( struct http_transaction *http, char *buf,
+ size_t len ) {
+
+ /* Construct host URI */
+ return snprintf ( buf, len, "%s", http->request.host );
+}
+
+/** HTTP "Host" header "*/
+struct http_request_header http_request_host __http_request_header = {
+ .name = "Host",
+ .format = http_format_host,
+};
+
+/**
+ * Construct HTTP "User-Agent" header
+ *
+ * @v http HTTP transaction
+ * @v buf Buffer
+ * @v len Length of buffer
+ * @ret len Length of header value, or negative error
+ */
+static int http_format_user_agent ( struct http_transaction *http __unused,
+ char *buf, size_t len ) {
+
+ /* Construct user agent */
+ return snprintf ( buf, len, "iPXE/%s", product_version );
+}
+
+/** HTTP "User-Agent" header */
+struct http_request_header http_request_user_agent __http_request_header = {
+ .name = "User-Agent",
+ .format = http_format_user_agent,
+};
+
+/**
+ * Construct HTTP "Connection" header
+ *
+ * @v http HTTP transaction
+ * @v buf Buffer
+ * @v len Length of buffer
+ * @ret len Length of header value, or negative error
+ */
+static int http_format_connection ( struct http_transaction *http __unused,
+ char *buf, size_t len ) {
+
+ /* Always request keep-alive */
+ return snprintf ( buf, len, "keep-alive" );
+}
+
+/** HTTP "Connection" header */
+struct http_request_header http_request_connection __http_request_header = {
+ .name = "Connection",
+ .format = http_format_connection,
+};
+
+/**
+ * Construct HTTP "Range" header
+ *
+ * @v http HTTP transaction
+ * @v buf Buffer
+ * @v len Length of buffer
+ * @ret len Length of header value, or negative error
+ */
+static int http_format_range ( struct http_transaction *http,
+ char *buf, size_t len ) {
+
+ /* Construct range, if applicable */
+ if ( http->request.range.len ) {
+ return snprintf ( buf, len, "bytes=%zd-%zd",
+ http->request.range.start,
+ ( http->request.range.start +
+ http->request.range.len - 1 ) );
+ } else {
return 0;
+ }
+}
+
+/** HTTP "Range" header */
+struct http_request_header http_request_range __http_request_header = {
+ .name = "Range",
+ .format = http_format_range,
+};
- /* Use seek() to notify recipient of filesize */
- xfer_seek ( &http->xfer, http->remaining );
- xfer_seek ( &http->xfer, 0 );
+/**
+ * Construct HTTP "Content-Type" header
+ *
+ * @v http HTTP transaction
+ * @v buf Buffer
+ * @v len Length of buffer
+ * @ret len Length of header value, or negative error
+ */
+static int http_format_content_type ( struct http_transaction *http,
+ char *buf, size_t len ) {
- /* Report block device capacity if applicable */
- if ( http->flags & HTTP_HEAD_ONLY ) {
- capacity.blocks = ( content_len / HTTP_BLKSIZE );
- capacity.blksize = HTTP_BLKSIZE;
- capacity.max_count = -1U;
- block_capacity ( &http->partial, &capacity );
+ /* Construct content type, if applicable */
+ if ( http->request.content.type ) {
+ return snprintf ( buf, len, "%s", http->request.content.type );
+ } else {
+ return 0;
}
- return 0;
}
+/** HTTP "Content-Type" header */
+struct http_request_header http_request_content_type __http_request_header = {
+ .name = "Content-Type",
+ .format = http_format_content_type,
+};
+
/**
- * Handle HTTP Transfer-Encoding header
+ * Construct HTTP "Content-Length" header
*
- * @v http HTTP request
- * @v value HTTP header value
- * @ret rc Return status code
+ * @v http HTTP transaction
+ * @v buf Buffer
+ * @v len Length of buffer
+ * @ret len Length of header value, or negative error
*/
-static int http_rx_transfer_encoding ( struct http_request *http, char *value ){
+static int http_format_content_length ( struct http_transaction *http,
+ char *buf, size_t len ) {
- if ( strcasecmp ( value, "chunked" ) == 0 ) {
- /* Mark connection as using chunked transfer encoding */
- http->chunked = 1;
+ /* Construct content length, if applicable */
+ if ( http->request.content.len ) {
+ return snprintf ( buf, len, "%zd", http->request.content.len );
+ } else {
+ return 0;
}
+}
- return 0;
+/** HTTP "Content-Length" header */
+struct http_request_header http_request_content_length __http_request_header = {
+ .name = "Content-Length",
+ .format = http_format_content_length,
+};
+
+/**
+ * Construct HTTP "Accept-Encoding" header
+ *
+ * @v http HTTP transaction
+ * @v buf Buffer
+ * @v len Length of buffer
+ * @ret len Length of header value, or negative error
+ */
+static int http_format_accept_encoding ( struct http_transaction *http,
+ char *buf, size_t len ) {
+ struct http_content_encoding *encoding;
+ const char *sep = "";
+ size_t used = 0;
+
+ /* Construct list of content encodings */
+ for_each_table_entry ( encoding, HTTP_CONTENT_ENCODINGS ) {
+ if ( encoding->supported && ( ! encoding->supported ( http ) ) )
+ continue;
+ used += ssnprintf ( ( buf + used ), ( len - used ),
+ "%s%s", sep, encoding->name );
+ sep = ", ";
+ }
+
+ return used;
}
+/** HTTP "Accept-Encoding" header */
+struct http_request_header http_request_accept_encoding __http_request_header ={
+ .name = "Accept-Encoding",
+ .format = http_format_accept_encoding,
+};
+
/**
- * Handle HTTP Connection header
+ * Transmit request
*
- * @v http HTTP request
- * @v value HTTP header value
+ * @v http HTTP transaction
* @ret rc Return status code
*/
-static int http_rx_connection ( struct http_request *http, char *value ) {
+static int http_tx_request ( struct http_transaction *http ) {
+ struct io_buffer *iobuf;
+ int len;
+ int check_len;
+ int rc;
+
+ /* Calculate request length */
+ len = http_format_headers ( http, NULL, 0 );
+ if ( len < 0 ) {
+ rc = len;
+ DBGC ( http, "HTTP %p could not construct request: %s\n",
+ http, strerror ( rc ) );
+ goto err_len;
+ }
+
+ /* Allocate I/O buffer */
+ iobuf = alloc_iob ( len + 1 /* NUL */ + http->request.content.len );
+ if ( ! iobuf ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
- if ( strcasecmp ( value, "keep-alive" ) == 0 ) {
- /* Mark connection as being kept alive by the server */
- http->flags |= HTTP_SERVER_KEEPALIVE;
+ /* Construct request */
+ check_len = http_format_headers ( http, iob_put ( iobuf, len ),
+ ( len + 1 /* NUL */ ) );
+ assert ( check_len == len );
+ memcpy ( iob_put ( iobuf, http->request.content.len ),
+ http->request.content.data, http->request.content.len );
+
+ /* Deliver request */
+ if ( ( rc = xfer_deliver_iob ( &http->conn,
+ iob_disown ( iobuf ) ) ) != 0 ) {
+ DBGC ( http, "HTTP %p could not deliver request: %s\n",
+ http, strerror ( rc ) );
+ goto err_deliver;
}
+ /* Clear any previous response */
+ empty_line_buffer ( &http->response.headers );
+ memset ( &http->response, 0, sizeof ( http->response ) );
+
+ /* Move to response headers state */
+ http->state = &http_headers;
+
return 0;
+
+ err_deliver:
+ free_iob ( iobuf );
+ err_alloc:
+ err_len:
+ return rc;
}
+/** HTTP request state */
+static struct http_state http_request = {
+ .tx = http_tx_request,
+ .close = http_close_error,
+};
+
+/******************************************************************************
+ *
+ * Response headers
+ *
+ ******************************************************************************
+ */
+
/**
- * Handle WWW-Authenticate Basic header
+ * Parse HTTP status line
*
- * @v http HTTP request
- * @v params Parameters
+ * @v http HTTP transaction
+ * @v line Status line
* @ret rc Return status code
*/
-static int http_rx_basic_auth ( struct http_request *http, char *params ) {
+static int http_parse_status ( struct http_transaction *http, char *line ) {
+ char *endp;
+ char *version;
+ char *vernum;
+ char *status;
+ int response_rc;
+
+ DBGC2 ( http, "HTTP %p RX %s\n", http, line );
+
+ /* Parse HTTP version */
+ version = http_token ( &line, NULL );
+ if ( ( ! version ) || ( strncmp ( version, "HTTP/", 5 ) != 0 ) ) {
+ DBGC ( http, "HTTP %p malformed version \"%s\"\n", http, line );
+ return -EINVAL_STATUS;
+ }
- DBGC ( http, "HTTP %p Basic authentication required (%s)\n",
- http, params );
+ /* Keepalive is enabled by default for anything newer than HTTP/1.0 */
+ vernum = ( version + 5 /* "HTTP/" (presence already checked) */ );
+ if ( vernum[0] == '0' ) {
+ /* HTTP/0.x : keepalive not enabled by default */
+ } else if ( strncmp ( vernum, "1.0", 3 ) == 0 ) {
+ /* HTTP/1.0 : keepalive not enabled by default */
+ } else {
+ /* HTTP/1.1 or newer: keepalive enabled by default */
+ http->response.flags |= HTTP_RESPONSE_KEEPALIVE;
+ }
- /* If we received a 401 Unauthorized response, then retry
- * using Basic authentication
- */
- if ( ( http->code == 401 ) &&
- ( ! ( http->flags & HTTP_BASIC_AUTH ) ) &&
- ( http->uri->user != NULL ) ) {
- http->flags |= ( HTTP_TRY_AGAIN | HTTP_BASIC_AUTH );
+ /* Parse status code */
+ status = line;
+ http->response.status = strtoul ( status, &endp, 10 );
+ if ( *endp != ' ' ) {
+ DBGC ( http, "HTTP %p malformed status code \"%s\"\n",
+ http, status );
+ return -EINVAL_STATUS;
+ }
+
+ /* Convert HTTP status code to iPXE return status code */
+ if ( status[0] == '2' ) {
+ /* 2xx Success */
+ response_rc = 0;
+ } else if ( status[0] == '3' ) {
+ /* 3xx Redirection */
+ response_rc = -EXDEV;
+ } else if ( http->response.status == 401 ) {
+ /* 401 Unauthorized */
+ response_rc = -EACCES_401;
+ } else if ( http->response.status == 403 ) {
+ /* 403 Forbidden */
+ response_rc = -EPERM_403;
+ } else if ( http->response.status == 404 ) {
+ /* 404 Not Found */
+ response_rc = -ENOENT_404;
+ } else if ( status[0] == '4' ) {
+ /* 4xx Client Error (not already specified) */
+ response_rc = -EIO_4XX;
+ } else if ( status[0] == '5' ) {
+ /* 5xx Server Error */
+ response_rc = -EIO_5XX;
+ } else {
+ /* Unrecognised */
+ response_rc = -EIO_OTHER;
}
+ http->response.rc = response_rc;
return 0;
}
/**
- * Parse Digest authentication parameter
+ * Parse HTTP header
*
- * @v params Parameters
- * @v name Parameter name (including trailing "=\"")
- * @ret value Parameter value, or NULL
+ * @v http HTTP transaction
+ * @v line Header line
+ * @ret rc Return status code
*/
-static char * http_digest_param ( char *params, const char *name ) {
- char *key;
- char *value;
- char *terminator;
-
- /* Locate parameter */
- key = strstr ( params, name );
- if ( ! key )
- return NULL;
+static int http_parse_header ( struct http_transaction *http, char *line ) {
+ struct http_response_header *header;
+ char *name = line;
+ char *sep;
- /* Extract value */
- value = ( key + strlen ( name ) );
- terminator = strchr ( value, '"' );
- if ( ! terminator )
- return NULL;
- return strndup ( value, ( terminator - value ) );
+ DBGC2 ( http, "HTTP %p RX %s\n", http, line );
+
+ /* Extract header name */
+ sep = strstr ( line, ": " );
+ if ( ! sep ) {
+ DBGC ( http, "HTTP %p malformed header \"%s\"\n", http, line );
+ return -EINVAL_HEADER;
+ }
+ *sep = '\0';
+ line = ( sep + 2 /* ": " */ );
+
+ /* Process header, if recognised */
+ for_each_table_entry ( header, HTTP_RESPONSE_HEADERS ) {
+ if ( strcasecmp ( name, header->name ) == 0 )
+ return header->parse ( http, line );
+ }
+
+ /* Unrecognised headers should be ignored */
+ return 0;
}
/**
- * Handle WWW-Authenticate Digest header
+ * Parse HTTP response headers
*
- * @v http HTTP request
- * @v params Parameters
+ * @v http HTTP transaction
* @ret rc Return status code
*/
-static int http_rx_digest_auth ( struct http_request *http, char *params ) {
+static int http_parse_headers ( struct http_transaction *http ) {
+ char *line;
+ char *next;
+ int rc;
- DBGC ( http, "HTTP %p Digest authentication required (%s)\n",
- http, params );
+ /* Get status line */
+ line = http->response.headers.data;
+ assert ( line != NULL );
+ next = ( line + strlen ( line ) + 1 /* NUL */ );
- /* If we received a 401 Unauthorized response, then retry
- * using Digest authentication
- */
- if ( ( http->code == 401 ) &&
- ( ! ( http->flags & HTTP_DIGEST_AUTH ) ) &&
- ( http->uri->user != NULL ) ) {
-
- /* Extract realm */
- free ( http->auth_realm );
- http->auth_realm = http_digest_param ( params, "realm=\"" );
- if ( ! http->auth_realm ) {
- DBGC ( http, "HTTP %p Digest prompt missing realm\n",
- http );
- return -EINVAL_HEADER;
- }
+ /* Parse status line */
+ if ( ( rc = http_parse_status ( http, line ) ) != 0 )
+ return rc;
- /* Extract nonce */
- free ( http->auth_nonce );
- http->auth_nonce = http_digest_param ( params, "nonce=\"" );
- if ( ! http->auth_nonce ) {
- DBGC ( http, "HTTP %p Digest prompt missing nonce\n",
- http );
- return -EINVAL_HEADER;
- }
+ /* Process header lines */
+ while ( 1 ) {
- /* Extract opaque */
- free ( http->auth_opaque );
- http->auth_opaque = http_digest_param ( params, "opaque=\"" );
- if ( ! http->auth_opaque ) {
- /* Not an error; "opaque" is optional */
- }
+ /* Move to next line */
+ line = next;
+ next = ( line + strlen ( line ) + 1 /* NUL */ );
+
+ /* Stop on terminating blank line */
+ if ( ! line[0] )
+ return 0;
- http->flags |= ( HTTP_TRY_AGAIN | HTTP_DIGEST_AUTH );
+ /* Process header line */
+ if ( ( rc = http_parse_header ( http, line ) ) != 0 )
+ return rc;
}
+}
+/**
+ * Parse HTTP "Location" header
+ *
+ * @v http HTTP transaction
+ * @v line Remaining header line
+ * @ret rc Return status code
+ */
+static int http_parse_location ( struct http_transaction *http, char *line ) {
+
+ /* Store location */
+ http->response.location = line;
return 0;
}
-/** An HTTP WWW-Authenticate header handler */
-struct http_auth_header_handler {
- /** Scheme (e.g. "Basic") */
- const char *scheme;
- /** Handle received parameters
- *
- * @v http HTTP request
- * @v params Parameters
- * @ret rc Return status code
- */
- int ( * rx ) ( struct http_request *http, char *params );
+/** HTTP "Location" header */
+struct http_response_header http_response_location __http_response_header = {
+ .name = "Location",
+ .parse = http_parse_location,
};
-/** List of HTTP WWW-Authenticate header handlers */
-static struct http_auth_header_handler http_auth_header_handlers[] = {
- {
- .scheme = "Basic",
- .rx = http_rx_basic_auth,
- },
- {
- .scheme = "Digest",
- .rx = http_rx_digest_auth,
- },
- { NULL, NULL },
+/**
+ * Parse HTTP "Transfer-Encoding" header
+ *
+ * @v http HTTP transaction
+ * @v line Remaining header line
+ * @ret rc Return status code
+ */
+static int http_parse_transfer_encoding ( struct http_transaction *http,
+ char *line ) {
+ struct http_transfer_encoding *encoding;
+
+ /* Check for known transfer encodings */
+ for_each_table_entry ( encoding, HTTP_TRANSFER_ENCODINGS ) {
+ if ( strcasecmp ( line, encoding->name ) == 0 ) {
+ http->response.transfer.encoding = encoding;
+ return 0;
+ }
+ }
+
+ DBGC ( http, "HTTP %p unrecognised Transfer-Encoding \"%s\"\n",
+ http, line );
+ return -ENOTSUP_TRANSFER;
+}
+
+/** HTTP "Transfer-Encoding" header */
+struct http_response_header
+http_response_transfer_encoding __http_response_header = {
+ .name = "Transfer-Encoding",
+ .parse = http_parse_transfer_encoding,
};
/**
- * Handle HTTP WWW-Authenticate header
+ * Parse HTTP "Connection" header
*
- * @v http HTTP request
- * @v value HTTP header value
+ * @v http HTTP transaction
+ * @v line Remaining header line
* @ret rc Return status code
*/
-static int http_rx_www_authenticate ( struct http_request *http, char *value ) {
- struct http_auth_header_handler *handler;
- char *separator;
- char *scheme;
- char *params;
- int rc;
+static int http_parse_connection ( struct http_transaction *http, char *line ) {
- /* Extract scheme */
- separator = strchr ( value, ' ' );
- if ( ! separator ) {
- DBGC ( http, "HTTP %p malformed WWW-Authenticate header\n",
- http );
- return -EINVAL_HEADER;
+ /* Check for known connection intentions */
+ if ( strcasecmp ( line, "keep-alive" ) == 0 ) {
+ http->response.flags |= HTTP_RESPONSE_KEEPALIVE;
+ return 0;
}
- *separator = '\0';
- scheme = value;
- params = ( separator + 1 );
-
- /* Hand off to header handler, if one exists */
- for ( handler = http_auth_header_handlers; handler->scheme; handler++ ){
- if ( strcasecmp ( scheme, handler->scheme ) == 0 ) {
- if ( ( rc = handler->rx ( http, params ) ) != 0 )
- return rc;
- break;
- }
+ if ( strcasecmp ( line, "close" ) == 0 ) {
+ http->response.flags &= ~HTTP_RESPONSE_KEEPALIVE;
+ return 0;
}
- return 0;
+
+ DBGC ( http, "HTTP %p unrecognised Connection \"%s\"\n", http, line );
+ return -ENOTSUP_CONNECTION;
}
+/** HTTP "Connection" header */
+struct http_response_header http_response_connection __http_response_header = {
+ .name = "Connection",
+ .parse = http_parse_connection,
+};
+
/**
- * Handle HTTP Retry-After header
+ * Parse HTTP "Content-Length" header
*
- * @v http HTTP request
- * @v value HTTP header value
+ * @v http HTTP transaction
+ * @v line Remaining header line
* @ret rc Return status code
*/
-static int http_rx_retry_after ( struct http_request *http, char *value ) {
- unsigned long seconds;
+static int http_parse_content_length ( struct http_transaction *http,
+ char *line ) {
char *endp;
- DBGC ( http, "HTTP %p retry requested (%s)\n", http, value );
+ /* Parse length */
+ http->response.content.len = strtoul ( line, &endp, 10 );
+ if ( *endp != '\0' ) {
+ DBGC ( http, "HTTP %p invalid Content-Length \"%s\"\n",
+ http, line );
+ return -EINVAL_CONTENT_LENGTH;
+ }
- /* If we received a 503 Service Unavailable response, then
- * retry after the specified number of seconds. If the value
- * is not a simple number of seconds (e.g. a full HTTP date),
- * then retry after a fixed delay, since we don't have code
- * able to parse full HTTP dates.
- */
- if ( http->code == 503 ) {
- seconds = strtoul ( value, &endp, 10 );
- if ( *endp != '\0' ) {
- seconds = HTTP_RETRY_SECONDS;
- DBGC ( http, "HTTP %p cannot understand \"%s\"; "
- "using %ld seconds\n", http, value, seconds );
+ /* Record that we have a content length (since it may be zero) */
+ http->response.flags |= HTTP_RESPONSE_CONTENT_LEN;
+
+ return 0;
+}
+
+/** HTTP "Content-Length" header */
+struct http_response_header
+http_response_content_length __http_response_header = {
+ .name = "Content-Length",
+ .parse = http_parse_content_length,
+};
+
+/**
+ * Parse HTTP "Content-Encoding" header
+ *
+ * @v http HTTP transaction
+ * @v line Remaining header line
+ * @ret rc Return status code
+ */
+static int http_parse_content_encoding ( struct http_transaction *http,
+ char *line ) {
+ struct http_content_encoding *encoding;
+
+ /* Check for known content encodings */
+ for_each_table_entry ( encoding, HTTP_CONTENT_ENCODINGS ) {
+ if ( encoding->supported && ( ! encoding->supported ( http ) ) )
+ continue;
+ if ( strcasecmp ( line, encoding->name ) == 0 ) {
+ http->response.content.encoding = encoding;
+ return 0;
}
- http->flags |= HTTP_TRY_AGAIN;
- http->retry_delay = ( seconds * TICKS_PER_SEC );
}
+ /* Some servers (e.g. Apache) have a habit of specifying
+ * unwarranted content encodings. For example, if Apache
+ * detects (via /etc/httpd/conf/magic) that a file's contents
+ * are gzip-compressed, it will set "Content-Encoding: x-gzip"
+ * regardless of the client's Accept-Encoding header. The
+ * only viable way to handle such servers is to treat unknown
+ * content encodings as equivalent to "identity".
+ */
+ DBGC ( http, "HTTP %p unrecognised Content-Encoding \"%s\"\n",
+ http, line );
return 0;
}
-/** An HTTP header handler */
-struct http_header_handler {
- /** Name (e.g. "Content-Length") */
- const char *header;
- /** Handle received header
- *
- * @v http HTTP request
- * @v value HTTP header value
- * @ret rc Return status code
- *
- * If an error is returned, the download will be aborted.
- */
- int ( * rx ) ( struct http_request *http, char *value );
+/** HTTP "Content-Encoding" header */
+struct http_response_header
+http_response_content_encoding __http_response_header = {
+ .name = "Content-Encoding",
+ .parse = http_parse_content_encoding,
};
-/** List of HTTP header handlers */
-static struct http_header_handler http_header_handlers[] = {
- {
- .header = "Location",
- .rx = http_rx_location,
- },
- {
- .header = "Content-Length",
- .rx = http_rx_content_length,
- },
- {
- .header = "Transfer-Encoding",
- .rx = http_rx_transfer_encoding,
- },
- {
- .header = "Connection",
- .rx = http_rx_connection,
- },
- {
- .header = "WWW-Authenticate",
- .rx = http_rx_www_authenticate,
- },
- {
- .header = "Retry-After",
- .rx = http_rx_retry_after,
- },
- { NULL, NULL }
+/**
+ * Parse HTTP "Retry-After" header
+ *
+ * @v http HTTP transaction
+ * @v line Remaining header line
+ * @ret rc Return status code
+ */
+static int http_parse_retry_after ( struct http_transaction *http,
+ char *line ) {
+ char *endp;
+
+ /* Try to parse value as a simple number of seconds */
+ http->response.retry_after = strtoul ( line, &endp, 10 );
+ if ( *endp != '\0' ) {
+ /* For any value which is not a simple number of
+ * seconds (e.g. a full HTTP date), just retry after a
+ * fixed delay, since we don't have code able to parse
+ * full HTTP dates.
+ */
+ http->response.retry_after = HTTP_RETRY_SECONDS;
+ DBGC ( http, "HTTP %p cannot understand Retry-After \"%s\"; "
+ "using %d seconds\n", http, line, HTTP_RETRY_SECONDS );
+ }
+
+ /* Allow HTTP request to be retried after specified delay */
+ http->response.flags |= HTTP_RESPONSE_RETRY;
+
+ return 0;
+}
+
+/** HTTP "Retry-After" header */
+struct http_response_header http_response_retry_after __http_response_header = {
+ .name = "Retry-After",
+ .parse = http_parse_retry_after,
};
/**
- * Handle HTTP header
+ * Handle received HTTP headers
*
- * @v http HTTP request
- * @v header HTTP header
+ * @v http HTTP transaction
+ * @v iobuf I/O buffer (may be claimed)
* @ret rc Return status code
*/
-static int http_rx_header ( struct http_request *http, char *header ) {
- struct http_header_handler *handler;
- char *separator;
- char *value;
+static int http_rx_headers ( struct http_transaction *http,
+ struct io_buffer **iobuf ) {
+ struct http_transfer_encoding *transfer;
+ struct http_content_encoding *content;
+ char *line;
int rc;
- /* An empty header line marks the end of this phase */
- if ( ! header[0] ) {
- empty_line_buffer ( &http->linebuf );
+ /* Buffer header line */
+ if ( ( rc = http_rx_linebuf ( http, *iobuf,
+ &http->response.headers ) ) != 0 )
+ return rc;
- /* Handle response code */
- if ( ! ( http->flags & HTTP_TRY_AGAIN ) ) {
- if ( ( rc = http_response_to_rc ( http->code ) ) != 0 )
- return rc;
- }
+ /* Wait until we see the empty line marking end of headers */
+ line = buffered_line ( &http->response.headers );
+ if ( ( line == NULL ) || ( line[0] != '\0' ) )
+ return 0;
- /* Move to next state */
- if ( http->rx_state == HTTP_RX_HEADER ) {
- DBGC ( http, "HTTP %p start of data\n", http );
- http->rx_state = ( http->chunked ?
- HTTP_RX_CHUNK_LEN : HTTP_RX_DATA );
- if ( ( http->partial_len != 0 ) &&
- ( ! ( http->flags & HTTP_TRY_AGAIN ) ) ) {
- http->remaining = http->partial_len;
- }
- return 0;
- } else {
- DBGC ( http, "HTTP %p end of trailer\n", http );
- http_done ( http );
- return 0;
- }
+ /* Process headers */
+ if ( ( rc = http_parse_headers ( http ) ) != 0 )
+ return rc;
+
+ /* Initialise content encoding, if applicable */
+ if ( ( content = http->response.content.encoding ) &&
+ ( ( rc = content->init ( http ) ) != 0 ) ) {
+ DBGC ( http, "HTTP %p could not initialise %s content "
+ "encoding: %s\n", http, content->name, strerror ( rc ) );
+ return rc;
}
- DBGC ( http, "HTTP %p header \"%s\"\n", http, header );
+ /* Presize receive buffer, if we have a content length */
+ if ( http->response.content.len ) {
+ xfer_seek ( &http->transfer, http->response.content.len );
+ xfer_seek ( &http->transfer, 0 );
+ }
- /* Split header at the ": " */
- separator = strstr ( header, ": " );
- if ( ! separator ) {
- DBGC ( http, "HTTP %p malformed header\n", http );
- return -EINVAL_HEADER;
+ /* Complete transfer if this is a HEAD request */
+ if ( http->request.method == &http_head ) {
+ if ( ( rc = http_transfer_complete ( http ) ) != 0 )
+ return rc;
+ return 0;
}
- *separator = '\0';
- value = ( separator + 2 );
-
- /* Hand off to header handler, if one exists */
- for ( handler = http_header_handlers ; handler->header ; handler++ ) {
- if ( strcasecmp ( header, handler->header ) == 0 ) {
- if ( ( rc = handler->rx ( http, value ) ) != 0 )
- return rc;
- break;
- }
+
+ /* Default to identity transfer encoding, if none specified */
+ if ( ! http->response.transfer.encoding )
+ http->response.transfer.encoding = &http_transfer_identity;
+
+ /* Move to transfer encoding-specific data state */
+ transfer = http->response.transfer.encoding;
+ http->state = &transfer->state;
+
+ /* Initialise transfer encoding */
+ if ( ( rc = transfer->init ( http ) ) != 0 ) {
+ DBGC ( http, "HTTP %p could not initialise %s transfer "
+ "encoding: %s\n", http, transfer->name, strerror ( rc ));
+ return rc;
}
+
return 0;
}
+/** HTTP response headers state */
+static struct http_state http_headers = {
+ .rx = http_rx_headers,
+ .close = http_close_error,
+};
+
+/******************************************************************************
+ *
+ * Identity transfer encoding
+ *
+ ******************************************************************************
+ */
+
/**
- * Handle HTTP chunk length
+ * Initialise transfer encoding
*
- * @v http HTTP request
- * @v length HTTP chunk length
+ * @v http HTTP transaction
* @ret rc Return status code
*/
-static int http_rx_chunk_len ( struct http_request *http, char *length ) {
- char *endp;
+static int http_init_transfer_identity ( struct http_transaction *http ) {
+ int rc;
- /* Skip blank lines between chunks */
- if ( length[0] == '\0' )
- return 0;
+ /* Complete transfer immediately if we have a zero content length */
+ if ( ( http->response.flags & HTTP_RESPONSE_CONTENT_LEN ) &&
+ ( http->response.content.len == 0 ) &&
+ ( ( rc = http_transfer_complete ( http ) ) != 0 ) )
+ return rc;
- /* Parse chunk length */
- http->chunk_remaining = strtoul ( length, &endp, 16 );
- if ( *endp != '\0' ) {
- DBGC ( http, "HTTP %p invalid chunk length \"%s\"\n",
- http, length );
- return -EINVAL_CHUNK_LENGTH;
- }
+ return 0;
+}
- /* Terminate chunked encoding if applicable */
- if ( http->chunk_remaining == 0 ) {
- DBGC ( http, "HTTP %p end of chunks\n", http );
- http->chunked = 0;
- http->rx_state = HTTP_RX_TRAILER;
- return 0;
- }
+/**
+ * Handle received data
+ *
+ * @v http HTTP transaction
+ * @v iobuf I/O buffer (may be claimed)
+ * @ret rc Return status code
+ */
+static int http_rx_transfer_identity ( struct http_transaction *http,
+ struct io_buffer **iobuf ) {
+ size_t len = iob_len ( *iobuf );
+ int rc;
+
+ /* Update lengths */
+ http->len += len;
- /* Use seek() to notify recipient of new filesize */
- DBGC ( http, "HTTP %p start of chunk of length %zd\n",
- http, http->chunk_remaining );
- if ( ! ( http->flags & HTTP_TRY_AGAIN ) ) {
- xfer_seek ( &http->xfer,
- ( http->rx_len + http->chunk_remaining ) );
- xfer_seek ( &http->xfer, http->rx_len );
+ /* Fail if this transfer would overrun the expected content
+ * length (if any).
+ */
+ if ( ( http->response.flags & HTTP_RESPONSE_CONTENT_LEN ) &&
+ ( http->len > http->response.content.len ) ) {
+ DBGC ( http, "HTTP %p content length overrun\n", http );
+ return -EIO_CONTENT_LENGTH;
}
- /* Start receiving data */
- http->rx_state = HTTP_RX_DATA;
+ /* Hand off to content encoding */
+ if ( ( rc = xfer_deliver_iob ( &http->transfer,
+ iob_disown ( *iobuf ) ) ) != 0 )
+ return rc;
+
+ /* Complete transfer if we have received the expected content
+ * length (if any).
+ */
+ if ( ( http->response.flags & HTTP_RESPONSE_CONTENT_LEN ) &&
+ ( http->len == http->response.content.len ) &&
+ ( ( rc = http_transfer_complete ( http ) ) != 0 ) )
+ return rc;
return 0;
}
-/** An HTTP line-based data handler */
-struct http_line_handler {
- /** Handle line
- *
- * @v http HTTP request
- * @v line Line to handle
- * @ret rc Return status code
+/**
+ * Handle server connection close
+ *
+ * @v http HTTP transaction
+ * @v rc Reason for close
+ */
+static void http_close_transfer_identity ( struct http_transaction *http,
+ int rc ) {
+
+ /* Fail if any error occurred */
+ if ( rc != 0 )
+ goto err;
+
+ /* Fail if we have a content length (since we would have
+ * already closed the connection if we had received the
+ * correct content length).
*/
- int ( * rx ) ( struct http_request *http, char *line );
-};
+ if ( http->response.flags & HTTP_RESPONSE_CONTENT_LEN ) {
+ DBGC ( http, "HTTP %p content length underrun\n", http );
+ rc = EIO_CONTENT_LENGTH;
+ goto err;
+ }
+
+ /* Indicate that transfer is complete */
+ if ( ( rc = http_transfer_complete ( http ) ) != 0 )
+ goto err;
-/** List of HTTP line-based data handlers */
-static struct http_line_handler http_line_handlers[] = {
- [HTTP_RX_RESPONSE] = { .rx = http_rx_response },
- [HTTP_RX_HEADER] = { .rx = http_rx_header },
- [HTTP_RX_CHUNK_LEN] = { .rx = http_rx_chunk_len },
- [HTTP_RX_TRAILER] = { .rx = http_rx_header },
+ return;
+
+ err:
+ http_close ( http, rc );
+}
+
+/** Identity transfer encoding */
+static struct http_transfer_encoding http_transfer_identity = {
+ .name = "identity",
+ .init = http_init_transfer_identity,
+ .state = {
+ .rx = http_rx_transfer_identity,
+ .close = http_close_transfer_identity,
+ },
};
+/******************************************************************************
+ *
+ * Chunked transfer encoding
+ *
+ ******************************************************************************
+ */
+
/**
- * Handle new data arriving via HTTP connection
+ * Initialise transfer encoding
*
- * @v http HTTP request
- * @v iobuf I/O buffer
- * @v meta Data transfer metadata
+ * @v http HTTP transaction
* @ret rc Return status code
*/
-static int http_socket_deliver ( struct http_request *http,
- struct io_buffer *iobuf,
- struct xfer_metadata *meta __unused ) {
- struct http_line_handler *lh;
+static int http_init_transfer_chunked ( struct http_transaction *http ) {
+
+ /* Sanity checks */
+ assert ( http->remaining == 0 );
+ assert ( http->linebuf.len == 0 );
+
+ return 0;
+}
+
+/**
+ * Handle received chunk length
+ *
+ * @v http HTTP transaction
+ * @v iobuf I/O buffer (may be claimed)
+ * @ret rc Return status code
+ */
+static int http_rx_chunk_len ( struct http_transaction *http,
+ struct io_buffer **iobuf ) {
char *line;
- size_t data_len;
- ssize_t line_len;
- int rc = 0;
+ char *endp;
+ size_t len;
+ int rc;
- profile_start ( &http_rx_profiler );
- while ( iobuf && iob_len ( iobuf ) ) {
+ /* Receive into temporary line buffer */
+ if ( ( rc = http_rx_linebuf ( http, *iobuf, &http->linebuf ) ) != 0 )
+ return rc;
- switch ( http->rx_state ) {
- case HTTP_RX_IDLE:
- /* Receiving any data in this state is an error */
- DBGC ( http, "HTTP %p received %zd bytes while %s\n",
- http, iob_len ( iobuf ),
- ( ( http->rx_state == HTTP_RX_IDLE ) ?
- "idle" : "dead" ) );
- rc = -EPROTO_UNSOLICITED;
- goto done;
- case HTTP_RX_DEAD:
- /* Do no further processing */
- goto done;
- case HTTP_RX_DATA:
- /* Pass received data to caller */
- data_len = iob_len ( iobuf );
- if ( http->chunk_remaining &&
- ( http->chunk_remaining < data_len ) ) {
- data_len = http->chunk_remaining;
- }
- if ( http->remaining &&
- ( http->remaining < data_len ) ) {
- data_len = http->remaining;
- }
- if ( http->flags & HTTP_TRY_AGAIN ) {
- /* Discard all received data */
- iob_pull ( iobuf, data_len );
- } else if ( http->rx_buffer != UNULL ) {
- /* Copy to partial transfer buffer */
- copy_to_user ( http->rx_buffer, http->rx_len,
- iobuf->data, data_len );
- iob_pull ( iobuf, data_len );
- } else if ( data_len < iob_len ( iobuf ) ) {
- /* Deliver partial buffer as raw data */
- profile_start ( &http_xfer_profiler );
- rc = xfer_deliver_raw ( &http->xfer,
- iobuf->data, data_len );
- iob_pull ( iobuf, data_len );
- if ( rc != 0 )
- goto done;
- profile_stop ( &http_xfer_profiler );
- } else {
- /* Deliver whole I/O buffer */
- profile_start ( &http_xfer_profiler );
- if ( ( rc = xfer_deliver_iob ( &http->xfer,
- iob_disown ( iobuf ) ) ) != 0 )
- goto done;
- profile_stop ( &http_xfer_profiler );
- }
- http->rx_len += data_len;
- if ( http->chunk_remaining ) {
- http->chunk_remaining -= data_len;
- if ( http->chunk_remaining == 0 )
- http->rx_state = HTTP_RX_CHUNK_LEN;
- }
- if ( http->remaining ) {
- http->remaining -= data_len;
- if ( ( http->remaining == 0 ) &&
- ( http->rx_state == HTTP_RX_DATA ) ) {
- http_done ( http );
- }
- }
- break;
- case HTTP_RX_RESPONSE:
- case HTTP_RX_HEADER:
- case HTTP_RX_CHUNK_LEN:
- case HTTP_RX_TRAILER:
- /* In the other phases, buffer and process a
- * line at a time
- */
- line_len = line_buffer ( &http->linebuf, iobuf->data,
- iob_len ( iobuf ) );
- if ( line_len < 0 ) {
- rc = line_len;
- DBGC ( http, "HTTP %p could not buffer line: "
- "%s\n", http, strerror ( rc ) );
- goto done;
- }
- iob_pull ( iobuf, line_len );
- line = buffered_line ( &http->linebuf );
- if ( line ) {
- lh = &http_line_handlers[http->rx_state];
- if ( ( rc = lh->rx ( http, line ) ) != 0 )
- goto done;
- }
- break;
- default:
- assert ( 0 );
- break;
- }
+ /* Wait until we receive a non-empty line */
+ line = buffered_line ( &http->linebuf );
+ if ( ( line == NULL ) || ( line[0] == '\0' ) )
+ return 0;
+
+ /* Parse chunk length */
+ http->remaining = strtoul ( line, &endp, 16 );
+ if ( *endp != '\0' ) {
+ DBGC ( http, "HTTP %p invalid chunk length \"%s\"\n",
+ http, line );
+ return -EINVAL_CHUNK_LENGTH;
}
- done:
- if ( rc )
- http_close ( http, rc );
- free_iob ( iobuf );
- profile_stop ( &http_rx_profiler );
- return rc;
+ /* Empty line buffer */
+ empty_line_buffer ( &http->linebuf );
+
+ /* Update expected length */
+ len = ( http->len + http->remaining );
+ xfer_seek ( &http->transfer, len );
+ xfer_seek ( &http->transfer, http->len );
+
+ /* If chunk length is zero, then move to response trailers state */
+ if ( ! http->remaining )
+ http->state = &http_trailers;
+
+ return 0;
}
/**
- * Check HTTP socket flow control window
+ * Handle received chunk data
*
- * @v http HTTP request
- * @ret len Length of window
+ * @v http HTTP transaction
+ * @v iobuf I/O buffer (may be claimed)
+ * @ret rc Return status code
*/
-static size_t http_socket_window ( struct http_request *http __unused ) {
+static int http_rx_chunk_data ( struct http_transaction *http,
+ struct io_buffer **iobuf ) {
+ struct io_buffer *payload;
+ uint8_t *crlf;
+ size_t len;
+ int rc;
- /* Window is always open. This is to prevent TCP from
- * stalling if our parent window is not currently open.
+ /* In the common case of a final chunk in a packet which also
+ * includes the terminating CRLF, strip the terminating CRLF
+ * (which we would ignore anyway) and hence avoid
+ * unnecessarily copying the data.
*/
- return ( ~( ( size_t ) 0 ) );
+ if ( iob_len ( *iobuf ) == ( http->remaining + 2 /* CRLF */ ) ) {
+ crlf = ( (*iobuf)->data + http->remaining );
+ if ( ( crlf[0] == '\r' ) && ( crlf[1] == '\n' ) )
+ iob_unput ( (*iobuf), 2 /* CRLF */ );
+ }
+ len = iob_len ( *iobuf );
+
+ /* Use whole/partial buffer as applicable */
+ if ( len <= http->remaining ) {
+
+ /* Whole buffer is to be consumed: decrease remaining
+ * length and use original I/O buffer as payload.
+ */
+ payload = iob_disown ( *iobuf );
+ http->len += len;
+ http->remaining -= len;
+
+ } else {
+
+ /* Partial buffer is to be consumed: copy data to a
+ * temporary I/O buffer.
+ */
+ payload = alloc_iob ( http->remaining );
+ if ( ! payload ) {
+ rc = -ENOMEM;
+ goto err;
+ }
+ memcpy ( iob_put ( payload, http->remaining ), (*iobuf)->data,
+ http->remaining );
+ iob_pull ( *iobuf, http->remaining );
+ http->len += http->remaining;
+ http->remaining = 0;
+ }
+
+ /* Hand off to content encoding */
+ if ( ( rc = xfer_deliver_iob ( &http->transfer,
+ iob_disown ( payload ) ) ) != 0 )
+ goto err;
+
+ return 0;
+
+ err:
+ assert ( payload == NULL );
+ return rc;
}
/**
- * Close HTTP socket
+ * Handle received chunked data
*
- * @v http HTTP request
- * @v rc Reason for close
+ * @v http HTTP transaction
+ * @v iobuf I/O buffer (may be claimed)
+ * @ret rc Return status code
*/
-static void http_socket_close ( struct http_request *http, int rc ) {
+static int http_rx_transfer_chunked ( struct http_transaction *http,
+ struct io_buffer **iobuf ) {
- /* If we have an error, terminate */
- if ( rc != 0 ) {
- http_close ( http, rc );
- return;
+ /* Handle as chunk length or chunk data as appropriate */
+ if ( http->remaining ) {
+ return http_rx_chunk_data ( http, iobuf );
+ } else {
+ return http_rx_chunk_len ( http, iobuf );
}
-
- /* Mark HTTP request as complete */
- http_done ( http );
}
-/**
- * Generate HTTP Basic authorisation string
+/** Chunked transfer encoding */
+struct http_transfer_encoding http_transfer_chunked __http_transfer_encoding = {
+ .name = "chunked",
+ .init = http_init_transfer_chunked,
+ .state = {
+ .rx = http_rx_transfer_chunked,
+ .close = http_close_error,
+ },
+};
+
+/******************************************************************************
*
- * @v http HTTP request
- * @ret auth Authorisation string, or NULL on error
+ * Response trailers
*
- * The authorisation string is dynamically allocated, and must be
- * freed by the caller.
+ ******************************************************************************
*/
-static char * http_basic_auth ( struct http_request *http ) {
- const char *user = http->uri->user;
- const char *password = ( http->uri->password ?
- http->uri->password : "" );
- size_t user_pw_len =
- ( strlen ( user ) + 1 /* ":" */ + strlen ( password ) );
- char user_pw[ user_pw_len + 1 /* NUL */ ];
- size_t user_pw_base64_len = base64_encoded_len ( user_pw_len );
- char user_pw_base64[ user_pw_base64_len + 1 /* NUL */ ];
- char *auth;
- int len;
- /* Sanity check */
- assert ( user != NULL );
+/**
+ * Handle received HTTP trailer
+ *
+ * @v http HTTP transaction
+ * @v iobuf I/O buffer (may be claimed)
+ * @ret rc Return status code
+ */
+static int http_rx_trailers ( struct http_transaction *http,
+ struct io_buffer **iobuf ) {
+ char *line;
+ int rc;
- /* Make "user:password" string from decoded fields */
- snprintf ( user_pw, sizeof ( user_pw ), "%s:%s", user, password );
+ /* Buffer trailer line */
+ if ( ( rc = http_rx_linebuf ( http, *iobuf, &http->linebuf ) ) != 0 )
+ return rc;
- /* Base64-encode the "user:password" string */
- base64_encode ( ( void * ) user_pw, user_pw_len, user_pw_base64 );
+ /* Wait until we see the empty line marking end of trailers */
+ line = buffered_line ( &http->linebuf );
+ if ( ( line == NULL ) || ( line[0] != '\0' ) )
+ return 0;
- /* Generate the authorisation string */
- len = asprintf ( &auth, "Authorization: Basic %s\r\n",
- user_pw_base64 );
- if ( len < 0 )
- return NULL;
+ /* Empty line buffer */
+ empty_line_buffer ( &http->linebuf );
- return auth;
+ /* Transfer is complete */
+ if ( ( rc = http_transfer_complete ( http ) ) != 0 )
+ return rc;
+
+ return 0;
}
-/**
- * Generate HTTP Digest authorisation string
+/** HTTP response trailers state */
+static struct http_state http_trailers = {
+ .rx = http_rx_trailers,
+ .close = http_close_error,
+};
+
+/******************************************************************************
*
- * @v http HTTP request
- * @v method HTTP method (e.g. "GET")
- * @v uri HTTP request URI (e.g. "/index.html")
- * @ret auth Authorisation string, or NULL on error
+ * Simple URI openers
*
- * The authorisation string is dynamically allocated, and must be
- * freed by the caller.
+ ******************************************************************************
*/
-static char * http_digest_auth ( struct http_request *http,
- const char *method, const char *uri ) {
- const char *user = http->uri->user;
- const char *password = ( http->uri->password ?
- http->uri->password : "" );
- const char *realm = http->auth_realm;
- const char *nonce = http->auth_nonce;
- const char *opaque = http->auth_opaque;
- static const char colon = ':';
- uint8_t ctx[MD5_CTX_SIZE];
- uint8_t digest[MD5_DIGEST_SIZE];
- char ha1[ base16_encoded_len ( sizeof ( digest ) ) + 1 /* NUL */ ];
- char ha2[ base16_encoded_len ( sizeof ( digest ) ) + 1 /* NUL */ ];
- char response[ base16_encoded_len ( sizeof ( digest ) ) + 1 /* NUL */ ];
- char *auth;
- int len;
-
- /* Sanity checks */
- assert ( user != NULL );
- assert ( realm != NULL );
- assert ( nonce != NULL );
-
- /* Generate HA1 */
- digest_init ( &md5_algorithm, ctx );
- digest_update ( &md5_algorithm, ctx, user, strlen ( user ) );
- digest_update ( &md5_algorithm, ctx, &colon, sizeof ( colon ) );
- digest_update ( &md5_algorithm, ctx, realm, strlen ( realm ) );
- digest_update ( &md5_algorithm, ctx, &colon, sizeof ( colon ) );
- digest_update ( &md5_algorithm, ctx, password, strlen ( password ) );
- digest_final ( &md5_algorithm, ctx, digest );
- base16_encode ( digest, sizeof ( digest ), ha1 );
-
- /* Generate HA2 */
- digest_init ( &md5_algorithm, ctx );
- digest_update ( &md5_algorithm, ctx, method, strlen ( method ) );
- digest_update ( &md5_algorithm, ctx, &colon, sizeof ( colon ) );
- digest_update ( &md5_algorithm, ctx, uri, strlen ( uri ) );
- digest_final ( &md5_algorithm, ctx, digest );
- base16_encode ( digest, sizeof ( digest ), ha2 );
-
- /* Generate response */
- digest_init ( &md5_algorithm, ctx );
- digest_update ( &md5_algorithm, ctx, ha1, strlen ( ha1 ) );
- digest_update ( &md5_algorithm, ctx, &colon, sizeof ( colon ) );
- digest_update ( &md5_algorithm, ctx, nonce, strlen ( nonce ) );
- digest_update ( &md5_algorithm, ctx, &colon, sizeof ( colon ) );
- digest_update ( &md5_algorithm, ctx, ha2, strlen ( ha2 ) );
- digest_final ( &md5_algorithm, ctx, digest );
- base16_encode ( digest, sizeof ( digest ), response );
-
- /* Generate the authorisation string */
- len = asprintf ( &auth, "Authorization: Digest username=\"%s\", "
- "realm=\"%s\", nonce=\"%s\", uri=\"%s\", "
- "%s%s%sresponse=\"%s\"\r\n", user, realm, nonce, uri,
- ( opaque ? "opaque=\"" : "" ),
- ( opaque ? opaque : "" ),
- ( opaque ? "\", " : "" ), response );
- if ( len < 0 )
- return NULL;
-
- return auth;
-}
/**
- * Generate HTTP POST parameter list
+ * Construct HTTP parameter list
*
- * @v http HTTP request
+ * @v params Parameter list
* @v buf Buffer to contain HTTP POST parameters
* @v len Length of buffer
* @ret len Length of parameter list (excluding terminating NUL)
*/
-static size_t http_post_params ( struct http_request *http,
- char *buf, size_t len ) {
+static size_t http_params ( struct parameters *params, char *buf, size_t len ) {
struct parameter *param;
ssize_t remaining = len;
size_t frag_len;
/* Add each parameter in the form "key=value", joined with "&" */
len = 0;
- for_each_param ( param, http->uri->params ) {
+ for_each_param ( param, params ) {
/* Add the "&", if applicable */
if ( len ) {
@@ -1201,374 +1853,78 @@ static size_t http_post_params ( struct http_request *http,
}
/**
- * Generate HTTP POST body
+ * Open HTTP transaction for simple GET URI
*
- * @v http HTTP request
- * @ret post I/O buffer containing POST body, or NULL on error
+ * @v xfer Data transfer interface
+ * @v uri Request URI
+ * @ret rc Return status code
*/
-static struct io_buffer * http_post ( struct http_request *http ) {
- struct io_buffer *post;
- size_t len;
- size_t check_len;
+static int http_open_get_uri ( struct interface *xfer, struct uri *uri ) {
- /* Calculate length of parameter list */
- len = http_post_params ( http, NULL, 0 );
-
- /* Allocate parameter list */
- post = alloc_iob ( len + 1 /* NUL */ );
- if ( ! post )
- return NULL;
-
- /* Fill parameter list */
- check_len = http_post_params ( http, iob_put ( post, len ),
- ( len + 1 /* NUL */ ) );
- assert ( len == check_len );
- DBGC ( http, "HTTP %p POST %s\n", http, ( ( char * ) post->data ) );
-
- return post;
+ return http_open ( xfer, &http_get, uri, NULL, NULL );
}
/**
- * HTTP process
+ * Open HTTP transaction for simple POST URI
*
- * @v http HTTP request
+ * @v xfer Data transfer interface
+ * @v uri Request URI
+ * @ret rc Return status code
*/
-static void http_step ( struct http_request *http ) {
- struct io_buffer *post;
- struct uri host_uri;
- struct uri path_uri;
- char *host_uri_string;
- char *path_uri_string;
- char *method;
- char *range;
- char *auth;
- char *content;
- int len;
+static int http_open_post_uri ( struct interface *xfer, struct uri *uri ) {
+ struct parameters *params = uri->params;
+ struct http_request_content content;
+ void *data;
+ size_t len;
+ size_t check_len;
int rc;
- /* Do nothing if we have already transmitted the request */
- if ( ! ( http->flags & HTTP_TX_PENDING ) )
- return;
-
- /* Do nothing until socket is ready */
- if ( ! xfer_window ( &http->socket ) )
- return;
-
- /* Force a HEAD request if we have nowhere to send any received data */
- if ( ( xfer_window ( &http->xfer ) == 0 ) &&
- ( http->rx_buffer == UNULL ) ) {
- http->flags |= ( HTTP_HEAD_ONLY | HTTP_CLIENT_KEEPALIVE );
- }
-
- /* Determine method */
- method = ( ( http->flags & HTTP_HEAD_ONLY ) ? "HEAD" :
- ( http->uri->params ? "POST" : "GET" ) );
+ /* Calculate length of parameter list */
+ len = http_params ( params, NULL, 0 );
- /* Construct host URI */
- memset ( &host_uri, 0, sizeof ( host_uri ) );
- host_uri.host = http->uri->host;
- host_uri.port = http->uri->port;
- host_uri_string = format_uri_alloc ( &host_uri );
- if ( ! host_uri_string ) {
+ /* Allocate temporary parameter list */
+ data = zalloc ( len + 1 /* NUL */ );
+ if ( ! data ) {
rc = -ENOMEM;
- goto err_host_uri;
+ goto err_alloc;
}
- /* Construct path URI */
- memset ( &path_uri, 0, sizeof ( path_uri ) );
- path_uri.path = ( http->uri->path ? http->uri->path : "/" );
- path_uri.query = http->uri->query;
- path_uri_string = format_uri_alloc ( &path_uri );
- if ( ! path_uri_string ) {
- rc = -ENOMEM;
- goto err_path_uri;
- }
+ /* Construct temporary parameter list */
+ check_len = http_params ( params, data, ( len + 1 /* NUL */ ) );
+ assert ( check_len == len );
- /* Calculate range request parameters if applicable */
- if ( http->partial_len ) {
- len = asprintf ( &range, "Range: bytes=%zd-%zd\r\n",
- http->partial_start,
- ( http->partial_start + http->partial_len
- - 1 ) );
- if ( len < 0 ) {
- rc = len;
- goto err_range;
- }
- } else {
- range = NULL;
- }
+ /* Construct request content */
+ content.type = "application/x-www-form-urlencoded";
+ content.data = data;
+ content.len = len;
- /* Construct authorisation, if applicable */
- if ( http->flags & HTTP_BASIC_AUTH ) {
- auth = http_basic_auth ( http );
- if ( ! auth ) {
- rc = -ENOMEM;
- goto err_auth;
- }
- } else if ( http->flags & HTTP_DIGEST_AUTH ) {
- auth = http_digest_auth ( http, method, path_uri_string );
- if ( ! auth ) {
- rc = -ENOMEM;
- goto err_auth;
- }
- } else {
- auth = NULL;
- }
+ /* Open HTTP transaction */
+ if ( ( rc = http_open ( xfer, &http_post, uri, NULL, &content ) ) != 0 )
+ goto err_open;
- /* Construct POST content, if applicable */
- if ( http->uri->params ) {
- post = http_post ( http );
- if ( ! post ) {
- rc = -ENOMEM;
- goto err_post;
- }
- len = asprintf ( &content, "Content-Type: "
- "application/x-www-form-urlencoded\r\n"
- "Content-Length: %zd\r\n", iob_len ( post ) );
- if ( len < 0 ) {
- rc = len;
- goto err_content;
- }
- } else {
- post = NULL;
- content = NULL;
- }
-
- /* Mark request as transmitted */
- http->flags &= ~HTTP_TX_PENDING;
-
- /* Send request */
- if ( ( rc = xfer_printf ( &http->socket,
- "%s %s HTTP/1.1\r\n"
- "User-Agent: iPXE/%s\r\n"
- "Host: %s\r\n"
- "%s%s%s%s"
- "\r\n",
- method, path_uri_string, product_version,
- host_uri_string,
- ( ( http->flags & HTTP_CLIENT_KEEPALIVE ) ?
- "Connection: keep-alive\r\n" : "" ),
- ( range ? range : "" ),
- ( auth ? auth : "" ),
- ( content ? content : "" ) ) ) != 0 ) {
- goto err_xfer;
- }
-
- /* Send POST content, if applicable */
- if ( post ) {
- if ( ( rc = xfer_deliver_iob ( &http->socket,
- iob_disown ( post ) ) ) != 0 )
- goto err_xfer_post;
- }
-
- err_xfer_post:
- err_xfer:
- free ( content );
- err_content:
- free ( post );
- err_post:
- free ( auth );
- err_auth:
- free ( range );
- err_range:
- free ( path_uri_string );
- err_path_uri:
- free ( host_uri_string );
- err_host_uri:
- if ( rc != 0 )
- http_close ( http, rc );
-}
-
-/**
- * Check HTTP data transfer flow control window
- *
- * @v http HTTP request
- * @ret len Length of window
- */
-static size_t http_xfer_window ( struct http_request *http ) {
-
- /* New block commands may be issued only when we are idle */
- return ( ( http->rx_state == HTTP_RX_IDLE ) ? 1 : 0 );
-}
-
-/**
- * Initiate HTTP partial read
- *
- * @v http HTTP request
- * @v partial Partial transfer interface
- * @v offset Starting offset
- * @v buffer Data buffer
- * @v len Length
- * @ret rc Return status code
- */
-static int http_partial_read ( struct http_request *http,
- struct interface *partial,
- size_t offset, userptr_t buffer, size_t len ) {
-
- /* Sanity check */
- if ( http_xfer_window ( http ) == 0 )
- return -EBUSY;
-
- /* Initialise partial transfer parameters */
- http->rx_buffer = buffer;
- http->partial_start = offset;
- http->partial_len = len;
-
- /* Schedule request */
- http->rx_state = HTTP_RX_RESPONSE;
- http->flags = ( HTTP_TX_PENDING | HTTP_CLIENT_KEEPALIVE );
- if ( ! len )
- http->flags |= HTTP_HEAD_ONLY;
- process_add ( &http->process );
-
- /* Attach to parent interface and return */
- intf_plug_plug ( &http->partial, partial );
-
- return 0;
-}
-
-/**
- * Issue HTTP block device read
- *
- * @v http HTTP request
- * @v block Block data interface
- * @v lba Starting logical block address
- * @v count Number of blocks to transfer
- * @v buffer Data buffer
- * @v len Length of data buffer
- * @ret rc Return status code
- */
-static int http_block_read ( struct http_request *http,
- struct interface *block,
- uint64_t lba, unsigned int count,
- userptr_t buffer, size_t len __unused ) {
-
- return http_partial_read ( http, block, ( lba * HTTP_BLKSIZE ),
- buffer, ( count * HTTP_BLKSIZE ) );
-}
-
-/**
- * Read HTTP block device capacity
- *
- * @v http HTTP request
- * @v block Block data interface
- * @ret rc Return status code
- */
-static int http_block_read_capacity ( struct http_request *http,
- struct interface *block ) {
-
- return http_partial_read ( http, block, 0, 0, 0 );
-}
-
-/**
- * Describe HTTP device in an ACPI table
- *
- * @v http HTTP request
- * @v acpi ACPI table
- * @v len Length of ACPI table
- * @ret rc Return status code
- */
-static int http_acpi_describe ( struct http_request *http,
- struct acpi_description_header *acpi,
- size_t len ) {
-
- DBGC ( http, "HTTP %p cannot yet describe device in an ACPI table\n",
- http );
- ( void ) acpi;
- ( void ) len;
- return 0;
+ err_open:
+ free ( data );
+ err_alloc:
+ return rc;
}
-/** HTTP socket interface operations */
-static struct interface_operation http_socket_operations[] = {
- INTF_OP ( xfer_window, struct http_request *, http_socket_window ),
- INTF_OP ( xfer_deliver, struct http_request *, http_socket_deliver ),
- INTF_OP ( xfer_window_changed, struct http_request *, http_step ),
- INTF_OP ( intf_close, struct http_request *, http_socket_close ),
-};
-
-/** HTTP socket interface descriptor */
-static struct interface_descriptor http_socket_desc =
- INTF_DESC_PASSTHRU ( struct http_request, socket,
- http_socket_operations, xfer );
-
-/** HTTP partial transfer interface operations */
-static struct interface_operation http_partial_operations[] = {
- INTF_OP ( intf_close, struct http_request *, http_close ),
-};
-
-/** HTTP partial transfer interface descriptor */
-static struct interface_descriptor http_partial_desc =
- INTF_DESC ( struct http_request, partial, http_partial_operations );
-
-/** HTTP data transfer interface operations */
-static struct interface_operation http_xfer_operations[] = {
- INTF_OP ( xfer_window, struct http_request *, http_xfer_window ),
- INTF_OP ( block_read, struct http_request *, http_block_read ),
- INTF_OP ( block_read_capacity, struct http_request *,
- http_block_read_capacity ),
- INTF_OP ( intf_close, struct http_request *, http_close ),
- INTF_OP ( acpi_describe, struct http_request *, http_acpi_describe ),
-};
-
-/** HTTP data transfer interface descriptor */
-static struct interface_descriptor http_xfer_desc =
- INTF_DESC_PASSTHRU ( struct http_request, xfer,
- http_xfer_operations, socket );
-
-/** HTTP process descriptor */
-static struct process_descriptor http_process_desc =
- PROC_DESC_ONCE ( struct http_request, process, http_step );
-
/**
- * Initiate an HTTP connection, with optional filter
+ * Open HTTP transaction for simple URI
*
* @v xfer Data transfer interface
- * @v uri Uniform Resource Identifier
- * @v default_port Default port number
- * @v filter Filter to apply to socket, or NULL
+ * @v uri Request URI
* @ret rc Return status code
*/
-int http_open_filter ( struct interface *xfer, struct uri *uri,
- unsigned int default_port,
- int ( * filter ) ( struct interface *xfer,
- const char *name,
- struct interface **next ) ) {
- struct http_request *http;
- int rc;
-
- /* Sanity checks */
- if ( ! uri->host )
- return -EINVAL;
-
- /* Allocate and populate HTTP structure */
- http = zalloc ( sizeof ( *http ) );
- if ( ! http )
- return -ENOMEM;
- ref_init ( &http->refcnt, http_free );
- intf_init ( &http->xfer, &http_xfer_desc, &http->refcnt );
- intf_init ( &http->partial, &http_partial_desc, &http->refcnt );
- http->uri = uri_get ( uri );
- http->default_port = default_port;
- http->filter = filter;
- intf_init ( &http->socket, &http_socket_desc, &http->refcnt );
- process_init ( &http->process, &http_process_desc, &http->refcnt );
- timer_init ( &http->timer, http_retry, &http->refcnt );
- http->flags = HTTP_TX_PENDING;
+int http_open_uri ( struct interface *xfer, struct uri *uri ) {
- /* Open socket */
- if ( ( rc = http_socket_open ( http ) ) != 0 )
- goto err;
-
- /* Attach to parent interface, mortalise self, and return */
- intf_plug_plug ( &http->xfer, xfer );
- ref_put ( &http->refcnt );
- return 0;
-
- err:
- DBGC ( http, "HTTP %p could not create request: %s\n",
- http, strerror ( rc ) );
- http_close ( http, rc );
- ref_put ( &http->refcnt );
- return rc;
+ /* Open GET/POST URI as applicable */
+ if ( uri->params ) {
+ return http_open_post_uri ( xfer, uri );
+ } else {
+ return http_open_get_uri ( xfer, uri );
+ }
}
+
+/* Drag in HTTP extensions */
+REQUIRING_SYMBOL ( http_open );
+REQUIRE_OBJECT ( config_http );
diff --git a/roms/ipxe/src/net/tcp/httpdigest.c b/roms/ipxe/src/net/tcp/httpdigest.c
new file mode 100644
index 000000000..626dd7e9d
--- /dev/null
+++ b/roms/ipxe/src/net/tcp/httpdigest.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/**
+ * @file
+ *
+ * Hyper Text Transfer Protocol (HTTP) Digest authentication
+ *
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <strings.h>
+#include <ipxe/uri.h>
+#include <ipxe/md5.h>
+#include <ipxe/base16.h>
+#include <ipxe/vsprintf.h>
+#include <ipxe/http.h>
+
+/* Disambiguate the various error causes */
+#define EACCES_USERNAME __einfo_error ( EINFO_EACCES_USERNAME )
+#define EINFO_EACCES_USERNAME \
+ __einfo_uniqify ( EINFO_EACCES, 0x01, \
+ "No username available for Digest authentication" )
+
+/**
+ * Initialise HTTP Digest
+ *
+ * @v ctx Digest context
+ * @v string Initial string
+ */
+static void http_digest_init ( struct md5_context *ctx ) {
+
+ /* Initialise MD5 digest */
+ digest_init ( &md5_algorithm, ctx );
+}
+
+/**
+ * Update HTTP Digest with new data
+ *
+ * @v ctx Digest context
+ * @v string String to append
+ */
+static void http_digest_update ( struct md5_context *ctx, const char *string ) {
+ static const char colon = ':';
+
+ /* Add (possibly colon-separated) field to MD5 digest */
+ if ( ctx->len )
+ digest_update ( &md5_algorithm, ctx, &colon, sizeof ( colon ) );
+ digest_update ( &md5_algorithm, ctx, string, strlen ( string ) );
+}
+
+/**
+ * Finalise HTTP Digest
+ *
+ * @v ctx Digest context
+ * @v out Buffer for digest output
+ * @v len Buffer length
+ */
+static void http_digest_final ( struct md5_context *ctx, char *out,
+ size_t len ) {
+ uint8_t digest[MD5_DIGEST_SIZE];
+
+ /* Finalise and base16-encode MD5 digest */
+ digest_final ( &md5_algorithm, ctx, digest );
+ base16_encode ( digest, sizeof ( digest ), out, len );
+}
+
+/**
+ * Perform HTTP Digest authentication
+ *
+ * @v http HTTP transaction
+ * @ret rc Return status code
+ */
+static int http_digest_authenticate ( struct http_transaction *http ) {
+ struct http_request_auth *req = &http->request.auth;
+ struct http_response_auth *rsp = &http->response.auth;
+ char ha1[ base16_encoded_len ( MD5_DIGEST_SIZE ) + 1 /* NUL */ ];
+ char ha2[ base16_encoded_len ( MD5_DIGEST_SIZE ) + 1 /* NUL */ ];
+ static const char md5sess[] = "MD5-sess";
+ static const char md5[] = "MD5";
+ struct md5_context ctx;
+
+ /* Check for required response parameters */
+ if ( ! rsp->realm ) {
+ DBGC ( http, "HTTP %p has no realm for Digest authentication\n",
+ http );
+ return -EINVAL;
+ }
+ if ( ! rsp->nonce ) {
+ DBGC ( http, "HTTP %p has no nonce for Digest authentication\n",
+ http );
+ return -EINVAL;
+ }
+
+ /* Record username and password */
+ if ( ! http->uri->user ) {
+ DBGC ( http, "HTTP %p has no username for Digest "
+ "authentication\n", http );
+ return -EACCES_USERNAME;
+ }
+ req->username = http->uri->user;
+ req->password = ( http->uri->password ? http->uri->password : "" );
+
+ /* Handle quality of protection */
+ if ( rsp->qop ) {
+
+ /* Use "auth" in subsequent request */
+ req->qop = "auth";
+
+ /* Generate a client nonce */
+ snprintf ( req->cnonce, sizeof ( req->cnonce ),
+ "%08lx", random() );
+
+ /* Determine algorithm */
+ req->algorithm = md5;
+ if ( rsp->algorithm &&
+ ( strcasecmp ( rsp->algorithm, md5sess ) == 0 ) ) {
+ req->algorithm = md5sess;
+ }
+ }
+
+ /* Generate HA1 */
+ http_digest_init ( &ctx );
+ http_digest_update ( &ctx, req->username );
+ http_digest_update ( &ctx, rsp->realm );
+ http_digest_update ( &ctx, req->password );
+ http_digest_final ( &ctx, ha1, sizeof ( ha1 ) );
+ if ( req->algorithm == md5sess ) {
+ http_digest_init ( &ctx );
+ http_digest_update ( &ctx, ha1 );
+ http_digest_update ( &ctx, rsp->nonce );
+ http_digest_update ( &ctx, req->cnonce );
+ http_digest_final ( &ctx, ha1, sizeof ( ha1 ) );
+ }
+
+ /* Generate HA2 */
+ http_digest_init ( &ctx );
+ http_digest_update ( &ctx, http->request.method->name );
+ http_digest_update ( &ctx, http->request.uri );
+ http_digest_final ( &ctx, ha2, sizeof ( ha2 ) );
+
+ /* Generate response */
+ http_digest_init ( &ctx );
+ http_digest_update ( &ctx, ha1 );
+ http_digest_update ( &ctx, rsp->nonce );
+ if ( req->qop ) {
+ http_digest_update ( &ctx, HTTP_DIGEST_NC );
+ http_digest_update ( &ctx, req->cnonce );
+ http_digest_update ( &ctx, req->qop );
+ }
+ http_digest_update ( &ctx, ha2 );
+ http_digest_final ( &ctx, req->response, sizeof ( req->response ) );
+
+ return 0;
+}
+
+/**
+ * Construct HTTP "Authorization" header for Digest authentication
+ *
+ * @v http HTTP transaction
+ * @v buf Buffer
+ * @v len Length of buffer
+ * @ret len Length of header value, or negative error
+ */
+static int http_format_digest_auth ( struct http_transaction *http,
+ char *buf, size_t len ) {
+ struct http_request_auth *req = &http->request.auth;
+ struct http_response_auth *rsp = &http->response.auth;
+ size_t used = 0;
+
+ /* Sanity checks */
+ assert ( rsp->realm != NULL );
+ assert ( rsp->nonce != NULL );
+ assert ( req->username != NULL );
+ if ( req->qop ) {
+ assert ( req->algorithm != NULL );
+ assert ( req->cnonce[0] != '\0' );
+ }
+ assert ( req->response[0] != '\0' );
+
+ /* Construct response */
+ used += ssnprintf ( ( buf + used ), ( len - used ),
+ "realm=\"%s\", nonce=\"%s\", uri=\"%s\", "
+ "username=\"%s\"", rsp->realm, rsp->nonce,
+ http->request.uri, req->username );
+ if ( rsp->opaque ) {
+ used += ssnprintf ( ( buf + used ), ( len - used ),
+ ", opaque=\"%s\"", rsp->opaque );
+ }
+ if ( req->qop ) {
+ used += ssnprintf ( ( buf + used ), ( len - used ),
+ ", qop=%s, algorithm=%s, cnonce=\"%s\", "
+ "nc=" HTTP_DIGEST_NC, req->qop,
+ req->algorithm, req->cnonce );
+ }
+ used += ssnprintf ( ( buf + used ), ( len - used ),
+ ", response=\"%s\"", req->response );
+
+ return used;
+}
+
+/** HTTP Digest authentication scheme */
+struct http_authentication http_digest_auth __http_authentication = {
+ .name = "Digest",
+ .authenticate = http_digest_authenticate,
+ .format = http_format_digest_auth,
+};
+
+/* Drag in HTTP authentication support */
+REQUIRING_SYMBOL ( http_digest_auth );
+REQUIRE_OBJECT ( httpauth );
diff --git a/roms/ipxe/src/net/tcp/https.c b/roms/ipxe/src/net/tcp/https.c
index 6112acdae..e91000322 100644
--- a/roms/ipxe/src/net/tcp/https.c
+++ b/roms/ipxe/src/net/tcp/https.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @file
@@ -26,7 +30,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
*/
-#include <stddef.h>
#include <ipxe/open.h>
#include <ipxe/tls.h>
#include <ipxe/http.h>
@@ -34,19 +37,15 @@ FILE_LICENCE ( GPL2_OR_LATER );
FEATURE ( FEATURE_PROTOCOL, "HTTPS", DHCP_EB_FEATURE_HTTPS, 1 );
-/**
- * Initiate an HTTPS connection
- *
- * @v xfer Data transfer interface
- * @v uri Uniform Resource Identifier
- * @ret rc Return status code
- */
-static int https_open ( struct interface *xfer, struct uri *uri ) {
- return http_open_filter ( xfer, uri, HTTPS_PORT, add_tls );
-}
-
/** HTTPS URI opener */
struct uri_opener https_uri_opener __uri_opener = {
.scheme = "https",
- .open = https_open,
+ .open = http_open_uri,
+};
+
+/** HTTP URI scheme */
+struct http_scheme https_scheme __http_scheme = {
+ .name = "https",
+ .port = HTTPS_PORT,
+ .filter = add_tls,
};
diff --git a/roms/ipxe/src/net/tcp/iscsi.c b/roms/ipxe/src/net/tcp/iscsi.c
index 03c6d0f23..019a4c14e 100644
--- a/roms/ipxe/src/net/tcp/iscsi.c
+++ b/roms/ipxe/src/net/tcp/iscsi.c
@@ -15,14 +15,19 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
+#include <ctype.h>
#include <errno.h>
#include <assert.h>
#include <byteswap.h>
@@ -127,7 +132,7 @@ FEATURE ( FEATURE_PROTOCOL, "iSCSI", DHCP_EB_FEATURE_ISCSI, 1 );
#define EPROTO_INVALID_LARGE_BINARY \
__einfo_error ( EINFO_EPROTO_INVALID_LARGE_BINARY )
#define EINFO_EPROTO_INVALID_LARGE_BINARY \
- __einfo_uniqify ( EINFO_EPROTO, 0x03, "Invalid large binary" )
+ __einfo_uniqify ( EINFO_EPROTO, 0x03, "Invalid large binary value" )
#define EPROTO_INVALID_CHAP_RESPONSE \
__einfo_error ( EINFO_EPROTO_INVALID_CHAP_RESPONSE )
#define EINFO_EPROTO_INVALID_CHAP_RESPONSE \
@@ -704,7 +709,7 @@ static int iscsi_build_login_request_strings ( struct iscsi_session *iscsi,
char buf[ base16_encoded_len ( iscsi->chap.response_len ) + 1 ];
assert ( iscsi->initiator_username != NULL );
base16_encode ( iscsi->chap.response, iscsi->chap.response_len,
- buf );
+ buf, sizeof ( buf ) );
used += ssnprintf ( data + used, len - used,
"CHAP_N=%s%cCHAP_R=0x%s%c",
iscsi->initiator_username, 0, buf, 0 );
@@ -714,7 +719,7 @@ static int iscsi_build_login_request_strings ( struct iscsi_session *iscsi,
size_t challenge_len = ( sizeof ( iscsi->chap_challenge ) - 1 );
char buf[ base16_encoded_len ( challenge_len ) + 1 ];
base16_encode ( ( iscsi->chap_challenge + 1 ), challenge_len,
- buf );
+ buf, sizeof ( buf ) );
used += ssnprintf ( data + used, len - used,
"CHAP_I=%d%cCHAP_C=0x%s%c",
iscsi->chap_challenge[0], 0, buf, 0 );
@@ -824,38 +829,27 @@ static int iscsi_tx_login_request ( struct iscsi_session *iscsi ) {
}
/**
- * Calculate maximum length of decoded large binary value
- *
- * @v encoded Encoded large binary value
- * @v max_raw_len Maximum length of raw data
- */
-static inline size_t
-iscsi_large_binary_decoded_max_len ( const char *encoded ) {
- return ( strlen ( encoded ) ); /* Decoding never expands data */
-}
-
-/**
* Decode large binary value
*
* @v encoded Encoded large binary value
* @v raw Raw data
+ * @v len Length of data buffer
* @ret len Length of raw data, or negative error
*/
-static int iscsi_large_binary_decode ( const char *encoded, uint8_t *raw ) {
-
- if ( encoded[0] != '0' )
- return -EPROTO_INVALID_LARGE_BINARY;
-
- switch ( encoded[1] ) {
- case 'x' :
- case 'X' :
- return base16_decode ( ( encoded + 2 ), raw );
- case 'b' :
- case 'B' :
- return base64_decode ( ( encoded + 2 ), raw );
- default:
- return -EPROTO_INVALID_LARGE_BINARY;
+static int iscsi_large_binary_decode ( const char *encoded, uint8_t *raw,
+ size_t len ) {
+
+ /* Check for initial '0x' or '0b' and decode as appropriate */
+ if ( *(encoded++) == '0' ) {
+ switch ( tolower ( *(encoded++) ) ) {
+ case 'x' :
+ return base16_decode ( encoded, raw, len );
+ case 'b' :
+ return base64_decode ( encoded, raw, len );
+ }
}
+
+ return -EPROTO_INVALID_LARGE_BINARY;
}
/**
@@ -982,19 +976,19 @@ static int iscsi_handle_chap_i_value ( struct iscsi_session *iscsi,
*/
static int iscsi_handle_chap_c_value ( struct iscsi_session *iscsi,
const char *value ) {
- uint8_t buf[ iscsi_large_binary_decoded_max_len ( value ) ];
+ uint8_t buf[ strlen ( value ) ]; /* Decoding never expands data */
unsigned int i;
- size_t len;
+ int len;
int rc;
/* Process challenge */
- rc = iscsi_large_binary_decode ( value, buf );
- if ( rc < 0 ) {
+ len = iscsi_large_binary_decode ( value, buf, sizeof ( buf ) );
+ if ( len < 0 ) {
+ rc = len;
DBGC ( iscsi, "iSCSI %p invalid CHAP challenge \"%s\": %s\n",
iscsi, value, strerror ( rc ) );
return rc;
}
- len = rc;
chap_update ( &iscsi->chap, buf, len );
/* Build CHAP response */
@@ -1052,8 +1046,8 @@ static int iscsi_handle_chap_n_value ( struct iscsi_session *iscsi,
*/
static int iscsi_handle_chap_r_value ( struct iscsi_session *iscsi,
const char *value ) {
- uint8_t buf[ iscsi_large_binary_decoded_max_len ( value ) ];
- size_t len;
+ uint8_t buf[ strlen ( value ) ]; /* Decoding never expands data */
+ int len;
int rc;
/* Generate CHAP response for verification */
@@ -1073,16 +1067,16 @@ static int iscsi_handle_chap_r_value ( struct iscsi_session *iscsi,
chap_respond ( &iscsi->chap );
/* Process response */
- rc = iscsi_large_binary_decode ( value, buf );
- if ( rc < 0 ) {
+ len = iscsi_large_binary_decode ( value, buf, sizeof ( buf ) );
+ if ( len < 0 ) {
+ rc = len;
DBGC ( iscsi, "iSCSI %p invalid CHAP response \"%s\": %s\n",
iscsi, value, strerror ( rc ) );
return rc;
}
- len = rc;
/* Check CHAP response */
- if ( len != iscsi->chap.response_len ) {
+ if ( len != ( int ) iscsi->chap.response_len ) {
DBGC ( iscsi, "iSCSI %p invalid CHAP response length\n",
iscsi );
return -EPROTO_INVALID_CHAP_RESPONSE;
@@ -1445,8 +1439,10 @@ static void iscsi_tx_done ( struct iscsi_session *iscsi ) {
switch ( common->opcode & ISCSI_OPCODE_MASK ) {
case ISCSI_OPCODE_DATA_OUT:
iscsi_data_out_done ( iscsi );
+ break;
case ISCSI_OPCODE_LOGIN_REQUEST:
iscsi_login_request_done ( iscsi );
+ break;
default:
/* No action */
break;
diff --git a/roms/ipxe/src/net/tcp/syslogs.c b/roms/ipxe/src/net/tcp/syslogs.c
index 095afc543..0c07f86d5 100644
--- a/roms/ipxe/src/net/tcp/syslogs.c
+++ b/roms/ipxe/src/net/tcp/syslogs.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/net/tcpip.c b/roms/ipxe/src/net/tcpip.c
index 4bcbe64bb..5ad982fd1 100644
--- a/roms/ipxe/src/net/tcpip.c
+++ b/roms/ipxe/src/net/tcpip.c
@@ -17,7 +17,7 @@
* TCP/IP transport-network layer interface
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* Process a received TCP/IP packet
@@ -235,7 +235,7 @@ int tcpip_bind ( struct sockaddr_tcpip *st_local,
/* Otherwise, find an available port in the range [1,1023] or
* [1025,65535] as appropriate.
*/
- min_port = ( ( ( ! flags ) & TCPIP_BIND_PRIVILEGED ) + 1 );
+ min_port = ( ( ( ~flags ) & TCPIP_BIND_PRIVILEGED ) + 1 );
max_port = ( ( flags & TCPIP_BIND_PRIVILEGED ) - 1 );
offset = random();
for ( i = 0 ; i <= max_port ; i++ ) {
diff --git a/roms/ipxe/src/net/tls.c b/roms/ipxe/src/net/tls.c
index 30ccc932e..db01fb291 100644
--- a/roms/ipxe/src/net/tls.c
+++ b/roms/ipxe/src/net/tls.c
@@ -179,20 +179,29 @@ static void tls_clear_cipher ( struct tls_session *tls,
******************************************************************************
*/
+/** A TLS 24-bit integer
+ *
+ * TLS uses 24-bit integers in several places, which are awkward to
+ * parse in C.
+ */
+typedef struct {
+ /** High byte */
+ uint8_t high;
+ /** Low word */
+ uint16_t low;
+} __attribute__ (( packed )) tls24_t;
+
/**
* 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 inline __attribute__ (( always_inline )) unsigned long
-tls_uint24 ( const uint8_t field24[3] ) {
- const uint32_t *field32 __attribute__ (( may_alias )) =
- ( ( const void * ) field24 );
- return ( be32_to_cpu ( *field32 ) >> 8 );
+tls_uint24 ( const tls24_t *field24 ) {
+
+ return ( ( field24->high << 16 ) | be16_to_cpu ( field24->low ) );
}
/**
@@ -200,13 +209,11 @@ tls_uint24 ( const uint8_t field24[3] ) {
*
* @v field24 24-bit field
* @v value Field value
- *
- * The field must be pre-zeroed.
*/
-static void tls_set_uint24 ( uint8_t field24[3], unsigned long value ) {
- uint32_t *field32 __attribute__ (( may_alias )) =
- ( ( void * ) field24 );
- *field32 |= cpu_to_be32 ( value << 8 );
+static void tls_set_uint24 ( tls24_t *field24, unsigned long value ) {
+
+ field24->high = ( value >> 16 );
+ field24->low = cpu_to_be16 ( value );
}
/**
@@ -659,41 +666,8 @@ struct tls_cipher_suite tls_cipher_suite_null = {
.digest = &digest_null,
};
-/** Supported cipher suites, in order of preference */
-struct tls_cipher_suite tls_cipher_suites[] = {
- {
- .code = htons ( TLS_RSA_WITH_AES_256_CBC_SHA256 ),
- .key_len = ( 256 / 8 ),
- .pubkey = &rsa_algorithm,
- .cipher = &aes_cbc_algorithm,
- .digest = &sha256_algorithm,
- },
- {
- .code = htons ( TLS_RSA_WITH_AES_128_CBC_SHA256 ),
- .key_len = ( 128 / 8 ),
- .pubkey = &rsa_algorithm,
- .cipher = &aes_cbc_algorithm,
- .digest = &sha256_algorithm,
- },
- {
- .code = htons ( TLS_RSA_WITH_AES_256_CBC_SHA ),
- .key_len = ( 256 / 8 ),
- .pubkey = &rsa_algorithm,
- .cipher = &aes_cbc_algorithm,
- .digest = &sha1_algorithm,
- },
- {
- .code = htons ( TLS_RSA_WITH_AES_128_CBC_SHA ),
- .key_len = ( 128 / 8 ),
- .pubkey = &rsa_algorithm,
- .cipher = &aes_cbc_algorithm,
- .digest = &sha1_algorithm,
- },
-};
-
/** Number of supported cipher suites */
-#define TLS_NUM_CIPHER_SUITES \
- ( sizeof ( tls_cipher_suites ) / sizeof ( tls_cipher_suites[0] ) )
+#define TLS_NUM_CIPHER_SUITES table_num_entries ( TLS_CIPHER_SUITES )
/**
* Identify cipher suite
@@ -704,11 +678,9 @@ struct tls_cipher_suite tls_cipher_suites[] = {
static struct tls_cipher_suite *
tls_find_cipher_suite ( unsigned int cipher_suite ) {
struct tls_cipher_suite *suite;
- unsigned int i;
/* Identify cipher suite */
- for ( i = 0 ; i < TLS_NUM_CIPHER_SUITES ; i++ ) {
- suite = &tls_cipher_suites[i];
+ for_each_table_entry ( suite, TLS_CIPHER_SUITES ) {
if ( suite->code == cipher_suite )
return suite;
}
@@ -841,26 +813,9 @@ static int tls_change_cipher ( struct tls_session *tls,
******************************************************************************
*/
-/** Supported signature and hash algorithms
- *
- * Note that the default (TLSv1.1 and earlier) algorithm using
- * MD5+SHA1 is never explicitly specified.
- */
-struct tls_signature_hash_algorithm tls_signature_hash_algorithms[] = {
- {
- .code = {
- .signature = TLS_RSA_ALGORITHM,
- .hash = TLS_SHA256_ALGORITHM,
- },
- .pubkey = &rsa_algorithm,
- .digest = &sha256_algorithm,
- },
-};
-
/** Number of supported signature and hash algorithms */
-#define TLS_NUM_SIG_HASH_ALGORITHMS \
- ( sizeof ( tls_signature_hash_algorithms ) / \
- sizeof ( tls_signature_hash_algorithms[0] ) )
+#define TLS_NUM_SIG_HASH_ALGORITHMS \
+ table_num_entries ( TLS_SIG_HASH_ALGORITHMS )
/**
* Find TLS signature and hash algorithm
@@ -873,11 +828,9 @@ static struct tls_signature_hash_algorithm *
tls_signature_hash_algorithm ( struct pubkey_algorithm *pubkey,
struct digest_algorithm *digest ) {
struct tls_signature_hash_algorithm *sig_hash;
- unsigned int i;
/* Identify signature and hash algorithm */
- for ( i = 0 ; i < TLS_NUM_SIG_HASH_ALGORITHMS ; i++ ) {
- sig_hash = &tls_signature_hash_algorithms[i];
+ for_each_table_entry ( sig_hash, TLS_SIG_HASH_ALGORITHMS ) {
if ( ( sig_hash->pubkey == pubkey ) &&
( sig_hash->digest == digest ) ) {
return sig_hash;
@@ -994,8 +947,17 @@ static int tls_send_client_hello ( struct tls_session *tls ) {
struct {
uint8_t max;
} __attribute__ (( packed )) max_fragment_length;
+ uint16_t signature_algorithms_type;
+ uint16_t signature_algorithms_len;
+ struct {
+ uint16_t len;
+ struct tls_signature_hash_id
+ code[TLS_NUM_SIG_HASH_ALGORITHMS];
+ } __attribute__ (( packed )) signature_algorithms;
} __attribute__ (( packed )) extensions;
} __attribute__ (( packed )) hello;
+ struct tls_cipher_suite *suite;
+ struct tls_signature_hash_algorithm *sighash;
unsigned int i;
memset ( &hello, 0, sizeof ( hello ) );
@@ -1005,8 +967,8 @@ static int tls_send_client_hello ( struct tls_session *tls ) {
hello.version = htons ( tls->version );
memcpy ( &hello.random, &tls->client_random, sizeof ( hello.random ) );
hello.cipher_suite_len = htons ( sizeof ( hello.cipher_suites ) );
- for ( i = 0 ; i < TLS_NUM_CIPHER_SUITES ; i++ )
- hello.cipher_suites[i] = tls_cipher_suites[i].code;
+ i = 0 ; for_each_table_entry ( suite, TLS_CIPHER_SUITES )
+ hello.cipher_suites[i++] = suite->code;
hello.compression_methods_len = sizeof ( hello.compression_methods );
hello.extensions_len = htons ( sizeof ( hello.extensions ) );
hello.extensions.server_name_type = htons ( TLS_SERVER_NAME );
@@ -1025,6 +987,14 @@ static int tls_send_client_hello ( struct tls_session *tls ) {
= htons ( sizeof ( hello.extensions.max_fragment_length ) );
hello.extensions.max_fragment_length.max
= TLS_MAX_FRAGMENT_LENGTH_4096;
+ hello.extensions.signature_algorithms_type
+ = htons ( TLS_SIGNATURE_ALGORITHMS );
+ hello.extensions.signature_algorithms_len
+ = htons ( sizeof ( hello.extensions.signature_algorithms ) );
+ hello.extensions.signature_algorithms.len
+ = htons ( sizeof ( hello.extensions.signature_algorithms.code));
+ i = 0 ; for_each_table_entry ( sighash, TLS_SIG_HASH_ALGORITHMS )
+ hello.extensions.signature_algorithms.code[i++] = sighash->code;
return tls_send_handshake ( tls, &hello, sizeof ( hello ) );
}
@@ -1038,9 +1008,9 @@ static int tls_send_client_hello ( struct tls_session *tls ) {
static int tls_send_certificate ( struct tls_session *tls ) {
struct {
uint32_t type_length;
- uint8_t length[3];
+ tls24_t length;
struct {
- uint8_t length[3];
+ tls24_t length;
uint8_t data[ tls->cert->raw.len ];
} __attribute__ (( packed )) certificates[1];
} __attribute__ (( packed )) *certificate;
@@ -1058,9 +1028,9 @@ static int tls_send_certificate ( struct tls_session *tls ) {
( cpu_to_le32 ( TLS_CERTIFICATE ) |
htonl ( sizeof ( *certificate ) -
sizeof ( certificate->type_length ) ) );
- tls_set_uint24 ( certificate->length,
+ tls_set_uint24 ( &certificate->length,
sizeof ( certificate->certificates ) );
- tls_set_uint24 ( certificate->certificates[0].length,
+ tls_set_uint24 ( &certificate->certificates[0].length,
sizeof ( certificate->certificates[0].data ) );
memcpy ( certificate->certificates[0].data,
tls->cert->raw.data,
@@ -1412,7 +1382,7 @@ static int tls_parse_chain ( struct tls_session *tls,
const void *data, size_t len ) {
const void *end = ( data + len );
const struct {
- uint8_t length[3];
+ tls24_t length;
uint8_t data[0];
} __attribute__ (( packed )) *certificate;
size_t certificate_len;
@@ -1436,7 +1406,7 @@ static int tls_parse_chain ( struct tls_session *tls,
/* Extract raw certificate data */
certificate = data;
- certificate_len = tls_uint24 ( certificate->length );
+ certificate_len = tls_uint24 ( &certificate->length );
next = ( certificate->data + certificate_len );
if ( next > end ) {
DBGC ( tls, "TLS %p overlength certificate:\n", tls );
@@ -1482,10 +1452,10 @@ static int tls_parse_chain ( struct tls_session *tls,
static int tls_new_certificate ( struct tls_session *tls,
const void *data, size_t len ) {
const struct {
- uint8_t length[3];
+ tls24_t length;
uint8_t certificates[0];
} __attribute__ (( packed )) *certificate = data;
- size_t certificates_len = tls_uint24 ( certificate->length );
+ size_t certificates_len = tls_uint24 ( &certificate->length );
const void *end = ( certificate->certificates + certificates_len );
int rc;
@@ -1634,12 +1604,12 @@ static int tls_new_handshake ( struct tls_session *tls,
while ( data != end ) {
const struct {
uint8_t type;
- uint8_t length[3];
+ tls24_t length;
uint8_t payload[0];
} __attribute__ (( packed )) *handshake = data;
- void *payload = &handshake->payload;
- size_t payload_len = tls_uint24 ( handshake->length );
- void *next = ( payload + payload_len );
+ const void *payload = &handshake->payload;
+ size_t payload_len = tls_uint24 ( &handshake->length );
+ const void *next = ( payload + payload_len );
/* Sanity check */
if ( next > end ) {
@@ -2637,3 +2607,9 @@ int add_tls ( struct interface *xfer, const char *name,
err_alloc:
return rc;
}
+
+/* Drag in objects via add_tls() */
+REQUIRING_SYMBOL ( add_tls );
+
+/* Drag in crypto configuration */
+REQUIRE_OBJECT ( config_crypto );
diff --git a/roms/ipxe/src/net/udp.c b/roms/ipxe/src/net/udp.c
index 76da67ecf..0f7dfb24a 100644
--- a/roms/ipxe/src/net/udp.c
+++ b/roms/ipxe/src/net/udp.c
@@ -17,7 +17,7 @@
* UDP protocol
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* A UDP connection
diff --git a/roms/ipxe/src/net/udp/dhcp.c b/roms/ipxe/src/net/udp/dhcp.c
index 04fad04c2..aed5ee360 100644
--- a/roms/ipxe/src/net/udp/dhcp.c
+++ b/roms/ipxe/src/net/udp/dhcp.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <stdlib.h>
@@ -44,6 +48,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/dhcppkt.h>
#include <ipxe/dhcp_arch.h>
#include <ipxe/features.h>
+#include <config/dhcp.h>
/** @file
*
@@ -149,30 +154,32 @@ struct dhcp_session_state {
* @v dhcppkt DHCP packet
* @v peer Destination address
*/
- int ( * tx ) ( struct dhcp_session *dhcp,
- struct dhcp_packet *dhcppkt,
+ int ( * tx ) ( struct dhcp_session *dhcp, struct dhcp_packet *dhcppkt,
struct sockaddr_in *peer );
- /** Handle received packet
+ /**
+ * 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
+ * @v pseudo_id DHCP server pseudo-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
+ void ( * rx ) ( struct dhcp_session *dhcp, struct dhcp_packet *dhcppkt,
+ struct sockaddr_in *peer, uint8_t msgtype,
+ struct in_addr server_id, struct in_addr pseudo_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;
+ /** Timeout parameters */
+ uint8_t min_timeout_sec;
+ uint8_t max_timeout_sec;
};
static struct dhcp_session_state dhcp_state_discover;
@@ -272,9 +279,9 @@ static void dhcp_set_state ( struct dhcp_session *dhcp,
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;
+ set_timer_limits ( &dhcp->timer,
+ ( state->min_timeout_sec * TICKS_PER_SEC ),
+ ( state->max_timeout_sec * TICKS_PER_SEC ) );
start_timer_nodelay ( &dhcp->timer );
}
@@ -334,11 +341,13 @@ static int dhcp_discovery_tx ( struct dhcp_session *dhcp,
* @v peer DHCP server address
* @v msgtype DHCP message type
* @v server_id DHCP server ID
+ * @v pseudo_id DHCP server pseudo-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 server_id,
+ struct in_addr pseudo_id ) {
struct in_addr ip;
char vci[9]; /* "PXEClient" */
int vci_len;
@@ -350,8 +359,11 @@ static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
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 ) );
+ if ( ( server_id.s_addr != peer->sin_addr.s_addr ) ||
+ ( pseudo_id.s_addr != peer->sin_addr.s_addr ) ) {
+ DBGC ( dhcp, " (%s/", inet_ntoa ( server_id ) );
+ DBGC ( dhcp, "%s)", inet_ntoa ( pseudo_id ) );
+ }
/* Identify offered IP address */
ip = dhcppkt->dhcphdr->yiaddr;
@@ -392,10 +404,10 @@ static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
}
/* Select as ProxyDHCP offer, if applicable */
- if ( server_id.s_addr && has_pxeclient &&
+ if ( pseudo_id.s_addr && has_pxeclient &&
( priority >= dhcp->proxy_priority ) ) {
dhcppkt_put ( dhcp->proxy_offer );
- dhcp->proxy_server = server_id;
+ dhcp->proxy_server = pseudo_id;
dhcp->proxy_offer = dhcppkt_get ( dhcppkt );
dhcp->proxy_priority = priority;
}
@@ -415,7 +427,7 @@ static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
/* If we can't yet transition to DHCPREQUEST, do nothing */
elapsed = ( currticks() - dhcp->start );
if ( ! ( dhcp->no_pxedhcp || dhcp->proxy_offer ||
- ( elapsed > PROXYDHCP_MAX_TIMEOUT ) ) )
+ ( elapsed > DHCP_DISC_PROXY_TIMEOUT_SEC * TICKS_PER_SEC ) ) )
return;
/* Transition to DHCPREQUEST */
@@ -430,8 +442,18 @@ static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
static void dhcp_discovery_expired ( struct dhcp_session *dhcp ) {
unsigned long elapsed = ( currticks() - dhcp->start );
+ /* If link is blocked, defer DHCP discovery (and reset timeout) */
+ if ( netdev_link_blocked ( dhcp->netdev ) ) {
+ DBGC ( dhcp, "DHCP %p deferring discovery\n", dhcp );
+ start_timer_fixed ( &dhcp->timer,
+ ( DHCP_DISC_START_TIMEOUT_SEC *
+ TICKS_PER_SEC ) );
+ return;
+ }
+
/* Give up waiting for ProxyDHCP before we reach the failure point */
- if ( dhcp->offer.s_addr && ( elapsed > PROXYDHCP_MAX_TIMEOUT ) ) {
+ if ( dhcp->offer.s_addr &&
+ ( elapsed > DHCP_DISC_PROXY_TIMEOUT_SEC * TICKS_PER_SEC ) ) {
dhcp_set_state ( dhcp, &dhcp_state_request );
return;
}
@@ -447,7 +469,8 @@ static struct dhcp_session_state dhcp_state_discover = {
.rx = dhcp_discovery_rx,
.expired = dhcp_discovery_expired,
.tx_msgtype = DHCPDISCOVER,
- .apply_min_timeout = 1,
+ .min_timeout_sec = DHCP_DISC_START_TIMEOUT_SEC,
+ .max_timeout_sec = DHCP_DISC_END_TIMEOUT_SEC,
};
/**
@@ -493,11 +516,13 @@ static int dhcp_request_tx ( struct dhcp_session *dhcp,
* @v peer DHCP server address
* @v msgtype DHCP message type
* @v server_id DHCP server ID
+ * @v pseudo_id DHCP server pseudo-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 server_id,
+ struct in_addr pseudo_id ) {
struct in_addr ip;
struct settings *parent;
struct settings *settings;
@@ -506,8 +531,11 @@ static void dhcp_request_rx ( struct dhcp_session *dhcp,
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 ) );
+ if ( ( server_id.s_addr != peer->sin_addr.s_addr ) ||
+ ( pseudo_id.s_addr != peer->sin_addr.s_addr ) ) {
+ DBGC ( dhcp, " (%s/", inet_ntoa ( server_id ) );
+ DBGC ( dhcp, "%s)", inet_ntoa ( pseudo_id ) );
+ }
/* Identify leased IP address */
ip = dhcppkt->dhcphdr->yiaddr;
@@ -584,7 +612,8 @@ static struct dhcp_session_state dhcp_state_request = {
.rx = dhcp_request_rx,
.expired = dhcp_request_expired,
.tx_msgtype = DHCPREQUEST,
- .apply_min_timeout = 0,
+ .min_timeout_sec = DHCP_REQ_START_TIMEOUT_SEC,
+ .max_timeout_sec = DHCP_REQ_END_TIMEOUT_SEC,
};
/**
@@ -623,19 +652,26 @@ static int dhcp_proxy_tx ( struct dhcp_session *dhcp,
* @v peer DHCP server address
* @v msgtype DHCP message type
* @v server_id DHCP server ID
+ * @v pseudo_id DHCP server pseudo-ID
*/
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 ) {
+ struct in_addr server_id,
+ struct in_addr pseudo_id ) {
struct settings *settings = &dhcppkt->settings;
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 ) );
+ if ( ( server_id.s_addr != peer->sin_addr.s_addr ) ||
+ ( pseudo_id.s_addr != peer->sin_addr.s_addr ) ) {
+ DBGC ( dhcp, " (%s/", inet_ntoa ( server_id ) );
+ DBGC ( dhcp, "%s)", inet_ntoa ( pseudo_id ) );
+ }
+ if ( dhcp_has_pxeopts ( dhcppkt ) )
+ DBGC ( dhcp, " pxe" );
DBGC ( dhcp, "\n" );
/* Filter out unacceptable responses */
@@ -643,8 +679,9 @@ static void dhcp_proxy_rx ( struct dhcp_session *dhcp,
return;
if ( ( msgtype != DHCPOFFER ) && ( msgtype != DHCPACK ) )
return;
- if ( server_id.s_addr /* Linux PXE server omits server ID */ &&
- ( server_id.s_addr != dhcp->proxy_server.s_addr ) )
+ if ( ( pseudo_id.s_addr != dhcp->proxy_server.s_addr ) )
+ return;
+ if ( ! dhcp_has_pxeopts ( dhcppkt ) )
return;
/* Register settings */
@@ -669,7 +706,7 @@ static void dhcp_proxy_expired ( struct dhcp_session *dhcp ) {
unsigned long elapsed = ( currticks() - dhcp->start );
/* Give up waiting for ProxyDHCP before we reach the failure point */
- if ( elapsed > PROXYDHCP_MAX_TIMEOUT ) {
+ if ( elapsed > DHCP_REQ_PROXY_TIMEOUT_SEC * TICKS_PER_SEC ) {
dhcp_finished ( dhcp, 0 );
return;
}
@@ -685,7 +722,8 @@ static struct dhcp_session_state dhcp_state_proxy = {
.rx = dhcp_proxy_rx,
.expired = dhcp_proxy_expired,
.tx_msgtype = DHCPREQUEST,
- .apply_min_timeout = 0,
+ .min_timeout_sec = DHCP_PROXY_START_TIMEOUT_SEC,
+ .max_timeout_sec = DHCP_PROXY_END_TIMEOUT_SEC,
};
/**
@@ -753,19 +791,24 @@ static int dhcp_pxebs_accept ( struct dhcp_session *dhcp,
* @v peer DHCP server address
* @v msgtype DHCP message type
* @v server_id DHCP server ID
+ * @v pseudo_id DHCP server pseudo-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 in_addr server_id,
+ struct in_addr pseudo_id ) {
struct dhcp_pxe_boot_menu_item menu_item = { 0, 0 };
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 ) );
+ if ( ( server_id.s_addr != peer->sin_addr.s_addr ) ||
+ ( pseudo_id.s_addr != peer->sin_addr.s_addr ) ) {
+ DBGC ( dhcp, " (%s/", inet_ntoa ( server_id ) );
+ DBGC ( dhcp, "%s)", inet_ntoa ( pseudo_id ) );
+ }
/* Identify boot menu item */
dhcppkt_fetch ( dhcppkt, DHCP_PXE_BOOT_MENU_ITEM,
@@ -782,8 +825,7 @@ static void dhcp_pxebs_rx ( struct dhcp_session *dhcp,
return;
if ( menu_item.type != dhcp->pxe_type )
return;
- if ( ! dhcp_pxebs_accept ( dhcp, ( server_id.s_addr ?
- server_id : peer->sin_addr ) ) )
+ if ( ! dhcp_pxebs_accept ( dhcp, pseudo_id ) )
return;
/* Register settings */
@@ -810,7 +852,7 @@ static void dhcp_pxebs_expired ( struct dhcp_session *dhcp ) {
/* 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 ) {
+ if ( elapsed > PXEBS_MAX_TIMEOUT_SEC * TICKS_PER_SEC ) {
dhcp->pxe_attempt++;
if ( dhcp->pxe_attempt->s_addr ) {
dhcp_set_state ( dhcp, &dhcp_state_pxebs );
@@ -832,7 +874,8 @@ static struct dhcp_session_state dhcp_state_pxebs = {
.rx = dhcp_pxebs_rx,
.expired = dhcp_pxebs_expired,
.tx_msgtype = DHCPREQUEST,
- .apply_min_timeout = 1,
+ .min_timeout_sec = PXEBS_START_TIMEOUT_SEC,
+ .max_timeout_sec = PXEBS_END_TIMEOUT_SEC,
};
/****************************************************************************
@@ -1114,6 +1157,7 @@ static int dhcp_deliver ( struct dhcp_session *dhcp,
struct dhcphdr *dhcphdr;
uint8_t msgtype = 0;
struct in_addr server_id = { 0 };
+ struct in_addr pseudo_id;
int rc = 0;
/* Sanity checks */
@@ -1148,6 +1192,13 @@ static int dhcp_deliver ( struct dhcp_session *dhcp,
dhcppkt_fetch ( dhcppkt, DHCP_SERVER_IDENTIFIER,
&server_id, sizeof ( server_id ) );
+ /* Identify server pseudo-ID */
+ pseudo_id = server_id;
+ if ( ! pseudo_id.s_addr )
+ pseudo_id = dhcppkt->dhcphdr->siaddr;
+ if ( ! pseudo_id.s_addr )
+ pseudo_id = peer->sin_addr;
+
/* Check for matching transaction ID */
if ( dhcphdr->xid != dhcp->xid ) {
DBGC ( dhcp, "DHCP %p %s from %s:%d has bad transaction "
@@ -1170,7 +1221,7 @@ static int dhcp_deliver ( struct dhcp_session *dhcp,
}
/* Handle packet based on current state */
- dhcp->state->rx ( dhcp, dhcppkt, peer, msgtype, server_id );
+ dhcp->state->rx ( dhcp, dhcppkt, peer, msgtype, server_id, pseudo_id );
err_chaddr:
err_xid:
diff --git a/roms/ipxe/src/net/udp/dhcpv6.c b/roms/ipxe/src/net/udp/dhcpv6.c
index f7736d08e..a63543775 100644
--- a/roms/ipxe/src/net/udp/dhcpv6.c
+++ b/roms/ipxe/src/net/udp/dhcpv6.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdlib.h>
#include <stdio.h>
diff --git a/roms/ipxe/src/net/udp/dns.c b/roms/ipxe/src/net/udp/dns.c
index fffe6e697..2d77477f6 100644
--- a/roms/ipxe/src/net/udp/dns.c
+++ b/roms/ipxe/src/net/udp/dns.c
@@ -18,9 +18,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/net/udp/slam.c b/roms/ipxe/src/net/udp/slam.c
index 3cb492d73..8b26bfb3c 100644
--- a/roms/ipxe/src/net/udp/slam.c
+++ b/roms/ipxe/src/net/udp/slam.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/net/udp/syslog.c b/roms/ipxe/src/net/udp/syslog.c
index d65d19ab8..b6eee6036 100644
--- a/roms/ipxe/src/net/udp/syslog.c
+++ b/roms/ipxe/src/net/udp/syslog.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/net/udp/tftp.c b/roms/ipxe/src/net/udp/tftp.c
index ee827ae3d..953bcb46a 100644
--- a/roms/ipxe/src/net/udp/tftp.c
+++ b/roms/ipxe/src/net/udp/tftp.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
@@ -149,8 +153,6 @@ enum {
TFTP_FL_RRQ_MULTICAST = 0x0004,
/** Perform MTFTP recovery on timeout */
TFTP_FL_MTFTP_RECOVERY = 0x0008,
- /** Only get filesize and then abort the transfer */
- TFTP_FL_SIZEONLY = 0x0010,
};
/** Maximum number of MTFTP open requests before falling back to TFTP */
@@ -759,14 +761,6 @@ static int tftp_rx_oack ( struct tftp_request *tftp, void *buf, size_t len ) {
goto done;
}
- /* Abort request if only trying to determine file size */
- if ( tftp->flags & TFTP_FL_SIZEONLY ) {
- rc = 0;
- tftp_send_error ( tftp, 0, "TFTP Aborted" );
- tftp_done ( tftp, rc );
- return rc;
- }
-
/* Request next data block */
tftp_send_packet ( tftp );
@@ -794,13 +788,6 @@ static int tftp_rx_data ( struct tftp_request *tftp,
size_t data_len;
int rc;
- if ( tftp->flags & TFTP_FL_SIZEONLY ) {
- /* If we get here then server doesn't support SIZE option */
- rc = -ENOTSUP;
- tftp_send_error ( tftp, 0, "TFTP Aborted" );
- goto done;
- }
-
/* Sanity check */
if ( iob_len ( iobuf ) < sizeof ( *data ) ) {
DBGC ( tftp, "TFTP %p received underlength DATA packet "
@@ -1036,10 +1023,25 @@ static size_t tftp_xfer_window ( struct tftp_request *tftp ) {
return tftp->blksize;
}
+/**
+ * Terminate download
+ *
+ * @v tftp TFTP connection
+ * @v rc Reason for close
+ */
+static void tftp_close ( struct tftp_request *tftp, int rc ) {
+
+ /* Abort download */
+ tftp_send_error ( tftp, 0, "TFTP Aborted" );
+
+ /* Close TFTP request */
+ tftp_done ( tftp, rc );
+}
+
/** TFTP data transfer interface operations */
static struct interface_operation tftp_xfer_operations[] = {
INTF_OP ( xfer_window, struct tftp_request *, tftp_xfer_window ),
- INTF_OP ( intf_close, struct tftp_request *, tftp_done ),
+ INTF_OP ( intf_close, struct tftp_request *, tftp_close ),
};
/** TFTP data transfer interface descriptor */
@@ -1126,26 +1128,6 @@ struct uri_opener tftp_uri_opener __uri_opener = {
};
/**
- * Initiate TFTP-size request
- *
- * @v xfer Data transfer interface
- * @v uri Uniform Resource Identifier
- * @ret rc Return status code
- */
-static int tftpsize_open ( struct interface *xfer, struct uri *uri ) {
- return tftp_core_open ( xfer, uri, TFTP_PORT, NULL,
- ( TFTP_FL_RRQ_SIZES |
- TFTP_FL_SIZEONLY ) );
-
-}
-
-/** TFTP URI opener */
-struct uri_opener tftpsize_uri_opener __uri_opener = {
- .scheme = "tftpsize",
- .open = tftpsize_open,
-};
-
-/**
* Initiate TFTM download
*
* @v xfer Data transfer interface
diff --git a/roms/ipxe/src/net/validator.c b/roms/ipxe/src/net/validator.c
index 74d70e312..db968398a 100644
--- a/roms/ipxe/src/net/validator.c
+++ b/roms/ipxe/src/net/validator.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <stdio.h>
@@ -79,7 +83,7 @@ static void validator_free ( struct refcnt *refcnt ) {
DBGC2 ( validator, "VALIDATOR %p freed\n", validator );
x509_chain_put ( validator->chain );
ocsp_put ( validator->ocsp );
- xferbuf_done ( &validator->buffer );
+ xferbuf_free ( &validator->buffer );
free ( validator );
}
@@ -250,7 +254,8 @@ static int validator_start_download ( struct validator *validator,
/* Generate URI string */
len = snprintf ( uri_string, uri_string_len, "%s/%08x.der?subject=",
crosscert, crc );
- base64_encode ( issuer->data, issuer->len, ( uri_string + len ) );
+ base64_encode ( issuer->data, issuer->len, ( uri_string + len ),
+ ( uri_string_len - len ) );
DBGC ( validator, "VALIDATOR %p downloading cross-signed certificate "
"from %s\n", validator, uri_string );
@@ -387,7 +392,7 @@ static void validator_xfer_close ( struct validator *validator, int rc ) {
goto err_append;
/* Free downloaded data */
- xferbuf_done ( &validator->buffer );
+ xferbuf_free ( &validator->buffer );
/* Resume validation process */
process_add ( &validator->process );
@@ -552,6 +557,7 @@ int create_validator ( struct interface *job, struct x509_chain *chain ) {
process_init ( &validator->process, &validator_process_desc,
&validator->refcnt );
validator->chain = x509_chain_get ( chain );
+ xferbuf_malloc_init ( &validator->buffer );
/* Attach parent interface, mortalise self, and return */
intf_plug_plug ( &validator->job, job );
diff --git a/roms/ipxe/src/net/vlan.c b/roms/ipxe/src/net/vlan.c
index b4ddde42d..f515c2dc9 100644
--- a/roms/ipxe/src/net/vlan.c
+++ b/roms/ipxe/src/net/vlan.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <string.h>
@@ -385,6 +389,10 @@ int vlan_create ( struct net_device *trunk, unsigned int tag,
snprintf ( netdev->name, sizeof ( netdev->name ), "%s-%d",
trunk->name, vlan->tag );
+ /* Mark device as not supporting interrupts, if applicable */
+ if ( ! netdev_irq_supported ( trunk ) )
+ netdev->state |= NETDEV_IRQ_UNSUPPORTED;
+
/* Register VLAN device */
if ( ( rc = register_netdev ( netdev ) ) != 0 ) {
DBGC ( netdev, "VLAN %s could not register: %s\n",
diff --git a/roms/ipxe/src/tests/aes_cbc_test.c b/roms/ipxe/src/tests/aes_cbc_test.c
deleted file mode 100644
index 4ae3a92e5..000000000
--- a/roms/ipxe/src/tests/aes_cbc_test.c
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-/** @file
- *
- * AES-in-CBC-mode tests
- *
- * These test vectors are provided by NIST as part of the
- * Cryptographic Toolkit Examples, downloadable from:
- *
- * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/AES_CBC.pdf
- *
- */
-
-/* Forcibly enable assertions */
-#undef NDEBUG
-
-#include <assert.h>
-#include <string.h>
-#include <ipxe/aes.h>
-#include <ipxe/test.h>
-#include "cbc_test.h"
-
-/** Define inline key */
-#define KEY(...) { __VA_ARGS__ }
-
-/** Define inline initialisation vector */
-#define IV(...) { __VA_ARGS__ }
-
-/** Define inline plaintext data */
-#define PLAINTEXT(...) { __VA_ARGS__ }
-
-/** Define inline ciphertext data */
-#define CIPHERTEXT(...) { __VA_ARGS__ }
-
-/** An AES-in-CBC-mode test */
-struct aes_cbc_test {
- /** Key */
- const void *key;
- /** Length of key */
- size_t key_len;
- /** Initialisation vector */
- const void *iv;
- /** Length of initialisation vector */
- size_t iv_len;
- /** Plaintext */
- const void *plaintext;
- /** Length of plaintext */
- size_t plaintext_len;
- /** Ciphertext */
- const void *ciphertext;
- /** Length of ciphertext */
- size_t ciphertext_len;
-};
-
-/**
- * Define an AES-in-CBC-mode test
- *
- * @v name Test name
- * @v key_array Key
- * @v iv_array Initialisation vector
- * @v plaintext_array Plaintext
- * @v ciphertext_array Ciphertext
- * @ret test AES-in-CBC-mode test
- */
-#define AES_CBC_TEST( name, key_array, iv_array, plaintext_array, \
- ciphertext_array ) \
- static const uint8_t name ## _key [] = key_array; \
- static const uint8_t name ## _iv [] = iv_array; \
- static const uint8_t name ## _plaintext [] = plaintext_array; \
- static const uint8_t name ## _ciphertext [] = ciphertext_array; \
- static struct aes_cbc_test name = { \
- .key = name ## _key, \
- .key_len = sizeof ( name ## _key ), \
- .iv = name ## _iv, \
- .iv_len = sizeof ( name ## _iv ), \
- .plaintext = name ## _plaintext, \
- .plaintext_len = sizeof ( name ## _plaintext ), \
- .ciphertext = name ## _ciphertext, \
- .ciphertext_len = sizeof ( name ## _ciphertext ), \
- }
-
-/**
- * Report AES-in-CBC-mode
- *
- * @v state HMAC_DRBG internal state
- * @v test Instantiation test
- */
-#define aes_cbc_ok( test ) do { \
- struct cipher_algorithm *cipher = &aes_cbc_algorithm; \
- \
- assert ( (test)->iv_len == cipher->blocksize ); \
- assert ( (test)->plaintext_len == (test)->ciphertext_len ); \
- cbc_encrypt_ok ( cipher, (test)->key, (test)->key_len, \
- (test)->iv, (test)->plaintext, \
- (test)->ciphertext, (test)->plaintext_len ); \
- cbc_decrypt_ok ( cipher, (test)->key, (test)->key_len, \
- (test)->iv, (test)->ciphertext, \
- (test)->plaintext, (test)->ciphertext_len ); \
- } while ( 0 )
-
-/** CBC_AES128 */
-AES_CBC_TEST ( test_128,
- KEY ( 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15,
- 0x88, 0x09, 0xcf, 0x4f, 0x3c ),
- IV ( 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
- 0x0b, 0x0c, 0x0d, 0x0e, 0x0f ),
- PLAINTEXT ( 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
- 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
- 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
- 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
- 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
- 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
- 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
- 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 ),
- CIPHERTEXT ( 0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46,
- 0xce, 0xe9, 0x8e, 0x9b, 0x12, 0xe9, 0x19, 0x7d,
- 0x50, 0x86, 0xcb, 0x9b, 0x50, 0x72, 0x19, 0xee,
- 0x95, 0xdb, 0x11, 0x3a, 0x91, 0x76, 0x78, 0xb2,
- 0x73, 0xbe, 0xd6, 0xb8, 0xe3, 0xc1, 0x74, 0x3b,
- 0x71, 0x16, 0xe6, 0x9e, 0x22, 0x22, 0x95, 0x16,
- 0x3f, 0xf1, 0xca, 0xa1, 0x68, 0x1f, 0xac, 0x09,
- 0x12, 0x0e, 0xca, 0x30, 0x75, 0x86, 0xe1, 0xa7 ) );
-
-/** CBC_AES256 */
-AES_CBC_TEST ( test_256,
- KEY ( 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae,
- 0xf0, 0x85, 0x7d, 0x77, 0x81, 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61,
- 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4 ),
- IV ( 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
- 0x0b, 0x0c, 0x0d, 0x0e, 0x0f ),
- PLAINTEXT ( 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
- 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
- 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
- 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
- 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
- 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
- 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
- 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 ),
- CIPHERTEXT ( 0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba,
- 0x77, 0x9e, 0xab, 0xfb, 0x5f, 0x7b, 0xfb, 0xd6,
- 0x9c, 0xfc, 0x4e, 0x96, 0x7e, 0xdb, 0x80, 0x8d,
- 0x67, 0x9f, 0x77, 0x7b, 0xc6, 0x70, 0x2c, 0x7d,
- 0x39, 0xf2, 0x33, 0x69, 0xa9, 0xd9, 0xba, 0xcf,
- 0xa5, 0x30, 0xe2, 0x63, 0x04, 0x23, 0x14, 0x61,
- 0xb2, 0xeb, 0x05, 0xe2, 0xc3, 0x9b, 0xe9, 0xfc,
- 0xda, 0x6c, 0x19, 0x07, 0x8c, 0x6a, 0x9d, 0x1b ) );
-
-/**
- * Perform AES-in-CBC-mode self-test
- *
- */
-static void aes_cbc_test_exec ( void ) {
- struct cipher_algorithm *cipher = &aes_cbc_algorithm;
-
- /* Correctness tests */
- aes_cbc_ok ( &test_128 );
- aes_cbc_ok ( &test_256 );
-
- /* Speed tests */
- DBG ( "AES128 encryption required %ld cycles per byte\n",
- cbc_cost_encrypt ( cipher, test_128.key_len ) );
- DBG ( "AES128 decryption required %ld cycles per byte\n",
- cbc_cost_decrypt ( cipher, test_128.key_len ) );
- DBG ( "AES256 encryption required %ld cycles per byte\n",
- cbc_cost_encrypt ( cipher, test_256.key_len ) );
- DBG ( "AES256 decryption required %ld cycles per byte\n",
- cbc_cost_decrypt ( cipher, test_256.key_len ) );
-}
-
-/** AES-in-CBC-mode self-test */
-struct self_test aes_cbc_test __self_test = {
- .name = "aes_cbc",
- .exec = aes_cbc_test_exec,
-};
diff --git a/roms/ipxe/src/tests/aes_test.c b/roms/ipxe/src/tests/aes_test.c
new file mode 100644
index 000000000..ad66c734c
--- /dev/null
+++ b/roms/ipxe/src/tests/aes_test.c
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/** @file
+ *
+ * AES tests
+ *
+ * These test vectors are provided by NIST as part of the
+ * Cryptographic Toolkit Examples, downloadable from:
+ *
+ * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/AES_Core_All.pdf
+ * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/AES_ECB.pdf
+ * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/AES_CBC.pdf
+ *
+ */
+
+/* Forcibly enable assertions */
+#undef NDEBUG
+
+#include <assert.h>
+#include <string.h>
+#include <ipxe/aes.h>
+#include <ipxe/test.h>
+#include "cipher_test.h"
+
+/** Key used for NIST 128-bit test vectors */
+#define AES_KEY_NIST_128 \
+ KEY ( 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, \
+ 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c )
+
+/** Key used for NIST 192-bit test vectors */
+#define AES_KEY_NIST_192 \
+ KEY ( 0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, 0xc8, \
+ 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5, 0x62, 0xf8, \
+ 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b )
+
+/** Key used for NIST 256-bit test vectors */
+#define AES_KEY_NIST_256 \
+ KEY ( 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, \
+ 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, 0x1f, 0x35, \
+ 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, \
+ 0xa3, 0x09, 0x14, 0xdf, 0xf4 )
+
+/** Dummy initialisation vector used for NIST ECB-mode test vectors */
+#define AES_IV_NIST_DUMMY \
+ IV ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 )
+
+/** Initialisation vector used for NIST CBC-mode test vectors */
+#define AES_IV_NIST_CBC \
+ IV ( 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, \
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f )
+
+/** Plaintext used for NIST test vectors */
+#define AES_PLAINTEXT_NIST \
+ PLAINTEXT ( 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, \
+ 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, \
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, \
+ 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, \
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, \
+ 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, \
+ 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, \
+ 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 )
+
+/** AES-128-ECB (same test as AES-128-Core) */
+CIPHER_TEST ( aes_128_ecb, &aes_ecb_algorithm,
+ AES_KEY_NIST_128, AES_IV_NIST_DUMMY, AES_PLAINTEXT_NIST,
+ CIPHERTEXT ( 0x3a, 0xd7, 0x7b, 0xb4, 0x0d, 0x7a, 0x36, 0x60,
+ 0xa8, 0x9e, 0xca, 0xf3, 0x24, 0x66, 0xef, 0x97,
+ 0xf5, 0xd3, 0xd5, 0x85, 0x03, 0xb9, 0x69, 0x9d,
+ 0xe7, 0x85, 0x89, 0x5a, 0x96, 0xfd, 0xba, 0xaf,
+ 0x43, 0xb1, 0xcd, 0x7f, 0x59, 0x8e, 0xce, 0x23,
+ 0x88, 0x1b, 0x00, 0xe3, 0xed, 0x03, 0x06, 0x88,
+ 0x7b, 0x0c, 0x78, 0x5e, 0x27, 0xe8, 0xad, 0x3f,
+ 0x82, 0x23, 0x20, 0x71, 0x04, 0x72, 0x5d, 0xd4 ) );
+
+/** AES-128-CBC */
+CIPHER_TEST ( aes_128_cbc, &aes_cbc_algorithm,
+ AES_KEY_NIST_128, AES_IV_NIST_CBC, AES_PLAINTEXT_NIST,
+ CIPHERTEXT ( 0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46,
+ 0xce, 0xe9, 0x8e, 0x9b, 0x12, 0xe9, 0x19, 0x7d,
+ 0x50, 0x86, 0xcb, 0x9b, 0x50, 0x72, 0x19, 0xee,
+ 0x95, 0xdb, 0x11, 0x3a, 0x91, 0x76, 0x78, 0xb2,
+ 0x73, 0xbe, 0xd6, 0xb8, 0xe3, 0xc1, 0x74, 0x3b,
+ 0x71, 0x16, 0xe6, 0x9e, 0x22, 0x22, 0x95, 0x16,
+ 0x3f, 0xf1, 0xca, 0xa1, 0x68, 0x1f, 0xac, 0x09,
+ 0x12, 0x0e, 0xca, 0x30, 0x75, 0x86, 0xe1, 0xa7 ) );
+
+/** AES-192-ECB (same test as AES-192-Core) */
+CIPHER_TEST ( aes_192_ecb, &aes_ecb_algorithm,
+ AES_KEY_NIST_192, AES_IV_NIST_DUMMY, AES_PLAINTEXT_NIST,
+ CIPHERTEXT ( 0xbd, 0x33, 0x4f, 0x1d, 0x6e, 0x45, 0xf2, 0x5f,
+ 0xf7, 0x12, 0xa2, 0x14, 0x57, 0x1f, 0xa5, 0xcc,
+ 0x97, 0x41, 0x04, 0x84, 0x6d, 0x0a, 0xd3, 0xad,
+ 0x77, 0x34, 0xec, 0xb3, 0xec, 0xee, 0x4e, 0xef,
+ 0xef, 0x7a, 0xfd, 0x22, 0x70, 0xe2, 0xe6, 0x0a,
+ 0xdc, 0xe0, 0xba, 0x2f, 0xac, 0xe6, 0x44, 0x4e,
+ 0x9a, 0x4b, 0x41, 0xba, 0x73, 0x8d, 0x6c, 0x72,
+ 0xfb, 0x16, 0x69, 0x16, 0x03, 0xc1, 0x8e, 0x0e ) );
+
+/** AES-192-CBC */
+CIPHER_TEST ( aes_192_cbc, &aes_cbc_algorithm,
+ AES_KEY_NIST_192, AES_IV_NIST_CBC, AES_PLAINTEXT_NIST,
+ CIPHERTEXT ( 0x4f, 0x02, 0x1d, 0xb2, 0x43, 0xbc, 0x63, 0x3d,
+ 0x71, 0x78, 0x18, 0x3a, 0x9f, 0xa0, 0x71, 0xe8,
+ 0xb4, 0xd9, 0xad, 0xa9, 0xad, 0x7d, 0xed, 0xf4,
+ 0xe5, 0xe7, 0x38, 0x76, 0x3f, 0x69, 0x14, 0x5a,
+ 0x57, 0x1b, 0x24, 0x20, 0x12, 0xfb, 0x7a, 0xe0,
+ 0x7f, 0xa9, 0xba, 0xac, 0x3d, 0xf1, 0x02, 0xe0,
+ 0x08, 0xb0, 0xe2, 0x79, 0x88, 0x59, 0x88, 0x81,
+ 0xd9, 0x20, 0xa9, 0xe6, 0x4f, 0x56, 0x15, 0xcd ) );
+
+/** AES-256-ECB (same test as AES-256-Core) */
+CIPHER_TEST ( aes_256_ecb, &aes_ecb_algorithm,
+ AES_KEY_NIST_256, AES_IV_NIST_DUMMY, AES_PLAINTEXT_NIST,
+ CIPHERTEXT ( 0xf3, 0xee, 0xd1, 0xbd, 0xb5, 0xd2, 0xa0, 0x3c,
+ 0x06, 0x4b, 0x5a, 0x7e, 0x3d, 0xb1, 0x81, 0xf8,
+ 0x59, 0x1c, 0xcb, 0x10, 0xd4, 0x10, 0xed, 0x26,
+ 0xdc, 0x5b, 0xa7, 0x4a, 0x31, 0x36, 0x28, 0x70,
+ 0xb6, 0xed, 0x21, 0xb9, 0x9c, 0xa6, 0xf4, 0xf9,
+ 0xf1, 0x53, 0xe7, 0xb1, 0xbe, 0xaf, 0xed, 0x1d,
+ 0x23, 0x30, 0x4b, 0x7a, 0x39, 0xf9, 0xf3, 0xff,
+ 0x06, 0x7d, 0x8d, 0x8f, 0x9e, 0x24, 0xec, 0xc7 ) );
+
+/** AES-256-CBC */
+CIPHER_TEST ( aes_256_cbc, &aes_cbc_algorithm,
+ AES_KEY_NIST_256, AES_IV_NIST_CBC, AES_PLAINTEXT_NIST,
+ CIPHERTEXT ( 0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba,
+ 0x77, 0x9e, 0xab, 0xfb, 0x5f, 0x7b, 0xfb, 0xd6,
+ 0x9c, 0xfc, 0x4e, 0x96, 0x7e, 0xdb, 0x80, 0x8d,
+ 0x67, 0x9f, 0x77, 0x7b, 0xc6, 0x70, 0x2c, 0x7d,
+ 0x39, 0xf2, 0x33, 0x69, 0xa9, 0xd9, 0xba, 0xcf,
+ 0xa5, 0x30, 0xe2, 0x63, 0x04, 0x23, 0x14, 0x61,
+ 0xb2, 0xeb, 0x05, 0xe2, 0xc3, 0x9b, 0xe9, 0xfc,
+ 0xda, 0x6c, 0x19, 0x07, 0x8c, 0x6a, 0x9d, 0x1b ) );
+
+/**
+ * Perform AES self-test
+ *
+ */
+static void aes_test_exec ( void ) {
+ struct cipher_algorithm *ecb = &aes_ecb_algorithm;
+ struct cipher_algorithm *cbc = &aes_cbc_algorithm;
+ unsigned int keylen;
+
+ /* Correctness tests */
+ cipher_ok ( &aes_128_ecb );
+ cipher_ok ( &aes_128_cbc );
+ cipher_ok ( &aes_192_ecb );
+ cipher_ok ( &aes_192_cbc );
+ cipher_ok ( &aes_256_ecb );
+ cipher_ok ( &aes_256_cbc );
+
+ /* Speed tests */
+ for ( keylen = 128 ; keylen <= 256 ; keylen += 64 ) {
+ DBG ( "AES-%d-ECB encryption required %ld cycles per byte\n",
+ keylen, cipher_cost_encrypt ( ecb, ( keylen / 8 ) ) );
+ DBG ( "AES-%d-ECB decryption required %ld cycles per byte\n",
+ keylen, cipher_cost_decrypt ( ecb, ( keylen / 8 ) ) );
+ DBG ( "AES-%d-CBC encryption required %ld cycles per byte\n",
+ keylen, cipher_cost_encrypt ( cbc, ( keylen / 8 ) ) );
+ DBG ( "AES-%d-CBC decryption required %ld cycles per byte\n",
+ keylen, cipher_cost_decrypt ( cbc, ( keylen / 8 ) ) );
+ }
+}
+
+/** AES self-test */
+struct self_test aes_test __self_test = {
+ .name = "aes",
+ .exec = aes_test_exec,
+};
diff --git a/roms/ipxe/src/tests/base16_test.c b/roms/ipxe/src/tests/base16_test.c
index 9b047b74c..46884aef7 100644
--- a/roms/ipxe/src/tests/base16_test.c
+++ b/roms/ipxe/src/tests/base16_test.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
@@ -73,30 +77,42 @@ BASE16 ( random_test,
* Report a base16 encoding test result
*
* @v test Base16 test
+ * @v file Test code file
+ * @v line Test code line
*/
-#define base16_encode_ok( test ) do { \
- size_t len = base16_encoded_len ( (test)->len ); \
- char buf[ len + 1 /* NUL */ ]; \
- ok ( len == strlen ( (test)->encoded ) ); \
- base16_encode ( (test)->data, (test)->len, buf ); \
- ok ( strcmp ( (test)->encoded, buf ) == 0 ); \
- } while ( 0 )
+static void base16_encode_okx ( struct base16_test *test, const char *file,
+ unsigned int line ) {
+ size_t len = base16_encoded_len ( test->len );
+ char buf[ len + 1 /* NUL */ ];
+ size_t check_len;
+
+ okx ( len == strlen ( test->encoded ), file, line );
+ check_len = base16_encode ( test->data, test->len, buf, sizeof ( buf ));
+ okx ( check_len == len, file, line );
+ okx ( strcmp ( test->encoded, buf ) == 0, file, line );
+}
+#define base16_encode_ok( test ) base16_encode_okx ( test, __FILE__, __LINE__ )
/**
* Report a base16 decoding test result
*
* @v test Base16 test
+ * @v file Test code file
+ * @v line Test code line
*/
-#define base16_decode_ok( test ) do { \
- size_t max_len = base16_decoded_max_len ( (test)->encoded ); \
- uint8_t buf[max_len]; \
- int len; \
- len = base16_decode ( (test)->encoded, buf ); \
- ok ( len >= 0 ); \
- ok ( ( size_t ) len <= max_len ); \
- ok ( ( size_t ) len == (test)->len ); \
- ok ( memcmp ( (test)->data, buf, len ) == 0 ); \
- } while ( 0 )
+static void base16_decode_okx ( struct base16_test *test, const char *file,
+ unsigned int line ) {
+ size_t max_len = base16_decoded_max_len ( test->encoded );
+ uint8_t buf[max_len];
+ int len;
+
+ len = base16_decode ( test->encoded, buf, sizeof ( buf ) );
+ okx ( len >= 0, file, line );
+ okx ( ( size_t ) len <= max_len, file, line );
+ okx ( ( size_t ) len == test->len, file, line );
+ okx ( memcmp ( test->data, buf, len ) == 0, file, line );
+}
+#define base16_decode_ok( test ) base16_decode_okx ( test, __FILE__, __LINE__ )
/**
* Perform Base16 self-tests
diff --git a/roms/ipxe/src/tests/base64_test.c b/roms/ipxe/src/tests/base64_test.c
index c088298ca..0fc595d90 100644
--- a/roms/ipxe/src/tests/base64_test.c
+++ b/roms/ipxe/src/tests/base64_test.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
@@ -76,30 +80,42 @@ BASE64 ( random_test,
* Report a base64 encoding test result
*
* @v test Base64 test
+ * @v file Test code file
+ * @v line Test code line
*/
-#define base64_encode_ok( test ) do { \
- size_t len = base64_encoded_len ( (test)->len ); \
- char buf[ len + 1 /* NUL */ ]; \
- ok ( len == strlen ( (test)->encoded ) ); \
- base64_encode ( (test)->data, (test)->len, buf ); \
- ok ( strcmp ( (test)->encoded, buf ) == 0 ); \
- } while ( 0 )
+static void base64_encode_okx ( struct base64_test *test, const char *file,
+ unsigned int line ) {
+ size_t len = base64_encoded_len ( test->len );
+ char buf[ len + 1 /* NUL */ ];
+ size_t check_len;
+
+ okx ( len == strlen ( test->encoded ), file, line );
+ check_len = base64_encode ( test->data, test->len, buf, sizeof ( buf ));
+ okx ( check_len == len, file, line );
+ okx ( strcmp ( test->encoded, buf ) == 0, file, line );
+}
+#define base64_encode_ok( test ) base64_encode_okx ( test, __FILE__, __LINE__ )
/**
* Report a base64 decoding test result
*
* @v test Base64 test
+ * @v file Test code file
+ * @v line Test code line
*/
-#define base64_decode_ok( test ) do { \
- size_t max_len = base64_decoded_max_len ( (test)->encoded ); \
- uint8_t buf[max_len]; \
- int len; \
- len = base64_decode ( (test)->encoded, buf ); \
- ok ( len >= 0 ); \
- ok ( ( size_t ) len <= max_len ); \
- ok ( ( size_t ) len == (test)->len ); \
- ok ( memcmp ( (test)->data, buf, len ) == 0 ); \
- } while ( 0 )
+static void base64_decode_okx ( struct base64_test *test, const char *file,
+ unsigned int line ) {
+ size_t max_len = base64_decoded_max_len ( test->encoded );
+ uint8_t buf[max_len];
+ int len;
+
+ len = base64_decode ( test->encoded, buf, sizeof ( buf ) );
+ okx ( len >= 0, file, line );
+ okx ( ( size_t ) len <= max_len, file, line );
+ okx ( ( size_t ) len == test->len, file, line );
+ okx ( memcmp ( test->data, buf, len ) == 0, file, line );
+}
+#define base64_decode_ok( test ) base64_decode_okx ( test, __FILE__, __LINE__ )
/**
* Perform Base64 self-tests
diff --git a/roms/ipxe/src/tests/bigint_test.c b/roms/ipxe/src/tests/bigint_test.c
index 75a80622f..8d40c3188 100644
--- a/roms/ipxe/src/tests/bigint_test.c
+++ b/roms/ipxe/src/tests/bigint_test.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/tests/bofm_test.c b/roms/ipxe/src/tests/bofm_test.c
index e430d12d4..829924887 100644
--- a/roms/ipxe/src/tests/bofm_test.c
+++ b/roms/ipxe/src/tests/bofm_test.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdio.h>
diff --git a/roms/ipxe/src/tests/byteswap_test.c b/roms/ipxe/src/tests/byteswap_test.c
index a500218be..92bdb1d59 100644
--- a/roms/ipxe/src/tests/byteswap_test.c
+++ b/roms/ipxe/src/tests/byteswap_test.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/tests/cbc_test.h b/roms/ipxe/src/tests/cbc_test.h
deleted file mode 100644
index ad9e6f341..000000000
--- a/roms/ipxe/src/tests/cbc_test.h
+++ /dev/null
@@ -1,57 +0,0 @@
-#ifndef _CBC_TEST_H
-#define _CBC_TEST_H
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#include <stdint.h>
-#include <ipxe/crypto.h>
-#include <ipxe/test.h>
-
-extern int cbc_test_encrypt ( struct cipher_algorithm *cipher, const void *key,
- size_t key_len, const void *iv,
- const void *plaintext,
- const void *expected_ciphertext, size_t len );
-extern int cbc_test_decrypt ( struct cipher_algorithm *cipher, const void *key,
- size_t key_len, const void *iv,
- const void *ciphertext,
- const void *expected_plaintext, size_t len );
-extern unsigned long cbc_cost_encrypt ( struct cipher_algorithm *cipher,
- size_t key_len );
-extern unsigned long cbc_cost_decrypt ( struct cipher_algorithm *cipher,
- size_t key_len );
-
-/**
- * Report CBC encryption test result
- *
- * @v cipher Cipher algorithm
- * @v key Key
- * @v key_len Length of key
- * @v iv Initialisation vector
- * @v plaintext Plaintext data
- * @v expected_ciphertext Expected ciphertext data
- * @v len Length of data
- */
-#define cbc_encrypt_ok( cipher, key, key_len, iv, plaintext, \
- expected_ciphertext, len ) do { \
- ok ( cbc_test_encrypt ( cipher, key, key_len, iv, plaintext, \
- expected_ciphertext, len ) ); \
- } while ( 0 )
-
-/**
- * Report CBC decryption test result
- *
- * @v cipher Cipher algorithm
- * @v key Key
- * @v key_len Length of key
- * @v iv Initialisation vector
- * @v ciphertext Ciphertext data
- * @v expected_plaintext Expected plaintext data
- * @v len Length of data
- */
-#define cbc_decrypt_ok( cipher, key, key_len, iv, ciphertext, \
- expected_plaintext, len ) do { \
- ok ( cbc_test_decrypt ( cipher, key, key_len, iv, ciphertext, \
- expected_plaintext, len ) ); \
- } while ( 0 )
-
-#endif /* _CBC_TEST_H */
diff --git a/roms/ipxe/src/tests/cbc_test.c b/roms/ipxe/src/tests/cipher_test.c
index cb0f7bdea..800d6c138 100644
--- a/roms/ipxe/src/tests/cbc_test.c
+++ b/roms/ipxe/src/tests/cipher_test.c
@@ -15,13 +15,17 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
- * CBC self-tests
+ * Cipher self-tests
*
*/
@@ -34,86 +38,90 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <assert.h>
#include <ipxe/crypto.h>
#include <ipxe/profile.h>
-#include "cbc_test.h"
+#include <ipxe/test.h>
+#include "cipher_test.h"
/** Number of sample iterations for profiling */
#define PROFILE_COUNT 16
/**
- * Test CBC encryption
+ * Report a cipher encryption test result
*
- * @v cipher Cipher algorithm
- * @v key Key
- * @v key_len Length of key
- * @v iv Initialisation vector
- * @v plaintext Plaintext data
- * @v expected_ciphertext Expected ciphertext data
- * @v len Length of data
- * @ret ok Ciphertext is as expected
+ * @v test Cipher test
+ * @v file Test code file
+ * @v line Test code line
*/
-int cbc_test_encrypt ( struct cipher_algorithm *cipher, const void *key,
- size_t key_len, const void *iv, const void *plaintext,
- const void *expected_ciphertext, size_t len ) {
+void cipher_encrypt_okx ( struct cipher_test *test, const char *file,
+ unsigned int line ) {
+ struct cipher_algorithm *cipher = test->cipher;
+ size_t len = test->len;
uint8_t ctx[cipher->ctxsize];
uint8_t ciphertext[len];
- int rc;
/* Initialise cipher */
- rc = cipher_setkey ( cipher, ctx, key, key_len );
- assert ( rc == 0 );
- cipher_setiv ( cipher, ctx, iv );
+ okx ( cipher_setkey ( cipher, ctx, test->key, test->key_len ) == 0,
+ file, line );
+ cipher_setiv ( cipher, ctx, test->iv );
/* Perform encryption */
- cipher_encrypt ( cipher, ctx, plaintext, ciphertext, len );
+ cipher_encrypt ( cipher, ctx, test->plaintext, ciphertext, len );
- /* Verify result */
- return ( memcmp ( ciphertext, expected_ciphertext, len ) == 0 );
+ /* Compare against expected ciphertext */
+ okx ( memcmp ( ciphertext, test->ciphertext, len ) == 0, file, line );
}
/**
- * Test CBC decryption
+ * Report a cipher decryption test result
*
- * @v cipher Cipher algorithm
- * @v key Key
- * @v key_len Length of key
- * @v iv Initialisation vector
- * @v ciphertext Ciphertext data
- * @v expected_plaintext Expected plaintext data
- * @v len Length of data
- * @ret ok Plaintext is as expected
+ * @v test Cipher test
+ * @v file Test code file
+ * @v line Test code line
*/
-int cbc_test_decrypt ( struct cipher_algorithm *cipher, const void *key,
- size_t key_len, const void *iv, const void *ciphertext,
- const void *expected_plaintext, size_t len ) {
+void cipher_decrypt_okx ( struct cipher_test *test, const char *file,
+ unsigned int line ) {
+ struct cipher_algorithm *cipher = test->cipher;
+ size_t len = test->len;
uint8_t ctx[cipher->ctxsize];
uint8_t plaintext[len];
- int rc;
/* Initialise cipher */
- rc = cipher_setkey ( cipher, ctx, key, key_len );
- assert ( rc == 0 );
- cipher_setiv ( cipher, ctx, iv );
+ okx ( cipher_setkey ( cipher, ctx, test->key, test->key_len ) == 0,
+ file, line );
+ cipher_setiv ( cipher, ctx, test->iv );
/* Perform encryption */
- cipher_decrypt ( cipher, ctx, ciphertext, plaintext, len );
+ cipher_decrypt ( cipher, ctx, test->ciphertext, plaintext, len );
+
+ /* Compare against expected plaintext */
+ okx ( memcmp ( plaintext, test->plaintext, len ) == 0, file, line );
+}
+
+/**
+ * Report a cipher encryption and decryption test result
+ *
+ * @v test Cipher test
+ * @v file Test code file
+ * @v line Test code line
+ */
+void cipher_okx ( struct cipher_test *test, const char *file,
+ unsigned int line ) {
- /* Verify result */
- return ( memcmp ( plaintext, expected_plaintext, len ) == 0 );
+ cipher_encrypt_okx ( test, file, line );
+ cipher_decrypt_okx ( test, file, line );
}
/**
- * Calculate CBC encryption or decryption cost
+ * Calculate cipher encryption or decryption cost
*
* @v cipher Cipher algorithm
* @v key_len Length of key
* @v op Encryption or decryption operation
* @ret cost Cost (in cycles per byte)
*/
-static unsigned long cbc_cost ( struct cipher_algorithm *cipher,
- size_t key_len,
- void ( * op ) ( struct cipher_algorithm *cipher,
- void *ctx, const void *src,
- void *dst, size_t len ) ) {
+static unsigned long
+cipher_cost ( struct cipher_algorithm *cipher, size_t key_len,
+ void ( * op ) ( struct cipher_algorithm *cipher, void *ctx,
+ const void *src, void *dst, size_t len ) ) {
static uint8_t random[8192]; /* Too large for stack */
uint8_t key[key_len];
uint8_t iv[cipher->blocksize];
@@ -153,25 +161,25 @@ static unsigned long cbc_cost ( struct cipher_algorithm *cipher,
}
/**
- * Calculate CBC encryption cost
+ * Calculate cipher encryption cost
*
* @v cipher Cipher algorithm
* @v key_len Length of key
* @ret cost Cost (in cycles per byte)
*/
-unsigned long cbc_cost_encrypt ( struct cipher_algorithm *cipher,
- size_t key_len ) {
- return cbc_cost ( cipher, key_len, cipher_encrypt );
+unsigned long cipher_cost_encrypt ( struct cipher_algorithm *cipher,
+ size_t key_len ) {
+ return cipher_cost ( cipher, key_len, cipher_encrypt );
}
/**
- * Calculate CBC decryption cost
+ * Calculate cipher decryption cost
*
* @v cipher Cipher algorithm
* @v key_len Length of key
* @ret cost Cost (in cycles per byte)
*/
-unsigned long cbc_cost_decrypt ( struct cipher_algorithm *cipher,
- size_t key_len ) {
- return cbc_cost ( cipher, key_len, cipher_decrypt );
+unsigned long cipher_cost_decrypt ( struct cipher_algorithm *cipher,
+ size_t key_len ) {
+ return cipher_cost ( cipher, key_len, cipher_decrypt );
}
diff --git a/roms/ipxe/src/tests/cipher_test.h b/roms/ipxe/src/tests/cipher_test.h
new file mode 100644
index 000000000..d7c5aef8f
--- /dev/null
+++ b/roms/ipxe/src/tests/cipher_test.h
@@ -0,0 +1,111 @@
+#ifndef _CIPHER_TEST_H
+#define _CIPHER_TEST_H
+
+/** @file
+ *
+ * Cipher self-tests
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
+#include <ipxe/crypto.h>
+#include <ipxe/test.h>
+
+/** A cipher test */
+struct cipher_test {
+ /** Cipher algorithm */
+ struct cipher_algorithm *cipher;
+ /** Key */
+ const void *key;
+ /** Length of key */
+ size_t key_len;
+ /** Initialisation vector */
+ const void *iv;
+ /** Length of initialisation vector */
+ size_t iv_len;
+ /** Plaintext */
+ const void *plaintext;
+ /** Ciphertext */
+ const void *ciphertext;
+ /** Length of text */
+ size_t len;
+};
+
+/** Define inline key */
+#define KEY(...) { __VA_ARGS__ }
+
+/** Define inline initialisation vector */
+#define IV(...) { __VA_ARGS__ }
+
+/** Define inline plaintext data */
+#define PLAINTEXT(...) { __VA_ARGS__ }
+
+/** Define inline ciphertext data */
+#define CIPHERTEXT(...) { __VA_ARGS__ }
+
+/**
+ * Define a cipher test
+ *
+ * @v name Test name
+ * @v CIPHER Cipher algorithm
+ * @v KEY Key
+ * @v IV Initialisation vector
+ * @v PLAINTEXT Plaintext
+ * @v CIPHERTEXT Ciphertext
+ * @ret test Cipher test
+ */
+#define CIPHER_TEST( name, CIPHER, KEY, IV, PLAINTEXT, CIPHERTEXT ) \
+ static const uint8_t name ## _key [] = KEY; \
+ static const uint8_t name ## _iv [] = IV; \
+ static const uint8_t name ## _plaintext [] = PLAINTEXT; \
+ static const uint8_t name ## _ciphertext \
+ [ sizeof ( name ## _plaintext ) ] = CIPHERTEXT; \
+ static struct cipher_test name = { \
+ .cipher = CIPHER, \
+ .key = name ## _key, \
+ .key_len = sizeof ( name ## _key ), \
+ .iv = name ## _iv, \
+ .iv_len = sizeof ( name ## _iv ), \
+ .plaintext = name ## _plaintext, \
+ .ciphertext = name ## _ciphertext, \
+ .len = sizeof ( name ## _plaintext ), \
+ }
+
+extern void cipher_encrypt_okx ( struct cipher_test *test, const char *file,
+ unsigned int line );
+extern void cipher_decrypt_okx ( struct cipher_test *test, const char *file,
+ unsigned int line );
+extern void cipher_okx ( struct cipher_test *test, const char *file,
+ unsigned int line );
+extern unsigned long cipher_cost_encrypt ( struct cipher_algorithm *cipher,
+ size_t key_len );
+extern unsigned long cipher_cost_decrypt ( struct cipher_algorithm *cipher,
+ size_t key_len );
+
+/**
+ * Report a cipher encryption test result
+ *
+ * @v test Cipher test
+ */
+#define cipher_encrypt_ok( test ) \
+ cipher_encrypt_okx ( test, __FILE__, __LINE__ )
+
+/**
+ * Report a cipher decryption test result
+ *
+ * @v test Cipher test
+ */
+#define cipher_decrypt_ok( test ) \
+ cipher_decrypt_okx ( test, __FILE__, __LINE__ )
+
+/**
+ * Report a cipher encryption and decryption test result
+ *
+ * @v test Cipher test
+ */
+#define cipher_ok( test ) \
+ cipher_okx ( test, __FILE__, __LINE__ )
+
+#endif /* _CIPHER_TEST_H */
diff --git a/roms/ipxe/src/tests/cms_test.c b/roms/ipxe/src/tests/cms_test.c
index 8767504c0..b805a9974 100644
--- a/roms/ipxe/src/tests/cms_test.c
+++ b/roms/ipxe/src/tests/cms_test.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
@@ -1470,6 +1474,7 @@ struct self_test cms_test __self_test = {
};
/* Drag in algorithms required for tests */
+REQUIRING_SYMBOL ( cms_test );
REQUIRE_OBJECT ( rsa );
REQUIRE_OBJECT ( md5 );
REQUIRE_OBJECT ( sha1 );
diff --git a/roms/ipxe/src/tests/crc32_test.c b/roms/ipxe/src/tests/crc32_test.c
index 873f633a5..46cde0f7b 100644
--- a/roms/ipxe/src/tests/crc32_test.c
+++ b/roms/ipxe/src/tests/crc32_test.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/tests/deflate_test.c b/roms/ipxe/src/tests/deflate_test.c
index 68c1aad96..20ff5b9a2 100644
--- a/roms/ipxe/src/tests/deflate_test.c
+++ b/roms/ipxe/src/tests/deflate_test.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/tests/digest_test.c b/roms/ipxe/src/tests/digest_test.c
index 4df26c099..c3a128853 100644
--- a/roms/ipxe/src/tests/digest_test.c
+++ b/roms/ipxe/src/tests/digest_test.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
@@ -34,27 +38,47 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/profile.h>
#include "digest_test.h"
+/** Maximum number of digest test fragments */
+#define NUM_DIGEST_TEST_FRAG 8
+
+/** A digest test fragment list */
+struct digest_test_fragments {
+ /** Fragment lengths */
+ size_t len[NUM_DIGEST_TEST_FRAG];
+};
+
+/** Digest test fragment lists */
+static struct digest_test_fragments digest_test_fragments[] = {
+ { { 0, -1UL, } },
+ { { 1, 1, 1, 1, 1, 1, 1, 1 } },
+ { { 2, 0, 23, 4, 6, 1, 0 } },
+};
+
/** Number of sample iterations for profiling */
#define PROFILE_COUNT 16
/**
- * Test digest algorithm
+ * Report a digest fragmented test result
*
- * @v digest Digest algorithm
- * @v fragments Digest test fragment list, or NULL
- * @v data Test data
- * @v len Length of test data
- * @v expected Expected digest value
- * @ret ok Digest value is as expected
+ * @v test Digest test
+ * @v fragments Fragment list
+ * @v file Test code file
+ * @v line Test code line
*/
-int digest_test ( struct digest_algorithm *digest,
- struct digest_test_fragments *fragments,
- void *data, size_t len, void *expected ) {
+void digest_frag_okx ( struct digest_test *test,
+ struct digest_test_fragments *fragments,
+ const char *file, unsigned int line ) {
+ struct digest_algorithm *digest = test->digest;
uint8_t ctx[digest->ctxsize];
uint8_t out[digest->digestsize];
+ const void *data = test->data;
+ size_t len = test->len;
size_t frag_len = 0;
unsigned int i;
+ /* Sanity check */
+ okx ( test->expected_len == sizeof ( out ), file, line );
+
/* Initialise digest */
digest_init ( digest, ctx );
@@ -74,7 +98,28 @@ int digest_test ( struct digest_algorithm *digest,
digest_final ( digest, ctx, out );
/* Compare against expected output */
- return ( memcmp ( expected, out, sizeof ( out ) ) == 0 );
+ okx ( memcmp ( test->expected, out, sizeof ( out ) ) == 0, file, line );
+}
+
+/**
+ * Report a digest test result
+ *
+ * @v test Digest test
+ * @v file Test code file
+ * @v line Test code line
+ */
+void digest_okx ( struct digest_test *test, const char *file,
+ unsigned int line ) {
+ unsigned int i;
+
+ /* Test with a single pass */
+ digest_frag_okx ( test, NULL, file, line );
+
+ /* Test with fragment lists */
+ for ( i = 0 ; i < ( sizeof ( digest_test_fragments ) /
+ sizeof ( digest_test_fragments[0] ) ) ; i++ ) {
+ digest_frag_okx ( test, &digest_test_fragments[i], file, line );
+ }
}
/**
diff --git a/roms/ipxe/src/tests/digest_test.h b/roms/ipxe/src/tests/digest_test.h
index 49e06d1cb..abf1b834f 100644
--- a/roms/ipxe/src/tests/digest_test.h
+++ b/roms/ipxe/src/tests/digest_test.h
@@ -1,37 +1,115 @@
#ifndef _DIGEST_TEST_H
#define _DIGEST_TEST_H
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/crypto.h>
#include <ipxe/test.h>
-/** Maximum number of digest test fragments */
-#define NUM_DIGEST_TEST_FRAG 8
-
-/** A digest test fragment list */
-struct digest_test_fragments {
- /** Fragment lengths */
- size_t len[NUM_DIGEST_TEST_FRAG];
+/** A digest test */
+struct digest_test {
+ /** Digest algorithm */
+ struct digest_algorithm *digest;
+ /** Test data */
+ const void *data;
+ /** Length of test data */
+ size_t len;
+ /** Expected digest value */
+ const void *expected;
+ /** Expected digest length */
+ size_t expected_len;
};
-extern int digest_test ( struct digest_algorithm *digest,
- struct digest_test_fragments *fragments,
- void *data, size_t len, void *expected );
-extern unsigned long digest_cost ( struct digest_algorithm *digest );
+/** Define inline test data */
+#define DATA(...) { __VA_ARGS__ }
+
+/** Define inline expected digest value */
+#define DIGEST(...) { __VA_ARGS__ }
+
+/**
+ * Define a digest test
+ *
+ * @v name Test name
+ * @v DIGEST Digest algorithm
+ * @v DATA Test data
+ * @v EXPECTED Expected digest value
+ * @ret test Digest test
+ */
+#define DIGEST_TEST( name, DIGEST, DATA, EXPECTED ) \
+ static const uint8_t name ## _data[] = DATA; \
+ static const uint8_t name ## _expected[] = EXPECTED; \
+ static struct digest_test name = { \
+ .digest = DIGEST, \
+ .data = name ## _data, \
+ .len = sizeof ( name ## _data ), \
+ .expected = name ## _expected, \
+ .expected_len = sizeof ( name ## _expected ), \
+ };
+
+/** Standard test vector: empty data */
+#define DIGEST_EMPTY DATA()
+
+/** Standard test vector: NIST string "abc"
+ *
+ * The NIST Cryptographic Toolkit examples for all digest algorithms
+ * include a test vector which is the unterminated string
+ *
+ * "abc"
+ */
+#define DIGEST_NIST_ABC \
+ DATA ( 0x61, 0x62, 0x63 )
+
+/** Standard test vector: NIST string "abc...opq"
+ *
+ * The NIST Cryptographic Toolkit examples for all 32-bit digest
+ * algorithms (SHA-1 and the SHA-256 family) include a test vector
+ * which is the unterminated string
+ *
+ * "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+ */
+#define DIGEST_NIST_ABC_OPQ \
+ DATA ( 0x61, 0x62, 0x63, 0x64, 0x62, 0x63, 0x64, 0x65, 0x63, \
+ 0x64, 0x65, 0x66, 0x64, 0x65, 0x66, 0x67, 0x65, 0x66, \
+ 0x67, 0x68, 0x66, 0x67, 0x68, 0x69, 0x67, 0x68, 0x69, \
+ 0x6a, 0x68, 0x69, 0x6a, 0x6b, 0x69, 0x6a, 0x6b, 0x6c, \
+ 0x6a, 0x6b, 0x6c, 0x6d, 0x6b, 0x6c, 0x6d, 0x6e, 0x6c, \
+ 0x6d, 0x6e, 0x6f, 0x6d, 0x6e, 0x6f, 0x70, 0x6e, 0x6f, \
+ 0x70, 0x71 )
+
+/** Standard test vector: NIST string "abc...stu"
+ *
+ * The NIST Cryptographic Toolkit examples for all 64-bit digest
+ * algorithms (SHA-512 family) include a test vector which is the
+ * unterminated string
+ *
+ * "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
+ * "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"
+ */
+#define DIGEST_NIST_ABC_STU \
+ DATA ( 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x62, \
+ 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x63, 0x64, \
+ 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x64, 0x65, 0x66, \
+ 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x65, 0x66, 0x67, 0x68, \
+ 0x69, 0x6a, 0x6b, 0x6c, 0x66, 0x67, 0x68, 0x69, 0x6a, \
+ 0x6b, 0x6c, 0x6d, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, \
+ 0x6d, 0x6e, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, \
+ 0x6f, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, \
+ 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x6b, \
+ 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x6c, 0x6d, \
+ 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x6d, 0x6e, 0x6f, \
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x6e, 0x6f, 0x70, 0x71, \
+ 0x72, 0x73, 0x74, 0x75 )
/**
- * Report digest test result
+ * Report a digest test result
*
- * @v digest Digest algorithm
- * @v fragments Digest test fragment list, or NULL
- * @v data Test data
- * @v len Length of test data
- * @v expected Expected digest value
+ * @v test Digest test
*/
-#define digest_ok( digest, fragments, data, len, expected ) do { \
- ok ( digest_test ( digest, fragments, data, len, expected ) ); \
- } while ( 0 )
+#define digest_ok(test) digest_okx ( test, __FILE__, __LINE__ )
+
+extern void digest_okx ( struct digest_test *test, const char *file,
+ unsigned int line );
+extern unsigned long digest_cost ( struct digest_algorithm *digest );
#endif /* _DIGEST_TEST_H */
diff --git a/roms/ipxe/src/tests/dns_test.c b/roms/ipxe/src/tests/dns_test.c
index 52f5f19f2..f08e7810f 100644
--- a/roms/ipxe/src/tests/dns_test.c
+++ b/roms/ipxe/src/tests/dns_test.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/tests/entropy_sample.c b/roms/ipxe/src/tests/entropy_sample.c
index 95a662e3e..b45648c11 100644
--- a/roms/ipxe/src/tests/entropy_sample.c
+++ b/roms/ipxe/src/tests/entropy_sample.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/tests/hash_df_test.c b/roms/ipxe/src/tests/hash_df_test.c
index 74c8d0f4d..0b7d56ad7 100644
--- a/roms/ipxe/src/tests/hash_df_test.c
+++ b/roms/ipxe/src/tests/hash_df_test.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/tests/hmac_drbg_test.c b/roms/ipxe/src/tests/hmac_drbg_test.c
index 8cbf1cc8b..ddf9db2c5 100644
--- a/roms/ipxe/src/tests/hmac_drbg_test.c
+++ b/roms/ipxe/src/tests/hmac_drbg_test.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/tests/ipv4_test.c b/roms/ipxe/src/tests/ipv4_test.c
new file mode 100644
index 000000000..f84a8b81f
--- /dev/null
+++ b/roms/ipxe/src/tests/ipv4_test.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2015 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/** @file
+ *
+ * IPv4 tests
+ *
+ */
+
+/* Forcibly enable assertions */
+#undef NDEBUG
+
+#include <stdint.h>
+#include <string.h>
+#include <byteswap.h>
+#include <ipxe/in.h>
+#include <ipxe/test.h>
+
+/** Define inline IPv4 address */
+#define IPV4(a,b,c,d) \
+ htonl ( ( (a) << 24 ) | ( (b) << 16 ) | ( (c) << 8 ) | (d) )
+
+/**
+ * Report an inet_ntoa() test result
+ *
+ * @v addr IPv4 address
+ * @v text Expected textual representation
+ * @v file Test code file
+ * @v line Test code line
+ */
+static void inet_ntoa_okx ( uint32_t addr, const char *text, const char *file,
+ unsigned int line ) {
+ struct in_addr in = { .s_addr = addr };
+ char *actual;
+
+ /* Format address */
+ actual = inet_ntoa ( in );
+ DBG ( "inet_ntoa ( %d.%d.%d.%d ) = %s\n",
+ ( ( ntohl ( addr ) >> 24 ) & 0xff ),
+ ( ( ntohl ( addr ) >> 16 ) & 0xff ),
+ ( ( ntohl ( addr ) >> 8 ) & 0xff ),
+ ( ( ntohl ( addr ) >> 0 ) & 0xff ), actual );
+ okx ( strcmp ( actual, text ) == 0, file, line );
+}
+#define inet_ntoa_ok( addr, text ) \
+ inet_ntoa_okx ( addr, text, __FILE__, __LINE__ )
+
+/**
+ * Report an inet_aton() test result
+ *
+ * @v text Textual representation
+ * @v addr Expected IPv4 address
+ * @v file Test code file
+ * @v line Test code line
+ */
+static void inet_aton_okx ( const char *text, uint32_t addr, const char *file,
+ unsigned int line ) {
+ struct in_addr actual;
+
+ /* Parse address */
+ okx ( inet_aton ( text, &actual ) != 0, file, line );
+ DBG ( "inet_aton ( \"%s\" ) = %s\n", text, inet_ntoa ( actual ) );
+ okx ( actual.s_addr == addr, file, line );
+};
+#define inet_aton_ok( text, addr ) \
+ inet_aton_okx ( text, addr, __FILE__, __LINE__ )
+
+/**
+ * Report an inet_aton() failure test result
+ *
+ * @v text Textual representation
+ * @v file Test code file
+ * @v line Test code line
+ */
+static void inet_aton_fail_okx ( const char *text, const char *file,
+ unsigned int line ) {
+ struct in_addr actual;
+
+ /* Attempt to parse address */
+ okx ( inet_aton ( text, &actual ) == 0, file, line );
+}
+#define inet_aton_fail_ok( text ) \
+ inet_aton_fail_okx ( text, __FILE__, __LINE__ )
+
+/**
+ * Perform IPv4 self-tests
+ *
+ */
+static void ipv4_test_exec ( void ) {
+
+ /* Address testing macros */
+ ok ( IN_IS_CLASSA ( IPV4 ( 10, 0, 0, 1 ) ) );
+ ok ( ! IN_IS_CLASSB ( IPV4 ( 10, 0, 0, 1 ) ) );
+ ok ( ! IN_IS_CLASSC ( IPV4 ( 10, 0, 0, 1 ) ) );
+ ok ( ! IN_IS_CLASSA ( IPV4 ( 172, 16, 0, 1 ) ) );
+ ok ( IN_IS_CLASSB ( IPV4 ( 172, 16, 0, 1 ) ) );
+ ok ( ! IN_IS_CLASSC ( IPV4 ( 172, 16, 0, 1 ) ) );
+ ok ( ! IN_IS_CLASSA ( IPV4 ( 192, 168, 0, 1 ) ) );
+ ok ( ! IN_IS_CLASSB ( IPV4 ( 192, 168, 0, 1 ) ) );
+ ok ( IN_IS_CLASSC ( IPV4 ( 192, 168, 0, 1 ) ) );
+ ok ( ! IN_IS_MULTICAST ( IPV4 ( 127, 0, 0, 1 ) ) );
+ ok ( ! IN_IS_MULTICAST ( IPV4 ( 8, 8, 8, 8 ) ) );
+ ok ( ! IN_IS_MULTICAST ( IPV4 ( 0, 0, 0, 0 ) ) );
+ ok ( ! IN_IS_MULTICAST ( IPV4 ( 223, 0, 0, 1 ) ) );
+ ok ( ! IN_IS_MULTICAST ( IPV4 ( 240, 0, 0, 1 ) ) );
+ ok ( IN_IS_MULTICAST ( IPV4 ( 224, 0, 0, 1 ) ) );
+ ok ( IN_IS_MULTICAST ( IPV4 ( 231, 89, 0, 2 ) ) );
+ ok ( IN_IS_MULTICAST ( IPV4 ( 239, 6, 1, 17 ) ) );
+
+ /* inet_ntoa() tests */
+ inet_ntoa_ok ( IPV4 ( 127, 0, 0, 1 ), "127.0.0.1" );
+ inet_ntoa_ok ( IPV4 ( 0, 0, 0, 0 ), "0.0.0.0" );
+ inet_ntoa_ok ( IPV4 ( 255, 255, 255, 255 ), "255.255.255.255" );
+ inet_ntoa_ok ( IPV4 ( 212, 13, 204, 60 ), "212.13.204.60" );
+
+ /* inet_aton() tests */
+ inet_aton_ok ( "212.13.204.60", IPV4 ( 212, 13, 204, 60 ) );
+ inet_aton_ok ( "127.0.0.1", IPV4 ( 127, 0, 0, 1 ) );
+
+ /* inet_aton() failure tests */
+ inet_aton_fail_ok ( "256.0.0.1" ); /* Byte out of range */
+ inet_aton_fail_ok ( "212.13.204.60.1" ); /* Too long */
+ inet_aton_fail_ok ( "127.0.0" ); /* Too short */
+ inet_aton_fail_ok ( "1.2.3.a" ); /* Invalid characters */
+ inet_aton_fail_ok ( "127.0..1" ); /* Missing bytes */
+}
+
+/** IPv4 self-test */
+struct self_test ipv4_test __self_test = {
+ .name = "ipv4",
+ .exec = ipv4_test_exec,
+};
diff --git a/roms/ipxe/src/tests/ipv6_test.c b/roms/ipxe/src/tests/ipv6_test.c
index e16fc7c3d..772eb1b82 100644
--- a/roms/ipxe/src/tests/ipv6_test.c
+++ b/roms/ipxe/src/tests/ipv6_test.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/tests/linebuf_test.c b/roms/ipxe/src/tests/linebuf_test.c
index e06ac7d86..0dd486e9d 100644
--- a/roms/ipxe/src/tests/linebuf_test.c
+++ b/roms/ipxe/src/tests/linebuf_test.c
@@ -1,35 +1,320 @@
-#include <stdint.h>
+/*
+ * Copyright (C) 2015 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/** @file
+ *
+ * Line buffer self-tests
+ *
+ */
+
+/* Forcibly enable assertions */
+#undef NDEBUG
+
#include <string.h>
-#include <stdio.h>
+#include <assert.h>
#include <ipxe/linebuf.h>
+#include <ipxe/test.h>
-static const char data1[] =
-"Hello world\r\n"
-"This is a reasonably nice set of lines\n"
-"with not many different terminators\r\n\r\n"
-"There should be exactly one blank line above\n"
-"and this line should never appear at all since it has no terminator";
+/** Define inline raw data */
+#define DATA(...) { __VA_ARGS__ }
-void linebuf_test ( void ) {
- struct line_buffer linebuf;
- const char *data = data1;
- size_t len = ( sizeof ( data1 ) - 1 /* be mean; strip the NUL */ );
- ssize_t frag_len;
- char *line;
-
- memset ( &linebuf, 0, sizeof ( linebuf ) );
- while ( len ) {
- frag_len = line_buffer ( &linebuf, data, len );
- if ( frag_len < 0 ) {
- printf ( "line_buffer() failed: %s\n",
- strerror ( frag_len ) );
+/** Define inline lines */
+#define LINES(...) { __VA_ARGS__ }
+
+/** A line buffer test */
+struct linebuf_test {
+ /** Raw data */
+ const void *data;
+ /** Length of raw data */
+ size_t len;
+ /** Expected sequence of lines */
+ const char **lines;
+ /** Number of expected lines */
+ unsigned int count;
+};
+
+/** Line buffer test expected failure indicator */
+static const char linebuf_failure[1];
+
+/**
+ * Define a line buffer test
+ *
+ * @v name Test name
+ * @v DATA Raw data
+ * @v LINES Expected sequence of lines
+ * @ret test Line buffer test
+ */
+#define LINEBUF_TEST( name, DATA, LINES ) \
+ static const char name ## _data[] = DATA; \
+ static const char * name ## _lines[] = LINES; \
+ static struct linebuf_test name = { \
+ .data = name ## _data, \
+ .len = ( sizeof ( name ## _data ) - 1 /* NUL */ ), \
+ .lines = name ## _lines, \
+ .count = ( sizeof ( name ## _lines ) / \
+ sizeof ( name ## _lines[0] ) ), \
+ }
+
+/** Simple line buffer test */
+LINEBUF_TEST ( simple,
+ ( "HTTP/1.1 200 OK\r\n"
+ "Content-Length: 123\r\n"
+ "Content-Type: text/plain\r\n"
+ "\r\n" ),
+ LINES ( "HTTP/1.1 200 OK",
+ "Content-Length: 123",
+ "Content-Type: text/plain",
+ "" ) );
+
+/** Mixed line terminators */
+LINEBUF_TEST ( mixed,
+ ( "LF only\n" "CRLF\r\n" "\n" "\n" "\r\n" "\r\n" "CR only\r" ),
+ LINES ( "LF only", "CRLF", "", "", "", "",
+ NULL /* \r should not be treated as a terminator */ ) );
+
+/** Split consumption: part 1 */
+LINEBUF_TEST ( split_1,
+ ( "This line was" ),
+ LINES ( NULL ) );
+
+/** Split consumption: part 2 */
+LINEBUF_TEST ( split_2,
+ ( " split across" ),
+ LINES ( NULL ) );
+
+/** Split consumption: part 3 */
+LINEBUF_TEST ( split_3,
+ ( " multiple calls\r\nand so was this one\r" ),
+ LINES ( "This line was split across multiple calls", NULL ) );
+
+/** Split consumption: part 4 */
+LINEBUF_TEST ( split_4,
+ ( "\nbut not this one\r\n" ),
+ LINES ( "and so was this one", "but not this one" ) );
+
+/** Split consumption: part 5 */
+LINEBUF_TEST ( split_5,
+ ( "" ),
+ LINES ( NULL ) );
+
+/** Split consumption: part 6 */
+LINEBUF_TEST ( split_6,
+ ( "This line came after a zero-length call\r\n" ),
+ LINES ( "This line came after a zero-length call" ) );
+
+/** Embedded NULs */
+LINEBUF_TEST ( embedded_nuls,
+ ( "This\r\ntest\r\nincludes\r\n\r\nsome\0binary\0data\r\n" ),
+ LINES ( "This", "test", "includes", "", linebuf_failure ) );
+
+/**
+ * Report line buffer initialisation test result
+ *
+ * @v linebuf Line buffer
+ * @v file Test code file
+ * @v line Test code line
+ */
+static void linebuf_init_okx ( struct line_buffer *linebuf,
+ const char *file, unsigned int line ) {
+
+ /* Initialise line buffer */
+ memset ( linebuf, 0, sizeof ( *linebuf ) );
+ okx ( buffered_line ( linebuf ) == NULL, file, line );
+}
+#define linebuf_init_ok( linebuf ) \
+ linebuf_init_okx ( linebuf, __FILE__, __LINE__ )
+
+/**
+ * Report line buffer consumption test result
+ *
+ * @v test Line buffer test
+ * @v linebuf Line buffer
+ * @v file Test code file
+ * @v line Test code line
+ */
+static void linebuf_consume_okx ( struct linebuf_test *test,
+ struct line_buffer *linebuf,
+ const char *file, unsigned int line ) {
+ const char *data = test->data;
+ size_t remaining = test->len;
+ int len;
+ unsigned int i;
+ const char *expected;
+ char *actual;
+ int rc;
+
+ DBGC ( test, "LINEBUF %p:\n", test );
+ DBGC_HDA ( test, 0, data, remaining );
+
+ /* Consume data one line at a time */
+ for ( i = 0 ; i < test->count ; i++ ) {
+
+ /* Add data to line buffer */
+ len = line_buffer ( linebuf, data, remaining );
+
+ /* Get buffered line, if any */
+ actual = buffered_line ( linebuf );
+ if ( len < 0 ) {
+ rc = len;
+ DBGC ( test, "LINEBUF %p %s\n", test, strerror ( rc ) );
+ } else if ( actual != NULL ) {
+ DBGC ( test, "LINEBUF %p \"%s\" (consumed %d)\n",
+ test, actual, len );
+ } else {
+ DBGC ( test, "LINEBUF %p unterminated (consumed %d)\n",
+ test, len );
+ }
+
+ /* Check for success/failure */
+ expected = test->lines[i];
+ if ( expected == linebuf_failure ) {
+ rc = len;
+ okx ( rc < 0, file, line );
+ okx ( remaining > 0, file, line );
return;
}
- data += frag_len;
- len -= frag_len;
- if ( ( line = buffered_line ( &linebuf ) ) )
- printf ( "\"%s\"\n", line );
+ okx ( len >= 0, file, line );
+ okx ( ( ( size_t ) len ) <= remaining, file, line );
+
+ /* Check expected result */
+ if ( expected == NULL ) {
+ okx ( actual == NULL, file, line );
+ } else {
+ okx ( actual != NULL, file, line );
+ okx ( strcmp ( actual, expected ) == 0, file, line );
+ }
+
+ /* Consume data */
+ data += len;
+ remaining -= len;
+ }
+
+ /* Check that all data was consumed */
+ okx ( remaining == 0, file, line );
+}
+#define linebuf_consume_ok( test, linebuf ) \
+ linebuf_consume_okx ( test, linebuf, __FILE__, __LINE__ )
+
+/**
+ * Report line buffer accumulation test result
+ *
+ * @v test Line buffer test
+ * @v linebuf Line buffer
+ * @v file Test code file
+ * @v line Test code line
+ */
+static void linebuf_accumulated_okx ( struct linebuf_test *test,
+ struct line_buffer *linebuf,
+ const char *file, unsigned int line ) {
+ const char *actual;
+ const char *expected;
+ unsigned int i;
+
+ /* Check each accumulated line */
+ actual = linebuf->data;
+ for ( i = 0 ; i < test->count ; i++ ) {
+
+ /* Check accumulated line */
+ okx ( actual != NULL, file, line );
+ okx ( actual >= linebuf->data, file, line );
+ expected = test->lines[i];
+ if ( ( expected == NULL ) || ( expected == linebuf_failure ) )
+ return;
+ okx ( strcmp ( actual, expected ) == 0, file, line );
+
+ /* Move to next line */
+ actual += ( strlen ( actual ) + 1 /* NUL */ );
+ okx ( actual <= ( linebuf->data + linebuf->len ), file, line );
}
+}
+#define linebuf_accumulated_ok( test, linebuf ) \
+ linebuf_accumulated_okx ( test, linebuf, __FILE__, __LINE__ )
+
+/**
+ * Report line buffer emptying test result
+ *
+ * @v linebuf Line buffer
+ * @v file Test code file
+ * @v line Test code line
+ */
+static void linebuf_empty_okx ( struct line_buffer *linebuf,
+ const char *file, unsigned int line ) {
- empty_line_buffer ( &linebuf );
+ /* Empty line buffer */
+ empty_line_buffer ( linebuf );
+ okx ( buffered_line ( linebuf ) == NULL, file, line );
}
+#define linebuf_empty_ok( linebuf ) \
+ linebuf_empty_okx ( linebuf, __FILE__, __LINE__ )
+
+/**
+ * Report line buffer combined test result
+ *
+ * @v test Line buffer test
+ * @v file Test code file
+ * @v line Test code line
+ */
+static void linebuf_okx ( struct linebuf_test *test, const char *file,
+ unsigned int line ) {
+ struct line_buffer linebuf;
+
+ linebuf_init_okx ( &linebuf, file, line );
+ linebuf_consume_okx ( test, &linebuf, file, line );
+ linebuf_accumulated_okx ( test, &linebuf, file, line );
+ linebuf_empty_okx ( &linebuf, file, line );
+}
+#define linebuf_ok( test ) \
+ linebuf_okx ( test, __FILE__, __LINE__ )
+
+/**
+ * Perform line buffer self-tests
+ *
+ */
+static void linebuf_test_exec ( void ) {
+ struct line_buffer linebuf;
+
+ /* Basic tests */
+ linebuf_ok ( &simple );
+ linebuf_ok ( &mixed );
+
+ /* Split consumption test */
+ linebuf_init_ok ( &linebuf );
+ linebuf_consume_ok ( &split_1, &linebuf );
+ linebuf_consume_ok ( &split_2, &linebuf );
+ linebuf_consume_ok ( &split_3, &linebuf );
+ linebuf_consume_ok ( &split_4, &linebuf );
+ linebuf_consume_ok ( &split_5, &linebuf );
+ linebuf_consume_ok ( &split_6, &linebuf );
+ linebuf_empty_ok ( &linebuf );
+
+ /* Embedded NULs */
+ linebuf_ok ( &embedded_nuls );
+}
+
+/** Line buffer self-test */
+struct self_test linebuf_test __self_test = {
+ .name = "linebuf",
+ .exec = linebuf_test_exec,
+};
diff --git a/roms/ipxe/src/tests/list_test.c b/roms/ipxe/src/tests/list_test.c
index 35cbd5e5f..352c87da0 100644
--- a/roms/ipxe/src/tests/list_test.c
+++ b/roms/ipxe/src/tests/list_test.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/tests/math_test.c b/roms/ipxe/src/tests/math_test.c
index e12b7939d..1a244f1eb 100644
--- a/roms/ipxe/src/tests/math_test.c
+++ b/roms/ipxe/src/tests/math_test.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
@@ -35,6 +39,26 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/isqrt.h>
/**
+ * Force a call to the non-constant implementation of ffsl()
+ *
+ * @v value Value
+ * @ret lsb Least significant bit set in value (LSB=1), or zero
+ */
+__attribute__ (( noinline )) int ffsl_var ( long value ) {
+ return ffsl ( value );
+}
+
+/**
+ * Force a call to the non-constant implementation of ffsll()
+ *
+ * @v value Value
+ * @ret lsb Least significant bit set in value (LSB=1), or zero
+ */
+__attribute__ (( noinline )) int ffsll_var ( long long value ) {
+ return ffsll ( value );
+}
+
+/**
* Force a call to the non-constant implementation of flsl()
*
* @v value Value
@@ -173,6 +197,44 @@ __attribute__ (( noinline )) int64_t s64mod_var ( int64_t dividend,
}
/**
+ * Report a ffsl() test result
+ *
+ * @v value Value
+ * @v lsb Expected LSB
+ * @v file Test code file
+ * @v line Test code line
+ */
+static inline __attribute__ (( always_inline )) void
+ffsl_okx ( long value, int lsb, const char *file, unsigned int line ) {
+
+ /* Verify as a constant (requires to be inlined) */
+ okx ( ffsl ( value ) == lsb, file, line );
+
+ /* Verify as a non-constant */
+ okx ( ffsl_var ( value ) == lsb, file, line );
+}
+#define ffsl_ok( value, lsb ) ffsl_okx ( value, lsb, __FILE__, __LINE__ )
+
+/**
+ * Report a ffsll() test result
+ *
+ * @v value Value
+ * @v lsb Expected LSB
+ * @v file Test code file
+ * @v line Test code line
+ */
+static inline __attribute__ (( always_inline )) void
+ffsll_okx ( long long value, int lsb, const char *file, unsigned int line ) {
+
+ /* Verify as a constant (requires to be inlined) */
+ okx ( ffsll ( value ) == lsb, file, line );
+
+ /* Verify as a non-constant */
+ okx ( ffsll_var ( value ) == lsb, file, line );
+}
+#define ffsll_ok( value, lsb ) ffsll_okx ( value, lsb, __FILE__, __LINE__ )
+
+/**
* Report a flsl() test result
*
* @v value Value
@@ -270,6 +332,22 @@ static void s64divmod_okx ( int64_t dividend, int64_t divisor,
*/
static void math_test_exec ( void ) {
+ /* Test ffsl() */
+ ffsl_ok ( 0, 0 );
+ ffsl_ok ( 1, 1 );
+ ffsl_ok ( 255, 1 );
+ ffsl_ok ( 256, 9 );
+ ffsl_ok ( 257, 1 );
+ ffsl_ok ( 0x54850596, 2 );
+ ffsl_ok ( 0x80000000, 32 );
+
+ /* Test ffsll() */
+ ffsll_ok ( 0, 0 );
+ ffsll_ok ( 1, 1 );
+ ffsll_ok ( 0x6d63623330ULL, 5 );
+ ffsll_ok ( 0x80000000UL, 32 );
+ ffsll_ok ( 0x8000000000000000ULL, 64 );
+
/* Test flsl() */
flsl_ok ( 0, 0 );
flsl_ok ( 1, 1 );
diff --git a/roms/ipxe/src/tests/md5_test.c b/roms/ipxe/src/tests/md5_test.c
index ba5f24c3e..e9ed2716a 100644
--- a/roms/ipxe/src/tests/md5_test.c
+++ b/roms/ipxe/src/tests/md5_test.c
@@ -15,82 +15,58 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
* MD5 tests
*
+ * Test inputs borrowed from NIST SHA-1 tests, with results calculated
+ * using md5sum.
*/
-#include <stdint.h>
+/* Forcibly enable assertions */
+#undef NDEBUG
+
#include <ipxe/md5.h>
#include <ipxe/test.h>
#include "digest_test.h"
-/** An MD5 test vector */
-struct md5_test_vector {
- /** Test data */
- void *data;
- /** Test data length */
- size_t len;
- /** Expected digest */
- uint8_t digest[MD5_DIGEST_SIZE];
-};
+/* Empty test vector (digest obtained from "md5sum /dev/null") */
+DIGEST_TEST ( md5_empty, &md5_algorithm, DIGEST_EMPTY,
+ DIGEST ( 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, 0xe9,
+ 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e ) );
-/** MD5 test vectors */
-static struct md5_test_vector md5_test_vectors[] = {
- /* Test inputs borrowed from SHA-1 tests, with results
- * calculated using md5sum.
- */
- { NULL, 0,
- { 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04,
- 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e } },
- { "abc", 3,
- { 0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0,
- 0xd6, 0x96, 0x3f, 0x7d, 0x28, 0xe1, 0x7f, 0x72 } },
- { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56,
- { 0x82, 0x15, 0xef, 0x07, 0x96, 0xa2, 0x0b, 0xca,
- 0xaa, 0xe1, 0x16, 0xd3, 0x87, 0x6c, 0x66, 0x4a } },
-};
+/* NIST test vector "abc" (digest obtained from "md5sum <data>") */
+DIGEST_TEST ( md5_nist_abc, &md5_algorithm, DIGEST_NIST_ABC,
+ DIGEST ( 0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0, 0xd6,
+ 0x96, 0x3f, 0x7d, 0x28, 0xe1, 0x7f, 0x72 ) );
-/** MD5 test fragment lists */
-static struct digest_test_fragments md5_test_fragments[] = {
- { { 0, -1UL, } },
- { { 1, 1, 1, 1, 1, 1, 1, 1 } },
- { { 2, 0, 23, 4, 6, 1, 0 } },
-};
+/* NIST test vector "abc...opq" (digest obtained from "md5sum <data>") */
+DIGEST_TEST ( md5_nist_abc_opq, &md5_algorithm, DIGEST_NIST_ABC_OPQ,
+ DIGEST ( 0x82, 0x15, 0xef, 0x07, 0x96, 0xa2, 0x0b, 0xca, 0xaa,
+ 0xe1, 0x16, 0xd3, 0x87, 0x6c, 0x66, 0x4a ) );
/**
* Perform MD5 self-test
*
*/
static void md5_test_exec ( void ) {
- struct digest_algorithm *digest = &md5_algorithm;
- struct md5_test_vector *test;
- unsigned long cost;
- unsigned int i;
- unsigned int j;
- /* Correctness test */
- for ( i = 0 ; i < ( sizeof ( md5_test_vectors ) /
- sizeof ( md5_test_vectors[0] ) ) ; i++ ) {
- test = &md5_test_vectors[i];
- /* Test with a single pass */
- digest_ok ( digest, NULL, test->data, test->len, test->digest );
- /* Test with fragment lists */
- for ( j = 0 ; j < ( sizeof ( md5_test_fragments ) /
- sizeof ( md5_test_fragments[0] ) ) ; j++ ){
- digest_ok ( digest, &md5_test_fragments[j],
- test->data, test->len, test->digest );
- }
- }
+ /* Correctness tests */
+ digest_ok ( &md5_empty );
+ digest_ok ( &md5_nist_abc );
+ digest_ok ( &md5_nist_abc_opq );
- /* Speed test */
- cost = digest_cost ( digest );
- DBG ( "MD5 required %ld cycles per byte\n", cost );
+ /* Speed tests */
+ DBG ( "MD5 required %ld cycles per byte\n",
+ digest_cost ( &md5_algorithm ) );
}
/** MD5 self-test */
diff --git a/roms/ipxe/src/tests/memcpy_test.c b/roms/ipxe/src/tests/memcpy_test.c
index f1e5503a6..0247c71d4 100644
--- a/roms/ipxe/src/tests/memcpy_test.c
+++ b/roms/ipxe/src/tests/memcpy_test.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/tests/memset_test.c b/roms/ipxe/src/tests/memset_test.c
new file mode 100644
index 000000000..d96f83fa6
--- /dev/null
+++ b/roms/ipxe/src/tests/memset_test.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2015 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/** @file
+ *
+ * memset() self-tests
+ *
+ */
+
+/* Forcibly enable assertions */
+#undef NDEBUG
+
+#include <string.h>
+#include <ipxe/test.h>
+
+/* Provide global functions to allow inspection of generated code */
+
+void memset_zero_0 ( void *dest ) { memset ( dest, 0, 0 ); }
+void memset_zero_1 ( void *dest ) { memset ( dest, 0, 1 ); }
+void memset_zero_2 ( void *dest ) { memset ( dest, 0, 2 ); }
+void memset_zero_3 ( void *dest ) { memset ( dest, 0, 3 ); }
+void memset_zero_4 ( void *dest ) { memset ( dest, 0, 4 ); }
+void memset_zero_5 ( void *dest ) { memset ( dest, 0, 5 ); }
+void memset_zero_6 ( void *dest ) { memset ( dest, 0, 6 ); }
+void memset_zero_7 ( void *dest ) { memset ( dest, 0, 7 ); }
+void memset_zero_8 ( void *dest ) { memset ( dest, 0, 8 ); }
+void memset_zero_9 ( void *dest ) { memset ( dest, 0, 9 ); }
+void memset_zero_10 ( void *dest ) { memset ( dest, 0, 10 ); }
+void memset_zero_11 ( void *dest ) { memset ( dest, 0, 11 ); }
+void memset_zero_12 ( void *dest ) { memset ( dest, 0, 12 ); }
+void memset_zero_13 ( void *dest ) { memset ( dest, 0, 13 ); }
+void memset_zero_14 ( void *dest ) { memset ( dest, 0, 14 ); }
+void memset_zero_15 ( void *dest ) { memset ( dest, 0, 15 ); }
+void memset_zero_16 ( void *dest ) { memset ( dest, 0, 16 ); }
+void memset_zero_17 ( void *dest ) { memset ( dest, 0, 17 ); }
+void memset_zero_18 ( void *dest ) { memset ( dest, 0, 18 ); }
+void memset_zero_19 ( void *dest ) { memset ( dest, 0, 19 ); }
+void memset_zero_20 ( void *dest ) { memset ( dest, 0, 20 ); }
+void memset_zero_21 ( void *dest ) { memset ( dest, 0, 21 ); }
+void memset_zero_22 ( void *dest ) { memset ( dest, 0, 22 ); }
+void memset_zero_23 ( void *dest ) { memset ( dest, 0, 23 ); }
+void memset_zero_24 ( void *dest ) { memset ( dest, 0, 24 ); }
+void memset_zero_25 ( void *dest ) { memset ( dest, 0, 25 ); }
+void memset_zero_26 ( void *dest ) { memset ( dest, 0, 26 ); }
+void memset_zero_27 ( void *dest ) { memset ( dest, 0, 27 ); }
+void memset_zero_28 ( void *dest ) { memset ( dest, 0, 28 ); }
+void memset_zero_29 ( void *dest ) { memset ( dest, 0, 29 ); }
+void memset_zero_30 ( void *dest ) { memset ( dest, 0, 30 ); }
+void memset_zero_31 ( void *dest ) { memset ( dest, 0, 31 ); }
+
+/**
+ * Force a call to the variable-length implementation of memset()
+ *
+ * @v dest Destination address
+ * @v fill Fill pattern
+ * @v len Length of data
+ * @ret dest Destination address
+ */
+__attribute__ (( noinline )) void * memset_var ( void *dest, unsigned int fill,
+ size_t len ) {
+ return memset ( dest, fill, len );
+}
+
+/**
+ * Perform a constant-length memset() test
+ *
+ * @v len Length of data
+ */
+#define MEMSET_TEST_CONSTANT( len ) do { \
+ uint8_t dest_const[ 1 + len + 1 ]; \
+ uint8_t dest_var[ 1 + len + 1 ]; \
+ static uint8_t zero[len]; \
+ unsigned int i; \
+ \
+ for ( i = 0 ; i < sizeof ( dest_const ) ; i++ ) \
+ dest_const[i] = 0xaa; \
+ memset ( ( dest_const + 1 ), 0, len ); \
+ ok ( dest_const[0] == 0xaa ); \
+ ok ( dest_const[ sizeof ( dest_const ) - 1 ] == 0xaa ); \
+ ok ( memcmp ( ( dest_const + 1 ), zero, len ) == 0 ); \
+ \
+ for ( i = 0 ; i < sizeof ( dest_var ) ; i++ ) \
+ dest_var[i] = 0xbb; \
+ memset_var ( ( dest_var + 1 ), 0, len ); \
+ ok ( dest_var[0] == 0xbb ); \
+ ok ( dest_var[ sizeof ( dest_var ) - 1 ] == 0xbb ); \
+ ok ( memcmp ( ( dest_var + 1 ), zero, len ) == 0 ); \
+ } while ( 0 )
+
+/**
+ * Perform memset() self-tests
+ *
+ */
+static void memset_test_exec ( void ) {
+
+ /* Constant-length tests */
+ MEMSET_TEST_CONSTANT ( 0 );
+ MEMSET_TEST_CONSTANT ( 1 );
+ MEMSET_TEST_CONSTANT ( 2 );
+ MEMSET_TEST_CONSTANT ( 3 );
+ MEMSET_TEST_CONSTANT ( 4 );
+ MEMSET_TEST_CONSTANT ( 5 );
+ MEMSET_TEST_CONSTANT ( 6 );
+ MEMSET_TEST_CONSTANT ( 7 );
+ MEMSET_TEST_CONSTANT ( 8 );
+ MEMSET_TEST_CONSTANT ( 9 );
+ MEMSET_TEST_CONSTANT ( 10 );
+ MEMSET_TEST_CONSTANT ( 11 );
+ MEMSET_TEST_CONSTANT ( 12 );
+ MEMSET_TEST_CONSTANT ( 13 );
+ MEMSET_TEST_CONSTANT ( 14 );
+ MEMSET_TEST_CONSTANT ( 15 );
+ MEMSET_TEST_CONSTANT ( 16 );
+ MEMSET_TEST_CONSTANT ( 17 );
+ MEMSET_TEST_CONSTANT ( 18 );
+ MEMSET_TEST_CONSTANT ( 19 );
+ MEMSET_TEST_CONSTANT ( 20 );
+ MEMSET_TEST_CONSTANT ( 21 );
+ MEMSET_TEST_CONSTANT ( 22 );
+ MEMSET_TEST_CONSTANT ( 23 );
+ MEMSET_TEST_CONSTANT ( 24 );
+ MEMSET_TEST_CONSTANT ( 25 );
+ MEMSET_TEST_CONSTANT ( 26 );
+ MEMSET_TEST_CONSTANT ( 27 );
+ MEMSET_TEST_CONSTANT ( 28 );
+ MEMSET_TEST_CONSTANT ( 29 );
+ MEMSET_TEST_CONSTANT ( 30 );
+ MEMSET_TEST_CONSTANT ( 31 );
+}
+
+/** memset() self-test */
+struct self_test memset_test __self_test = {
+ .name = "memset",
+ .exec = memset_test_exec,
+};
diff --git a/roms/ipxe/src/tests/ocsp_test.c b/roms/ipxe/src/tests/ocsp_test.c
index a318c185a..c6d458596 100644
--- a/roms/ipxe/src/tests/ocsp_test.c
+++ b/roms/ipxe/src/tests/ocsp_test.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
@@ -1857,5 +1861,6 @@ struct self_test ocsp_test __self_test = {
};
/* Drag in algorithms required for tests */
+REQUIRING_SYMBOL ( ocsp_test );
REQUIRE_OBJECT ( rsa );
REQUIRE_OBJECT ( sha1 );
diff --git a/roms/ipxe/src/tests/pccrc_test.c b/roms/ipxe/src/tests/pccrc_test.c
new file mode 100644
index 000000000..f4ab573ac
--- /dev/null
+++ b/roms/ipxe/src/tests/pccrc_test.c
@@ -0,0 +1,529 @@
+/*
+ * Copyright (C) 2015 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/** @file
+ *
+ * Peer Content Caching and Retrieval: Content Identification [MS-PCCRC] tests
+ *
+ */
+
+/* Forcibly enable assertions */
+#undef NDEBUG
+
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/pccrc.h>
+#include <ipxe/sha256.h>
+#include <ipxe/sha512.h>
+#include <ipxe/hmac.h>
+#include <ipxe/test.h>
+
+/** Define inline raw data */
+#define DATA(...) { __VA_ARGS__ }
+
+/**
+ * Define an inline content range
+ *
+ * @v START Start offset
+ * @v END End offset
+ * @ret range Content range
+ */
+#define RANGE( START, END ) { .start = START, .end = END }
+
+/**
+ * Define an inline trimmed content range
+ *
+ * @v START Start offset
+ * @v END End offset
+ * @ret trim Trimmed content range
+ */
+#define TRIM( START, END ) { .start = START, .end = END }
+
+/** A content information test */
+struct peerdist_info_test {
+ /** Raw content information */
+ const void *data;
+ /** Length of raw content information */
+ size_t len;
+ /** Expected digest algorithm */
+ struct digest_algorithm *expected_digest;
+ /** Expected digest size */
+ size_t expected_digestsize;
+ /** Expected content range */
+ struct peerdist_range expected_range;
+ /** Expected trimmed content range */
+ struct peerdist_range expected_trim;
+ /** Expected number of segments */
+ unsigned int expected_segments;
+};
+
+/**
+ * Define a content information test
+ *
+ * @v name Test name
+ * @v DATA Raw content information
+ * @v DIGEST Expected digest algorithm
+ * @v DIGESTSIZE Expected digest size
+ * @v RANGE Expected content range
+ * @v TRIM Expected trimmer content range
+ * @v SEGMENTS Expected number of segments
+ * @ret test Content information test
+ *
+ * Raw content information can be obtained from PeerDist-capable web
+ * servers using wget's "--header" option to inject the relevant
+ * PeerDist headers. For example:
+ *
+ * wget --header "Accept-Encoding: peerdist" \
+ * --header "X-P2P-PeerDist: Version=1.0" \
+ * http://peerdist.server.address/test.url -O - | xxd -i -c 11
+ *
+ * Version 1 content information can be retrieved using the headers:
+ *
+ * Accept-Encoding: peerdist
+ * X-P2P-PeerDist: Version=1.0
+ *
+ * Version 2 content information can be retrieved (from compatible
+ * servers) using the headers:
+ *
+ * Accept-Encoding: peerdist
+ * X-P2P-PeerDist: Version=1.1
+ * X-P2P-PeerDistEx: MinContentInformation=2.0, MaxContentInformation=2.0
+ */
+#define PEERDIST_INFO_TEST( name, DATA, DIGEST, DIGESTSIZE, RANGE, \
+ TRIM, SEGMENTS ) \
+ static const uint8_t name ## _data[] = DATA; \
+ static struct peerdist_info_test name = { \
+ .data = name ## _data, \
+ .len = sizeof ( name ## _data ), \
+ .expected_digest = DIGEST, \
+ .expected_digestsize = DIGESTSIZE, \
+ .expected_range = RANGE, \
+ .expected_trim = TRIM, \
+ .expected_segments = SEGMENTS, \
+ }
+
+/** A content information segment test */
+struct peerdist_info_segment_test {
+ /** Segment index */
+ unsigned int index;
+ /** Expected content range */
+ struct peerdist_range expected_range;
+ /** Expected number of blocks */
+ unsigned int expected_blocks;
+ /** Expected block size */
+ size_t expected_blksize;
+ /** Expected segment hash of data */
+ uint8_t expected_hash[PEERDIST_DIGEST_MAX_SIZE];
+ /** Expected segment secret */
+ uint8_t expected_secret[PEERDIST_DIGEST_MAX_SIZE];
+ /** Expected segment identifier */
+ uint8_t expected_id[PEERDIST_DIGEST_MAX_SIZE];
+};
+
+/**
+ * Define a content information segment test
+ *
+ * @v name Test name
+ * @v INDEX Segment index
+ * @v RANGE Expected content range
+ * @v BLOCKS Expected number of blocks
+ * @v BLKSIZE Expected block size
+ * @v HASH Expected segment hash of data
+ * @v SECRET Expected segment secret
+ * @v ID Expected segment identifier
+ * @ret test Content information segment test
+ */
+#define PEERDIST_INFO_SEGMENT_TEST( name, INDEX, RANGE, BLOCKS, \
+ BLKSIZE, HASH, SECRET, ID ) \
+ static struct peerdist_info_segment_test name = { \
+ .index = INDEX, \
+ .expected_range = RANGE, \
+ .expected_blocks = BLOCKS, \
+ .expected_blksize = BLKSIZE, \
+ .expected_hash = HASH, \
+ .expected_secret = SECRET, \
+ .expected_id = ID, \
+ }
+
+/** A content information block test */
+struct peerdist_info_block_test {
+ /** Block index */
+ unsigned int index;
+ /** Expected content range */
+ struct peerdist_range expected_range;
+ /** Expected trimmed content range */
+ struct peerdist_range expected_trim;
+ /** Expected hash of data */
+ uint8_t expected_hash[PEERDIST_DIGEST_MAX_SIZE];
+};
+
+/**
+ * Define a content information block test
+ *
+ * @v name Test name
+ * @v INDEX Block index
+ * @v RANGE Expected content range
+ * @v TRIM Expected trimmed content range
+ * @v HASH Expected hash of data
+ * @ret test Content information block test
+ */
+#define PEERDIST_INFO_BLOCK_TEST( name, INDEX, RANGE, TRIM, HASH ) \
+ static struct peerdist_info_block_test name = { \
+ .index = INDEX, \
+ .expected_range = RANGE, \
+ .expected_trim = TRIM, \
+ .expected_hash = HASH, \
+ }
+
+/**
+ * Define a server passphrase
+ *
+ * @v name Server passphrase name
+ * @v DATA Raw server passphrase
+ *
+ * The server passphrase can be exported from a Windows BranchCache
+ * server using the command:
+ *
+ * netsh branchcache exportkey exported.key somepassword
+ *
+ * and this encrypted exported key can be decrypted using the
+ * oSSL_key_dx or mcrypt_key_dx utilities found in the (prototype)
+ * Prequel project at https://fedorahosted.org/prequel/ :
+ *
+ * oSSL_key_dx exported.key somepassword
+ * or
+ * mcrypt_key_dx exported.key somepassword
+ *
+ * Either command will display both the server passphrase and the
+ * "Server Secret". Note that this latter is the version 1 server
+ * secret (i.e. the SHA-256 of the server passphrase); the
+ * corresponding version 2 server secret can be obtained by
+ * calculating the truncated SHA-512 of the server passphrase.
+ *
+ * We do not know the server passphrase during normal operation. We
+ * use it in the self-tests only to check for typos and other errors
+ * in the test vectors, by checking that the segment secret defined in
+ * a content information segment test is as expected.
+ */
+#define SERVER_PASSPHRASE( name, DATA ) \
+ static uint8_t name[] = DATA
+
+/** Server passphrase used for these test vectors */
+SERVER_PASSPHRASE ( passphrase,
+ DATA ( 0x2a, 0x3d, 0x73, 0xeb, 0x43, 0x5e, 0x9f, 0x2b, 0x8a, 0x34, 0x42,
+ 0x67, 0xe7, 0x46, 0x7a, 0x3c, 0x73, 0x85, 0xc6, 0xe0, 0x55, 0xe2,
+ 0xb4, 0xd3, 0x0d, 0xfe, 0xc7, 0xc3, 0x8b, 0x0e, 0xd7, 0x2c ) );
+
+/** IIS logo (iis-85.png) content information version 1 */
+PEERDIST_INFO_TEST ( iis_85_png_v1,
+ DATA ( 0x00, 0x01, 0x0c, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7e, 0x85, 0x01, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0xd8, 0xd9, 0x76, 0x35, 0x4a, 0x48, 0x72, 0xe9, 0x25, 0x76,
+ 0x18, 0x03, 0xf4, 0x58, 0xd9, 0xda, 0xaa, 0x67, 0xf8, 0xe3, 0x1c,
+ 0x63, 0x0f, 0xb7, 0x4e, 0x6a, 0x31, 0x2e, 0xf8, 0xa2, 0x5a, 0xba,
+ 0x11, 0xaf, 0xc0, 0xd7, 0x94, 0x92, 0x43, 0xf9, 0x4f, 0x9c, 0x1f,
+ 0xab, 0x35, 0xd9, 0xfd, 0x1e, 0x33, 0x1f, 0xcf, 0x78, 0x11, 0xa2,
+ 0xe0, 0x1d, 0x35, 0x87, 0xb3, 0x8d, 0x77, 0x0a, 0x29, 0xe2, 0x02,
+ 0x00, 0x00, 0x00, 0x73, 0xc1, 0x8a, 0xb8, 0x54, 0x91, 0x10, 0xf8,
+ 0xe9, 0x0e, 0x71, 0xbb, 0xc3, 0xab, 0x2a, 0xa8, 0xc4, 0x4d, 0x13,
+ 0xf4, 0x92, 0x94, 0x99, 0x25, 0x5b, 0x66, 0x0f, 0x24, 0xec, 0x77,
+ 0x80, 0x0b, 0x97, 0x4b, 0xdd, 0x65, 0x56, 0x7f, 0xde, 0xec, 0xcd,
+ 0xaf, 0xe4, 0x57, 0xa9, 0x50, 0x3b, 0x45, 0x48, 0xf6, 0x6e, 0xd3,
+ 0xb1, 0x88, 0xdc, 0xfd, 0xa0, 0xac, 0x38, 0x2b, 0x09, 0x71, 0x1a,
+ 0xcc ),
+ &sha256_algorithm, 32, RANGE ( 0, 99710 ), TRIM ( 0, 99710 ), 1 );
+
+/** IIS logo (iis-85.png) content information version 1 segment 0 */
+PEERDIST_INFO_SEGMENT_TEST ( iis_85_png_v1_s0, 0,
+ RANGE ( 0, 99710 ), 2, 65536,
+ DATA ( 0xd8, 0xd9, 0x76, 0x35, 0x4a, 0x48, 0x72, 0xe9, 0x25, 0x76, 0x18,
+ 0x03, 0xf4, 0x58, 0xd9, 0xda, 0xaa, 0x67, 0xf8, 0xe3, 0x1c, 0x63,
+ 0x0f, 0xb7, 0x4e, 0x6a, 0x31, 0x2e, 0xf8, 0xa2, 0x5a, 0xba ),
+ DATA ( 0x11, 0xaf, 0xc0, 0xd7, 0x94, 0x92, 0x43, 0xf9, 0x4f, 0x9c, 0x1f,
+ 0xab, 0x35, 0xd9, 0xfd, 0x1e, 0x33, 0x1f, 0xcf, 0x78, 0x11, 0xa2,
+ 0xe0, 0x1d, 0x35, 0x87, 0xb3, 0x8d, 0x77, 0x0a, 0x29, 0xe2 ),
+ DATA ( 0x49, 0x1b, 0x21, 0x7d, 0xbe, 0xe2, 0xb5, 0xf1, 0x2c, 0xa7, 0x9b,
+ 0x01, 0x5e, 0x06, 0xf4, 0xbb, 0xe6, 0x4f, 0x97, 0x45, 0xba, 0xd7,
+ 0x86, 0x7a, 0xef, 0x17, 0xde, 0x59, 0x92, 0x7e, 0xdc, 0xe9 ) );
+
+/** IIS logo (iis-85.png) content information version 1 segment 0 block 0 */
+PEERDIST_INFO_BLOCK_TEST ( iis_85_png_v1_s0_b0, 0,
+ RANGE ( 0, 65536 ),
+ TRIM ( 0, 65536 ),
+ DATA ( 0x73, 0xc1, 0x8a, 0xb8, 0x54, 0x91, 0x10, 0xf8, 0xe9, 0x0e, 0x71,
+ 0xbb, 0xc3, 0xab, 0x2a, 0xa8, 0xc4, 0x4d, 0x13, 0xf4, 0x92, 0x94,
+ 0x99, 0x25, 0x5b, 0x66, 0x0f, 0x24, 0xec, 0x77, 0x80, 0x0b ) );
+
+/** IIS logo (iis-85.png) content information version 1 segment 0 block 1 */
+PEERDIST_INFO_BLOCK_TEST ( iis_85_png_v1_s0_b1, 1,
+ RANGE ( 65536, 99710 ),
+ TRIM ( 65536, 99710 ),
+ DATA ( 0x97, 0x4b, 0xdd, 0x65, 0x56, 0x7f, 0xde, 0xec, 0xcd, 0xaf, 0xe4,
+ 0x57, 0xa9, 0x50, 0x3b, 0x45, 0x48, 0xf6, 0x6e, 0xd3, 0xb1, 0x88,
+ 0xdc, 0xfd, 0xa0, 0xac, 0x38, 0x2b, 0x09, 0x71, 0x1a, 0xcc ) );
+
+/** IIS logo (iis-85.png) content information version 2 */
+PEERDIST_INFO_TEST ( iis_85_png_v2,
+ DATA ( 0x00, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x88, 0x00, 0x00, 0x99, 0xde, 0xe0, 0xd0, 0xc3, 0x58,
+ 0xe2, 0x68, 0x4b, 0x62, 0x33, 0x0d, 0x32, 0xb5, 0xf1, 0x97, 0x87,
+ 0x24, 0xa0, 0xd0, 0xa5, 0x2b, 0xdc, 0x5e, 0x78, 0x1f, 0xae, 0x71,
+ 0xff, 0x57, 0xa8, 0xbe, 0x3d, 0xd4, 0x58, 0x03, 0x7e, 0xd4, 0x04,
+ 0x11, 0x6b, 0xb6, 0x16, 0xd9, 0xb1, 0x41, 0x16, 0x08, 0x85, 0x20,
+ 0xc4, 0x7c, 0xdc, 0x50, 0xab, 0xce, 0xa3, 0xfa, 0xe1, 0x88, 0xa9,
+ 0x8e, 0xa2, 0x2d, 0xf3, 0xc0, 0x00, 0x00, 0xeb, 0xa0, 0x33, 0x81,
+ 0xd0, 0xd0, 0xcb, 0x74, 0xf4, 0xb6, 0x13, 0xd8, 0x21, 0x0f, 0x37,
+ 0xf0, 0x02, 0xa0, 0x6f, 0x39, 0x10, 0x58, 0x60, 0x96, 0xa1, 0x30,
+ 0xd3, 0x43, 0x98, 0xc0, 0x8e, 0x66, 0xd7, 0xbc, 0xb8, 0xb6, 0xeb,
+ 0x77, 0x83, 0xe4, 0xf8, 0x07, 0x64, 0x7b, 0x63, 0xf1, 0x46, 0xb5,
+ 0x2f, 0x4a, 0xc8, 0x9c, 0xcc, 0x7a, 0xbf, 0x5f, 0xa1, 0x1a, 0xca,
+ 0xfc, 0x2a, 0xcf, 0x50, 0x28, 0x58, 0x6c ),
+ &sha512_algorithm, 32, RANGE ( 0, 99710 ), TRIM ( 0, 99710 ), 2 );
+
+/** IIS logo (iis-85.png) content information version 2 segment 0 */
+PEERDIST_INFO_SEGMENT_TEST ( iis_85_png_v2_s0, 0,
+ RANGE ( 0, 39390 ), 1, 39390,
+ DATA ( 0xe0, 0xd0, 0xc3, 0x58, 0xe2, 0x68, 0x4b, 0x62, 0x33, 0x0d, 0x32,
+ 0xb5, 0xf1, 0x97, 0x87, 0x24, 0xa0, 0xd0, 0xa5, 0x2b, 0xdc, 0x5e,
+ 0x78, 0x1f, 0xae, 0x71, 0xff, 0x57, 0xa8, 0xbe, 0x3d, 0xd4 ),
+ DATA ( 0x58, 0x03, 0x7e, 0xd4, 0x04, 0x11, 0x6b, 0xb6, 0x16, 0xd9, 0xb1,
+ 0x41, 0x16, 0x08, 0x85, 0x20, 0xc4, 0x7c, 0xdc, 0x50, 0xab, 0xce,
+ 0xa3, 0xfa, 0xe1, 0x88, 0xa9, 0x8e, 0xa2, 0x2d, 0xf3, 0xc0 ),
+ DATA ( 0x33, 0x71, 0xbb, 0xea, 0xdd, 0xb6, 0x23, 0x53, 0xad, 0xce, 0xf9,
+ 0x70, 0xa0, 0x6f, 0xdf, 0x65, 0x00, 0x1e, 0x04, 0x21, 0xf4, 0xc7,
+ 0x10, 0x82, 0x76, 0xb0, 0xc3, 0x7a, 0x9f, 0x9e, 0xc1, 0x0f ) );
+
+/** IIS logo (iis-85.png) content information version 2 segment 0 block 0 */
+PEERDIST_INFO_BLOCK_TEST ( iis_85_png_v2_s0_b0, 0,
+ RANGE ( 0, 39390 ),
+ TRIM ( 0, 39390 ),
+ DATA ( 0xe0, 0xd0, 0xc3, 0x58, 0xe2, 0x68, 0x4b, 0x62, 0x33, 0x0d, 0x32,
+ 0xb5, 0xf1, 0x97, 0x87, 0x24, 0xa0, 0xd0, 0xa5, 0x2b, 0xdc, 0x5e,
+ 0x78, 0x1f, 0xae, 0x71, 0xff, 0x57, 0xa8, 0xbe, 0x3d, 0xd4 ) );
+
+/** IIS logo (iis-85.png) content information version 2 segment 1 */
+PEERDIST_INFO_SEGMENT_TEST ( iis_85_png_v2_s1, 1,
+ RANGE ( 39390, 99710 ), 1, 60320,
+ DATA ( 0x33, 0x81, 0xd0, 0xd0, 0xcb, 0x74, 0xf4, 0xb6, 0x13, 0xd8, 0x21,
+ 0x0f, 0x37, 0xf0, 0x02, 0xa0, 0x6f, 0x39, 0x10, 0x58, 0x60, 0x96,
+ 0xa1, 0x30, 0xd3, 0x43, 0x98, 0xc0, 0x8e, 0x66, 0xd7, 0xbc ),
+ DATA ( 0xb8, 0xb6, 0xeb, 0x77, 0x83, 0xe4, 0xf8, 0x07, 0x64, 0x7b, 0x63,
+ 0xf1, 0x46, 0xb5, 0x2f, 0x4a, 0xc8, 0x9c, 0xcc, 0x7a, 0xbf, 0x5f,
+ 0xa1, 0x1a, 0xca, 0xfc, 0x2a, 0xcf, 0x50, 0x28, 0x58, 0x6c ),
+ DATA ( 0xd7, 0xe9, 0x24, 0x42, 0x5e, 0x8f, 0x4f, 0x88, 0xf0, 0x1d, 0xc6,
+ 0xa9, 0xbb, 0x1b, 0xc3, 0x7b, 0xe1, 0x13, 0xec, 0x79, 0x17, 0xc7,
+ 0x45, 0xd4, 0x96, 0x5c, 0x2b, 0x55, 0xfa, 0x16, 0x3a, 0x6e ) );
+
+/** IIS logo (iis-85.png) content information version 2 segment 1 block 0 */
+PEERDIST_INFO_BLOCK_TEST ( iis_85_png_v2_s1_b0, 0,
+ RANGE ( 39390, 99710 ),
+ TRIM ( 39390, 99710 ),
+ DATA ( 0x33, 0x81, 0xd0, 0xd0, 0xcb, 0x74, 0xf4, 0xb6, 0x13, 0xd8, 0x21,
+ 0x0f, 0x37, 0xf0, 0x02, 0xa0, 0x6f, 0x39, 0x10, 0x58, 0x60, 0x96,
+ 0xa1, 0x30, 0xd3, 0x43, 0x98, 0xc0, 0x8e, 0x66, 0xd7, 0xbc ) );
+
+/**
+ * Report content information test result
+ *
+ * @v test Content information test
+ * @v info Content information to fill in
+ * @v file Test code file
+ * @v line Test code line
+ */
+static void peerdist_info_okx ( struct peerdist_info_test *test,
+ struct peerdist_info *info,
+ const char *file, unsigned int line ) {
+
+ /* Parse content information */
+ okx ( peerdist_info ( virt_to_user ( test->data ), test->len,
+ info ) == 0, file, line );
+
+ /* Verify content information */
+ okx ( info->raw.data == virt_to_user ( test->data ), file, line );
+ okx ( info->raw.len == test->len, file, line );
+ okx ( info->digest == test->expected_digest, file, line );
+ okx ( info->digestsize == test->expected_digestsize, file, line );
+ okx ( info->range.start == test->expected_range.start, file, line );
+ okx ( info->range.end == test->expected_range.end, file, line );
+ okx ( info->trim.start == test->expected_trim.start, file, line );
+ okx ( info->trim.end == test->expected_trim.end, file, line );
+ okx ( info->trim.start >= info->range.start, file, line );
+ okx ( info->trim.end <= info->range.end, file, line );
+ okx ( info->segments == test->expected_segments, file, line );
+}
+#define peerdist_info_ok( test, info ) \
+ peerdist_info_okx ( test, info, __FILE__, __LINE__ )
+
+/**
+ * Report content information segment test result
+ *
+ * @v test Content information segment test
+ * @v info Content information
+ * @v segment Segment information to fill in
+ * @v file Test code file
+ * @v line Test code line
+ */
+static void peerdist_info_segment_okx ( struct peerdist_info_segment_test *test,
+ const struct peerdist_info *info,
+ struct peerdist_info_segment *segment,
+ const char *file, unsigned int line ) {
+ size_t digestsize = info->digestsize;
+
+ /* Parse content information segment */
+ okx ( peerdist_info_segment ( info, segment, test->index ) == 0,
+ file, line );
+
+ /* Verify content information segment */
+ okx ( segment->info == info, file, line );
+ okx ( segment->index == test->index, file, line );
+ okx ( segment->range.start == test->expected_range.start, file, line );
+ okx ( segment->range.end == test->expected_range.end, file, line );
+ okx ( segment->blocks == test->expected_blocks, file, line );
+ okx ( segment->blksize == test->expected_blksize, file, line );
+ okx ( memcmp ( segment->hash, test->expected_hash,
+ digestsize ) == 0, file, line );
+ okx ( memcmp ( segment->secret, test->expected_secret,
+ digestsize ) == 0, file, line );
+ okx ( memcmp ( segment->id, test->expected_id,
+ digestsize ) == 0, file, line );
+}
+#define peerdist_info_segment_ok( test, info, segment ) \
+ peerdist_info_segment_okx ( test, info, segment, __FILE__, __LINE__ )
+
+/**
+ * Report content information block test result
+ *
+ * @v test Content information block test
+ * @v segment Segment information
+ * @v block Block information to fill in
+ * @v file Test code file
+ * @v line Test code line
+ */
+static void
+peerdist_info_block_okx ( struct peerdist_info_block_test *test,
+ const struct peerdist_info_segment *segment,
+ struct peerdist_info_block *block,
+ const char *file, unsigned int line ) {
+ const struct peerdist_info *info = segment->info;
+ size_t digestsize = info->digestsize;
+
+ /* Parse content information block */
+ okx ( peerdist_info_block ( segment, block, test->index ) == 0,
+ file, line );
+
+ /* Verify content information block */
+ okx ( block->segment == segment, file, line );
+ okx ( block->index == test->index, file, line );
+ okx ( block->range.start == test->expected_range.start, file, line );
+ okx ( block->range.end == test->expected_range.end, file, line );
+ okx ( block->trim.start == test->expected_trim.start, file, line );
+ okx ( block->trim.end == test->expected_trim.end, file, line );
+ okx ( memcmp ( block->hash, test->expected_hash,
+ digestsize ) == 0, file, line );
+}
+#define peerdist_info_block_ok( test, segment, block ) \
+ peerdist_info_block_okx ( test, segment, block, __FILE__, __LINE__ )
+
+/**
+ * Report server passphrase test result
+ *
+ * @v test Content information segment test
+ * @v info Content information
+ * @v pass Server passphrase
+ * @v pass_len Length of server passphrase
+ * @v file Test code file
+ * @v line Test code line
+ */
+static void
+peerdist_info_passphrase_okx ( struct peerdist_info_segment_test *test,
+ const struct peerdist_info *info,
+ uint8_t *pass, size_t pass_len,
+ const char *file, unsigned int line ) {
+ struct digest_algorithm *digest = info->digest;
+ uint8_t ctx[digest->ctxsize];
+ uint8_t secret[digest->digestsize];
+ uint8_t expected[digest->digestsize];
+ size_t digestsize = info->digestsize;
+ size_t secretsize = digestsize;
+
+ /* Calculate server secret */
+ digest_init ( digest, ctx );
+ digest_update ( digest, ctx, pass, pass_len );
+ digest_final ( digest, ctx, secret );
+
+ /* Calculate expected segment secret */
+ hmac_init ( digest, ctx, secret, &secretsize );
+ assert ( secretsize == digestsize );
+ hmac_update ( digest, ctx, test->expected_hash, digestsize );
+ hmac_final ( digest, ctx, secret, &secretsize, expected );
+ assert ( secretsize == digestsize );
+
+ /* Verify segment secret */
+ okx ( memcmp ( test->expected_secret, expected, digestsize ) == 0,
+ file, line );
+}
+#define peerdist_info_passphrase_ok( test, info, pass, pass_len ) \
+ peerdist_info_passphrase_okx ( test, info, pass, pass_len, \
+ __FILE__, __LINE__ )
+
+/**
+ * Perform content information self-tests
+ *
+ */
+static void peerdist_info_test_exec ( void ) {
+ struct peerdist_info info;
+ struct peerdist_info_segment segment;
+ struct peerdist_info_block block;
+
+ /* IIS logo (iis-85.png) content information version 1 */
+ peerdist_info_ok ( &iis_85_png_v1, &info );
+ peerdist_info_passphrase_ok ( &iis_85_png_v1_s0, &info,
+ passphrase, sizeof ( passphrase ) );
+ peerdist_info_segment_ok ( &iis_85_png_v1_s0, &info, &segment );
+ peerdist_info_block_ok ( &iis_85_png_v1_s0_b0, &segment, &block );
+ peerdist_info_block_ok ( &iis_85_png_v1_s0_b1, &segment, &block );
+
+ /* IIS logo (iis-85.png) content information version 2 */
+ peerdist_info_ok ( &iis_85_png_v2, &info );
+ peerdist_info_passphrase_ok ( &iis_85_png_v2_s0, &info,
+ passphrase, sizeof ( passphrase ) );
+ peerdist_info_segment_ok ( &iis_85_png_v2_s0, &info, &segment );
+ peerdist_info_block_ok ( &iis_85_png_v2_s0_b0, &segment, &block );
+ peerdist_info_passphrase_ok ( &iis_85_png_v2_s1, &info,
+ passphrase, sizeof ( passphrase ) );
+ peerdist_info_segment_ok ( &iis_85_png_v2_s1, &info, &segment );
+ peerdist_info_block_ok ( &iis_85_png_v2_s1_b0, &segment, &block );
+}
+
+/** Content information self-test */
+struct self_test peerdist_info_test __self_test = {
+ .name = "pccrc",
+ .exec = peerdist_info_test_exec,
+};
diff --git a/roms/ipxe/src/tests/pixbuf_test.c b/roms/ipxe/src/tests/pixbuf_test.c
index 15cd33dfd..aaa516bb2 100644
--- a/roms/ipxe/src/tests/pixbuf_test.c
+++ b/roms/ipxe/src/tests/pixbuf_test.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
@@ -53,8 +57,8 @@ void pixbuf_okx ( struct pixel_buffer_test *test, const char *file,
/* Correct image data pointer */
test->image->data = virt_to_user ( ( void * ) test->image->data );
- /* Check that image is detected as PNM */
- okx ( image_probe ( test->image ) == 0, file, line );
+ /* Check that image is detected as correct type */
+ okx ( register_image ( test->image ) == 0, file, line );
okx ( test->image->type == test->type, file, line );
/* Check that a pixel buffer can be created from the image */
@@ -73,4 +77,7 @@ void pixbuf_okx ( struct pixel_buffer_test *test, const char *file,
pixbuf_put ( pixbuf );
}
+
+ /* Unregister image */
+ unregister_image ( test->image );
}
diff --git a/roms/ipxe/src/tests/pixbuf_test.h b/roms/ipxe/src/tests/pixbuf_test.h
index 394f7f5fa..d12829d89 100644
--- a/roms/ipxe/src/tests/pixbuf_test.h
+++ b/roms/ipxe/src/tests/pixbuf_test.h
@@ -1,7 +1,7 @@
#ifndef _PIXBUF_TEST_H
#define _PIXBUF_TEST_H
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/refcnt.h>
diff --git a/roms/ipxe/src/tests/png_test.c b/roms/ipxe/src/tests/png_test.c
index cf32f2034..e921aa2a6 100644
--- a/roms/ipxe/src/tests/png_test.c
+++ b/roms/ipxe/src/tests/png_test.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/tests/pnm_test.c b/roms/ipxe/src/tests/pnm_test.c
index 26b0c0726..d57fdaaef 100644
--- a/roms/ipxe/src/tests/pnm_test.c
+++ b/roms/ipxe/src/tests/pnm_test.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/tests/profile_test.c b/roms/ipxe/src/tests/profile_test.c
index 9d682bf2b..d2f8df211 100644
--- a/roms/ipxe/src/tests/profile_test.c
+++ b/roms/ipxe/src/tests/profile_test.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/tests/pubkey_test.h b/roms/ipxe/src/tests/pubkey_test.h
index 7678453a9..cd65b8703 100644
--- a/roms/ipxe/src/tests/pubkey_test.h
+++ b/roms/ipxe/src/tests/pubkey_test.h
@@ -1,7 +1,7 @@
#ifndef _PUBKEY_TEST_H
#define _PUBKEY_TEST_H
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/crypto.h>
diff --git a/roms/ipxe/src/tests/rsa_test.c b/roms/ipxe/src/tests/rsa_test.c
index 3b32c74bc..c0d05d263 100644
--- a/roms/ipxe/src/tests/rsa_test.c
+++ b/roms/ipxe/src/tests/rsa_test.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/tests/setjmp_test.c b/roms/ipxe/src/tests/setjmp_test.c
new file mode 100644
index 000000000..50ad13f3c
--- /dev/null
+++ b/roms/ipxe/src/tests/setjmp_test.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2015 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/** @file
+ *
+ * setjmp()/longjmp() tests
+ *
+ */
+
+/* Forcibly enable assertions */
+#undef NDEBUG
+
+#include <stddef.h>
+#include <assert.h>
+#include <setjmp.h>
+#include <ipxe/test.h>
+
+/** A setjmp()/longjmp() test */
+struct setjmp_test {
+ /** Jump buffer */
+ jmp_buf env;
+ /** Expected value */
+ int expected;
+ /** Test code file */
+ const char *file;
+ /** Test code line */
+ unsigned int line;
+};
+
+/** Expected jump */
+static struct setjmp_test *jumped;
+
+/**
+ * Report a setjmp() test result
+ *
+ * @v test setjmp()/longjmp() test
+ *
+ * This has to be implemented as a macro since if it were a function
+ * then the context saved by setjmp() would be invalidated when the
+ * function returned.
+ */
+#define setjmp_ok( test ) do { \
+ int value; \
+ /* Sanity check */ \
+ assert ( jumped == NULL ); \
+ /* Initialise test */ \
+ (test)->expected = 0; \
+ (test)->file = __FILE__; \
+ (test)->line = __LINE__; \
+ /* Perform setjmp() */ \
+ value = setjmp ( (test)->env ); \
+ /* Report setjmp()/longjmp() result */ \
+ setjmp_return_ok ( (test), value ); \
+ } while ( 0 )
+
+/**
+ * Report a setjmp()/longjmp() test result
+ *
+ * @v test setjmp()/longjmp() test
+ * @v value Value returned from setjmp()
+ *
+ * This function ends up reporting results from either setjmp() or
+ * longjmp() tests (since calls to longjmp() will return via the
+ * corresponding setjmp()). It therefore uses the test code file and
+ * line stored in the test structure, which will represent the line
+ * from which either setjmp() or longjmp() was called.
+ */
+static void setjmp_return_ok ( struct setjmp_test *test, int value ) {
+
+ /* Determine whether this was reached via setjmp() or longjmp() */
+ if ( value == 0 ) {
+ /* This is the initial call to setjmp() */
+ okx ( test->expected == 0, test->file, test->line );
+ okx ( jumped == NULL, test->file, test->line );
+ } else {
+ /* This is reached via a call to longjmp() */
+ okx ( value == test->expected, test->file, test->line );
+ okx ( jumped == test, test->file, test->line );
+ }
+
+ /* Clear expected jump */
+ jumped = NULL;
+}
+
+/**
+ * Report a longjmp() test result
+ *
+ * @v test setjmp()/longjmp() test
+ * @v file Test code file
+ * @v line Test code line
+ */
+static void longjmp_okx ( struct setjmp_test *test, int value,
+ const char *file, unsigned int line ) {
+
+ /* Record expected value. A zero passed to longjmp() should
+ * result in setjmp() returning a value of one.
+ */
+ test->expected = ( value ? value : 1 );
+
+ /* Record test code file and line */
+ test->file = file;
+ test->line = line;
+
+ /* Record expected jump */
+ jumped = test;
+
+ /* Perform longjmp(). Should return via setjmp_okx() */
+ longjmp ( test->env, value );
+
+ /* longjmp() should never return */
+ assert ( 0 );
+}
+#define longjmp_ok( test, value ) \
+ longjmp_okx ( test, value, __FILE__, __LINE__ )
+
+/**
+ * Perform setjmp()/longjmp() self-tests
+ *
+ */
+static void setjmp_test_exec ( void ) {
+ static struct setjmp_test alpha;
+ static struct setjmp_test beta;
+ static int iteration;
+
+ /* This is one of the very few situations in which the
+ * "for-case" pattern is justified.
+ */
+ for ( iteration = 0 ; iteration < 10 ; iteration++ ) {
+ DBGC ( jumped, "SETJMP test iteration %d\n", iteration );
+ switch ( iteration ) {
+ case 0: setjmp_ok ( &alpha ); break;
+ case 1: setjmp_ok ( &beta ); break;
+ case 2: longjmp_ok ( &alpha, 0 );
+ case 3: longjmp_ok ( &alpha, 1 );
+ case 4: longjmp_ok ( &alpha, 2 );
+ case 5: longjmp_ok ( &beta, 17 );
+ case 6: longjmp_ok ( &beta, 29 );
+ case 7: longjmp_ok ( &alpha, -1 );
+ case 8: longjmp_ok ( &beta, 0 );
+ case 9: longjmp_ok ( &beta, 42 );
+ }
+ }
+}
+
+/** setjmp()/longjmp() self-test */
+struct self_test setjmp_test __self_test = {
+ .name = "setjmp",
+ .exec = setjmp_test_exec,
+};
diff --git a/roms/ipxe/src/tests/settings_test.c b/roms/ipxe/src/tests/settings_test.c
index 4ee6a10fa..f7fb35d0d 100644
--- a/roms/ipxe/src/tests/settings_test.c
+++ b/roms/ipxe/src/tests/settings_test.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
@@ -228,6 +232,12 @@ static struct setting test_hexraw_setting = {
.type = &setting_type_hexraw,
};
+/** Test Base64 setting type */
+static struct setting test_base64_setting = {
+ .name = "test_base64",
+ .type = &setting_type_base64,
+};
+
/** Test UUID setting type */
static struct setting test_uuid_setting = {
.name = "test_uuid",
@@ -379,6 +389,15 @@ static void settings_test_exec ( void ) {
0x17, 0x06, 0x39, 0x6b, 0xf4, 0x48, 0x4e ),
"9e4b6eef36b646fe8f1706396bf4484e" );
+ /* "base64" setting type */
+ storef_ok ( &test_settings, &test_base64_setting,
+ "cGFzc6\nNwaHJhc2U= ",
+ RAW ( 0x70, 0x61, 0x73, 0x73, 0xa3, 0x70, 0x68, 0x72, 0x61,
+ 0x73, 0x65 ) );
+ fetchf_ok ( &test_settings, &test_base64_setting,
+ RAW ( 0x80, 0x81, 0x82, 0x83, 0x84, 0x00, 0xff ),
+ "gIGCg4QA/w==" );
+
/* "uuid" setting type (no store capability) */
fetchf_ok ( &test_settings, &test_uuid_setting,
RAW ( 0x1a, 0x6a, 0x74, 0x9d, 0x0e, 0xda, 0x46, 0x1a,0xa8,
@@ -399,3 +418,7 @@ struct self_test settings_test __self_test = {
.name = "settings",
.exec = settings_test_exec,
};
+
+/* Include real IPv6 setting type */
+REQUIRING_SYMBOL ( settings_test );
+REQUIRE_OBJECT ( ipv6 );
diff --git a/roms/ipxe/src/tests/sha1_test.c b/roms/ipxe/src/tests/sha1_test.c
index bcf761bdd..9f1d75686 100644
--- a/roms/ipxe/src/tests/sha1_test.c
+++ b/roms/ipxe/src/tests/sha1_test.c
@@ -15,87 +15,63 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
* SHA-1 tests
*
+ * NIST test vectors are taken from
+ *
+ * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA1.pdf
+ *
*/
-#include <stdint.h>
+/* Forcibly enable assertions */
+#undef NDEBUG
+
#include <ipxe/sha1.h>
#include <ipxe/test.h>
#include "digest_test.h"
-/** An SHA-1 test vector */
-struct sha1_test_vector {
- /** Test data */
- void *data;
- /** Test data length */
- size_t len;
- /** Expected digest */
- uint8_t digest[SHA1_DIGEST_SIZE];
-};
+/* Empty test vector (digest obtained from "sha1sum /dev/null") */
+DIGEST_TEST ( sha1_empty, &sha1_algorithm, DIGEST_EMPTY,
+ DIGEST ( 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32,
+ 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8,
+ 0x07, 0x09 ) );
-/** SHA-1 test vectors */
-static struct sha1_test_vector sha1_test_vectors[] = {
- /* Empty test data
- *
- * Expected digest value obtained from "sha1sum /dev/null"
- */
- { NULL, 0,
- { 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55,
- 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09 } },
- /* Test data and expected digests taken from the NIST
- * Cryptographic Toolkit Algorithm Examples at
- * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA1.pdf
- */
- { "abc", 3,
- { 0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81, 0x6a, 0xba, 0x3e,
- 0x25, 0x71, 0x78, 0x50, 0xc2, 0x6c, 0x9c, 0xd0, 0xd8, 0x9d } },
- { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56,
- { 0x84, 0x98, 0x3e, 0x44, 0x1c, 0x3b, 0xd2, 0x6e, 0xba, 0xae,
- 0x4a, 0xa1, 0xf9, 0x51, 0x29, 0xe5, 0xe5, 0x46, 0x70, 0xf1 } },
-};
+/* NIST test vector "abc" */
+DIGEST_TEST ( sha1_nist_abc, &sha1_algorithm, DIGEST_NIST_ABC,
+ DIGEST ( 0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81, 0x6a, 0xba,
+ 0x3e, 0x25, 0x71, 0x78, 0x50, 0xc2, 0x6c, 0x9c, 0xd0,
+ 0xd8, 0x9d ) );
-/** SHA-1 test fragment lists */
-static struct digest_test_fragments sha1_test_fragments[] = {
- { { 0, -1UL, } },
- { { 1, 1, 1, 1, 1, 1, 1, 1 } },
- { { 2, 0, 23, 4, 6, 1, 0 } },
-};
+/* NIST test vector "abc...opq" */
+DIGEST_TEST ( sha1_nist_abc_opq, &sha1_algorithm, DIGEST_NIST_ABC_OPQ,
+ DIGEST ( 0x84, 0x98, 0x3e, 0x44, 0x1c, 0x3b, 0xd2, 0x6e, 0xba,
+ 0xae, 0x4a, 0xa1, 0xf9, 0x51, 0x29, 0xe5, 0xe5, 0x46,
+ 0x70, 0xf1 ) );
/**
* Perform SHA-1 self-test
*
*/
static void sha1_test_exec ( void ) {
- struct digest_algorithm *digest = &sha1_algorithm;
- struct sha1_test_vector *test;
- unsigned long cost;
- unsigned int i;
- unsigned int j;
- /* Correctness test */
- for ( i = 0 ; i < ( sizeof ( sha1_test_vectors ) /
- sizeof ( sha1_test_vectors[0] ) ) ; i++ ) {
- test = &sha1_test_vectors[i];
- /* Test with a single pass */
- digest_ok ( digest, NULL, test->data, test->len, test->digest );
- /* Test with fragment lists */
- for ( j = 0 ; j < ( sizeof ( sha1_test_fragments ) /
- sizeof ( sha1_test_fragments[0] ) ) ; j++ ){
- digest_ok ( digest, &sha1_test_fragments[j],
- test->data, test->len, test->digest );
- }
- }
+ /* Correctness tests */
+ digest_ok ( &sha1_empty );
+ digest_ok ( &sha1_nist_abc );
+ digest_ok ( &sha1_nist_abc_opq );
- /* Speed test */
- cost = digest_cost ( digest );
- DBG ( "SHA1 required %ld cycles per byte\n", cost );
+ /* Speed tests */
+ DBG ( "SHA1 required %ld cycles per byte\n",
+ digest_cost ( &sha1_algorithm ) );
}
/** SHA-1 self-test */
diff --git a/roms/ipxe/src/tests/sha256_test.c b/roms/ipxe/src/tests/sha256_test.c
index 06a8cae25..3b4c423fd 100644
--- a/roms/ipxe/src/tests/sha256_test.c
+++ b/roms/ipxe/src/tests/sha256_test.c
@@ -15,93 +15,96 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
- * SHA-256 tests
+ * SHA-256 family tests
+ *
+ * NIST test vectors are taken from
+ *
+ * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA256.pdf
+ * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA224.pdf
*
*/
-#include <stdint.h>
+/* Forcibly enable assertions */
+#undef NDEBUG
+
#include <ipxe/sha256.h>
#include <ipxe/test.h>
#include "digest_test.h"
-/** An SHA-256 test vector */
-struct sha256_test_vector {
- /** Test data */
- void *data;
- /** Test data length */
- size_t len;
- /** Expected digest */
- uint8_t digest[SHA256_DIGEST_SIZE];
-};
+/* Empty test vector (digest obtained from "sha256sum /dev/null") */
+DIGEST_TEST ( sha256_empty, &sha256_algorithm, DIGEST_EMPTY,
+ DIGEST ( 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a,
+ 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae,
+ 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99,
+ 0x1b, 0x78, 0x52, 0xb8, 0x55 ) );
-/** SHA-256 test vectors */
-static struct sha256_test_vector sha256_test_vectors[] = {
- /* Empty test data
- *
- * Expected digest value obtained from "sha256sum /dev/null"
- */
- { NULL, 0,
- { 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4,
- 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b,
- 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55 } },
- /* Test data and expected digests taken from the NIST
- * Cryptographic Toolkit Algorithm Examples at
- * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA256.pdf
- */
- { "abc", 3,
- { 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40,
- 0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17,
- 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad } },
- { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56,
- { 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26,
- 0x93, 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff,
- 0x21, 0x67, 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1 } },
-};
+/* NIST test vector "abc" */
+DIGEST_TEST ( sha256_nist_abc, &sha256_algorithm, DIGEST_NIST_ABC,
+ DIGEST ( 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41,
+ 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03,
+ 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff,
+ 0x61, 0xf2, 0x00, 0x15, 0xad ) );
-/** SHA-256 test fragment lists */
-static struct digest_test_fragments sha256_test_fragments[] = {
- { { 0, -1UL, } },
- { { 1, 1, 1, 1, 1, 1, 1, 1 } },
- { { 2, 0, 23, 4, 6, 1, 0 } },
-};
+/* NIST test vector "abc...opq" */
+DIGEST_TEST ( sha256_nist_abc_opq, &sha256_algorithm, DIGEST_NIST_ABC_OPQ,
+ DIGEST ( 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5,
+ 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c,
+ 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, 0xf6, 0xec, 0xed,
+ 0xd4, 0x19, 0xdb, 0x06, 0xc1 ) );
+
+/* Empty test vector (digest obtained from "sha224sum /dev/null") */
+DIGEST_TEST ( sha224_empty, &sha224_algorithm, DIGEST_EMPTY,
+ DIGEST ( 0xd1, 0x4a, 0x02, 0x8c, 0x2a, 0x3a, 0x2b, 0xc9, 0x47,
+ 0x61, 0x02, 0xbb, 0x28, 0x82, 0x34, 0xc4, 0x15, 0xa2,
+ 0xb0, 0x1f, 0x82, 0x8e, 0xa6, 0x2a, 0xc5, 0xb3, 0xe4,
+ 0x2f ) );
+
+/* NIST test vector "abc" */
+DIGEST_TEST ( sha224_nist_abc, &sha224_algorithm, DIGEST_NIST_ABC,
+ DIGEST ( 0x23, 0x09, 0x7d, 0x22, 0x34, 0x05, 0xd8, 0x22, 0x86,
+ 0x42, 0xa4, 0x77, 0xbd, 0xa2, 0x55, 0xb3, 0x2a, 0xad,
+ 0xbc, 0xe4, 0xbd, 0xa0, 0xb3, 0xf7, 0xe3, 0x6c, 0x9d,
+ 0xa7 ) );
+
+/* NIST test vector "abc...opq" */
+DIGEST_TEST ( sha224_nist_abc_opq, &sha224_algorithm, DIGEST_NIST_ABC_OPQ,
+ DIGEST ( 0x75, 0x38, 0x8b, 0x16, 0x51, 0x27, 0x76, 0xcc, 0x5d,
+ 0xba, 0x5d, 0xa1, 0xfd, 0x89, 0x01, 0x50, 0xb0, 0xc6,
+ 0x45, 0x5c, 0xb4, 0xf5, 0x8b, 0x19, 0x52, 0x52, 0x25,
+ 0x25 ) );
/**
- * Perform SHA-256 self-test
+ * Perform SHA-256 family self-test
*
*/
static void sha256_test_exec ( void ) {
- struct digest_algorithm *digest = &sha256_algorithm;
- struct sha256_test_vector *test;
- unsigned long cost;
- unsigned int i;
- unsigned int j;
- /* Correctness test */
- for ( i = 0 ; i < ( sizeof ( sha256_test_vectors ) /
- sizeof ( sha256_test_vectors[0] ) ) ; i++ ) {
- test = &sha256_test_vectors[i];
- /* Test with a single pass */
- digest_ok ( digest, NULL, test->data, test->len, test->digest );
- /* Test with fragment lists */
- for ( j = 0 ; j < ( sizeof ( sha256_test_fragments ) /
- sizeof ( sha256_test_fragments[0] )); j++ ){
- digest_ok ( digest, &sha256_test_fragments[j],
- test->data, test->len, test->digest );
- }
- }
+ /* Correctness tests */
+ digest_ok ( &sha256_empty );
+ digest_ok ( &sha256_nist_abc );
+ digest_ok ( &sha256_nist_abc_opq );
+ digest_ok ( &sha224_empty );
+ digest_ok ( &sha224_nist_abc );
+ digest_ok ( &sha224_nist_abc_opq );
- /* Speed test */
- cost = digest_cost ( digest );
- DBG ( "SHA256 required %ld cycles per byte\n", cost );
+ /* Speed tests */
+ DBG ( "SHA256 required %ld cycles per byte\n",
+ digest_cost ( &sha256_algorithm ) );
+ DBG ( "SHA224 required %ld cycles per byte\n",
+ digest_cost ( &sha224_algorithm ) );
}
-/** SHA-256 self-test */
+/** SHA-256 family self-test */
struct self_test sha256_test __self_test = {
.name = "sha256",
.exec = sha256_test_exec,
diff --git a/roms/ipxe/src/tests/sha512_test.c b/roms/ipxe/src/tests/sha512_test.c
new file mode 100644
index 000000000..be530ebad
--- /dev/null
+++ b/roms/ipxe/src/tests/sha512_test.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/** @file
+ *
+ * SHA-512 family tests
+ *
+ * NIST test vectors are taken from
+ *
+ * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA512.pdf
+ * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA384.pdf
+ * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA512_256.pdf
+ * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA512_224.pdf
+ *
+ */
+
+/* Forcibly enable assertions */
+#undef NDEBUG
+
+#include <ipxe/sha512.h>
+#include <ipxe/test.h>
+#include "digest_test.h"
+
+/* Empty test vector (digest obtained from "sha512sum /dev/null") */
+DIGEST_TEST ( sha512_empty, &sha512_algorithm, DIGEST_EMPTY,
+ DIGEST ( 0xcf, 0x83, 0xe1, 0x35, 0x7e, 0xef, 0xb8, 0xbd, 0xf1,
+ 0x54, 0x28, 0x50, 0xd6, 0x6d, 0x80, 0x07, 0xd6, 0x20,
+ 0xe4, 0x05, 0x0b, 0x57, 0x15, 0xdc, 0x83, 0xf4, 0xa9,
+ 0x21, 0xd3, 0x6c, 0xe9, 0xce, 0x47, 0xd0, 0xd1, 0x3c,
+ 0x5d, 0x85, 0xf2, 0xb0, 0xff, 0x83, 0x18, 0xd2, 0x87,
+ 0x7e, 0xec, 0x2f, 0x63, 0xb9, 0x31, 0xbd, 0x47, 0x41,
+ 0x7a, 0x81, 0xa5, 0x38, 0x32, 0x7a, 0xf9, 0x27, 0xda,
+ 0x3e ) );
+
+/* NIST test vector "abc" */
+DIGEST_TEST ( sha512_nist_abc, &sha512_algorithm, DIGEST_NIST_ABC,
+ DIGEST ( 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, 0xcc,
+ 0x41, 0x73, 0x49, 0xae, 0x20, 0x41, 0x31, 0x12, 0xe6,
+ 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2, 0x0a, 0x9e, 0xee,
+ 0xe6, 0x4b, 0x55, 0xd3, 0x9a, 0x21, 0x92, 0x99, 0x2a,
+ 0x27, 0x4f, 0xc1, 0xa8, 0x36, 0xba, 0x3c, 0x23, 0xa3,
+ 0xfe, 0xeb, 0xbd, 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c,
+ 0xe8, 0x0e, 0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4,
+ 0x9f ) );
+
+/* NIST test vector "abc...stu" */
+DIGEST_TEST ( sha512_nist_abc_stu, &sha512_algorithm, DIGEST_NIST_ABC_STU,
+ DIGEST ( 0x8e, 0x95, 0x9b, 0x75, 0xda, 0xe3, 0x13, 0xda, 0x8c,
+ 0xf4, 0xf7, 0x28, 0x14, 0xfc, 0x14, 0x3f, 0x8f, 0x77,
+ 0x79, 0xc6, 0xeb, 0x9f, 0x7f, 0xa1, 0x72, 0x99, 0xae,
+ 0xad, 0xb6, 0x88, 0x90, 0x18, 0x50, 0x1d, 0x28, 0x9e,
+ 0x49, 0x00, 0xf7, 0xe4, 0x33, 0x1b, 0x99, 0xde, 0xc4,
+ 0xb5, 0x43, 0x3a, 0xc7, 0xd3, 0x29, 0xee, 0xb6, 0xdd,
+ 0x26, 0x54, 0x5e, 0x96, 0xe5, 0x5b, 0x87, 0x4b, 0xe9,
+ 0x09 ) );
+
+/* Empty test vector (digest obtained from "sha384sum /dev/null") */
+DIGEST_TEST ( sha384_empty, &sha384_algorithm, DIGEST_EMPTY,
+ DIGEST ( 0x38, 0xb0, 0x60, 0xa7, 0x51, 0xac, 0x96, 0x38, 0x4c,
+ 0xd9, 0x32, 0x7e, 0xb1, 0xb1, 0xe3, 0x6a, 0x21, 0xfd,
+ 0xb7, 0x11, 0x14, 0xbe, 0x07, 0x43, 0x4c, 0x0c, 0xc7,
+ 0xbf, 0x63, 0xf6, 0xe1, 0xda, 0x27, 0x4e, 0xde, 0xbf,
+ 0xe7, 0x6f, 0x65, 0xfb, 0xd5, 0x1a, 0xd2, 0xf1, 0x48,
+ 0x98, 0xb9, 0x5b ) );
+
+/* NIST test vector "abc" */
+DIGEST_TEST ( sha384_nist_abc, &sha384_algorithm, DIGEST_NIST_ABC,
+ DIGEST ( 0xcb, 0x00, 0x75, 0x3f, 0x45, 0xa3, 0x5e, 0x8b, 0xb5,
+ 0xa0, 0x3d, 0x69, 0x9a, 0xc6, 0x50, 0x07, 0x27, 0x2c,
+ 0x32, 0xab, 0x0e, 0xde, 0xd1, 0x63, 0x1a, 0x8b, 0x60,
+ 0x5a, 0x43, 0xff, 0x5b, 0xed, 0x80, 0x86, 0x07, 0x2b,
+ 0xa1, 0xe7, 0xcc, 0x23, 0x58, 0xba, 0xec, 0xa1, 0x34,
+ 0xc8, 0x25, 0xa7 ) );
+
+/* NIST test vector "abc...stu" */
+DIGEST_TEST ( sha384_nist_abc_stu, &sha384_algorithm, DIGEST_NIST_ABC_STU,
+ DIGEST ( 0x09, 0x33, 0x0c, 0x33, 0xf7, 0x11, 0x47, 0xe8, 0x3d,
+ 0x19, 0x2f, 0xc7, 0x82, 0xcd, 0x1b, 0x47, 0x53, 0x11,
+ 0x1b, 0x17, 0x3b, 0x3b, 0x05, 0xd2, 0x2f, 0xa0, 0x80,
+ 0x86, 0xe3, 0xb0, 0xf7, 0x12, 0xfc, 0xc7, 0xc7, 0x1a,
+ 0x55, 0x7e, 0x2d, 0xb9, 0x66, 0xc3, 0xe9, 0xfa, 0x91,
+ 0x74, 0x60, 0x39 ) );
+
+/* Empty test vector (digest obtained from "shasum -a 512256 /dev/null") */
+DIGEST_TEST ( sha512_256_empty, &sha512_256_algorithm, DIGEST_EMPTY,
+ DIGEST ( 0xc6, 0x72, 0xb8, 0xd1, 0xef, 0x56, 0xed, 0x28, 0xab,
+ 0x87, 0xc3, 0x62, 0x2c, 0x51, 0x14, 0x06, 0x9b, 0xdd,
+ 0x3a, 0xd7, 0xb8, 0xf9, 0x73, 0x74, 0x98, 0xd0, 0xc0,
+ 0x1e, 0xce, 0xf0, 0x96, 0x7a ) );
+
+/* NIST test vector "abc" */
+DIGEST_TEST ( sha512_256_nist_abc, &sha512_256_algorithm, DIGEST_NIST_ABC,
+ DIGEST ( 0x53, 0x04, 0x8e, 0x26, 0x81, 0x94, 0x1e, 0xf9, 0x9b,
+ 0x2e, 0x29, 0xb7, 0x6b, 0x4c, 0x7d, 0xab, 0xe4, 0xc2,
+ 0xd0, 0xc6, 0x34, 0xfc, 0x6d, 0x46, 0xe0, 0xe2, 0xf1,
+ 0x31, 0x07, 0xe7, 0xaf, 0x23 ) );
+
+/* NIST test vector "abc...stu" */
+DIGEST_TEST ( sha512_256_nist_abc_stu, &sha512_256_algorithm,
+ DIGEST_NIST_ABC_STU,
+ DIGEST ( 0x39, 0x28, 0xe1, 0x84, 0xfb, 0x86, 0x90, 0xf8, 0x40,
+ 0xda, 0x39, 0x88, 0x12, 0x1d, 0x31, 0xbe, 0x65, 0xcb,
+ 0x9d, 0x3e, 0xf8, 0x3e, 0xe6, 0x14, 0x6f, 0xea, 0xc8,
+ 0x61, 0xe1, 0x9b, 0x56, 0x3a ) );
+
+/* Empty test vector (digest obtained from "shasum -a 512224 /dev/null") */
+DIGEST_TEST ( sha512_224_empty, &sha512_224_algorithm, DIGEST_EMPTY,
+ DIGEST ( 0x6e, 0xd0, 0xdd, 0x02, 0x80, 0x6f, 0xa8, 0x9e, 0x25,
+ 0xde, 0x06, 0x0c, 0x19, 0xd3, 0xac, 0x86, 0xca, 0xbb,
+ 0x87, 0xd6, 0xa0, 0xdd, 0xd0, 0x5c, 0x33, 0x3b, 0x84,
+ 0xf4 ) );
+
+/* NIST test vector "abc" */
+DIGEST_TEST ( sha512_224_nist_abc, &sha512_224_algorithm, DIGEST_NIST_ABC,
+ DIGEST ( 0x46, 0x34, 0x27, 0x0f, 0x70, 0x7b, 0x6a, 0x54, 0xda,
+ 0xae, 0x75, 0x30, 0x46, 0x08, 0x42, 0xe2, 0x0e, 0x37,
+ 0xed, 0x26, 0x5c, 0xee, 0xe9, 0xa4, 0x3e, 0x89, 0x24,
+ 0xaa ) );
+
+/* NIST test vector "abc...stu" */
+DIGEST_TEST ( sha512_224_nist_abc_stu, &sha512_224_algorithm,
+ DIGEST_NIST_ABC_STU,
+ DIGEST ( 0x23, 0xfe, 0xc5, 0xbb, 0x94, 0xd6, 0x0b, 0x23, 0x30,
+ 0x81, 0x92, 0x64, 0x0b, 0x0c, 0x45, 0x33, 0x35, 0xd6,
+ 0x64, 0x73, 0x4f, 0xe4, 0x0e, 0x72, 0x68, 0x67, 0x4a,
+ 0xf9 ) );
+
+/**
+ * Perform SHA-512 family self-test
+ *
+ */
+static void sha512_test_exec ( void ) {
+
+ /* Correctness tests */
+ digest_ok ( &sha512_empty );
+ digest_ok ( &sha512_nist_abc );
+ digest_ok ( &sha512_nist_abc_stu );
+ digest_ok ( &sha384_empty );
+ digest_ok ( &sha384_nist_abc );
+ digest_ok ( &sha384_nist_abc_stu );
+ digest_ok ( &sha512_256_empty );
+ digest_ok ( &sha512_256_nist_abc );
+ digest_ok ( &sha512_256_nist_abc_stu );
+ digest_ok ( &sha512_224_empty );
+ digest_ok ( &sha512_224_nist_abc );
+ digest_ok ( &sha512_224_nist_abc_stu );
+
+ /* Speed tests */
+ DBG ( "SHA512 required %ld cycles per byte\n",
+ digest_cost ( &sha512_algorithm ) );
+ DBG ( "SHA384 required %ld cycles per byte\n",
+ digest_cost ( &sha384_algorithm ) );
+ DBG ( "SHA512/256 required %ld cycles per byte\n",
+ digest_cost ( &sha512_256_algorithm ) );
+ DBG ( "SHA512/224 required %ld cycles per byte\n",
+ digest_cost ( &sha512_224_algorithm ) );
+}
+
+/** SHA-512 family self-test */
+struct self_test sha512_test __self_test = {
+ .name = "sha512",
+ .exec = sha512_test_exec,
+};
diff --git a/roms/ipxe/src/tests/string_test.c b/roms/ipxe/src/tests/string_test.c
index 3b48d9f3d..4693b5f65 100644
--- a/roms/ipxe/src/tests/string_test.c
+++ b/roms/ipxe/src/tests/string_test.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
@@ -31,7 +35,10 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <stdint.h>
#include <stdlib.h>
+#include <stdio.h>
#include <string.h>
+#include <strings.h>
+#include <ipxe/string.h>
#include <ipxe/test.h>
/**
@@ -63,6 +70,18 @@ static void string_test_exec ( void ) {
ok ( *(strchr ( "Testing", 'g' )) == 'g' );
ok ( strchr ( "Testing", 'x' ) == NULL );
+ /* Test strrchr() */
+ ok ( strrchr ( "", 'a' ) == NULL );
+ ok ( *(strrchr ( "Haystack", 'a' )) == 'a' );
+ ok ( *(strrchr ( "Haystack", 'k' )) == 'k' );
+ ok ( strrchr ( "Haystack", 'x' ) == NULL );
+
+ /* Test memchr() */
+ ok ( memchr ( "", '\0', 0 ) == NULL );
+ ok ( *((uint8_t *)memchr ( "post\0null", 'l', 9 )) == 'l' );
+ ok ( *((uint8_t *)memchr ( "post\0null", '\0', 9 )) == '\0' );
+ ok ( memchr ( "thingy", 'z', 6 ) == NULL );
+
/* Test strcmp() */
ok ( strcmp ( "", "" ) == 0 );
ok ( strcmp ( "Hello", "Hello" ) == 0 );
@@ -78,11 +97,31 @@ static void string_test_exec ( void ) {
ok ( strncmp ( "Goodbye", "Goodbye world", 32 ) != 0 );
ok ( strncmp ( "Goodbye", "Goodbye world", 7 ) == 0 );
+ /* Test strcasecmp() */
+ ok ( strcasecmp ( "", "" ) == 0 );
+ ok ( strcasecmp ( "Uncle Jack", "Uncle jack" ) == 0 );
+ ok ( strcasecmp ( "Uncle Jack", "Uncle" ) != 0 );
+ ok ( strcasecmp ( "Uncle", "Uncle Jack" ) != 0 );
+ ok ( strcasecmp ( "not", "equal" ) != 0 );
+
/* Test memcmp() */
ok ( memcmp ( "", "", 0 ) == 0 );
ok ( memcmp ( "Foo", "Foo", 3 ) == 0 );
ok ( memcmp ( "Foo", "Bar", 3 ) != 0 );
+ /* Test strstr() */
+ {
+ const char haystack[] = "find me!";
+ char *found;
+
+ found = strstr ( haystack, "find" );
+ ok ( found == &haystack[0] );
+ found = strstr ( haystack, "me" );
+ ok ( found == &haystack[5] );
+ found = strstr ( haystack, "me." );
+ ok ( found == NULL );
+ }
+
/* Test memset() */
{
static uint8_t test[7] = { '>', 1, 1, 1, 1, 1, '<' };
@@ -154,6 +193,107 @@ static void string_test_exec ( void ) {
ok ( strcmp ( dup, "hello" ) == 0 );
free ( dup );
}
+
+ /* Test strcpy() */
+ {
+ const char longer[7] = "copyme";
+ const char shorter[3] = "hi";
+ char dest[7];
+ char *copy;
+
+ copy = strcpy ( dest, longer );
+ ok ( copy == dest );
+ ok ( memcmp ( dest, longer, 7 ) == 0 );
+ copy = strcpy ( dest, shorter );
+ ok ( copy == dest );
+ ok ( memcmp ( dest, shorter, 3 ) == 0 );
+ ok ( memcmp ( ( dest + 3 ), ( longer + 3 ), 4 ) == 0 );
+ }
+
+ /* Test strncpy() */
+ {
+ const char src[5] = "copy";
+ const char orig[8] = { 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x' };
+ const char zero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+ char dest[8];
+ char *copy;
+
+ memcpy ( dest, orig, sizeof ( dest ) );
+ copy = strncpy ( dest, src, 5 );
+ ok ( copy == dest );
+ ok ( memcmp ( dest, src, 5 ) == 0 );
+ ok ( memcmp ( dest + 5, orig + 5, 3 ) == 0 );
+ memcpy ( dest, orig, sizeof ( dest ) );
+ copy = strncpy ( dest, src, 4 );
+ ok ( copy == dest );
+ ok ( memcmp ( dest, src, 4 ) == 0 );
+ ok ( memcmp ( dest + 4, orig + 4, 4 ) == 0 );
+ memcpy ( dest, orig, sizeof ( dest ) );
+ copy = strncpy ( dest, src, 8 );
+ ok ( copy == dest );
+ ok ( memcmp ( dest, src, 5 ) == 0 );
+ ok ( memcmp ( dest + 5, zero + 5, 3 ) == 0 );
+ memcpy ( dest, orig, sizeof ( dest ) );
+ copy = strncpy ( dest, "", 8 );
+ ok ( copy == dest );
+ ok ( memcmp ( dest, zero, 8 ) == 0 );
+ }
+
+ /* Test strcat() */
+ {
+ char buf[16] = "append";
+ char *dest;
+
+ dest = strcat ( buf, " this" );
+ ok ( dest == buf );
+ ok ( strcmp ( buf, "append this" ) == 0 );
+ }
+
+ /* Test digit_value() */
+ {
+ unsigned int i;
+ char buf[2];
+ for ( i = 0 ; i < 16 ; i++ ) {
+ snprintf ( buf, sizeof ( buf ), "%x", i );
+ ok ( digit_value ( buf[0] ) == i );
+ snprintf ( buf, sizeof ( buf ), "%X", i );
+ ok ( digit_value ( buf[0] ) == i );
+ }
+ ok ( digit_value ( 0 ) >= 16 );
+ ok ( digit_value ( 9 ) >= 16 );
+ ok ( digit_value ( '0' - 1 ) >= 16 );
+ ok ( digit_value ( '9' + 1 ) >= 16 );
+ ok ( digit_value ( 'A' - 1 ) >= 16 );
+ ok ( digit_value ( 'F' + 1 ) >= 16 );
+ ok ( digit_value ( 'a' - 1 ) >= 16 );
+ ok ( digit_value ( 'f' + 1 ) >= 16 );
+ }
+
+ /* Test strtoul() */
+ ok ( strtoul ( "12345", NULL, 0 ) == 12345UL );
+ ok ( strtoul ( " 741", NULL, 10 ) == 741UL );
+ ok ( strtoul ( " 555a", NULL, 0 ) == 555UL );
+ ok ( strtoul ( " 555a", NULL, 16 ) == 0x555aUL );
+ ok ( strtoul ( "-12", NULL, 0 ) == -12UL );
+ ok ( strtoul ( "+3", NULL, 0 ) == 3UL );
+ ok ( strtoul ( "721", NULL, 0 ) == 721UL );
+ ok ( strtoul ( "721", NULL, 8 ) == 0721UL );
+ ok ( strtoul ( "0721", NULL, 0 ) == 0721UL );
+ ok ( strtoul ( "", NULL, 0 ) == 0UL );
+ ok ( strtoul ( "\t0xcAfe", NULL, 0 ) == 0xcafeUL );
+ ok ( strtoul ( "0xffffffff", NULL, 0 ) == 0xffffffffUL );
+ {
+ static const char string[] = "123aHa.world";
+ char *endp;
+ ok ( strtoul ( string, &endp, 0 ) == 123UL );
+ ok ( endp == &string[3] );
+ ok ( strtoul ( string, &endp, 16 ) == 0x123aUL );
+ ok ( endp == &string[4] );
+ ok ( strtoul ( string, &endp, 26 ) ==
+ ( ( ( ( ( 1 * 26 + 2 ) * 26 + 3 ) * 26 + 10 ) * 26
+ + 17 ) * 26 + 10 ) );
+ ok ( endp == &string[6] );
+ }
}
/** String self-test */
diff --git a/roms/ipxe/src/tests/tcpip_test.c b/roms/ipxe/src/tests/tcpip_test.c
index 00c88ae32..759f886bc 100644
--- a/roms/ipxe/src/tests/tcpip_test.c
+++ b/roms/ipxe/src/tests/tcpip_test.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/tests/test.c b/roms/ipxe/src/tests/test.c
index c05e72a76..67bd4cf89 100644
--- a/roms/ipxe/src/tests/test.c
+++ b/roms/ipxe/src/tests/test.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/tests/tests.c b/roms/ipxe/src/tests/tests.c
index 2b4b78c7c..54ce86677 100644
--- a/roms/ipxe/src/tests/tests.c
+++ b/roms/ipxe/src/tests/tests.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
@@ -26,6 +30,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
*/
/* Drag in all applicable self-tests */
+PROVIDE_REQUIRING_SYMBOL();
+REQUIRE_OBJECT ( memset_test );
REQUIRE_OBJECT ( memcpy_test );
REQUIRE_OBJECT ( string_test );
REQUIRE_OBJECT ( math_test );
@@ -37,12 +43,14 @@ REQUIRE_OBJECT ( base16_test );
REQUIRE_OBJECT ( settings_test );
REQUIRE_OBJECT ( time_test );
REQUIRE_OBJECT ( tcpip_test );
+REQUIRE_OBJECT ( ipv4_test );
REQUIRE_OBJECT ( ipv6_test );
REQUIRE_OBJECT ( crc32_test );
REQUIRE_OBJECT ( md5_test );
REQUIRE_OBJECT ( sha1_test );
REQUIRE_OBJECT ( sha256_test );
-REQUIRE_OBJECT ( aes_cbc_test );
+REQUIRE_OBJECT ( sha512_test );
+REQUIRE_OBJECT ( aes_test );
REQUIRE_OBJECT ( hmac_drbg_test );
REQUIRE_OBJECT ( hash_df_test );
REQUIRE_OBJECT ( bigint_test );
@@ -56,3 +64,6 @@ REQUIRE_OBJECT ( png_test );
REQUIRE_OBJECT ( dns_test );
REQUIRE_OBJECT ( uri_test );
REQUIRE_OBJECT ( profile_test );
+REQUIRE_OBJECT ( setjmp_test );
+REQUIRE_OBJECT ( pccrc_test );
+REQUIRE_OBJECT ( linebuf_test );
diff --git a/roms/ipxe/src/tests/time_test.c b/roms/ipxe/src/tests/time_test.c
index 28acebee6..3bf01dd1d 100644
--- a/roms/ipxe/src/tests/time_test.c
+++ b/roms/ipxe/src/tests/time_test.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/tests/uri_test.c b/roms/ipxe/src/tests/uri_test.c
index 14f1b4ad0..da7fb8abe 100644
--- a/roms/ipxe/src/tests/uri_test.c
+++ b/roms/ipxe/src/tests/uri_test.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
@@ -66,6 +70,8 @@ struct uri_resolve_test {
struct uri_tftp_test {
/** Next-server address */
struct in_addr next_server;
+ /** Port number */
+ unsigned int port;
/** Filename */
const char *filename;
/** URI */
@@ -330,7 +336,7 @@ static void uri_tftp_okx ( struct uri_tftp_test *test, const char *file,
size_t len;
/* Construct URI */
- uri = tftp_uri ( test->next_server, test->filename );
+ uri = tftp_uri ( test->next_server, test->port, test->filename );
okx ( uri != NULL, file, line );
if ( uri ) {
uri_okx ( uri, &test->uri, file, line );
@@ -674,7 +680,7 @@ static struct uri_resolve_test uri_fragment = {
/** TFTP URI with absolute path */
static struct uri_tftp_test uri_tftp_absolute = {
- { .s_addr = htonl ( 0xc0a80002 ) /* 192.168.0.2 */ },
+ { .s_addr = htonl ( 0xc0a80002 ) /* 192.168.0.2 */ }, 0,
"/absolute/path",
{
.scheme = "tftp",
@@ -686,7 +692,7 @@ static struct uri_tftp_test uri_tftp_absolute = {
/** TFTP URI with relative path */
static struct uri_tftp_test uri_tftp_relative = {
- { .s_addr = htonl ( 0xc0a80003 ) /* 192.168.0.3 */ },
+ { .s_addr = htonl ( 0xc0a80003 ) /* 192.168.0.3 */ }, 0,
"relative/path",
{
.scheme = "tftp",
@@ -698,7 +704,7 @@ static struct uri_tftp_test uri_tftp_relative = {
/** TFTP URI with path containing special characters */
static struct uri_tftp_test uri_tftp_icky = {
- { .s_addr = htonl ( 0x0a000006 ) /* 10.0.0.6 */ },
+ { .s_addr = htonl ( 0x0a000006 ) /* 10.0.0.6 */ }, 0,
"C:\\tftpboot\\icky#path",
{
.scheme = "tftp",
@@ -708,6 +714,19 @@ static struct uri_tftp_test uri_tftp_icky = {
"tftp://10.0.0.6/C%3A\\tftpboot\\icky%23path",
};
+/** TFTP URI with custom port */
+static struct uri_tftp_test uri_tftp_port = {
+ { .s_addr = htonl ( 0xc0a80001 ) /* 192.168.0.1 */ }, 4069,
+ "/another/path",
+ {
+ .scheme = "tftp",
+ .host = "192.168.0.1",
+ .port = "4069",
+ .path = "/another/path",
+ },
+ "tftp://192.168.0.1:4069/another/path",
+};
+
/** Current working URI test */
static struct uri_churi_test uri_churi[] = {
{
@@ -842,6 +861,7 @@ static void uri_test_exec ( void ) {
uri_tftp_ok ( &uri_tftp_absolute );
uri_tftp_ok ( &uri_tftp_relative );
uri_tftp_ok ( &uri_tftp_icky );
+ uri_tftp_ok ( &uri_tftp_port );
/* Current working URI tests */
uri_churi_ok ( uri_churi );
diff --git a/roms/ipxe/src/tests/vsprintf_test.c b/roms/ipxe/src/tests/vsprintf_test.c
index 11512ec8e..0ad4f1c56 100644
--- a/roms/ipxe/src/tests/vsprintf_test.c
+++ b/roms/ipxe/src/tests/vsprintf_test.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/tests/x509_test.c b/roms/ipxe/src/tests/x509_test.c
index fd39e12d2..658d5247c 100644
--- a/roms/ipxe/src/tests/x509_test.c
+++ b/roms/ipxe/src/tests/x509_test.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
@@ -1105,6 +1109,7 @@ struct self_test x509_test __self_test = {
};
/* Drag in algorithms required for tests */
+REQUIRING_SYMBOL ( x509_test );
REQUIRE_OBJECT ( rsa );
REQUIRE_OBJECT ( sha1 );
REQUIRE_OBJECT ( sha256 );
diff --git a/roms/ipxe/src/usr/autoboot.c b/roms/ipxe/src/usr/autoboot.c
index 47476ae40..912543828 100644
--- a/roms/ipxe/src/usr/autoboot.c
+++ b/roms/ipxe/src/usr/autoboot.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <stdio.h>
@@ -42,6 +46,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <usr/prompt.h>
#include <usr/autoboot.h>
#include <config/general.h>
+#include <config/branding.h>
/** @file
*
@@ -101,7 +106,7 @@ static struct uri * parse_next_server_and_filename ( struct in_addr next_server,
/* Construct a TFTP URI for the filename, if applicable */
if ( next_server.s_addr && filename[0] && ! uri_is_absolute ( uri ) ) {
uri_put ( uri );
- uri = tftp_uri ( next_server, filename );
+ uri = tftp_uri ( next_server, 0, filename );
if ( ! uri )
return NULL;
}
@@ -173,6 +178,7 @@ int uriboot ( struct uri *filename, struct uri *root_path, int drive,
if ( filename ) {
if ( ( rc = imgdownload ( filename, 0, &image ) ) != 0 )
goto err_download;
+ imgstat ( image );
image->flags |= IMAGE_AUTO_UNREGISTER;
if ( ( rc = image_exec ( image ) ) != 0 ) {
printf ( "Could not boot image: %s\n",
@@ -434,9 +440,14 @@ int netboot ( struct net_device *netdev ) {
* @ret is_autoboot Network device matches the autoboot device
*/
static int is_autoboot_busloc ( struct net_device *netdev ) {
+ struct device *dev;
- return ( ( netdev->dev->desc.bus_type == autoboot_desc.bus_type ) &&
- ( netdev->dev->desc.location == autoboot_desc.location ) );
+ for ( dev = netdev->dev ; dev ; dev = dev->parent ) {
+ if ( ( dev->desc.bus_type == autoboot_desc.bus_type ) &&
+ ( dev->desc.location == autoboot_desc.location ) )
+ return 1;
+ }
+ return 0;
}
/**
@@ -522,7 +533,8 @@ static int shell_banner ( void ) {
/* Prompt user */
printf ( "\n" );
- return ( prompt ( "Press Ctrl-B for the iPXE command line...",
+ return ( prompt ( "Press Ctrl-B for the " PRODUCT_SHORT_NAME
+ " command line...",
( ( BANNER_TIMEOUT * TICKS_PER_SEC ) / 10 ),
CTRL_B ) == 0 );
}
@@ -531,28 +543,29 @@ static int shell_banner ( void ) {
* Main iPXE flow of execution
*
* @v netdev Network device, or NULL
+ * @ret rc Return status code
*/
-void ipxe ( struct net_device *netdev ) {
+int ipxe ( struct net_device *netdev ) {
struct feature *feature;
struct image *image;
char *scriptlet;
+ int rc;
/*
* Print welcome banner
*
*
* If you wish to brand this build of iPXE, please do so by
- * defining the string PRODUCT_NAME in config/general.h.
+ * defining the string PRODUCT_NAME in config/branding.h.
*
* While nothing in the GPL prevents you from removing all
* references to iPXE or http://ipxe.org, we prefer you not to
* do so.
*
*/
- printf ( NORMAL "\n\n%s\n" BOLD "iPXE %s"
- NORMAL " -- Open Source Network Boot Firmware -- "
- CYAN "http://ipxe.org" NORMAL "\n"
- "Features:", product_name, product_version );
+ printf ( NORMAL "\n\n" PRODUCT_NAME "\n" BOLD PRODUCT_SHORT_NAME " %s"
+ NORMAL " -- " PRODUCT_TAG_LINE " -- "
+ CYAN PRODUCT_URI NORMAL "\nFeatures:", product_version );
for_each_table_entry ( feature, FEATURES )
printf ( " %s", feature->name );
printf ( "\n" );
@@ -560,28 +573,30 @@ void ipxe ( struct net_device *netdev ) {
/* Boot system */
if ( ( image = first_image() ) != NULL ) {
/* We have an embedded image; execute it */
- image_exec ( image );
+ return image_exec ( image );
} else if ( shell_banner() ) {
/* User wants shell; just give them a shell */
- shell();
+ return shell();
} else {
fetch_string_setting_copy ( NULL, &scriptlet_setting,
&scriptlet );
if ( scriptlet ) {
/* User has defined a scriptlet; execute it */
- system ( scriptlet );
+ rc = system ( scriptlet );
free ( scriptlet );
+ return rc;
} else {
/* Try booting. If booting fails, offer the
* user another chance to enter the shell.
*/
if ( netdev ) {
- netboot ( netdev );
+ rc = netboot ( netdev );
} else {
- autoboot();
+ rc = autoboot();
}
if ( shell_banner() )
- shell();
+ rc = shell();
+ return rc;
}
}
}
diff --git a/roms/ipxe/src/usr/dhcpmgmt.c b/roms/ipxe/src/usr/dhcpmgmt.c
index 23982b19c..dcb360b23 100644
--- a/roms/ipxe/src/usr/dhcpmgmt.c
+++ b/roms/ipxe/src/usr/dhcpmgmt.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <stdio.h>
diff --git a/roms/ipxe/src/usr/fcmgmt.c b/roms/ipxe/src/usr/fcmgmt.c
index a30f37a71..6f626143f 100644
--- a/roms/ipxe/src/usr/fcmgmt.c
+++ b/roms/ipxe/src/usr/fcmgmt.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <stdio.h>
diff --git a/roms/ipxe/src/usr/ifmgmt.c b/roms/ipxe/src/usr/ifmgmt.c
index 3d05895c2..aefdaa45d 100644
--- a/roms/ipxe/src/usr/ifmgmt.c
+++ b/roms/ipxe/src/usr/ifmgmt.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <stdio.h>
@@ -99,11 +103,12 @@ static void ifstat_errors ( struct net_device_stats *stats,
*/
void ifstat ( struct net_device *netdev ) {
printf ( "%s: %s using %s on %s (%s)\n"
- " [Link:%s, TX:%d TXE:%d RX:%d RXE:%d]\n",
+ " [Link:%s%s, TX:%d TXE:%d RX:%d RXE:%d]\n",
netdev->name, netdev_addr ( netdev ),
netdev->dev->driver_name, netdev->dev->name,
( netdev_is_open ( netdev ) ? "open" : "closed" ),
( netdev_link_ok ( netdev ) ? "up" : "down" ),
+ ( netdev_link_blocked ( netdev ) ? " (blocked)" : "" ),
netdev->tx_stats.good, netdev->tx_stats.bad,
netdev->rx_stats.good, netdev->rx_stats.bad );
if ( ! netdev_link_ok ( netdev ) ) {
diff --git a/roms/ipxe/src/usr/imgmgmt.c b/roms/ipxe/src/usr/imgmgmt.c
index c9c571640..352dd0242 100644
--- a/roms/ipxe/src/usr/imgmgmt.c
+++ b/roms/ipxe/src/usr/imgmgmt.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/usr/imgtrust.c b/roms/ipxe/src/usr/imgtrust.c
index da7ff2ef0..a269833a6 100644
--- a/roms/ipxe/src/usr/imgtrust.c
+++ b/roms/ipxe/src/usr/imgtrust.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdlib.h>
#include <errno.h>
diff --git a/roms/ipxe/src/usr/ipstat.c b/roms/ipxe/src/usr/ipstat.c
index 95ad799dc..0f09cc2ff 100644
--- a/roms/ipxe/src/usr/ipstat.c
+++ b/roms/ipxe/src/usr/ipstat.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdio.h>
#include <ipxe/ipstat.h>
diff --git a/roms/ipxe/src/usr/lotest.c b/roms/ipxe/src/usr/lotest.c
index ad7a2fad7..6b328713c 100644
--- a/roms/ipxe/src/usr/lotest.c
+++ b/roms/ipxe/src/usr/lotest.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/usr/neighmgmt.c b/roms/ipxe/src/usr/neighmgmt.c
index e4d21a208..9fd88f82b 100644
--- a/roms/ipxe/src/usr/neighmgmt.c
+++ b/roms/ipxe/src/usr/neighmgmt.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdio.h>
#include <ipxe/neighbour.h>
diff --git a/roms/ipxe/src/usr/pingmgmt.c b/roms/ipxe/src/usr/pingmgmt.c
index 16b3ec994..bb33c5d47 100644
--- a/roms/ipxe/src/usr/pingmgmt.c
+++ b/roms/ipxe/src/usr/pingmgmt.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdio.h>
diff --git a/roms/ipxe/src/usr/profstat.c b/roms/ipxe/src/usr/profstat.c
index 991427473..d80fa26b2 100644
--- a/roms/ipxe/src/usr/profstat.c
+++ b/roms/ipxe/src/usr/profstat.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdio.h>
#include <ipxe/profile.h>
diff --git a/roms/ipxe/src/usr/prompt.c b/roms/ipxe/src/usr/prompt.c
index 957b4ab3d..fca0a157c 100644
--- a/roms/ipxe/src/usr/prompt.c
+++ b/roms/ipxe/src/usr/prompt.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
diff --git a/roms/ipxe/src/usr/pxemenu.c b/roms/ipxe/src/usr/pxemenu.c
index b69905df1..2d05d3f51 100644
--- a/roms/ipxe/src/usr/pxemenu.c
+++ b/roms/ipxe/src/usr/pxemenu.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
diff --git a/roms/ipxe/src/usr/route.c b/roms/ipxe/src/usr/route.c
index ba4cc3221..690ba3b6b 100644
--- a/roms/ipxe/src/usr/route.c
+++ b/roms/ipxe/src/usr/route.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/netdevice.h>
#include <usr/route.h>
@@ -42,3 +46,7 @@ void route ( void ) {
}
}
}
+
+/* Drag in routing management configuration */
+REQUIRING_SYMBOL ( route );
+REQUIRE_OBJECT ( config_route );
diff --git a/roms/ipxe/src/usr/route_ipv4.c b/roms/ipxe/src/usr/route_ipv4.c
index b4d1b7bf3..6260335ac 100644
--- a/roms/ipxe/src/usr/route_ipv4.c
+++ b/roms/ipxe/src/usr/route_ipv4.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdio.h>
#include <ipxe/netdevice.h>
diff --git a/roms/ipxe/src/usr/route_ipv6.c b/roms/ipxe/src/usr/route_ipv6.c
index 6045f85bb..9e94b4a15 100644
--- a/roms/ipxe/src/usr/route_ipv6.c
+++ b/roms/ipxe/src/usr/route_ipv6.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdio.h>
#include <ipxe/netdevice.h>
diff --git a/roms/ipxe/src/usr/sync.c b/roms/ipxe/src/usr/sync.c
index f7a04c44c..f599588ae 100644
--- a/roms/ipxe/src/usr/sync.c
+++ b/roms/ipxe/src/usr/sync.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <ipxe/job.h>
diff --git a/roms/ipxe/src/util/Option/ROM.pm b/roms/ipxe/src/util/Option/ROM.pm
index 6c396730e..232cf16b8 100644
--- a/roms/ipxe/src/util/Option/ROM.pm
+++ b/roms/ipxe/src/util/Option/ROM.pm
@@ -529,6 +529,26 @@ sub new {
return $hash;
}
+sub device_list {
+ my $hash = shift;
+ my $self = tied(%$hash);
+
+ my $device_list = $hash->{device_list};
+ return undef unless $device_list;
+
+ my @ids;
+ my $offset = ( $self->{offset} + $device_list );
+ while ( 1 ) {
+ my $raw = substr ( ${$self->{data}}, $offset, 2 );
+ my $id = unpack ( "S", $raw );
+ last unless $id;
+ push @ids, $id;
+ $offset += 2;
+ }
+
+ return @ids;
+}
+
##############################################################################
#
# Option::ROM::PnP
diff --git a/roms/ipxe/src/util/disrom.pl b/roms/ipxe/src/util/disrom.pl
index 574957acd..920a86b24 100755
--- a/roms/ipxe/src/util/disrom.pl
+++ b/roms/ipxe/src/util/disrom.pl
@@ -55,6 +55,10 @@ do {
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};
+ if ( $pci->{device_list} ) {
+ printf " %-16s %s\n", "Device list:",
+ ( join ( ", ", map { sprintf "0x%04x", $_ } $pci->device_list ) );
+ }
printf " %-16s 0x%02x%02x%02x\n", "Device class:",
$pci->{base_class}, $pci->{sub_class}, $pci->{prog_intf};
printf " %-16s 0x%04x (%d)\n", "Image length:",
diff --git a/roms/ipxe/src/util/elf2efi.c b/roms/ipxe/src/util/elf2efi.c
index 45d539574..e68fa5d14 100644
--- a/roms/ipxe/src/util/elf2efi.c
+++ b/roms/ipxe/src/util/elf2efi.c
@@ -478,11 +478,13 @@ static void process_reloc ( bfd *bfd __attribute__ (( unused )),
/* Skip absolute symbols; the symbol value won't
* change when the object is loaded.
*/
+ } else if ( ( strcmp ( howto->name, "R_386_NONE" ) == 0 ) ||
+ ( strcmp ( howto->name, "R_X86_64_NONE" ) == 0 ) ) {
+ /* Ignore dummy relocations used by REQUIRE_SYMBOL() */
} 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 ) ) {
+ } else if ( strcmp ( howto->name, "R_386_32" ) == 0 ) {
/* Generate a 4-byte PE relocation */
generate_pe_reloc ( pe_reltab, offset, 4 );
} else if ( strcmp ( howto->name, "R_386_16" ) == 0 ) {
diff --git a/roms/ipxe/src/util/licence.pl b/roms/ipxe/src/util/licence.pl
index 0e43c7b4c..79e70fd65 100755
--- a/roms/ipxe/src/util/licence.pl
+++ b/roms/ipxe/src/util/licence.pl
@@ -37,6 +37,7 @@ my $known_licences = {
desc => "GPL version 2 (or, at your option, any later version)",
can_subsume => {
gpl_any => 1,
+ gpl2_or_later_or_ubdl => 1,
public_domain => 1,
bsd3 => 1,
bsd2 => 1,
@@ -49,6 +50,7 @@ my $known_licences = {
can_subsume => {
gpl_any => 1,
gpl2_or_later => 1,
+ gpl2_or_later_or_ubdl => 1,
public_domain => 1,
bsd3 => 1,
bsd2 => 1,
@@ -56,6 +58,17 @@ my $known_licences = {
isc => 1,
},
},
+ gpl2_or_later_or_ubdl => {
+ desc => ( "GPL version 2 (or, at your option, any later version) or ".
+ "Unmodified Binary Distribution Licence" ),
+ can_subsume => {
+ public_domain => 1,
+ bsd3 => 1,
+ bsd2 => 1,
+ mit => 1,
+ isc => 1,
+ },
+ },
public_domain => {
desc => "Public Domain",
can_subsume => {},
diff --git a/roms/ipxe/src/util/parserom.pl b/roms/ipxe/src/util/parserom.pl
index e278e6336..28df60652 100755
--- a/roms/ipxe/src/util/parserom.pl
+++ b/roms/ipxe/src/util/parserom.pl
@@ -1,66 +1,260 @@
#!/usr/bin/env perl
#
-# Parse PCI_ROM and ISA_ROM entries from a source file on stdin and
-# output the relevant Makefile variable definitions to stdout
+# Parse PCI_ROM and ISA_ROM entries from source file(s) specified as
+# arguments and output the relevant Makefile rules to STDOUT.
#
-# Based upon portions of Ken Yap's genrules.pl
+# Originally based on portions of Ken Yap's genrules.pl. Completely
+# rewritten by Robin Smidsrød to be more maintainable.
use strict;
use warnings;
+use Getopt::Long;
-die "Syntax: $0 driver_source.c" unless @ARGV == 1;
-my $source = shift;
-open DRV, "<$source" or die "Could not open $source: $!\n";
+# Parse command-line options
+my @exclude_driver_classes = ();
+my @exclude_drivers = ();
+my $debug = 0;
+my $help = 0;
+GetOptions(
+ "exclude-driver-class=s" => \@exclude_driver_classes,
+ "exclude-driver=s" => \@exclude_drivers,
+ "debug" => \$debug,
+ "help" => \$help,
+);
-( my $family, my $driver_name ) = ( $source =~ /^(.*?([^\/]+))\..$/ )
- or die "Could not parse source file name \"$source\"\n";
+# Convert exclution arrays to lookup tables
+my $exclude_driver_class_map = { map { $_ => 1 } @exclude_driver_classes };
+my $exclude_driver_map = { map { $_ => 1 } @exclude_drivers };
-my $printed_family;
+# Ensure STDOUT and STDERR are synchronized if debugging
+if ( $debug ) {
+ STDOUT->autoflush(1);
+ STDERR->autoflush(1);
+}
+
+# Compile regular expressions here for slight performance boost
+my %RE = (
+ 'parse_driver_class' => qr{ drivers/ (\w+?) / }x,
+ 'parse_family' => qr{^ (?:\./)? (.*) \..+? $}x,
+ 'find_rom_line' => qr/^ \s* ( (PCI|ISA)_ROM \s* \( \s* (.*?) ) $/x,
+ 'extract_pci_id' => qr/^ \s* 0x([0-9A-Fa-f]{4}) \s* ,? \s* (.*) $/x,
+ 'extract_quoted_string' => qr/^ \s* \" ([^\"]*?) \" \s* ,? \s* (.*) $/x,
+);
+
+# Show help if required arguments are missing or help was requested
+show_usage_and_exit() if $help or @ARGV < 1;
+
+# Process each source file specified
+process_source_file($_) for @ARGV;
+
+exit;
+
+sub show_usage_and_exit {
+ print STDERR <<"EOM";
+Syntax: $0 [<options>] <source-file> [<source-file>]
+Options:
+ --exclude-driver-class Exclude specified driver classes
+ --exclude-driver Exclude specified drivers
+ --debug Output debug information on STDERR
+ --help This help information
+EOM
+ exit 1;
+}
+
+# Figure out if source file is a driver and look for ROM declarations
+sub process_source_file {
+ my ($source_file) = @_;
+ return unless defined $source_file;
+ return unless length $source_file;
+ my $state = { 'source_file' => $source_file };
+ log_debug("SOURCE_FILE", $state->{source_file});
+ # Skip source files that aren't drivers
+ parse_driver_class( $state );
+ unless ( $state->{'driver_class'} ) {
+ log_debug("SKIP_NOT_DRIVER", $state->{source_file} );
+ return;
+ }
+ # Skip source files with driver classes that are explicitly excluded
+ if ( $exclude_driver_class_map->{ $state->{'driver_class'} } ) {
+ log_debug("SKIP_EXCL_CLASS", $state->{'driver_class'} );
+ return;
+ }
+ # Skip source files without driver information
+ parse_family( $state );
+ parse_driver_name( $state );
+ unless ( $state->{'family'} and $state->{'driver_name'} ) {
+ log_debug("SKIP_NO_DRV_INFO", $state->{source_file} );
+ return;
+ }
+ # Skip source files with drivers that are explicitly excluded
+ if ( $exclude_driver_map->{ $state->{'driver_name'} } ) {
+ log_debug("SKIP_EXCL_DRV", $state->{'driver_name'} );
+ return;
+ }
+ # Iterate through lines in source files looking for ROM declarations
+ # and # output Makefile rules
+ open( my $fh, "<", $state->{'source_file'} )
+ or die "Couldn't open $state->{source_file}: $!\n";
+ while (<$fh>) {
+ process_rom_decl($state, $1, $2, $3) if m/$RE{find_rom_line}/;
+ }
+ close($fh) or die "Couldn't close $source_file: $!\n";
+ return 1;
+}
+
+# Verify that the found ROM declaration is sane and dispatch to the right
+# handler depending on type
+sub process_rom_decl {
+ my ($state, $rom_line, $rom_type, $rom_decl) = @_;
+ return unless defined $rom_line;
+ return unless length $rom_line;
+ log_debug("ROM_LINE", $rom_line);
+ return unless defined $rom_type;
+ return unless length $rom_type;
+ log_debug("ROM_TYPE", $rom_type);
+ $state->{'type'} = lc $rom_type;
+ return process_pci_rom($state, $rom_decl) if $rom_type eq "PCI";
+ return process_isa_rom($state, $rom_decl) if $rom_type eq "ISA";
+ return;
+}
+
+# Extract values from PCI_ROM declaration lines and dispatch to
+# Makefile rule generator
+sub process_pci_rom {
+ my ($state, $decl) = @_;
+ return unless defined $decl;
+ return unless length $decl;
+ (my $vendor, $decl) = extract_pci_id($decl, 'PCI_VENDOR');
+ (my $device, $decl) = extract_pci_id($decl, 'PCI_DEVICE');
+ (my $image, $decl) = extract_quoted_string($decl, 'IMAGE');
+ (my $desc, $decl) = extract_quoted_string($decl, 'DESCRIPTION');
+ if ( $vendor and $device and $image and $desc ) {
+ print_make_rules( $state, "${vendor}${device}", $desc, $vendor, $device );
+ print_make_rules( $state, $image, $desc, $vendor, $device, 1 );
+ }
+ else {
+ log_debug("WARNING", "Malformed PCI_ROM macro on line $. of $state->{source_file}");
+ }
+ return 1;
+}
+
+# Extract values from ISA_ROM declaration lines and dispatch to
+# Makefile rule generator
+sub process_isa_rom {
+ my ($state, $decl) = @_;
+ return unless defined $decl;
+ return unless length $decl;
+ (my $image, $decl) = extract_quoted_string($decl, 'IMAGE');
+ (my $desc, $decl) = extract_quoted_string($decl, 'DESCRIPTION');
+ if ( $image and $desc ) {
+ print_make_rules( $state, $image, $desc );
+ }
+ else {
+ log_debug("WARNING", "Malformed ISA_ROM macro on line $. of $state->{source_file}");
+ }
+ return 1;
+}
-sub rom {
- ( my $type, my $image, my $desc, my $vendor, my $device, my $dup ) = @_;
- my $ids = $vendor ? "$vendor,$device" : "-";
- unless ( $printed_family ) {
+# Output Makefile rules for the specified ROM declarations
+sub print_make_rules {
+ my ( $state, my $image, my $desc, my $vendor, my $device, my $dup ) = @_;
+ unless ( $state->{'is_header_printed'} ) {
+ print "# NIC\t\n";
+ print "# NIC\tfamily\t$state->{family}\n";
+ print "DRIVERS_$state->{driver_class} += $state->{driver_name}\n";
+ print "DRIVERS += $state->{driver_name}\n";
+ print "\n";
+ $state->{'is_header_printed'} = 1;
+ }
+ return if $vendor and ( $vendor eq "ffff" or $device eq "ffff" );
+ my $ids = $vendor ? "$vendor,$device" : "-";
+ print "# NIC\t$image\t$ids\t$desc\n";
+ print "DRIVER_$image = $state->{driver_name}\n";
+ print "ROM_TYPE_$image = $state->{type}\n";
+ print "ROM_DESCRIPTION_$image = \"$desc\"\n";
+ print "PCI_VENDOR_$image = 0x$vendor\n" if $vendor;
+ print "PCI_DEVICE_$image = 0x$device\n" if $device;
+ print "ROMS += $image\n" unless $dup;
+ print "ROMS_$state->{driver_name} += $image\n" unless $dup;
print "\n";
- print "# NIC\t\n";
- print "# NIC\tfamily\t$family\n";
- print "DRIVERS += $driver_name\n";
- $printed_family = 1;
- }
- print "\n";
- return if ( $vendor && ( ( $vendor eq "ffff" ) || ( $device eq "ffff" ) ) );
- print "# NIC\t$image\t$ids\t$desc\n";
- print "DRIVER_$image = $driver_name\n";
- print "ROM_TYPE_$image = $type\n";
- print "ROM_DESCRIPTION_$image = \"$desc\"\n";
- print "PCI_VENDOR_$image = 0x$vendor\n" if $vendor;
- print "PCI_DEVICE_$image = 0x$device\n" if $device;
- print "ROMS += $image\n" unless $dup;
- print "ROMS_$driver_name += $image\n" unless $dup;
+ return 1;
+}
+
+# Driver class is whatever comes after the "drivers" part of the filename (relative path)
+sub parse_driver_class {
+ my ($state) = @_;
+ my $filename = $state->{'source_file'};
+ return unless defined $filename;
+ return unless length $filename;
+ if ( $filename =~ m/$RE{parse_driver_class}/ ) {
+ log_debug("DRIVER_CLASS", $1);
+ $state->{'driver_class'} = $1;
+ }
+ return;
+}
+
+# Family name is filename (relative path) without extension
+sub parse_family {
+ my ($state) = @_;
+ my $filename = $state->{'source_file'};
+ return unless defined $filename;
+ return unless length $filename;
+ if ( $filename =~ m/$RE{parse_family}/ ) {
+ log_debug("FAMILY", $1);
+ $state->{'family'} = $1;
+ }
+ return;
+}
+
+# Driver name is last part of family name
+sub parse_driver_name {
+ my ($state) = @_;
+ my $family = $state->{'family'};
+ return unless defined $family;
+ return unless length $family;
+ my @parts = split "/", $family;
+ $state->{'driver_name'} = $parts[-1];
+ log_debug("DRIVER", $state->{'driver_name'});
+ return;
}
-while ( <DRV> ) {
- next unless /(PCI|ISA)_ROM\s*\(/;
-
- if ( /^\s*PCI_ROM\s*\(
- \s*0x([0-9A-Fa-f]{4})\s*, # PCI vendor
- \s*0x([0-9A-Fa-f]{4})\s*, # PCI device
- \s*\"([^\"]*)\"\s*, # Image
- \s*\"([^\"]*)\"\s*, # Description
- \s*.*\s* # Driver data
- \)/x ) {
- ( my $vendor, my $device, my $image, my $desc ) = ( lc $1, lc $2, $3, $4 );
- rom ( "pci", lc "${vendor}${device}", $desc, $vendor, $device );
- rom ( "pci", $image, $desc, $vendor, $device, 1 );
- } elsif ( /^\s*ISA_ROM\s*\(
- \s*\"([^\"]*)\"\s*, # Image
- \s*\"([^\"]*)\"\s* # Description
- \)/x ) {
- ( my $image, my $desc ) = ( $1, $2 );
- rom ( "isa", $image, $desc );
- } else {
- warn "Malformed PCI_ROM or ISA_ROM macro on line $. of $source\n";
- }
+# Extract a PCI vendor/device ID e.g. 0x8086, possibly followed by a comma
+# Should always be 4-digit lower-case hex number
+sub extract_pci_id {
+ my ($str, $label) = @_;
+ return "", $str unless defined $str;
+ return "", $str unless length $str;
+ if ( $str =~ m/$RE{extract_pci_id}/ ) {
+ my $id = lc $1;
+ log_debug($label, $id);
+ return $id, $2;
+ }
+ return "", $str;
}
-close DRV;
+# Extract a double-quoted string, possibly followed by a comma
+sub extract_quoted_string {
+ my ($str, $label) = @_;
+ return "", $str unless defined $str;
+ return "", $str unless length $str;
+ if ( $str =~ m/$RE{extract_quoted_string}/ ) {
+ log_debug($label, $1);
+ return $1, $2;
+ }
+ return "", $str;
+}
+
+# Output debug info to STDERR (off by default)
+sub log_debug {
+ my ($label, $str) = @_;
+ return unless $debug;
+ return unless defined $str;
+ print STDERR "\n" if $label eq 'SOURCE_FILE';
+ print STDERR "=";
+ if ( defined $label ) {
+ my $pad_count = 16 - length $label;
+ print STDERR $label . ":" . ( " " x $pad_count );
+ }
+ print STDERR $str . "\n";
+ return;
+}
diff --git a/roms/ipxe/src/util/relicense.pl b/roms/ipxe/src/util/relicense.pl
new file mode 100755
index 000000000..41954c1b3
--- /dev/null
+++ b/roms/ipxe/src/util/relicense.pl
@@ -0,0 +1,169 @@
+#!/usr/bin/perl -w
+
+=head1 NAME
+
+relicense.pl
+
+=head1 SYNOPSIS
+
+relicense.pl [options] -p <permissions file> <file> [<file>...]
+
+Option:
+
+ -p,--permitted=FILE Specify file of emails with relicensing permission
+ -f,--force Manually force relicensing
+ -h,--help Display brief help message
+ -v,--verbose Increase verbosity
+ -q,--quiet Decrease verbosity
+
+=cut
+
+use File::Slurp;
+use IPC::Run qw ( run );
+use Getopt::Long;
+use Pod::Usage;
+use strict;
+use warnings;
+
+# Parse command-line options
+my $verbosity = 0;
+my $permfile;
+my $force;
+Getopt::Long::Configure ( "bundling", "auto_abbrev" );
+GetOptions (
+ 'permitted|p=s' => \$permfile,
+ 'force|f' => \$force,
+ 'verbose|v+' => sub { $verbosity++; },
+ 'quiet|q+' => sub { $verbosity--; },
+ 'help|h' => sub { pod2usage ( 1 ); },
+) or die "Could not parse command-line options";
+pod2usage ( 1 ) unless @ARGV;
+
+# Read permitted emails file
+my @emails = ( $permfile ? read_file ( $permfile ) : () );
+chomp @emails;
+my $permitted = { map { /^.*<(\S+)>$/; ( $1 || $_ ) => 1 } @emails };
+
+# Define list of relicensable licences
+my $relicensable = {
+ GPL2_OR_LATER => 1,
+};
+
+# Define blurb to be added to copyright notice
+my $blurb = '
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.';
+
+# Process files
+my @succeeded;
+my @failed;
+while ( my $filename = shift @ARGV ) {
+
+ # Read file to determine existing licence
+ my $file = read_file ( $filename );
+ my @licences = ( $file =~ /^\s*FILE_LICENCE\s*\(\s*(\S+)\s*\)\s*;?$/mg );
+ die "No licence declaration in $filename\n" unless @licences;
+ die "Multiple licence declarations in $filename\n" if @licences > 1;
+ my $licence = $licences[0];
+
+ # Skip if file is already UBDL-licensed
+ next if $licence =~ /_OR_UBDL$/;
+
+ # Fail immediately if file is not a candidate for relicensing
+ if ( ! exists $relicensable->{$licence} ) {
+ print "Non-relicensable licence $licence in $filename\n";
+ push @failed, $filename;
+ next;
+ }
+
+ # Run git-blame
+ my $stdout;
+ my $stderr;
+ run [ "git", "blame", "-M", "-C", "-p", "-w", $filename ],
+ \undef, \$stdout, \$stderr
+ or die "git-blame $filename: $?";
+ die $stderr if $stderr;
+
+ # Process output
+ my @stdout = split ( /\n/, $stdout );
+ chomp @stdout;
+ my $details = {};
+ my $failures = 0;
+ while ( @stdout ) {
+
+ # Parse output
+ my $commit_line = shift @stdout;
+ ( my $commit, undef, my $lineno, undef, my $count ) =
+ ( $commit_line =~
+ /^([0-9a-f]{40})\s+([0-9]+)\s+([0-9]+)(\s+([0-9]+))?$/ )
+ or die "Malformed commit line \"$commit_line\"\n";
+ if ( $count ) {
+ $details->{$commit} ||= {};
+ while ( ! ( $stdout[0] =~ /^\t/ ) ) {
+ my $detail_line = shift @stdout;
+ ( my $key, undef, my $value ) =
+ ( $detail_line =~ /^([a-z-]+)(\s+(.+))?$/ )
+ or die "Malformed detail line \"$detail_line\" for $commit_line\n";
+ $details->{$commit}->{$key} = $value;
+ }
+ }
+ die "Missing commit details for $commit_line\n"
+ unless %{$details->{$commit}};
+ my $code_line = shift @stdout;
+ ( my $line ) = ( $code_line =~ /^\t(.*)$/ )
+ or die "Malformed code line \"$code_line\" for $commit_line\n";
+
+ # Skip trivial lines and lines so common that they are likely to
+ # be misattributed by git-blame
+ next if $line =~ /^\s*$/; # Empty lines
+ next if $line =~ /^\s*\/\*/; # Start of comments
+ next if $line =~ /^\s*\*/; # Middle (or end) of comments
+ next if $line =~ /^\s*\{\s*$/; # Standalone opening braces
+ next if $line =~ /^\s*\};?\s*$/; # Standalone closing braces
+ next if $line =~ /^\#include/; # Header inclusions
+ next if $line =~ /^\s*return\s+0;/; # return 0;
+ next if $line =~ /^\s*return\s+rc;/; # return rc;
+ next if $line =~ /^\s*PCI_ROM\s*\(.*\)\s*,\s*$/; # PCI IDs
+ next if $line =~ /^\s*FILE_LICENCE\s*\(.*\)\s*;$/; # Licence declarations
+
+ # Identify author
+ my $author_mail = $details->{$commit}->{"author-mail"}
+ or die "Missing author email for $commit_line\n";
+ ( my $email ) = ( $author_mail =~ /^<(\S+)>$/ )
+ or die "Malformed author email \"$author_mail\" for $commit_line\n";
+ undef $email if exists $details->{$commit}->{boundary};
+
+ # Check for relicensing permission
+ next if defined $email && exists $permitted->{$email};
+
+ # Print out lines lacking permission
+ printf $filename."\n" unless $failures;
+ printf "%4d %-30s %s\n", $lineno, ( $email || "<root>" ), $line;
+ $failures++;
+ }
+
+ # Fail if there are any non-trivial lines lacking relicensing permission
+ if ( $failures && ! $force ) {
+ push @failed, $filename;
+ next;
+ }
+
+ # Modify FILE_LICENCE() line
+ $file =~ s/(^\s*FILE_LICENCE\s*\(\s*${licence})(\s*\)\s*;?$)/$1_OR_UBDL$2/m
+ or die "Could not modify FILE_LICENCE() in $filename\n";
+
+ # Modify copyright notice, if present
+ if ( $file =~ /GNU General Public License/i ) {
+ $file =~ s/(02110-1301, USA.$)/$1${blurb}/m
+ or die "Could not modify copyright notice in $filename\n";
+ }
+
+ # Write out modified file
+ write_file ( $filename, { atomic => 1 }, $file );
+ push @succeeded, $filename;
+}
+
+print "Relicensed: ".join ( " ", @succeeded )."\n" if @succeeded;
+die "Cannot relicense: ".join ( " ", @failed )."\n" if @failed;
diff --git a/roms/ipxe/src/util/zbin.c b/roms/ipxe/src/util/zbin.c
index 3b7cf95b3..1862a3827 100644
--- a/roms/ipxe/src/util/zbin.c
+++ b/roms/ipxe/src/util/zbin.c
@@ -1,13 +1,21 @@
+#include <stdint.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
#include <sys/stat.h>
-
-#define ENCODE
-#define VERBOSE
-#include "nrv2b.c"
-FILE *infile, *outfile;
+#include <lzma.h>
#define DEBUG 0
+/* LZMA filter choices. Must match those used by unlzma.S */
+#define LZMA_LC 2
+#define LZMA_LP 0
+#define LZMA_PB 0
+
+/* LZMA preset choice. This is a policy decision */
+#define LZMA_PRESET ( LZMA_PRESET_DEFAULT | LZMA_PRESET_EXTREME )
+
struct input_file {
void *buf;
size_t len;
@@ -177,13 +185,75 @@ static int process_zinfo_copy ( struct input_file *input,
return 0;
}
+#define OPCODE_CALL 0xe8
+#define OPCODE_JMP 0xe9
+
+static void bcj_filter ( void *data, size_t len ) {
+ struct {
+ uint8_t opcode;
+ int32_t target;
+ } __attribute__ (( packed )) *jump;
+ ssize_t limit = ( len - sizeof ( *jump ) );
+ ssize_t offset;
+
+ /* liblzma does include an x86 BCJ filter, but it's hideously
+ * convoluted and undocumented. This BCJ filter is
+ * substantially simpler and achieves the same compression (at
+ * the cost of requiring the decompressor to know the size of
+ * the decompressed data, which we already have in iPXE).
+ */
+ for ( offset = 0 ; offset <= limit ; offset++ ) {
+ jump = ( data + offset );
+
+ /* Skip instructions that are not followed by a rel32 address */
+ if ( ( jump->opcode != OPCODE_CALL ) &&
+ ( jump->opcode != OPCODE_JMP ) )
+ continue;
+
+ /* Convert rel32 address to an absolute address. To
+ * avoid false positives (which damage the compression
+ * ratio), we should check that the jump target is
+ * within the range [0,limit).
+ *
+ * Some output values would then end up being mapped
+ * from two distinct input values, making the
+ * transformation irreversible. To solve this, we
+ * transform such values back into the part of the
+ * range which would otherwise correspond to no input
+ * values.
+ */
+ if ( ( jump->target >= -offset ) &&
+ ( jump->target < ( limit - offset ) ) ) {
+ /* Convert relative addresses in the range
+ * [-offset,limit-offset) to absolute
+ * addresses in the range [0,limit).
+ */
+ jump->target += offset;
+ } else if ( ( jump->target >= ( limit - offset ) ) &&
+ ( jump->target < limit ) ) {
+ /* Convert positive numbers in the range
+ * [limit-offset,limit) to negative numbers in
+ * the range [-offset,0).
+ */
+ jump->target -= limit;
+ }
+ offset += sizeof ( jump->target );
+ };
+}
+
static int process_zinfo_pack ( struct input_file *input,
struct output_file *output,
union zinfo_record *zinfo ) {
struct zinfo_pack *pack = &zinfo->pack;
size_t offset = pack->offset;
size_t len = pack->len;
- unsigned long packed_len;
+ size_t packed_len = 0;
+ size_t remaining = ( output->max_len - output->len );
+ lzma_options_lzma options;
+ const lzma_filter filters[] = {
+ { .id = LZMA_FILTER_LZMA1, .options = &options },
+ { .id = LZMA_VLI_UNKNOWN }
+ };
if ( ( offset + len ) > input->len ) {
fprintf ( stderr, "Input buffer overrun on pack\n" );
@@ -196,9 +266,15 @@ static int process_zinfo_pack ( struct input_file *input,
return -1;
}
- if ( ucl_nrv2b_99_compress ( ( input->buf + offset ), len,
- ( output->buf + output->len ),
- &packed_len, 0 ) != UCL_E_OK ) {
+ bcj_filter ( ( input->buf + offset ), len );
+
+ lzma_lzma_preset ( &options, LZMA_PRESET );
+ options.lc = LZMA_LC;
+ options.lp = LZMA_LP;
+ options.pb = LZMA_PB;
+ if ( lzma_raw_buffer_encode ( filters, NULL, ( input->buf + offset ),
+ len, ( output->buf + output->len ),
+ &packed_len, remaining ) != LZMA_OK ) {
fprintf ( stderr, "Compression failure\n" );
return -1;
}
@@ -206,7 +282,7 @@ static int process_zinfo_pack ( struct input_file *input,
if ( DEBUG ) {
fprintf ( stderr, "PACK [%#zx,%#zx) to [%#zx,%#zx)\n",
offset, ( offset + len ), output->len,
- ( size_t )( output->len + packed_len ) );
+ ( output->len + packed_len ) );
}
output->len += packed_len;
diff --git a/roms/openbios/arch/ppc/qemu/init.c b/roms/openbios/arch/ppc/qemu/init.c
index 4fe8b7220..2b5b8e1a9 100644
--- a/roms/openbios/arch/ppc/qemu/init.c
+++ b/roms/openbios/arch/ppc/qemu/init.c
@@ -302,6 +302,11 @@ cpu_generic_init(const struct cpudef *cpu)
fword("encode-string");
push_str("state");
fword("property");
+
+ PUSH(0x20);
+ fword("encode-int");
+ push_str("reservation-granule-size");
+ fword("property");
}
static void
@@ -680,6 +685,60 @@ static void ffilll(void)
}
}
+/*
+ * adler32 ( adler buf len -- checksum )
+ *
+ * Adapted from Mark Adler's original implementation (zlib license)
+ *
+ * Both OS 9 and BootX require this word for payload validation.
+ */
+
+#define DO1(buf,i) {s1 += buf[i]; s2 += s1;}
+#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf) DO8(buf,0); DO8(buf,8);
+
+static void adler32(void)
+{
+ uint32_t len = (uint32_t)POP();
+ char *buf = (char *)POP();
+ uint32_t adler = (uint32_t)POP();
+
+ if (buf == NULL) {
+ RET(-1);
+ }
+
+ uint32_t base = 65521;
+ uint32_t nmax = 5552;
+
+ uint32_t s1 = adler & 0xffff;
+ uint32_t s2 = (adler >> 16) & 0xffff;
+
+ uint32_t k;
+ while (len > 0) {
+ k = (len < nmax ? len : nmax);
+ len -= k;
+
+ while (k >= 16) {
+ DO16(buf);
+ buf += 16;
+ k -= 16;
+ }
+ if (k != 0) {
+ do {
+ s1 += *buf++;
+ s2 += s1;
+ } while (--k);
+ }
+
+ s1 %= base;
+ s2 %= base;
+ }
+
+ RET(s2 << 16 | s1);
+}
+
void
arch_of_init(void)
{
@@ -945,6 +1004,9 @@ arch_of_init(void)
/* Implementation of filll word (required by BootX) */
bind_func("filll", ffilll);
+
+ /* Implementation of adler32 word (required by OS 9, BootX) */
+ bind_func("(adler32)", adler32);
bind_func("platform-boot", boot);
bind_func("(go)", go);
diff --git a/roms/openbios/arch/ppc/qemu/methods.c b/roms/openbios/arch/ppc/qemu/methods.c
index fd993daa9..930b47c4e 100644
--- a/roms/openbios/arch/ppc/qemu/methods.c
+++ b/roms/openbios/arch/ppc/qemu/methods.c
@@ -114,6 +114,8 @@ static void
ciface_quiesce( unsigned long args[], unsigned long ret[] )
{
usb_exit();
+
+ ob_ide_quiesce();
#if 0
unsigned long msr;
/* This seems to be the correct thing to do - but I'm not sure */
@@ -164,21 +166,21 @@ DECLARE_UNNAMED_NODE( mmu, INSTALL_OPEN, 0 );
DECLARE_NODE( mmu_ciface, 0, 0, "+/openprom/client-services" );
-/* ( phys size align --- base ) */
+/* ( [phys] size align --- base ) */
static void
mem_claim( void )
{
ucell align = POP();
ucell size = POP();
- ucell phys = POP();
- ucell ret = ofmem_claim_phys( phys, size, align );
+ phys_addr_t phys = -1;
- if( ret == -1 ) {
- printk("MEM: claim failure\n");
- throw( -13 );
- return;
+ if (!align) {
+ phys = POP();
}
- PUSH( ret );
+
+ phys = ofmem_claim_phys(phys, size, align);
+
+ PUSH(phys);
}
/* ( phys size --- ) */
@@ -188,24 +190,24 @@ mem_release( void )
POP(); POP();
}
-/* ( phys size align --- base ) */
+/* ( [virt] size align --- base ) */
static void
mmu_claim( void )
{
ucell align = POP();
ucell size = POP();
- ucell phys = POP();
- ucell ret = ofmem_claim_virt( phys, size, align );
+ ucell virt = -1;
- if( ret == -1 ) {
- printk("MMU: CLAIM failure\n");
- throw( -13 );
- return;
+ if (!align) {
+ virt = POP();
}
- PUSH( ret );
+
+ virt = ofmem_claim_virt(virt, size, align);
+
+ PUSH(virt);
}
-/* ( phys size --- ) */
+/* ( virt size --- ) */
static void
mmu_release( void )
{
diff --git a/roms/openbios/arch/ppc/qemu/qemu.fs b/roms/openbios/arch/ppc/qemu/qemu.fs
index 458af1bc7..11e344a59 100644
--- a/roms/openbios/arch/ppc/qemu/qemu.fs
+++ b/roms/openbios/arch/ppc/qemu/qemu.fs
@@ -93,3 +93,31 @@ variable keyboard-phandle 0 keyboard-phandle !
:noname
set-defaults
; PREPOST-initializer
+
+\ -------------------------------------------------------------------------
+\ Adler-32 wrapper
+\ -------------------------------------------------------------------------
+
+: adler32 ( adler buf len -- checksum )
+ \ Since Mac OS 9 is the only system using this word, we take this
+ \ opportunity to inject a copyright message that is necessary for the
+ \ system to boot.
+ " Copyright 1983-2001 Apple Computer, Inc. THIS MESSAGE FOR COMPATIBILITY ONLY"
+ encode-string " copyright"
+ " /" find-package if
+ " set-property" $find if
+ execute
+ else
+ 3drop drop
+ then
+ then
+
+ ( adler buf len )
+
+ " (adler32)" $find if
+ execute
+ else
+ ." Can't find " ( adler32-name ) type cr
+ 3drop 0
+ then
+;
diff --git a/roms/openbios/arch/ppc/qemu/tree.fs b/roms/openbios/arch/ppc/qemu/tree.fs
index 1ed838397..5b6bbc6f7 100644
--- a/roms/openbios/arch/ppc/qemu/tree.fs
+++ b/roms/openbios/arch/ppc/qemu/tree.fs
@@ -42,6 +42,14 @@ new-device
: close ;
finish-device
+new-device
+ " rom" device-name
+ h# ff800000 encode-int 0 encode-int encode+ " reg" property
+ 1 encode-int " #address-cells" property
+ h# ff800000 encode-int h# 800000 encode-int encode+
+ h# ff800000 encode-int encode+ " ranges" property
+finish-device
+
\ -------------------------------------------------------------
\ /packages
\ -------------------------------------------------------------
diff --git a/roms/openbios/config/scripts/switch-arch b/roms/openbios/config/scripts/switch-arch
index d5e2f7710..7b8b457f6 100755
--- a/roms/openbios/config/scripts/switch-arch
+++ b/roms/openbios/config/scripts/switch-arch
@@ -99,23 +99,25 @@ archname()
select_prefix()
{
- TARGETS="${1}-unknown-linux-gnu- ${1}-linux-gnu- ${1}-linux- ${1}-elf- ${1}-eabi-"
+ for target_arch ; do
+ TARGETS="${target_arch}-unknown-linux-gnu- ${target_arch}-linux-gnu- ${target_arch}-linux- ${target_arch}-elf- ${target_arch}-eabi-"
- if [ x"$CROSS_COMPILE" != "x" ]; then
- TARGETS=$CROSS_COMPILE
- fi
+ if [ x"$CROSS_COMPILE" != "x" ]; then
+ TARGETS=$CROSS_COMPILE
+ fi
- for TARGET in $TARGETS
- do
- if type ${TARGET}gcc > /dev/null 2>&1
- then
+ for TARGET in $TARGETS
+ do
+ if type ${TARGET}gcc > /dev/null 2>&1
+ then
+ return
+ fi
+ done
+ if [ "$ARCH" = "$HOSTARCH" ]; then
return
fi
done
- if [ "$ARCH" = "$HOSTARCH" ]; then
- return
- fi
- echo "ERROR: no ${1} cross-compiler found !" 1>&2
+ echo "ERROR: no $* cross-compiler found !" 1>&2
exit 1
}
@@ -251,7 +253,7 @@ for ARCH in $arch_list; do
;;
ppc)
- select_prefix powerpc
+ select_prefix powerpc powerpc64
if [ "$unix" = "no" ]; then
CFLAGS="-m32 -msoft-float -fno-builtin-bcopy -fno-builtin-log2"
AS_FLAGS="-m32"
diff --git a/roms/openbios/drivers/cuda.c b/roms/openbios/drivers/cuda.c
index 9555dea49..ff5d22de2 100644
--- a/roms/openbios/drivers/cuda.c
+++ b/roms/openbios/drivers/cuda.c
@@ -144,8 +144,22 @@ static int cuda_adb_req (void *host, const uint8_t *snd_buf, int len,
// CUDA_DPRINTF("len: %d %02x\n", len, snd_buf[0]);
len = cuda_request(host, ADB_PACKET, snd_buf, len, buffer);
if (len > 1 && buffer[0] == ADB_PACKET) {
- pos = buffer + 2;
- len -= 2;
+ /* We handle 2 types of ADB packet here:
+ Normal: <type> <status> <data> ...
+ Error : <type> <status> <cmd> (<data> ...)
+ Ideally we should use buffer[1] (status) to determine whether this
+ is a normal or error packet but this requires a corresponding fix
+ in QEMU <= 2.4. Hence we temporarily handle it this way to ease
+ the transition. */
+ if (len > 2 && buffer[2] == snd_buf[0]) {
+ /* Error */
+ pos = buffer + 3;
+ len -= 3;
+ } else {
+ /* Normal */
+ pos = buffer + 2;
+ len -= 2;
+ }
} else {
pos = buffer + 1;
len = -1;
@@ -380,7 +394,8 @@ powermgt_init(char *path)
ph = find_dev(buf);
set_property(ph, "device_type", "power-mgt", 10);
- set_property(ph, "compatible", "power-mgt", 10);
+ set_property(ph, "mgt-kind", "min-consumption-pwm-led", strlen("min-consumption-pwm-led") + 1);
+ set_property(ph, "compatible", "cuda", strlen("cuda") + 1);
}
cuda_t *cuda_init (const char *path, phys_addr_t base)
diff --git a/roms/openbios/drivers/escc.c b/roms/openbios/drivers/escc.c
index 240043be3..afb97fa8a 100644
--- a/roms/openbios/drivers/escc.c
+++ b/roms/openbios/drivers/escc.c
@@ -380,12 +380,22 @@ ob_zs_init(phys_addr_t base, uint64_t offset, int intr, int slave, int keyboard)
static void
escc_add_channel(const char *path, const char *node, phys_addr_t addr,
- uint32_t offset)
+ int esnum)
{
char buf[64], tty[32];
phandle_t dnode, aliases;
- int len;
- cell props[2];
+
+ cell props[10];
+ int offset;
+ int legacy;
+
+ switch (esnum) {
+ case 2: offset = 1; legacy = 0; break;
+ case 3: offset = 0; legacy = 0; break;
+ case 4: offset = 1; legacy = 1; break;
+ case 5: offset = 0; legacy = 1; break;
+ default: return;
+ }
/* add device */
@@ -411,16 +421,28 @@ escc_add_channel(const char *path, const char *node, phys_addr_t addr,
set_property(dnode, "device_type", "serial",
strlen("serial") + 1);
- snprintf(buf, sizeof(buf), "ch-%s", node);
- len = strlen(buf) + 1;
- snprintf(buf + len, sizeof(buf) - len, "CHRP,es2");
- set_property(dnode, "compatible", buf, len + 9);
-
- props[0] = IO_ESCC_OFFSET + offset * 0x20;
- props[1] = 0x00000020;
- set_property(dnode, "reg", (char *)&props, 2 * sizeof(cell));
+ snprintf(buf, sizeof(buf), "chrp,es%d", esnum);
+ set_property(dnode, "compatible", buf, 9);
+
+ if (legacy) {
+ props[0] = IO_ESCC_LEGACY_OFFSET + offset * 0x4;
+ props[1] = 0x00000001;
+ props[2] = IO_ESCC_LEGACY_OFFSET + offset * 0x4 + 2;
+ props[3] = 0x00000001;
+ props[4] = IO_ESCC_LEGACY_OFFSET + offset * 0x4 + 6;
+ props[5] = 0x00000001;
+ set_property(dnode, "reg", (char *)&props, 6 * sizeof(cell));
+ } else {
+ props[0] = IO_ESCC_OFFSET + offset * 0x20;
+ props[1] = 0x00000020;
+ set_property(dnode, "reg", (char *)&props, 2 * sizeof(cell));
+ }
- props[0] = addr + IO_ESCC_OFFSET + offset * 0x20;
+ if (legacy) {
+ props[0] = addr + IO_ESCC_LEGACY_OFFSET + offset * 0x4;
+ } else {
+ props[0] = addr + IO_ESCC_OFFSET + offset * 0x20;
+ }
OLDWORLD(set_property(dnode, "AAPL,address",
(char *)&props, 1 * sizeof(cell)));
@@ -430,13 +452,21 @@ escc_add_channel(const char *path, const char *node, phys_addr_t addr,
props[0] = (0x24) + offset;
props[1] = 0;
+ props[2] = 0;
NEWWORLD(set_property(dnode, "interrupts",
- (char *)&props, 2 * sizeof(cell)));
+ (char *)&props, 3 * sizeof(cell)));
device_end();
- uart_init_line((unsigned char*)addr + IO_ESCC_OFFSET + offset * 0x20,
- CONFIG_SERIAL_SPEED);
+ if (legacy) {
+ uart_init_line(
+ (unsigned char*)addr + IO_ESCC_LEGACY_OFFSET + offset * 0x4,
+ CONFIG_SERIAL_SPEED);
+ } else {
+ uart_init_line(
+ (unsigned char*)addr + IO_ESCC_OFFSET + offset * 0x20,
+ CONFIG_SERIAL_SPEED);
+ }
}
void
@@ -467,10 +497,34 @@ escc_init(const char *path, phys_addr_t addr)
fword("finish-device");
- escc_add_channel(buf, "a", addr, 1);
- escc_add_channel(buf, "b", addr, 0);
+ escc_add_channel(buf, "a", addr, 2);
+ escc_add_channel(buf, "b", addr, 3);
escc_serial_dev = (unsigned char *)addr + IO_ESCC_OFFSET +
(CONFIG_SERIAL_PORT ? 0 : 0x20);
+
+ push_str(path);
+ fword("find-device");
+ fword("new-device");
+
+ push_str("escc-legacy");
+ fword("device-name");
+
+ snprintf(buf, sizeof(buf), "%s/escc-legacy", path);
+
+ dnode = find_dev(buf);
+
+ set_int_property(dnode, "#address-cells", 1);
+ props[0] = __cpu_to_be32(IO_ESCC_LEGACY_OFFSET);
+ props[1] = __cpu_to_be32(IO_ESCC_LEGACY_SIZE);
+ set_property(dnode, "reg", (char *)&props, sizeof(props));
+ set_property(dnode, "device_type", "escc-legacy",
+ strlen("escc-legacy") + 1);
+ set_property(dnode, "compatible", "chrp,es1", 9);
+
+ fword("finish-device");
+
+ escc_add_channel(buf, "a", addr, 4);
+ escc_add_channel(buf, "b", addr, 5);
}
#endif
diff --git a/roms/openbios/drivers/escc.h b/roms/openbios/drivers/escc.h
index caaf00d40..e73f267b2 100644
--- a/roms/openbios/drivers/escc.h
+++ b/roms/openbios/drivers/escc.h
@@ -1,6 +1,8 @@
#define IO_ESCC_SIZE 0x00001000
#define IO_ESCC_OFFSET 0x00013000
+#define IO_ESCC_LEGACY_SIZE 0x00001000
+#define IO_ESCC_LEGACY_OFFSET 0x00012000
#define ZS_REGS 8
diff --git a/roms/openbios/drivers/ide.c b/roms/openbios/drivers/ide.c
index 327c64a40..5125b78b9 100644
--- a/roms/openbios/drivers/ide.c
+++ b/roms/openbios/drivers/ide.c
@@ -1488,6 +1488,28 @@ int ob_ide_init(const char *path, uint32_t io_port0, uint32_t ctl_port0,
return 0;
}
+void ob_ide_quiesce(void)
+{
+ struct ide_channel *channel;
+ int i;
+
+ channel = channels;
+ while (channel) {
+ for (i = 0; i < 2; i++) {
+ struct ide_drive *drive = &channel->drives[i];
+
+ if (!drive->present)
+ continue;
+
+ ob_ide_select_drive(drive);
+ ob_ide_software_reset(drive);
+ ob_ide_device_type_check(drive);
+ }
+
+ channel = channel->next;
+ }
+}
+
#if defined(CONFIG_DRIVER_MACIO)
static unsigned char
macio_ide_inb(struct ide_channel *chan, unsigned int port)
@@ -1581,6 +1603,12 @@ int macio_ide_init(const char *path, uint32_t addr, int nb_channels)
set_property(dnode, "compatible", (is_oldworld() ?
"heathrow-ata" : "keylargo-ata"), 13);
+ set_property(dnode, "model", ((current_channel == 3) ?
+ "ata-3" : "ata-4"), strlen("ata-*") + 1);
+
+ set_property(dnode, "AAPL,connector", "ata",
+ strlen("ata") + 1);
+
props[0] = 0x00000526;
props[1] = 0x00000085;
props[2] = 0x00000025;
@@ -1589,8 +1617,8 @@ int macio_ide_init(const char *path, uint32_t addr, int nb_channels)
props[5] = 0x00000000;
props[6] = 0x00000000;
props[7] = 0x00000000;
- OLDWORLD(set_property(dnode, "AAPL,pio-timing",
- (char *)&props, 8*sizeof(props[0])));
+ set_property(dnode, "AAPL,pio-timing",
+ (char *)&props, 8*sizeof(props[0]));
/* The first interrupt entry is the ide interrupt, the second
the dbdma interrupt */
@@ -1634,8 +1662,8 @@ int macio_ide_init(const char *path, uint32_t addr, int nb_channels)
(char *)&props, 2*sizeof(props[0])));
props[0] = 0;
- OLDWORLD(set_property(dnode, "AAPL,bus-id", (char*)props,
- 1 * sizeof(props[0])));
+ set_property(dnode, "AAPL,bus-id", (char*)props,
+ 1 * sizeof(props[0]));
IDE_DPRINTF(DEV_NAME": [io ports 0x%lx]\n",
current_channel, chan->mmio);
diff --git a/roms/openbios/drivers/pci.c b/roms/openbios/drivers/pci.c
index 366f4a17f..935ecb8f8 100644
--- a/roms/openbios/drivers/pci.c
+++ b/roms/openbios/drivers/pci.c
@@ -824,7 +824,7 @@ int ebus_config_cb(const pci_config_t *config)
ncells += pci_encode_phys_addr(props + ncells,
flags, space_code, config->dev,
PCI_BASE_ADDR_0 + (i * sizeof(uint32_t)),
- 0);
+ config->assigned[i] & ~mask);
props[ncells++] = config->sizes[i];
}
@@ -1420,6 +1420,12 @@ static void ob_pci_host_set_interrupt_map(phandle_t host)
target_node = find_dev("/pci/mac-io/escc/ch-b");
set_int_property(target_node, "interrupt-parent", dnode);
+ target_node = find_dev("/pci/mac-io/escc-legacy/ch-a");
+ set_int_property(target_node, "interrupt-parent", dnode);
+
+ target_node = find_dev("/pci/mac-io/escc-legacy/ch-b");
+ set_int_property(target_node, "interrupt-parent", dnode);
+
/* QEMU only emulates 2 of the 3 ata buses currently */
/* On a new world Mac these are not numbered but named by the
* ATA version they support. Thus we have: ata-3, ata-3, ata-4
diff --git a/roms/openbios/include/drivers/drivers.h b/roms/openbios/include/drivers/drivers.h
index 3b83b12d1..48f81a870 100644
--- a/roms/openbios/include/drivers/drivers.h
+++ b/roms/openbios/include/drivers/drivers.h
@@ -52,6 +52,7 @@ void kbd_init(uint64_t base);
/* drivers/ide.c */
int ob_ide_init(const char *path, uint32_t io_port0, uint32_t ctl_port0,
uint32_t io_port1, uint32_t ctl_port1);
+void ob_ide_quiesce(void);
int macio_ide_init(const char *path, uint32_t addr, int nb_channels);
#endif
#ifdef CONFIG_DRIVER_ESP
diff --git a/roms/openbios/libopenbios/bootinfo_load.c b/roms/openbios/libopenbios/bootinfo_load.c
index fa9e36bd4..f33678185 100644
--- a/roms/openbios/libopenbios/bootinfo_load.c
+++ b/roms/openbios/libopenbios/bootinfo_load.c
@@ -161,6 +161,12 @@ bootinfo_init_program(void)
feval("load-size");
size = POP();
+ /* Some bootinfo scripts contain a binary payload after the
+ NULL-terminated Forth string such as OS 9. Restrict our
+ size to just the Forth section, otherwise we end up trying
+ to allocate memory for the entire binary which might fail. */
+ size = strnlen(base, size);
+
bootscript = malloc(size);
if (bootscript == NULL) {
DPRINTF("Can't malloc %d bytes\n", size);