summaryrefslogtreecommitdiffstats
path: root/qemu/roms
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/roms')
-rw-r--r--qemu/roms/Makefile18
-rw-r--r--qemu/roms/SLOF/README36
-rw-r--r--qemu/roms/SLOF/VERSION2
-rw-r--r--qemu/roms/SLOF/board-js2x/llfw/stage2.lds3
-rw-r--r--qemu/roms/SLOF/board-js2x/llfw/stage2_head.S2
-rw-r--r--qemu/roms/SLOF/board-js2x/slof/Makefile1
-rw-r--r--qemu/roms/SLOF/board-js2x/slof/dma-function.fs31
-rw-r--r--qemu/roms/SLOF/board-js2x/slof/helper.fs11
-rw-r--r--qemu/roms/SLOF/board-qemu/llfw/stage2.lds3
-rw-r--r--qemu/roms/SLOF/board-qemu/llfw/stage2_head.S2
-rw-r--r--qemu/roms/SLOF/board-qemu/slof/Makefile5
-rw-r--r--qemu/roms/SLOF/board-qemu/slof/OF.fs4
-rw-r--r--qemu/roms/SLOF/board-qemu/slof/archsupport.fs (renamed from qemu/roms/SLOF/slof/fs/archsupport.fs)13
-rw-r--r--qemu/roms/SLOF/board-qemu/slof/helper.fs13
-rw-r--r--qemu/roms/SLOF/board-qemu/slof/pci-device_1234_1111.fs229
-rw-r--r--qemu/roms/SLOF/board-qemu/slof/pci-device_1af4_1001.fs9
-rw-r--r--qemu/roms/SLOF/board-qemu/slof/pci-device_1af4_1009.fs9
-rw-r--r--qemu/roms/SLOF/board-qemu/slof/pci-device_1af4_1041.fs15
-rw-r--r--qemu/roms/SLOF/board-qemu/slof/pci-device_1af4_1042.fs15
-rw-r--r--qemu/roms/SLOF/board-qemu/slof/pci-device_1af4_1048.fs15
-rw-r--r--qemu/roms/SLOF/board-qemu/slof/pci-device_1af4_1050.fs15
-rw-r--r--qemu/roms/SLOF/board-qemu/slof/qemu-vga.fs198
-rw-r--r--qemu/roms/SLOF/board-qemu/slof/tree.fs2
-rw-r--r--qemu/roms/SLOF/board-qemu/slof/virtio-block.fs3
-rw-r--r--qemu/roms/SLOF/board-qemu/slof/virtio-fs.fs3
-rw-r--r--qemu/roms/SLOF/board-qemu/slof/virtio-net.fs33
-rw-r--r--qemu/roms/SLOF/board-qemu/slof/virtio-scsi.fs3
-rw-r--r--qemu/roms/SLOF/board-qemu/slof/virtio.fs35
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netapps/netboot.c58
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/bootp.c5
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/dhcp.c221
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/dhcp.h1
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.c42
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.h11
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/dns.c4
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/dns.h2
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/ethernet.c42
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/icmpv6.c9
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/ipv4.c131
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/ipv4.h6
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/ipv6.c123
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/ipv6.h28
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/ndp.c19
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/ndp.h1
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/tcp.c16
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/tftp.c57
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/udp.c26
-rw-r--r--qemu/roms/SLOF/clients/net-snk/app/netlib/udp.h2
-rw-r--r--qemu/roms/SLOF/clients/net-snk/client.lds4
-rw-r--r--qemu/roms/SLOF/clients/net-snk/kernel/entry.S2
-rw-r--r--qemu/roms/SLOF/clients/takeover/client.lds4
-rw-r--r--qemu/roms/SLOF/clients/takeover/entry.S2
-rw-r--r--qemu/roms/SLOF/clients/takeover/main.c2
-rw-r--r--qemu/roms/SLOF/include/byteorder.h22
-rw-r--r--qemu/roms/SLOF/include/helpers.h2
-rw-r--r--qemu/roms/SLOF/include/ppc970/cache.h50
-rw-r--r--qemu/roms/SLOF/include/ppcp7/cache.h13
-rw-r--r--qemu/roms/SLOF/lib/libc/include/stdlib.h1
-rw-r--r--qemu/roms/SLOF/lib/libc/stdio/vsnprintf.c180
-rw-r--r--qemu/roms/SLOF/lib/libc/stdlib/rand.c9
-rw-r--r--qemu/roms/SLOF/lib/libhvcall/Makefile2
-rw-r--r--qemu/roms/SLOF/lib/libhvcall/rfill.c38
-rw-r--r--qemu/roms/SLOF/lib/libnvram/envvar.c40
-rw-r--r--qemu/roms/SLOF/lib/libnvram/libnvram.code75
-rw-r--r--qemu/roms/SLOF/lib/libnvram/nvram.c27
-rw-r--r--qemu/roms/SLOF/lib/libnvram/nvram.h10
-rw-r--r--qemu/roms/SLOF/lib/libusb/usb-core.c37
-rw-r--r--qemu/roms/SLOF/lib/libusb/usb-core.h7
-rw-r--r--qemu/roms/SLOF/lib/libusb/usb-ehci.c4
-rw-r--r--qemu/roms/SLOF/lib/libusb/usb-hid.c85
-rw-r--r--qemu/roms/SLOF/lib/libusb/usb-hub.c4
-rw-r--r--qemu/roms/SLOF/lib/libusb/usb-ohci.c16
-rw-r--r--qemu/roms/SLOF/lib/libusb/usb-slof.c34
-rw-r--r--qemu/roms/SLOF/lib/libusb/usb-xhci.c236
-rw-r--r--qemu/roms/SLOF/lib/libusb/usb-xhci.h5
-rw-r--r--qemu/roms/SLOF/lib/libvirtio/p9.c2
-rw-r--r--qemu/roms/SLOF/lib/libvirtio/p9.h2
-rw-r--r--qemu/roms/SLOF/lib/libvirtio/virtio-9p.c35
-rw-r--r--qemu/roms/SLOF/lib/libvirtio/virtio-9p.h2
-rw-r--r--qemu/roms/SLOF/lib/libvirtio/virtio-blk.c100
-rw-r--r--qemu/roms/SLOF/lib/libvirtio/virtio-blk.h2
-rw-r--r--qemu/roms/SLOF/lib/libvirtio/virtio-internal.h48
-rw-r--r--qemu/roms/SLOF/lib/libvirtio/virtio-net.c200
-rw-r--r--qemu/roms/SLOF/lib/libvirtio/virtio-net.h15
-rw-r--r--qemu/roms/SLOF/lib/libvirtio/virtio-scsi.c174
-rw-r--r--qemu/roms/SLOF/lib/libvirtio/virtio.c457
-rw-r--r--qemu/roms/SLOF/lib/libvirtio/virtio.code23
-rw-r--r--qemu/roms/SLOF/lib/libvirtio/virtio.h58
-rw-r--r--qemu/roms/SLOF/lib/libvirtio/virtio.in2
-rw-r--r--qemu/roms/SLOF/make.rules12
-rw-r--r--qemu/roms/SLOF/rtas/reloc.S2
-rw-r--r--qemu/roms/SLOF/rtas/rtas.lds3
-rw-r--r--qemu/roms/SLOF/rtas/rtas_entry.S2
-rw-r--r--qemu/roms/SLOF/slof/entry.S9
-rw-r--r--qemu/roms/SLOF/slof/fs/base.fs2
-rw-r--r--qemu/roms/SLOF/slof/fs/boot.fs8
-rw-r--r--qemu/roms/SLOF/slof/fs/client.fs12
-rw-r--r--qemu/roms/SLOF/slof/fs/fbuffer.fs30
-rw-r--r--qemu/roms/SLOF/slof/fs/little-endian.fs6
-rw-r--r--qemu/roms/SLOF/slof/fs/packages/disk-label.fs162
-rw-r--r--qemu/roms/SLOF/slof/fs/packages/fat-files.fs15
-rw-r--r--qemu/roms/SLOF/slof/fs/pci-config-bridge.fs20
-rw-r--r--qemu/roms/SLOF/slof/fs/pci-scan.fs19
-rw-r--r--qemu/roms/SLOF/slof/fs/rmove.fs53
-rw-r--r--qemu/roms/SLOF/slof/fs/root.fs1
-rw-r--r--qemu/roms/SLOF/slof/fs/terminal.fs3
-rw-r--r--qemu/roms/SLOF/slof/helpers.c14
-rw-r--r--qemu/roms/SLOF/slof/paflof.c9
-rw-r--r--qemu/roms/SLOF/slof/ppc64.c19
-rw-r--r--qemu/roms/SLOF/slof/prim.code13
-rw-r--r--qemu/roms/SLOF/slof/prim.in3
-rw-r--r--qemu/roms/config.ipxe.general.h4
-rw-r--r--qemu/roms/config.seabios-128k2
-rw-r--r--qemu/roms/ipxe/COPYING345
-rw-r--r--qemu/roms/ipxe/COPYING.GPLv2339
-rw-r--r--qemu/roms/ipxe/COPYING.UBDL59
-rw-r--r--qemu/roms/ipxe/COPYRIGHTS12
-rw-r--r--qemu/roms/ipxe/src/Makefile4
-rw-r--r--qemu/roms/ipxe/src/Makefile.housekeeping131
-rw-r--r--qemu/roms/ipxe/src/arch/i386/Makefile11
-rw-r--r--qemu/roms/ipxe/src/arch/i386/core/basemem_packet.c6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/core/cachedhcp.c6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/core/gdbmach.c6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/core/patch_cf.S6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/core/pci_autoboot.c6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/core/rdtsc_timer.c12
-rw-r--r--qemu/roms/ipxe/src/arch/i386/core/relocate.c2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/core/runtime.c6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/core/setjmp.S84
-rw-r--r--qemu/roms/ipxe/src/arch/i386/core/stack.S2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/core/stack16.S2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/core/timer2.c87
-rw-r--r--qemu/roms/ipxe/src/arch/i386/core/virtaddr.S2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/drivers/net/undi.c7
-rw-r--r--qemu/roms/ipxe/src/arch/i386/drivers/net/undiload.c6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/drivers/net/undionly.c6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/drivers/net/undipreload.c6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/firmware/pcbios/basemem.c6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/firmware/pcbios/bios_console.c12
-rw-r--r--qemu/roms/ipxe/src/arch/i386/firmware/pcbios/e820mangler.S6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/firmware/pcbios/fakee820.c6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/firmware/pcbios/hidemem.c6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/firmware/pcbios/memmap.c6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/firmware/pcbios/pnpbios.c6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/hci/commands/pxe_cmd.c6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/image/bootsector.c6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/image/bzimage.c6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/image/elfboot.c39
-rw-r--r--qemu/roms/ipxe/src/arch/i386/image/initrd.c6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/image/multiboot.c6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/image/pxe_image.c52
-rw-r--r--qemu/roms/ipxe/src/arch/i386/image/sdi.c6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/basemem.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/basemem_packet.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/bios.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/biosint.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/bits/byteswap.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/bits/compiler.h5
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/bits/endian.h8
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/bits/entropy.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/bits/hyperv.h72
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/bits/nap.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/bits/profile.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/bits/reboot.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/bits/sanboot.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/bits/smbios.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/bits/stdint.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/bits/strings.h48
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/bits/time.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/bits/timer.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/bits/uaccess.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/bits/umalloc.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/bootsector.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/bzimage.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/efi/ipxe/dhcp_arch.h11
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/fakee820.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/initrd.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/int13.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/ipxe/bios_nap.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/ipxe/bios_reboot.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/ipxe/bios_sanboot.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/ipxe/bios_smbios.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/ipxe/bios_timer.h8
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/ipxe/errno/pcbios.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/ipxe/guestrpc.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/ipxe/memtop_umalloc.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/ipxe/msr.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/ipxe/rdtsc_timer.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/ipxe/rtc_entropy.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/ipxe/rtc_time.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/ipxe/timer2.h14
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/ipxe/vesafb.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/ipxe/vmware.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/librm.h14
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/limits.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/memsizes.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/multiboot.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/pcbios/ipxe/dhcp_arch.h11
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/pnpbios.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/pxe.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/pxe_api.h6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/pxe_call.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/pxe_error.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/pxe_types.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/realmode.h14
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/registers.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/rtc.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/sdi.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/setjmp.h46
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/undi.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/undiload.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/undinet.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/undipreload.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/include/undirom.h2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/interface/pcbios/apm.c6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/interface/pcbios/bios_nap.c2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/interface/pcbios/bios_reboot.c6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/interface/pcbios/bios_smbios.c6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/interface/pcbios/bios_timer.c6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/interface/pcbios/biosint.c2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/interface/pcbios/int13.c6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/interface/pcbios/int13con.c284
-rw-r--r--qemu/roms/ipxe/src/arch/i386/interface/pcbios/memtop_umalloc.c6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/interface/pcbios/pcibios.c12
-rw-r--r--qemu/roms/ipxe/src/arch/i386/interface/pcbios/rtc_entropy.c6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/interface/pcbios/rtc_time.c6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/interface/pcbios/vesafb.c6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/interface/pxe/pxe_call.c7
-rw-r--r--qemu/roms/ipxe/src/arch/i386/interface/pxe/pxe_entry.S6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/interface/pxe/pxe_exit_hook.c6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/interface/pxe/pxe_file.c6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/interface/pxe/pxe_loader.c6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/interface/pxe/pxe_preboot.c24
-rw-r--r--qemu/roms/ipxe/src/arch/i386/interface/pxe/pxe_tftp.c43
-rw-r--r--qemu/roms/ipxe/src/arch/i386/interface/pxe/pxe_udp.c130
-rw-r--r--qemu/roms/ipxe/src/arch/i386/interface/pxe/pxe_undi.c6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/interface/syslinux/comboot_call.c29
-rw-r--r--qemu/roms/ipxe/src/arch/i386/interface/vmware/guestrpc.c6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/interface/vmware/vmconsole.c6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/interface/vmware/vmware.c6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/prefix/bootpart.S2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/prefix/exeprefix.S6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/prefix/hdprefix.S2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/prefix/isaromprefix.S6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/prefix/kkkpxeprefix.S6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/prefix/kkpxeprefix.S5
-rw-r--r--qemu/roms/ipxe/src/arch/i386/prefix/kpxeprefix.S2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/prefix/libprefix.S75
-rw-r--r--qemu/roms/ipxe/src/arch/i386/prefix/lkrnprefix.S2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/prefix/mbr.S2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/prefix/mromprefix.S7
-rw-r--r--qemu/roms/ipxe/src/arch/i386/prefix/nbiprefix.S2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/prefix/nullprefix.S2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/prefix/pciromprefix.S6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/prefix/pxeprefix.S2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/prefix/romprefix.S31
-rw-r--r--qemu/roms/ipxe/src/arch/i386/prefix/undiloader.S2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/prefix/unlzma.S942
-rw-r--r--qemu/roms/ipxe/src/arch/i386/prefix/unlzma16.S (renamed from qemu/roms/ipxe/src/arch/i386/prefix/unnrv2b16.S)4
-rw-r--r--qemu/roms/ipxe/src/arch/i386/prefix/unnrv2b.S184
-rw-r--r--qemu/roms/ipxe/src/arch/i386/prefix/usbdisk.S23
-rw-r--r--qemu/roms/ipxe/src/arch/i386/scripts/i386.lds9
-rw-r--r--qemu/roms/ipxe/src/arch/i386/transitions/liba20.S6
-rw-r--r--qemu/roms/ipxe/src/arch/i386/transitions/libkir.S2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/transitions/librm.S2
-rw-r--r--qemu/roms/ipxe/src/arch/i386/transitions/librm_mgmt.c4
-rw-r--r--qemu/roms/ipxe/src/arch/i386/transitions/librm_test.c7
-rw-r--r--qemu/roms/ipxe/src/arch/x86/Makefile5
-rw-r--r--qemu/roms/ipxe/src/arch/x86/Makefile.efi2
-rw-r--r--qemu/roms/ipxe/src/arch/x86/core/cpuid.c6
-rw-r--r--qemu/roms/ipxe/src/arch/x86/core/cpuid_settings.c6
-rw-r--r--qemu/roms/ipxe/src/arch/x86/core/debugcon.c6
-rw-r--r--qemu/roms/ipxe/src/arch/x86/core/pcidirect.c6
-rw-r--r--qemu/roms/ipxe/src/arch/x86/core/pic8259.c (renamed from qemu/roms/ipxe/src/arch/i386/core/pic8259.c)0
-rw-r--r--qemu/roms/ipxe/src/arch/x86/core/pit8254.c70
-rw-r--r--qemu/roms/ipxe/src/arch/x86/core/vram_settings.c72
-rw-r--r--qemu/roms/ipxe/src/arch/x86/core/x86_bigint.c6
-rw-r--r--qemu/roms/ipxe/src/arch/x86/core/x86_io.c6
-rw-r--r--qemu/roms/ipxe/src/arch/x86/core/x86_string.c90
-rw-r--r--qemu/roms/ipxe/src/arch/x86/core/x86_tcpip.c6
-rw-r--r--qemu/roms/ipxe/src/arch/x86/core/x86_uart.c69
-rw-r--r--qemu/roms/ipxe/src/arch/x86/drivers/hyperv/hyperv.c597
-rw-r--r--qemu/roms/ipxe/src/arch/x86/drivers/hyperv/hyperv.h57
-rw-r--r--qemu/roms/ipxe/src/arch/x86/drivers/xen/hvm.c9
-rw-r--r--qemu/roms/ipxe/src/arch/x86/drivers/xen/hvm.h2
-rw-r--r--qemu/roms/ipxe/src/arch/x86/hci/commands/cpuid_cmd.c6
-rw-r--r--qemu/roms/ipxe/src/arch/x86/include/bits/bigint.h2
-rw-r--r--qemu/roms/ipxe/src/arch/x86/include/bits/endian.h8
-rw-r--r--qemu/roms/ipxe/src/arch/x86/include/bits/errfile.h6
-rw-r--r--qemu/roms/ipxe/src/arch/x86/include/bits/io.h2
-rw-r--r--qemu/roms/ipxe/src/arch/x86/include/bits/pci_io.h2
-rw-r--r--qemu/roms/ipxe/src/arch/x86/include/bits/string.h140
-rw-r--r--qemu/roms/ipxe/src/arch/x86/include/bits/tcpip.h2
-rw-r--r--qemu/roms/ipxe/src/arch/x86/include/bits/uart.h41
-rw-r--r--qemu/roms/ipxe/src/arch/x86/include/bits/xen.h21
-rw-r--r--qemu/roms/ipxe/src/arch/x86/include/ipxe/cpuid.h5
-rw-r--r--qemu/roms/ipxe/src/arch/x86/include/ipxe/efi/efix86_nap.h2
-rw-r--r--qemu/roms/ipxe/src/arch/x86/include/ipxe/pcibios.h2
-rw-r--r--qemu/roms/ipxe/src/arch/x86/include/ipxe/pcidirect.h2
-rw-r--r--qemu/roms/ipxe/src/arch/x86/include/ipxe/pit8254.h81
-rw-r--r--qemu/roms/ipxe/src/arch/x86/include/ipxe/x86_io.h2
-rw-r--r--qemu/roms/ipxe/src/arch/x86/include/linux/ipxe/dhcp_arch.h11
-rw-r--r--qemu/roms/ipxe/src/arch/x86/include/pic8259.h (renamed from qemu/roms/ipxe/src/arch/i386/include/pic8259.h)5
-rw-r--r--qemu/roms/ipxe/src/arch/x86/interface/efi/efi_entropy.c223
-rw-r--r--qemu/roms/ipxe/src/arch/x86/interface/efi/efix86_nap.c6
-rw-r--r--qemu/roms/ipxe/src/arch/x86/prefix/efidrvprefix.c35
-rw-r--r--qemu/roms/ipxe/src/arch/x86/prefix/efiprefix.c5
-rw-r--r--qemu/roms/ipxe/src/arch/x86_64/Makefile1
-rw-r--r--qemu/roms/ipxe/src/arch/x86_64/core/setjmp.S65
-rw-r--r--qemu/roms/ipxe/src/arch/x86_64/include/bits/byteswap.h2
-rw-r--r--qemu/roms/ipxe/src/arch/x86_64/include/bits/compiler.h3
-rw-r--r--qemu/roms/ipxe/src/arch/x86_64/include/bits/endian.h6
-rw-r--r--qemu/roms/ipxe/src/arch/x86_64/include/bits/entropy.h2
-rw-r--r--qemu/roms/ipxe/src/arch/x86_64/include/bits/hyperv.h75
-rw-r--r--qemu/roms/ipxe/src/arch/x86_64/include/bits/profile.h2
-rw-r--r--qemu/roms/ipxe/src/arch/x86_64/include/bits/reboot.h2
-rw-r--r--qemu/roms/ipxe/src/arch/x86_64/include/bits/sanboot.h2
-rw-r--r--qemu/roms/ipxe/src/arch/x86_64/include/bits/strings.h40
-rw-r--r--qemu/roms/ipxe/src/arch/x86_64/include/bits/time.h2
-rw-r--r--qemu/roms/ipxe/src/arch/x86_64/include/efi/ipxe/dhcp_arch.h11
-rw-r--r--qemu/roms/ipxe/src/arch/x86_64/include/ipxe/msr.h2
-rw-r--r--qemu/roms/ipxe/src/arch/x86_64/include/setjmp.h34
-rw-r--r--qemu/roms/ipxe/src/config/.gitignore1
-rw-r--r--qemu/roms/ipxe/src/config/branding.h174
-rw-r--r--qemu/roms/ipxe/src/config/colour.h2
-rw-r--r--qemu/roms/ipxe/src/config/config.c59
-rw-r--r--qemu/roms/ipxe/src/config/config_crypto.c76
-rw-r--r--qemu/roms/ipxe/src/config/config_ethernet.c25
-rw-r--r--qemu/roms/ipxe/src/config/config_fc.c22
-rw-r--r--qemu/roms/ipxe/src/config/config_http.c45
-rw-r--r--qemu/roms/ipxe/src/config/config_infiniband.c22
-rw-r--r--qemu/roms/ipxe/src/config/config_net80211.c16
-rw-r--r--qemu/roms/ipxe/src/config/config_romprefix.c22
-rw-r--r--qemu/roms/ipxe/src/config/config_route.c22
-rw-r--r--qemu/roms/ipxe/src/config/config_usb.c52
-rw-r--r--qemu/roms/ipxe/src/config/console.h3
-rw-r--r--qemu/roms/ipxe/src/config/crypto.h35
-rw-r--r--qemu/roms/ipxe/src/config/defaults.h2
-rw-r--r--qemu/roms/ipxe/src/config/defaults/efi.h6
-rw-r--r--qemu/roms/ipxe/src/config/defaults/pcbios.h8
-rw-r--r--qemu/roms/ipxe/src/config/dhcp.h87
-rw-r--r--qemu/roms/ipxe/src/config/entropy.h2
-rw-r--r--qemu/roms/ipxe/src/config/fault.h34
-rw-r--r--qemu/roms/ipxe/src/config/general.h31
-rw-r--r--qemu/roms/ipxe/src/config/ioapi.h2
-rw-r--r--qemu/roms/ipxe/src/config/named.h2
-rw-r--r--qemu/roms/ipxe/src/config/nap.h2
-rw-r--r--qemu/roms/ipxe/src/config/qemu/colour.h0
-rw-r--r--qemu/roms/ipxe/src/config/qemu/console.h0
-rw-r--r--qemu/roms/ipxe/src/config/qemu/crypto.h0
-rw-r--r--qemu/roms/ipxe/src/config/qemu/general.h10
-rw-r--r--qemu/roms/ipxe/src/config/qemu/serial.h0
-rw-r--r--qemu/roms/ipxe/src/config/qemu/settings.h0
-rw-r--r--qemu/roms/ipxe/src/config/qemu/sideband.h0
-rw-r--r--qemu/roms/ipxe/src/config/qemu/usb.h0
-rw-r--r--qemu/roms/ipxe/src/config/reboot.h2
-rw-r--r--qemu/roms/ipxe/src/config/sanboot.h2
-rw-r--r--qemu/roms/ipxe/src/config/serial.h5
-rw-r--r--qemu/roms/ipxe/src/config/settings.h3
-rw-r--r--qemu/roms/ipxe/src/config/sideband.h2
-rw-r--r--qemu/roms/ipxe/src/config/time.h2
-rw-r--r--qemu/roms/ipxe/src/config/timer.h2
-rw-r--r--qemu/roms/ipxe/src/config/umalloc.h2
-rw-r--r--qemu/roms/ipxe/src/config/usb.h33
-rw-r--r--qemu/roms/ipxe/src/config/vbox/general.h8
-rw-r--r--qemu/roms/ipxe/src/config/vbox/usb.h0
-rw-r--r--qemu/roms/ipxe/src/core/acpi.c6
-rw-r--r--qemu/roms/ipxe/src/core/ansicol.c6
-rw-r--r--qemu/roms/ipxe/src/core/ansicoldef.c6
-rw-r--r--qemu/roms/ipxe/src/core/ansiesc.c6
-rw-r--r--qemu/roms/ipxe/src/core/asprintf.c2
-rw-r--r--qemu/roms/ipxe/src/core/assert.c6
-rw-r--r--qemu/roms/ipxe/src/core/base16.c96
-rw-r--r--qemu/roms/ipxe/src/core/base64.c106
-rw-r--r--qemu/roms/ipxe/src/core/basename.c6
-rw-r--r--qemu/roms/ipxe/src/core/bitmap.c6
-rw-r--r--qemu/roms/ipxe/src/core/blockdev.c6
-rw-r--r--qemu/roms/ipxe/src/core/blocktrans.c261
-rw-r--r--qemu/roms/ipxe/src/core/console.c2
-rw-r--r--qemu/roms/ipxe/src/core/cpio.c6
-rw-r--r--qemu/roms/ipxe/src/core/ctype.c13
-rw-r--r--qemu/roms/ipxe/src/core/cwuri.c6
-rw-r--r--qemu/roms/ipxe/src/core/debug.c6
-rw-r--r--qemu/roms/ipxe/src/core/debug_md5.c6
-rw-r--r--qemu/roms/ipxe/src/core/device.c6
-rw-r--r--qemu/roms/ipxe/src/core/downloader.c112
-rw-r--r--qemu/roms/ipxe/src/core/edd.c6
-rw-r--r--qemu/roms/ipxe/src/core/errno.c2
-rw-r--r--qemu/roms/ipxe/src/core/exec.c6
-rw-r--r--qemu/roms/ipxe/src/core/fault.c82
-rw-r--r--qemu/roms/ipxe/src/core/fbcon.c6
-rw-r--r--qemu/roms/ipxe/src/core/fnrec.c6
-rw-r--r--qemu/roms/ipxe/src/core/gdbserial.c80
-rw-r--r--qemu/roms/ipxe/src/core/gdbstub.c6
-rw-r--r--qemu/roms/ipxe/src/core/gdbudp.c6
-rw-r--r--qemu/roms/ipxe/src/core/getkey.c6
-rw-r--r--qemu/roms/ipxe/src/core/getopt.c6
-rw-r--r--qemu/roms/ipxe/src/core/image.c89
-rw-r--r--qemu/roms/ipxe/src/core/init.c6
-rw-r--r--qemu/roms/ipxe/src/core/interface.c31
-rw-r--r--qemu/roms/ipxe/src/core/iobuf.c36
-rw-r--r--qemu/roms/ipxe/src/core/isqrt.c6
-rw-r--r--qemu/roms/ipxe/src/core/job.c6
-rw-r--r--qemu/roms/ipxe/src/core/linebuf.c59
-rw-r--r--qemu/roms/ipxe/src/core/lineconsole.c6
-rw-r--r--qemu/roms/ipxe/src/core/list.c6
-rw-r--r--qemu/roms/ipxe/src/core/log.c6
-rw-r--r--qemu/roms/ipxe/src/core/main.c11
-rw-r--r--qemu/roms/ipxe/src/core/malloc.c63
-rw-r--r--qemu/roms/ipxe/src/core/memblock.c6
-rw-r--r--qemu/roms/ipxe/src/core/memmap_settings.c6
-rw-r--r--qemu/roms/ipxe/src/core/menu.c6
-rw-r--r--qemu/roms/ipxe/src/core/misc.c85
-rw-r--r--qemu/roms/ipxe/src/core/monojob.c6
-rw-r--r--qemu/roms/ipxe/src/core/null_reboot.c6
-rw-r--r--qemu/roms/ipxe/src/core/null_sanboot.c6
-rw-r--r--qemu/roms/ipxe/src/core/null_time.c6
-rw-r--r--qemu/roms/ipxe/src/core/nvo.c6
-rw-r--r--qemu/roms/ipxe/src/core/open.c6
-rw-r--r--qemu/roms/ipxe/src/core/params.c6
-rw-r--r--qemu/roms/ipxe/src/core/parseopt.c9
-rw-r--r--qemu/roms/ipxe/src/core/pending.c6
-rw-r--r--qemu/roms/ipxe/src/core/pinger.c6
-rw-r--r--qemu/roms/ipxe/src/core/pixbuf.c6
-rw-r--r--qemu/roms/ipxe/src/core/pool.c114
-rw-r--r--qemu/roms/ipxe/src/core/posix_io.c6
-rw-r--r--qemu/roms/ipxe/src/core/process.c6
-rw-r--r--qemu/roms/ipxe/src/core/profile.c6
-rw-r--r--qemu/roms/ipxe/src/core/random.c2
-rw-r--r--qemu/roms/ipxe/src/core/refcnt.c6
-rw-r--r--qemu/roms/ipxe/src/core/resolv.c6
-rw-r--r--qemu/roms/ipxe/src/core/serial.c349
-rw-r--r--qemu/roms/ipxe/src/core/serial_console.c42
-rw-r--r--qemu/roms/ipxe/src/core/settings.c102
-rw-r--r--qemu/roms/ipxe/src/core/string.c648
-rw-r--r--qemu/roms/ipxe/src/core/stringextra.c188
-rw-r--r--qemu/roms/ipxe/src/core/strtoull.c60
-rw-r--r--qemu/roms/ipxe/src/core/time.c6
-rw-r--r--qemu/roms/ipxe/src/core/timer.c6
-rw-r--r--qemu/roms/ipxe/src/core/uart.c153
-rw-r--r--qemu/roms/ipxe/src/core/uri.c15
-rw-r--r--qemu/roms/ipxe/src/core/uuid.c6
-rw-r--r--qemu/roms/ipxe/src/core/version.c7
-rw-r--r--qemu/roms/ipxe/src/core/vsprintf.c6
-rw-r--r--qemu/roms/ipxe/src/core/wchar.c6
-rw-r--r--qemu/roms/ipxe/src/core/xfer.c49
-rw-r--r--qemu/roms/ipxe/src/core/xferbuf.c262
-rw-r--r--qemu/roms/ipxe/src/crypto/aes.c808
-rw-r--r--qemu/roms/ipxe/src/crypto/asn1.c6
-rw-r--r--qemu/roms/ipxe/src/crypto/axtls/aes.c457
-rw-r--r--qemu/roms/ipxe/src/crypto/axtls/bigint.h99
-rw-r--r--qemu/roms/ipxe/src/crypto/axtls/bigint_impl.h131
-rw-r--r--qemu/roms/ipxe/src/crypto/axtls/config.h13
-rw-r--r--qemu/roms/ipxe/src/crypto/axtls/crypto.h229
-rw-r--r--qemu/roms/ipxe/src/crypto/axtls/os_port.h54
-rw-r--r--qemu/roms/ipxe/src/crypto/axtls_aes.c160
-rw-r--r--qemu/roms/ipxe/src/crypto/bigint.c6
-rw-r--r--qemu/roms/ipxe/src/crypto/cbc.c6
-rw-r--r--qemu/roms/ipxe/src/crypto/certstore.c6
-rw-r--r--qemu/roms/ipxe/src/crypto/chap.c6
-rw-r--r--qemu/roms/ipxe/src/crypto/cms.c6
-rw-r--r--qemu/roms/ipxe/src/crypto/crypto_null.c6
-rw-r--r--qemu/roms/ipxe/src/crypto/deflate.c6
-rw-r--r--qemu/roms/ipxe/src/crypto/drbg.c6
-rw-r--r--qemu/roms/ipxe/src/crypto/ecb.c80
-rw-r--r--qemu/roms/ipxe/src/crypto/entropy.c6
-rw-r--r--qemu/roms/ipxe/src/crypto/hash_df.c6
-rw-r--r--qemu/roms/ipxe/src/crypto/hmac.c6
-rw-r--r--qemu/roms/ipxe/src/crypto/hmac_drbg.c6
-rw-r--r--qemu/roms/ipxe/src/crypto/md5.c6
-rw-r--r--qemu/roms/ipxe/src/crypto/mishmash/rsa_aes_cbc_sha1.c48
-rw-r--r--qemu/roms/ipxe/src/crypto/mishmash/rsa_aes_cbc_sha256.c48
-rw-r--r--qemu/roms/ipxe/src/crypto/mishmash/rsa_md5.c51
-rw-r--r--qemu/roms/ipxe/src/crypto/mishmash/rsa_sha1.c62
-rw-r--r--qemu/roms/ipxe/src/crypto/mishmash/rsa_sha224.c62
-rw-r--r--qemu/roms/ipxe/src/crypto/mishmash/rsa_sha256.c62
-rw-r--r--qemu/roms/ipxe/src/crypto/mishmash/rsa_sha384.c62
-rw-r--r--qemu/roms/ipxe/src/crypto/mishmash/rsa_sha512.c62
-rw-r--r--qemu/roms/ipxe/src/crypto/null_entropy.c6
-rw-r--r--qemu/roms/ipxe/src/crypto/ocsp.c2
-rw-r--r--qemu/roms/ipxe/src/crypto/privkey.c6
-rw-r--r--qemu/roms/ipxe/src/crypto/random_nz.c6
-rw-r--r--qemu/roms/ipxe/src/crypto/rbg.c6
-rw-r--r--qemu/roms/ipxe/src/crypto/rootcert.c6
-rw-r--r--qemu/roms/ipxe/src/crypto/rsa.c78
-rw-r--r--qemu/roms/ipxe/src/crypto/sha1.c6
-rw-r--r--qemu/roms/ipxe/src/crypto/sha224.c82
-rw-r--r--qemu/roms/ipxe/src/crypto/sha256.c63
-rw-r--r--qemu/roms/ipxe/src/crypto/sha384.c82
-rw-r--r--qemu/roms/ipxe/src/crypto/sha512.c303
-rw-r--r--qemu/roms/ipxe/src/crypto/sha512_224.c83
-rw-r--r--qemu/roms/ipxe/src/crypto/sha512_256.c83
-rw-r--r--qemu/roms/ipxe/src/crypto/x509.c15
-rw-r--r--qemu/roms/ipxe/src/drivers/bitbash/bitbash.c6
-rw-r--r--qemu/roms/ipxe/src/drivers/bitbash/i2c_bit.c6
-rw-r--r--qemu/roms/ipxe/src/drivers/bitbash/spi_bit.c6
-rw-r--r--qemu/roms/ipxe/src/drivers/block/ata.c6
-rw-r--r--qemu/roms/ipxe/src/drivers/block/scsi.c6
-rw-r--r--qemu/roms/ipxe/src/drivers/bus/cdc.c54
-rw-r--r--qemu/roms/ipxe/src/drivers/bus/pci.c31
-rw-r--r--qemu/roms/ipxe/src/drivers/bus/pci_settings.c6
-rw-r--r--qemu/roms/ipxe/src/drivers/bus/pcibackup.c6
-rw-r--r--qemu/roms/ipxe/src/drivers/bus/pciextra.c12
-rw-r--r--qemu/roms/ipxe/src/drivers/bus/pcivpd.c6
-rw-r--r--qemu/roms/ipxe/src/drivers/bus/usb.c2128
-rw-r--r--qemu/roms/ipxe/src/drivers/infiniband/arbel.c6
-rw-r--r--qemu/roms/ipxe/src/drivers/infiniband/arbel.h2
-rw-r--r--qemu/roms/ipxe/src/drivers/infiniband/linda.c6
-rw-r--r--qemu/roms/ipxe/src/drivers/infiniband/linda.h6
-rw-r--r--qemu/roms/ipxe/src/drivers/infiniband/qib7322.c6
-rw-r--r--qemu/roms/ipxe/src/drivers/infiniband/qib7322.h6
-rw-r--r--qemu/roms/ipxe/src/drivers/net/amd8111e.h6
-rw-r--r--qemu/roms/ipxe/src/drivers/net/ath/ath9k/ani.h2
-rw-r--r--qemu/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ani.c16
-rw-r--r--qemu/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar5008_phy.c18
-rw-r--r--qemu/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9003_phy.c12
-rw-r--r--qemu/roms/ipxe/src/drivers/net/atl1e.c2
-rw-r--r--qemu/roms/ipxe/src/drivers/net/davicom.c1
-rw-r--r--qemu/roms/ipxe/src/drivers/net/dm96xx.c671
-rw-r--r--qemu/roms/ipxe/src/drivers/net/dm96xx.h194
-rw-r--r--qemu/roms/ipxe/src/drivers/net/dmfe.c2
-rw-r--r--qemu/roms/ipxe/src/drivers/net/ecm.c520
-rw-r--r--qemu/roms/ipxe/src/drivers/net/ecm.h93
-rw-r--r--qemu/roms/ipxe/src/drivers/net/eepro.c20
-rw-r--r--qemu/roms/ipxe/src/drivers/net/eepro100.c1
-rw-r--r--qemu/roms/ipxe/src/drivers/net/efi/nii.c150
-rw-r--r--qemu/roms/ipxe/src/drivers/net/efi/nii.h2
-rw-r--r--qemu/roms/ipxe/src/drivers/net/efi/snp.c6
-rw-r--r--qemu/roms/ipxe/src/drivers/net/efi/snponly.c6
-rw-r--r--qemu/roms/ipxe/src/drivers/net/etherfabric.c2
-rw-r--r--qemu/roms/ipxe/src/drivers/net/forcedeth.c6
-rw-r--r--qemu/roms/ipxe/src/drivers/net/igbvf/igbvf_main.c2
-rw-r--r--qemu/roms/ipxe/src/drivers/net/intel.c148
-rw-r--r--qemu/roms/ipxe/src/drivers/net/intel.h123
-rw-r--r--qemu/roms/ipxe/src/drivers/net/intelvf.c340
-rw-r--r--qemu/roms/ipxe/src/drivers/net/intelvf.h109
-rw-r--r--qemu/roms/ipxe/src/drivers/net/intelx.c25
-rw-r--r--qemu/roms/ipxe/src/drivers/net/intelx.h2
-rw-r--r--qemu/roms/ipxe/src/drivers/net/intelxvf.c466
-rw-r--r--qemu/roms/ipxe/src/drivers/net/intelxvf.h104
-rw-r--r--qemu/roms/ipxe/src/drivers/net/ipoib.c90
-rw-r--r--qemu/roms/ipxe/src/drivers/net/legacy.c2
-rw-r--r--qemu/roms/ipxe/src/drivers/net/mii.c38
-rw-r--r--qemu/roms/ipxe/src/drivers/net/myson.c6
-rw-r--r--qemu/roms/ipxe/src/drivers/net/myson.h2
-rw-r--r--qemu/roms/ipxe/src/drivers/net/ncm.c672
-rw-r--r--qemu/roms/ipxe/src/drivers/net/ncm.h173
-rw-r--r--qemu/roms/ipxe/src/drivers/net/netfront.c16
-rw-r--r--qemu/roms/ipxe/src/drivers/net/netfront.h2
-rw-r--r--qemu/roms/ipxe/src/drivers/net/netvsc.c848
-rw-r--r--qemu/roms/ipxe/src/drivers/net/netvsc.h365
-rw-r--r--qemu/roms/ipxe/src/drivers/net/phantom/nx_bitops.h6
-rw-r--r--qemu/roms/ipxe/src/drivers/net/phantom/phantom.c6
-rw-r--r--qemu/roms/ipxe/src/drivers/net/phantom/phantom.h6
-rw-r--r--qemu/roms/ipxe/src/drivers/net/phantom/phantom_hw.h6
-rw-r--r--qemu/roms/ipxe/src/drivers/net/pnic.c14
-rw-r--r--qemu/roms/ipxe/src/drivers/net/prism2.c14
-rw-r--r--qemu/roms/ipxe/src/drivers/net/prism2_pci.c16
-rw-r--r--qemu/roms/ipxe/src/drivers/net/prism2_plx.c18
-rw-r--r--qemu/roms/ipxe/src/drivers/net/realtek.c11
-rw-r--r--qemu/roms/ipxe/src/drivers/net/realtek.h2
-rw-r--r--qemu/roms/ipxe/src/drivers/net/rtl818x/rtl8180.c20
-rw-r--r--qemu/roms/ipxe/src/drivers/net/rtl818x/rtl8185.c14
-rw-r--r--qemu/roms/ipxe/src/drivers/net/rtl818x/rtl818x.c26
-rw-r--r--qemu/roms/ipxe/src/drivers/net/rtl818x/rtl818x.h4
-rw-r--r--qemu/roms/ipxe/src/drivers/net/skeleton.c6
-rw-r--r--qemu/roms/ipxe/src/drivers/net/skeleton.h2
-rw-r--r--qemu/roms/ipxe/src/drivers/net/smsc75xx.c1057
-rw-r--r--qemu/roms/ipxe/src/drivers/net/smsc75xx.h309
-rw-r--r--qemu/roms/ipxe/src/drivers/net/sundance.c2
-rw-r--r--qemu/roms/ipxe/src/drivers/net/tg3/tg3.c1
-rw-r--r--qemu/roms/ipxe/src/drivers/net/tg3/tg3.h5
-rw-r--r--qemu/roms/ipxe/src/drivers/net/tg3/tg3_hw.c1
-rw-r--r--qemu/roms/ipxe/src/drivers/net/virtio-net.c14
-rw-r--r--qemu/roms/ipxe/src/drivers/net/vmxnet3.c6
-rw-r--r--qemu/roms/ipxe/src/drivers/net/vmxnet3.h6
-rw-r--r--qemu/roms/ipxe/src/drivers/net/vxge/vxge.c3
-rw-r--r--qemu/roms/ipxe/src/drivers/net/vxge/vxge_main.c2
-rw-r--r--qemu/roms/ipxe/src/drivers/net/w89c840.c2
-rw-r--r--qemu/roms/ipxe/src/drivers/nvs/nvs.c6
-rw-r--r--qemu/roms/ipxe/src/drivers/nvs/nvsvpd.c6
-rw-r--r--qemu/roms/ipxe/src/drivers/nvs/spi.c6
-rw-r--r--qemu/roms/ipxe/src/drivers/nvs/threewire.c6
-rw-r--r--qemu/roms/ipxe/src/drivers/usb/ehci.c1994
-rw-r--r--qemu/roms/ipxe/src/drivers/usb/ehci.h544
-rw-r--r--qemu/roms/ipxe/src/drivers/usb/uhci.c1577
-rw-r--r--qemu/roms/ipxe/src/drivers/usb/uhci.h350
-rw-r--r--qemu/roms/ipxe/src/drivers/usb/usbhid.c151
-rw-r--r--qemu/roms/ipxe/src/drivers/usb/usbhub.c547
-rw-r--r--qemu/roms/ipxe/src/drivers/usb/usbhub.h279
-rw-r--r--qemu/roms/ipxe/src/drivers/usb/usbkbd.c509
-rw-r--r--qemu/roms/ipxe/src/drivers/usb/usbkbd.h154
-rw-r--r--qemu/roms/ipxe/src/drivers/usb/usbnet.c284
-rw-r--r--qemu/roms/ipxe/src/drivers/usb/xhci.c3321
-rw-r--r--qemu/roms/ipxe/src/drivers/usb/xhci.h1150
-rw-r--r--qemu/roms/ipxe/src/hci/commands/autoboot_cmd.c6
-rw-r--r--qemu/roms/ipxe/src/hci/commands/config_cmd.c6
-rw-r--r--qemu/roms/ipxe/src/hci/commands/console_cmd.c6
-rw-r--r--qemu/roms/ipxe/src/hci/commands/dhcp_cmd.c6
-rw-r--r--qemu/roms/ipxe/src/hci/commands/fcmgmt_cmd.c6
-rw-r--r--qemu/roms/ipxe/src/hci/commands/gdbstub_cmd.c6
-rw-r--r--qemu/roms/ipxe/src/hci/commands/ifmgmt_cmd.c6
-rw-r--r--qemu/roms/ipxe/src/hci/commands/image_cmd.c6
-rw-r--r--qemu/roms/ipxe/src/hci/commands/image_trust_cmd.c9
-rw-r--r--qemu/roms/ipxe/src/hci/commands/ipstat_cmd.c6
-rw-r--r--qemu/roms/ipxe/src/hci/commands/login_cmd.c6
-rw-r--r--qemu/roms/ipxe/src/hci/commands/lotest_cmd.c6
-rw-r--r--qemu/roms/ipxe/src/hci/commands/menu_cmd.c6
-rw-r--r--qemu/roms/ipxe/src/hci/commands/neighbour_cmd.c6
-rw-r--r--qemu/roms/ipxe/src/hci/commands/nvo_cmd.c6
-rw-r--r--qemu/roms/ipxe/src/hci/commands/param_cmd.c6
-rw-r--r--qemu/roms/ipxe/src/hci/commands/pci_cmd.c6
-rw-r--r--qemu/roms/ipxe/src/hci/commands/ping_cmd.c6
-rw-r--r--qemu/roms/ipxe/src/hci/commands/poweroff_cmd.c6
-rw-r--r--qemu/roms/ipxe/src/hci/commands/profstat_cmd.c6
-rw-r--r--qemu/roms/ipxe/src/hci/commands/reboot_cmd.c6
-rw-r--r--qemu/roms/ipxe/src/hci/commands/route_cmd.c6
-rw-r--r--qemu/roms/ipxe/src/hci/commands/sanboot_cmd.c6
-rw-r--r--qemu/roms/ipxe/src/hci/commands/sync_cmd.c6
-rw-r--r--qemu/roms/ipxe/src/hci/commands/vlan_cmd.c6
-rw-r--r--qemu/roms/ipxe/src/hci/editstring.c6
-rw-r--r--qemu/roms/ipxe/src/hci/jumpscroll.c140
-rw-r--r--qemu/roms/ipxe/src/hci/mucurses/alert.c2
-rw-r--r--qemu/roms/ipxe/src/hci/mucurses/ansi_screen.c2
-rw-r--r--qemu/roms/ipxe/src/hci/mucurses/clear.c2
-rw-r--r--qemu/roms/ipxe/src/hci/mucurses/colour.c2
-rw-r--r--qemu/roms/ipxe/src/hci/mucurses/cursor.h2
-rw-r--r--qemu/roms/ipxe/src/hci/mucurses/edging.c2
-rw-r--r--qemu/roms/ipxe/src/hci/mucurses/kb.c2
-rw-r--r--qemu/roms/ipxe/src/hci/mucurses/mucurses.c2
-rw-r--r--qemu/roms/ipxe/src/hci/mucurses/mucurses.h2
-rw-r--r--qemu/roms/ipxe/src/hci/mucurses/print.c2
-rw-r--r--qemu/roms/ipxe/src/hci/mucurses/print_nadv.c2
-rw-r--r--qemu/roms/ipxe/src/hci/mucurses/slk.c2
-rw-r--r--qemu/roms/ipxe/src/hci/mucurses/widgets/editbox.c6
-rw-r--r--qemu/roms/ipxe/src/hci/mucurses/winattrs.c2
-rw-r--r--qemu/roms/ipxe/src/hci/mucurses/windows.c2
-rw-r--r--qemu/roms/ipxe/src/hci/mucurses/wininit.c2
-rw-r--r--qemu/roms/ipxe/src/hci/readline.c6
-rw-r--r--qemu/roms/ipxe/src/hci/shell.c9
-rw-r--r--qemu/roms/ipxe/src/hci/strerror.c9
-rw-r--r--qemu/roms/ipxe/src/hci/tui/login_ui.c6
-rw-r--r--qemu/roms/ipxe/src/hci/tui/menu_ui.c102
-rw-r--r--qemu/roms/ipxe/src/hci/tui/settings_ui.c355
-rw-r--r--qemu/roms/ipxe/src/image/elf.c145
-rw-r--r--qemu/roms/ipxe/src/image/embedded.c2
-rw-r--r--qemu/roms/ipxe/src/image/png.c6
-rw-r--r--qemu/roms/ipxe/src/image/pnm.c6
-rw-r--r--qemu/roms/ipxe/src/image/script.c6
-rw-r--r--qemu/roms/ipxe/src/image/segment.c6
-rw-r--r--qemu/roms/ipxe/src/include/.gitignore1
-rw-r--r--qemu/roms/ipxe/src/include/assert.h2
-rw-r--r--qemu/roms/ipxe/src/include/big_bswap.h35
-rw-r--r--qemu/roms/ipxe/src/include/byteswap.h185
-rw-r--r--qemu/roms/ipxe/src/include/compiler.h203
-rw-r--r--qemu/roms/ipxe/src/include/ctype.h118
-rw-r--r--qemu/roms/ipxe/src/include/curses.h2
-rw-r--r--qemu/roms/ipxe/src/include/elf.h277
-rw-r--r--qemu/roms/ipxe/src/include/endian.h31
-rw-r--r--qemu/roms/ipxe/src/include/errno.h6
-rw-r--r--qemu/roms/ipxe/src/include/getopt.h2
-rw-r--r--qemu/roms/ipxe/src/include/hci/ifmgmt_cmd.h6
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/acpi.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/aes.h44
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/ansicol.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/ansiesc.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/aoe.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/api.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/arp.h6
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/asn1.h55
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/ata.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/base16.h35
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/base64.h7
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/bigint.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/bitbash.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/bitmap.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/bitops.h6
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/blockdev.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/blocktrans.h38
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/bofm.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/cbc.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/cdc.h55
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/certstore.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/chap.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/cms.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/command.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/console.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/cpio.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/crc32.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/crypto.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/deflate.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/device.h33
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/dhcp.h12
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/dhcpopts.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/dhcppkt.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/dhcpv6.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/dns.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/downloader.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/drbg.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/ecb.h55
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/edd.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/editbox.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/editstring.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/efi/ProcessorBind.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/efi/Protocol/Rng.h158
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/efi/efi_autoboot.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/efi/efi_driver.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/efi/efi_entropy.h35
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/efi/efi_hii.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/efi/efi_pci.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/efi/efi_pci_api.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/efi/efi_reboot.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/efi/efi_smbios.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/efi/efi_snp.h27
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/efi/efi_strings.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/efi/efi_time.h20
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/efi/efi_timer.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/efi/efi_uaccess.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/efi/efi_umalloc.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/efi/efi_utils.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/efi/efi_watchdog.h31
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/efi/efi_wrap.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/eisa.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/elf.h13
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/eltorito.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/entropy.h3
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/errfile.h37
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/errno/efi.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/errno/linux.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/errortab.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/eth_slow.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/ethernet.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/fakedhcp.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/fault.h53
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/fbcon.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/fc.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/fcels.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/fcns.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/fcoe.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/fcp.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/features.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/fragment.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/ftp.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/gdbserial.h13
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/gdbstub.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/gdbudp.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/hash_df.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/hidemem.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/hmac.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/hmac_drbg.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/http.h490
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/hyperv.h232
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/i2c.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/ib_cm.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/ib_mad.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/ib_mcast.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/ib_mi.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/ib_packet.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/ib_pathrec.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/ib_sma.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/ib_smc.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/icmp.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/icmpv6.h14
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/if_arp.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/if_ether.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/image.h3
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/in.h40
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/infiniband.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/init.h9
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/interface.h7
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/io.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/iobuf.h3
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/ip.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/ipoib.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/ipstat.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/ipv6.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/isa_ids.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/isapnp.h6
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/iscsi.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/iso9660.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/isqrt.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/job.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/jumpscroll.h50
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/keymap.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/keys.h4
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/linebuf.h14
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/lineconsole.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/linux/linux_entropy.h12
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/linux/linux_nap.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/linux/linux_pci.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/linux/linux_smbios.h4
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/linux/linux_time.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/linux/linux_timer.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/linux/linux_uaccess.h126
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/linux/linux_umalloc.h6
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/linux_compat.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/list.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/login_ui.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/malloc.h4
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/mca.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/md5.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/memblock.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/menu.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/mii.h4
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/monojob.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/mount.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/nap.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/ndp.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/neighbour.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/net80211_err.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/netdevice.h41
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/nfs.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/nfs_open.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/nfs_uri.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/null_entropy.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/null_nap.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/null_reboot.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/null_sanboot.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/null_time.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/nvo.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/nvs.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/nvsvpd.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/ocsp.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/oncrpc.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/oncrpc_iob.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/open.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/params.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/parseopt.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/pccrc.h447
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/pccrd.h47
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/pccrr.h376
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/pci.h382
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/pci_ids.h351
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/pci_io.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/pcibackup.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/pcivpd.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/peerblk.h144
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/peerdisc.h116
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/peermux.h73
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/pending.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/ping.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/pinger.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/pixbuf.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/png.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/pnm.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/pool.h127
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/portmap.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/posix_io.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/privkey.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/process.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/profile.h16
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/random_nz.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/rarp.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/rbg.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/reboot.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/refcnt.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/resolv.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/retry.h36
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/rndis.h370
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/rootcert.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/rotate.h22
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/rsa.h3
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/sanboot.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/script.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/scsi.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/segment.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/serial.h11
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/settings.h3
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/settings_ui.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/sha256.h17
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/sha512.h98
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/shell.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/smbios.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/socket.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/spi.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/spi_bit.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/stp.h76
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/string.h14
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/syslog.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/tables.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/tcp.h53
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/tcpip.h11
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/test.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/tftp.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/time.h3
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/timer.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/tls.h30
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/uaccess.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/uart.h132
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/udp.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/umalloc.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/uri.h4
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/usb.h1319
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/usbhid.h106
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/usbnet.h62
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/uuid.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/validator.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/version.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/vlan.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/vmbus.h634
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/vsprintf.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/x509.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/xen.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/xenbus.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/xenevent.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/xengrant.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/xenmem.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/xenstore.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/xenver.h2
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/xfer.h4
-rw-r--r--qemu/roms/ipxe/src/include/ipxe/xferbuf.h78
-rw-r--r--qemu/roms/ipxe/src/include/libgen.h2
-rw-r--r--qemu/roms/ipxe/src/include/little_bswap.h37
-rw-r--r--qemu/roms/ipxe/src/include/nic.h19
-rw-r--r--qemu/roms/ipxe/src/include/readline/readline.h2
-rw-r--r--qemu/roms/ipxe/src/include/stdarg.h2
-rw-r--r--qemu/roms/ipxe/src/include/stddef.h40
-rw-r--r--qemu/roms/ipxe/src/include/stdint.h2
-rw-r--r--qemu/roms/ipxe/src/include/stdio.h2
-rw-r--r--qemu/roms/ipxe/src/include/stdlib.h30
-rw-r--r--qemu/roms/ipxe/src/include/string.h83
-rw-r--r--qemu/roms/ipxe/src/include/strings.h145
-rw-r--r--qemu/roms/ipxe/src/include/sys/time.h2
-rw-r--r--qemu/roms/ipxe/src/include/syslog.h2
-rw-r--r--qemu/roms/ipxe/src/include/time.h2
-rw-r--r--qemu/roms/ipxe/src/include/unistd.h2
-rw-r--r--qemu/roms/ipxe/src/include/usr/autoboot.h4
-rw-r--r--qemu/roms/ipxe/src/include/usr/dhcpmgmt.h2
-rw-r--r--qemu/roms/ipxe/src/include/usr/fcmgmt.h2
-rw-r--r--qemu/roms/ipxe/src/include/usr/ifmgmt.h2
-rw-r--r--qemu/roms/ipxe/src/include/usr/imgmgmt.h2
-rw-r--r--qemu/roms/ipxe/src/include/usr/imgtrust.h2
-rw-r--r--qemu/roms/ipxe/src/include/usr/ipstat.h2
-rw-r--r--qemu/roms/ipxe/src/include/usr/lotest.h2
-rw-r--r--qemu/roms/ipxe/src/include/usr/neighmgmt.h2
-rw-r--r--qemu/roms/ipxe/src/include/usr/pingmgmt.h2
-rw-r--r--qemu/roms/ipxe/src/include/usr/profstat.h2
-rw-r--r--qemu/roms/ipxe/src/include/usr/prompt.h2
-rw-r--r--qemu/roms/ipxe/src/include/usr/route.h2
-rw-r--r--qemu/roms/ipxe/src/include/usr/sync.h2
-rw-r--r--qemu/roms/ipxe/src/include/valgrind/memcheck.h (renamed from qemu/roms/ipxe/src/arch/x86/include/valgrind/memcheck.h)0
-rw-r--r--qemu/roms/ipxe/src/include/valgrind/valgrind.h (renamed from qemu/roms/ipxe/src/arch/x86/include/valgrind/valgrind.h)0
-rw-r--r--qemu/roms/ipxe/src/include/wchar.h2
-rw-r--r--qemu/roms/ipxe/src/interface/bofm/bofm.c6
-rw-r--r--qemu/roms/ipxe/src/interface/efi/efi_autoboot.c6
-rw-r--r--qemu/roms/ipxe/src/interface/efi/efi_bofm.c6
-rw-r--r--qemu/roms/ipxe/src/interface/efi/efi_debug.c8
-rw-r--r--qemu/roms/ipxe/src/interface/efi/efi_file.c6
-rw-r--r--qemu/roms/ipxe/src/interface/efi/efi_guid.c6
-rw-r--r--qemu/roms/ipxe/src/interface/efi/efi_hii.c6
-rw-r--r--qemu/roms/ipxe/src/interface/efi/efi_pci.c6
-rw-r--r--qemu/roms/ipxe/src/interface/efi/efi_reboot.c6
-rw-r--r--qemu/roms/ipxe/src/interface/efi/efi_snp.c181
-rw-r--r--qemu/roms/ipxe/src/interface/efi/efi_snp_hii.c9
-rw-r--r--qemu/roms/ipxe/src/interface/efi/efi_strings.c6
-rw-r--r--qemu/roms/ipxe/src/interface/efi/efi_time.c75
-rw-r--r--qemu/roms/ipxe/src/interface/efi/efi_timer.c6
-rw-r--r--qemu/roms/ipxe/src/interface/efi/efi_uaccess.c6
-rw-r--r--qemu/roms/ipxe/src/interface/efi/efi_umalloc.c6
-rw-r--r--qemu/roms/ipxe/src/interface/efi/efi_watchdog.c82
-rw-r--r--qemu/roms/ipxe/src/interface/efi/efi_wrap.c6
-rw-r--r--qemu/roms/ipxe/src/interface/hyperv/vmbus.c1333
-rw-r--r--qemu/roms/ipxe/src/interface/linux/linux_entropy.c6
-rw-r--r--qemu/roms/ipxe/src/interface/linux/linux_pci.c6
-rw-r--r--qemu/roms/ipxe/src/interface/linux/linux_time.c6
-rw-r--r--qemu/roms/ipxe/src/interface/linux/linux_uaccess.c1
-rw-r--r--qemu/roms/ipxe/src/interface/smbios/smbios.c6
-rw-r--r--qemu/roms/ipxe/src/interface/smbios/smbios_settings.c6
-rw-r--r--qemu/roms/ipxe/src/interface/xen/xenbus.c6
-rw-r--r--qemu/roms/ipxe/src/interface/xen/xengrant.c6
-rw-r--r--qemu/roms/ipxe/src/interface/xen/xenstore.c10
-rw-r--r--qemu/roms/ipxe/src/net/80211/net80211.c10
-rw-r--r--qemu/roms/ipxe/src/net/80211/wpa.c1
-rw-r--r--qemu/roms/ipxe/src/net/80211/wpa_ccmp.c2
-rw-r--r--qemu/roms/ipxe/src/net/80211/wpa_tkip.c2
-rw-r--r--qemu/roms/ipxe/src/net/aoe.c6
-rw-r--r--qemu/roms/ipxe/src/net/arp.c12
-rw-r--r--qemu/roms/ipxe/src/net/dhcpopts.c6
-rw-r--r--qemu/roms/ipxe/src/net/dhcppkt.c6
-rw-r--r--qemu/roms/ipxe/src/net/eth_slow.c6
-rw-r--r--qemu/roms/ipxe/src/net/ethernet.c50
-rw-r--r--qemu/roms/ipxe/src/net/fakedhcp.c6
-rw-r--r--qemu/roms/ipxe/src/net/fc.c12
-rw-r--r--qemu/roms/ipxe/src/net/fcels.c6
-rw-r--r--qemu/roms/ipxe/src/net/fcns.c6
-rw-r--r--qemu/roms/ipxe/src/net/fcoe.c6
-rw-r--r--qemu/roms/ipxe/src/net/fcp.c6
-rw-r--r--qemu/roms/ipxe/src/net/fragment.c6
-rw-r--r--qemu/roms/ipxe/src/net/icmp.c6
-rw-r--r--qemu/roms/ipxe/src/net/icmpv4.c6
-rw-r--r--qemu/roms/ipxe/src/net/icmpv6.c86
-rw-r--r--qemu/roms/ipxe/src/net/infiniband.c18
-rw-r--r--qemu/roms/ipxe/src/net/infiniband/ib_cm.c6
-rw-r--r--qemu/roms/ipxe/src/net/infiniband/ib_mcast.c12
-rw-r--r--qemu/roms/ipxe/src/net/infiniband/ib_mi.c6
-rw-r--r--qemu/roms/ipxe/src/net/infiniband/ib_packet.c6
-rw-r--r--qemu/roms/ipxe/src/net/infiniband/ib_pathrec.c6
-rw-r--r--qemu/roms/ipxe/src/net/infiniband/ib_sma.c6
-rw-r--r--qemu/roms/ipxe/src/net/infiniband/ib_smc.c6
-rw-r--r--qemu/roms/ipxe/src/net/infiniband/ib_srp.c2
-rw-r--r--qemu/roms/ipxe/src/net/iobpad.c6
-rw-r--r--qemu/roms/ipxe/src/net/ipv4.c130
-rw-r--r--qemu/roms/ipxe/src/net/ipv6.c22
-rw-r--r--qemu/roms/ipxe/src/net/neighbour.c12
-rw-r--r--qemu/roms/ipxe/src/net/netdev_settings.c10
-rw-r--r--qemu/roms/ipxe/src/net/netdevice.c74
-rw-r--r--qemu/roms/ipxe/src/net/nullnet.c6
-rw-r--r--qemu/roms/ipxe/src/net/pccrc.c818
-rw-r--r--qemu/roms/ipxe/src/net/pccrd.c286
-rw-r--r--qemu/roms/ipxe/src/net/peerblk.c1366
-rw-r--r--qemu/roms/ipxe/src/net/peerdisc.c551
-rw-r--r--qemu/roms/ipxe/src/net/peerdist.c145
-rw-r--r--qemu/roms/ipxe/src/net/peermux.c387
-rw-r--r--qemu/roms/ipxe/src/net/ping.c6
-rw-r--r--qemu/roms/ipxe/src/net/rarp.c6
-rw-r--r--qemu/roms/ipxe/src/net/retry.c90
-rw-r--r--qemu/roms/ipxe/src/net/rndis.c1052
-rw-r--r--qemu/roms/ipxe/src/net/socket.c6
-rw-r--r--qemu/roms/ipxe/src/net/stp.c152
-rw-r--r--qemu/roms/ipxe/src/net/tcp.c245
-rw-r--r--qemu/roms/ipxe/src/net/tcp/http.c26
-rw-r--r--qemu/roms/ipxe/src/net/tcp/httpauth.c190
-rw-r--r--qemu/roms/ipxe/src/net/tcp/httpbasic.c102
-rw-r--r--qemu/roms/ipxe/src/net/tcp/httpblock.c134
-rw-r--r--qemu/roms/ipxe/src/net/tcp/httpconn.c309
-rw-r--r--qemu/roms/ipxe/src/net/tcp/httpcore.c2676
-rw-r--r--qemu/roms/ipxe/src/net/tcp/httpdigest.c234
-rw-r--r--qemu/roms/ipxe/src/net/tcp/https.c27
-rw-r--r--qemu/roms/ipxe/src/net/tcp/iscsi.c76
-rw-r--r--qemu/roms/ipxe/src/net/tcp/syslogs.c6
-rw-r--r--qemu/roms/ipxe/src/net/tcpip.c4
-rw-r--r--qemu/roms/ipxe/src/net/tls.c146
-rw-r--r--qemu/roms/ipxe/src/net/udp.c2
-rw-r--r--qemu/roms/ipxe/src/net/udp/dhcp.c133
-rw-r--r--qemu/roms/ipxe/src/net/udp/dhcpv6.c6
-rw-r--r--qemu/roms/ipxe/src/net/udp/dns.c6
-rw-r--r--qemu/roms/ipxe/src/net/udp/slam.c6
-rw-r--r--qemu/roms/ipxe/src/net/udp/syslog.c6
-rw-r--r--qemu/roms/ipxe/src/net/udp/tftp.c60
-rw-r--r--qemu/roms/ipxe/src/net/validator.c14
-rw-r--r--qemu/roms/ipxe/src/net/vlan.c10
-rw-r--r--qemu/roms/ipxe/src/tests/aes_cbc_test.c193
-rw-r--r--qemu/roms/ipxe/src/tests/aes_test.c193
-rw-r--r--qemu/roms/ipxe/src/tests/base16_test.c52
-rw-r--r--qemu/roms/ipxe/src/tests/base64_test.c52
-rw-r--r--qemu/roms/ipxe/src/tests/bigint_test.c6
-rw-r--r--qemu/roms/ipxe/src/tests/bofm_test.c6
-rw-r--r--qemu/roms/ipxe/src/tests/byteswap_test.c6
-rw-r--r--qemu/roms/ipxe/src/tests/cbc_test.h57
-rw-r--r--qemu/roms/ipxe/src/tests/cipher_test.c (renamed from qemu/roms/ipxe/src/tests/cbc_test.c)118
-rw-r--r--qemu/roms/ipxe/src/tests/cipher_test.h111
-rw-r--r--qemu/roms/ipxe/src/tests/cms_test.c7
-rw-r--r--qemu/roms/ipxe/src/tests/crc32_test.c6
-rw-r--r--qemu/roms/ipxe/src/tests/deflate_test.c6
-rw-r--r--qemu/roms/ipxe/src/tests/digest_test.c69
-rw-r--r--qemu/roms/ipxe/src/tests/digest_test.h120
-rw-r--r--qemu/roms/ipxe/src/tests/dns_test.c6
-rw-r--r--qemu/roms/ipxe/src/tests/entropy_sample.c6
-rw-r--r--qemu/roms/ipxe/src/tests/hash_df_test.c6
-rw-r--r--qemu/roms/ipxe/src/tests/hmac_drbg_test.c6
-rw-r--r--qemu/roms/ipxe/src/tests/ipv4_test.c154
-rw-r--r--qemu/roms/ipxe/src/tests/ipv6_test.c6
-rw-r--r--qemu/roms/ipxe/src/tests/linebuf_test.c337
-rw-r--r--qemu/roms/ipxe/src/tests/list_test.c6
-rw-r--r--qemu/roms/ipxe/src/tests/math_test.c80
-rw-r--r--qemu/roms/ipxe/src/tests/md5_test.c82
-rw-r--r--qemu/roms/ipxe/src/tests/memcpy_test.c6
-rw-r--r--qemu/roms/ipxe/src/tests/memset_test.c157
-rw-r--r--qemu/roms/ipxe/src/tests/ocsp_test.c7
-rw-r--r--qemu/roms/ipxe/src/tests/pccrc_test.c529
-rw-r--r--qemu/roms/ipxe/src/tests/pixbuf_test.c13
-rw-r--r--qemu/roms/ipxe/src/tests/pixbuf_test.h2
-rw-r--r--qemu/roms/ipxe/src/tests/png_test.c6
-rw-r--r--qemu/roms/ipxe/src/tests/pnm_test.c6
-rw-r--r--qemu/roms/ipxe/src/tests/profile_test.c6
-rw-r--r--qemu/roms/ipxe/src/tests/pubkey_test.h2
-rw-r--r--qemu/roms/ipxe/src/tests/rsa_test.c6
-rw-r--r--qemu/roms/ipxe/src/tests/setjmp_test.c171
-rw-r--r--qemu/roms/ipxe/src/tests/settings_test.c25
-rw-r--r--qemu/roms/ipxe/src/tests/sha1_test.c92
-rw-r--r--qemu/roms/ipxe/src/tests/sha256_test.c131
-rw-r--r--qemu/roms/ipxe/src/tests/sha512_test.c185
-rw-r--r--qemu/roms/ipxe/src/tests/string_test.c142
-rw-r--r--qemu/roms/ipxe/src/tests/tcpip_test.c6
-rw-r--r--qemu/roms/ipxe/src/tests/test.c6
-rw-r--r--qemu/roms/ipxe/src/tests/tests.c15
-rw-r--r--qemu/roms/ipxe/src/tests/time_test.c6
-rw-r--r--qemu/roms/ipxe/src/tests/uri_test.c30
-rw-r--r--qemu/roms/ipxe/src/tests/vsprintf_test.c6
-rw-r--r--qemu/roms/ipxe/src/tests/x509_test.c7
-rw-r--r--qemu/roms/ipxe/src/usr/autoboot.c49
-rw-r--r--qemu/roms/ipxe/src/usr/dhcpmgmt.c6
-rw-r--r--qemu/roms/ipxe/src/usr/fcmgmt.c6
-rw-r--r--qemu/roms/ipxe/src/usr/ifmgmt.c9
-rw-r--r--qemu/roms/ipxe/src/usr/imgmgmt.c6
-rw-r--r--qemu/roms/ipxe/src/usr/imgtrust.c6
-rw-r--r--qemu/roms/ipxe/src/usr/ipstat.c6
-rw-r--r--qemu/roms/ipxe/src/usr/lotest.c6
-rw-r--r--qemu/roms/ipxe/src/usr/neighmgmt.c6
-rw-r--r--qemu/roms/ipxe/src/usr/pingmgmt.c6
-rw-r--r--qemu/roms/ipxe/src/usr/profstat.c6
-rw-r--r--qemu/roms/ipxe/src/usr/prompt.c6
-rw-r--r--qemu/roms/ipxe/src/usr/pxemenu.c6
-rw-r--r--qemu/roms/ipxe/src/usr/route.c10
-rw-r--r--qemu/roms/ipxe/src/usr/route_ipv4.c6
-rw-r--r--qemu/roms/ipxe/src/usr/route_ipv6.c6
-rw-r--r--qemu/roms/ipxe/src/usr/sync.c6
-rw-r--r--qemu/roms/ipxe/src/util/Option/ROM.pm20
-rwxr-xr-xqemu/roms/ipxe/src/util/disrom.pl4
-rw-r--r--qemu/roms/ipxe/src/util/elf2efi.c6
-rwxr-xr-xqemu/roms/ipxe/src/util/licence.pl13
-rwxr-xr-xqemu/roms/ipxe/src/util/parserom.pl296
-rwxr-xr-xqemu/roms/ipxe/src/util/relicense.pl169
-rw-r--r--qemu/roms/ipxe/src/util/zbin.c96
-rw-r--r--qemu/roms/openbios/Makefile.target2
-rw-r--r--qemu/roms/openbios/arch/ppc/qemu/init.c67
-rw-r--r--qemu/roms/openbios/arch/ppc/qemu/methods.c36
-rw-r--r--qemu/roms/openbios/arch/ppc/qemu/qemu.fs45
-rw-r--r--qemu/roms/openbios/arch/ppc/qemu/tree.fs8
-rw-r--r--qemu/roms/openbios/arch/sparc64/call-client.S218
-rw-r--r--qemu/roms/openbios/arch/sparc64/context.c4
-rw-r--r--qemu/roms/openbios/arch/sparc64/cpustate.h244
-rw-r--r--qemu/roms/openbios/arch/sparc64/ldscript5
-rw-r--r--qemu/roms/openbios/arch/sparc64/lib.c4
-rw-r--r--qemu/roms/openbios/arch/sparc64/vectors.S300
-rwxr-xr-xqemu/roms/openbios/config/scripts/switch-arch118
-rw-r--r--qemu/roms/openbios/drivers/cuda.c21
-rw-r--r--qemu/roms/openbios/drivers/escc.c112
-rw-r--r--qemu/roms/openbios/drivers/escc.h2
-rw-r--r--qemu/roms/openbios/drivers/ide.c82
-rw-r--r--qemu/roms/openbios/drivers/ide.h2
-rw-r--r--qemu/roms/openbios/drivers/obio.c66
-rw-r--r--qemu/roms/openbios/drivers/pci.c147
-rw-r--r--qemu/roms/openbios/drivers/pci.fs68
-rw-r--r--qemu/roms/openbios/drivers/pci.h9
-rw-r--r--qemu/roms/openbios/drivers/sbus.c25
-rw-r--r--qemu/roms/openbios/drivers/usbohci_private.h28
-rw-r--r--qemu/roms/openbios/drivers/vga.fs11
-rw-r--r--qemu/roms/openbios/forth/lib/string.fs14
-rw-r--r--qemu/roms/openbios/forth/system/ciface.fs8
-rw-r--r--qemu/roms/openbios/include/arch/ppc/types.h8
-rw-r--r--qemu/roms/openbios/include/arch/sparc64/io.h2
-rw-r--r--qemu/roms/openbios/include/drivers/drivers.h1
-rw-r--r--qemu/roms/openbios/include/libopenbios/bindings.h1
-rw-r--r--qemu/roms/openbios/libopenbios/bindings.c8
-rw-r--r--qemu/roms/openbios/libopenbios/bootinfo_load.c6
-rw-r--r--qemu/roms/seabios/.version2
-rw-r--r--qemu/roms/seabios/Makefile28
-rw-r--r--qemu/roms/seabios/docs/Build_overview.md34
-rw-r--r--qemu/roms/seabios/docs/Contributing.md20
-rw-r--r--qemu/roms/seabios/docs/Debugging.md27
-rw-r--r--qemu/roms/seabios/docs/Developer_Documentation.md11
-rw-r--r--qemu/roms/seabios/docs/Download.md6
-rw-r--r--qemu/roms/seabios/docs/Execution_and_code_flow.md2
-rw-r--r--qemu/roms/seabios/docs/Linking_overview.md12
-rw-r--r--qemu/roms/seabios/docs/Releases.md29
-rw-r--r--qemu/roms/seabios/docs/Runtime_config.md191
-rw-r--r--qemu/roms/seabios/docs/SeaBIOS.md2
-rw-r--r--qemu/roms/seabios/docs/SeaVGABIOS.md39
-rwxr-xr-xqemu/roms/seabios/scripts/buildversion.py134
-rwxr-xr-xqemu/roms/seabios/scripts/buildversion.sh31
-rwxr-xr-xqemu/roms/seabios/scripts/checkrom.py2
-rwxr-xr-xqemu/roms/seabios/scripts/checkstack.py270
-rw-r--r--qemu/roms/seabios/scripts/kconfig/lxdialog/util.c2
-rwxr-xr-xqemu/roms/seabios/scripts/layoutrom.py8
-rw-r--r--qemu/roms/seabios/src/Kconfig59
-rw-r--r--qemu/roms/seabios/src/biosvar.h8
-rw-r--r--qemu/roms/seabios/src/block.c248
-rw-r--r--qemu/roms/seabios/src/block.h16
-rw-r--r--qemu/roms/seabios/src/bmp.c2
-rw-r--r--qemu/roms/seabios/src/boot.c22
-rw-r--r--qemu/roms/seabios/src/cdrom.c23
-rw-r--r--qemu/roms/seabios/src/clock.c57
-rw-r--r--qemu/roms/seabios/src/config.h3
-rw-r--r--qemu/roms/seabios/src/disk.c5
-rw-r--r--qemu/roms/seabios/src/e820map.c (renamed from qemu/roms/seabios/src/memmap.c)18
-rw-r--r--qemu/roms/seabios/src/e820map.h26
-rw-r--r--qemu/roms/seabios/src/fw/biostables.c66
-rw-r--r--qemu/roms/seabios/src/fw/coreboot.c17
-rw-r--r--qemu/roms/seabios/src/fw/csm.c23
-rw-r--r--qemu/roms/seabios/src/fw/dev-q35.h3
-rw-r--r--qemu/roms/seabios/src/fw/multiboot.c111
-rw-r--r--qemu/roms/seabios/src/fw/paravirt.c93
-rw-r--r--qemu/roms/seabios/src/fw/paravirt.h26
-rw-r--r--qemu/roms/seabios/src/fw/pciinit.c24
-rw-r--r--qemu/roms/seabios/src/fw/shadow.c12
-rw-r--r--qemu/roms/seabios/src/fw/smbios.c2
-rw-r--r--qemu/roms/seabios/src/fw/smm.c8
-rw-r--r--qemu/roms/seabios/src/fw/smp.c3
-rw-r--r--qemu/roms/seabios/src/fw/xen.c9
-rw-r--r--qemu/roms/seabios/src/hw/ahci.c36
-rw-r--r--qemu/roms/seabios/src/hw/ahci.h4
-rw-r--r--qemu/roms/seabios/src/hw/ata.c42
-rw-r--r--qemu/roms/seabios/src/hw/ata.h6
-rw-r--r--qemu/roms/seabios/src/hw/blockcmd.c139
-rw-r--r--qemu/roms/seabios/src/hw/blockcmd.h4
-rw-r--r--qemu/roms/seabios/src/hw/esp-scsi.c33
-rw-r--r--qemu/roms/seabios/src/hw/esp-scsi.h2
-rw-r--r--qemu/roms/seabios/src/hw/floppy.c2
-rw-r--r--qemu/roms/seabios/src/hw/lsi-scsi.c32
-rw-r--r--qemu/roms/seabios/src/hw/lsi-scsi.h2
-rw-r--r--qemu/roms/seabios/src/hw/megasas.c26
-rw-r--r--qemu/roms/seabios/src/hw/megasas.h2
-rw-r--r--qemu/roms/seabios/src/hw/pci.c11
-rw-r--r--qemu/roms/seabios/src/hw/pci.h2
-rw-r--r--qemu/roms/seabios/src/hw/pci_ids.h8
-rw-r--r--qemu/roms/seabios/src/hw/pic.c14
-rw-r--r--qemu/roms/seabios/src/hw/pic.h4
-rw-r--r--qemu/roms/seabios/src/hw/ps2port.c53
-rw-r--r--qemu/roms/seabios/src/hw/ps2port.h3
-rw-r--r--qemu/roms/seabios/src/hw/pvscsi.c64
-rw-r--r--qemu/roms/seabios/src/hw/pvscsi.h2
-rw-r--r--qemu/roms/seabios/src/hw/ramdisk.c17
-rw-r--r--qemu/roms/seabios/src/hw/rtc.c7
-rw-r--r--qemu/roms/seabios/src/hw/sdcard.c415
-rw-r--r--qemu/roms/seabios/src/hw/timer.c25
-rw-r--r--qemu/roms/seabios/src/hw/tpm_drivers.c291
-rw-r--r--qemu/roms/seabios/src/hw/tpm_drivers.h90
-rw-r--r--qemu/roms/seabios/src/hw/usb-hid.h8
-rw-r--r--qemu/roms/seabios/src/hw/usb-msc.c14
-rw-r--r--qemu/roms/seabios/src/hw/usb-msc.h2
-rw-r--r--qemu/roms/seabios/src/hw/usb-uas.c6
-rw-r--r--qemu/roms/seabios/src/hw/usb-uas.h2
-rw-r--r--qemu/roms/seabios/src/hw/usb-xhci.c46
-rw-r--r--qemu/roms/seabios/src/hw/usb.c9
-rw-r--r--qemu/roms/seabios/src/hw/virtio-blk.c126
-rw-r--r--qemu/roms/seabios/src/hw/virtio-blk.h2
-rw-r--r--qemu/roms/seabios/src/hw/virtio-pci.c228
-rw-r--r--qemu/roms/seabios/src/hw/virtio-pci.h260
-rw-r--r--qemu/roms/seabios/src/hw/virtio-ring.c65
-rw-r--r--qemu/roms/seabios/src/hw/virtio-ring.h45
-rw-r--r--qemu/roms/seabios/src/hw/virtio-scsi.c98
-rw-r--r--qemu/roms/seabios/src/hw/virtio-scsi.h2
-rw-r--r--qemu/roms/seabios/src/list.h10
-rw-r--r--qemu/roms/seabios/src/malloc.c296
-rw-r--r--qemu/roms/seabios/src/malloc.h13
-rw-r--r--qemu/roms/seabios/src/memmap.h38
-rw-r--r--qemu/roms/seabios/src/misc.c2
-rw-r--r--qemu/roms/seabios/src/mouse.c3
-rw-r--r--qemu/roms/seabios/src/optionroms.c39
-rw-r--r--qemu/roms/seabios/src/output.c1
-rw-r--r--qemu/roms/seabios/src/pmm.c16
-rw-r--r--qemu/roms/seabios/src/post.c60
-rw-r--r--qemu/roms/seabios/src/resume.c3
-rw-r--r--qemu/roms/seabios/src/romlayout.S103
-rw-r--r--qemu/roms/seabios/src/sha1.c147
-rw-r--r--qemu/roms/seabios/src/sha1.h8
-rw-r--r--qemu/roms/seabios/src/stacks.c382
-rw-r--r--qemu/roms/seabios/src/stacks.h27
-rw-r--r--qemu/roms/seabios/src/std/acpi.h20
-rw-r--r--qemu/roms/seabios/src/std/bda.h2
-rw-r--r--qemu/roms/seabios/src/std/multiboot.h260
-rw-r--r--qemu/roms/seabios/src/std/smbios.h4
-rw-r--r--qemu/roms/seabios/src/string.c2
-rw-r--r--qemu/roms/seabios/src/string.h8
-rw-r--r--qemu/roms/seabios/src/system.c2
-rw-r--r--qemu/roms/seabios/src/tcgbios.c1480
-rw-r--r--qemu/roms/seabios/src/tcgbios.h375
-rw-r--r--qemu/roms/seabios/src/types.h2
-rw-r--r--qemu/roms/seabios/src/util.h16
-rw-r--r--qemu/roms/seabios/src/version.c5
-rw-r--r--qemu/roms/seabios/src/vgahooks.c2
-rw-r--r--qemu/roms/seabios/src/x86.h27
-rw-r--r--qemu/roms/seabios/vgasrc/Kconfig29
-rw-r--r--qemu/roms/seabios/vgasrc/geodevga.h2
-rw-r--r--qemu/roms/seabios/vgasrc/vgabios.c6
-rw-r--r--qemu/roms/seabios/vgasrc/vgabios.h4
-rw-r--r--qemu/roms/seabios/vgasrc/vgaentry.S18
-rw-r--r--qemu/roms/seabios/vgasrc/vgafb.c17
-rw-r--r--qemu/roms/seabios/vgasrc/vgainit.c1
-rw-r--r--qemu/roms/seabios/vgasrc/vgaversion.c6
1271 files changed, 59247 insertions, 12324 deletions
diff --git a/qemu/roms/Makefile b/qemu/roms/Makefile
index 7b3f15632..7bd125273 100644
--- a/qemu/roms/Makefile
+++ b/qemu/roms/Makefile
@@ -35,7 +35,7 @@ powerpc_cross_prefix := $(call find-cross-prefix,powerpc)
x86_64_cross_prefix := $(call find-cross-prefix,x86_64)
# tag our seabios builds
-SEABIOS_VERSION="$(shell cd seabios; git describe --tags --long) by qemu-project.org"
+SEABIOS_EXTRAVERSION="-prebuilt.qemu-project.org"
#
# EfiRom utility is shipped with edk2 / tianocore, in BaseTools/
@@ -64,7 +64,6 @@ default:
bios: build-seabios-config-seabios-128k build-seabios-config-seabios-256k
cp seabios/builds/seabios-128k/bios.bin ../pc-bios/bios.bin
cp seabios/builds/seabios-256k/bios.bin ../pc-bios/bios-256k.bin
- cp seabios/builds/seabios-256k/src/fw/*dsdt.aml ../pc-bios/
seavgabios: $(patsubst %,seavgabios-%,$(vgabios_variants))
@@ -78,12 +77,12 @@ build-seabios-config-%: config.%
mkdir -p seabios/builds/$*
cp $< seabios/builds/$*/.config
$(MAKE) -C seabios \
- VERSION=$(SEABIOS_VERSION) \
+ EXTRAVERSION=$(SEABIOS_EXTRAVERSION) \
CROSS_COMPILE=$(x86_64_cross_prefix) \
KCONFIG_CONFIG=$(CURDIR)/seabios/builds/$*/.config \
OUT=$(CURDIR)/seabios/builds/$*/ oldnoconfig
$(MAKE) -C seabios \
- VERSION=$(SEABIOS_VERSION) \
+ EXTRAVERSION=$(SEABIOS_EXTRAVERSION) \
CROSS_COMPILE=$(x86_64_cross_prefix) \
KCONFIG_CONFIG=$(CURDIR)/seabios/builds/$*/.config \
OUT=$(CURDIR)/seabios/builds/$*/ all
@@ -120,20 +119,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/qemu/roms/SLOF/README b/qemu/roms/SLOF/README
index 58e929427..294458880 100644
--- a/qemu/roms/SLOF/README
+++ b/qemu/roms/SLOF/README
@@ -11,6 +11,8 @@ Index
2.2 Overview of the source code
2.4 Extending the Forth engine
3.0 Limitations
+4.0 Submitting patches
+5.0 Coding style
1.0 Introduction to Slimline Open Firmware
@@ -236,6 +238,34 @@ 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.
+
+
+5.0 Coding style
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+New C code submitted to SLOF should follow the coding style guidelines
+for the Linux kernel [4] with the following exceptions:
+
+- in the event that you require a specific width, use a standard type
+ like int32_t, uint32_t, uint64_t, etc. Don't use Linux kernel internal
+ types like u32, __u32 or __le32.
+
+New Forth code should use 4 space indentations and no tabs. Patches for
+the old code should keep the existing style which usually is
+3 space indentation.
+
+New assembly code submitted to SLOF should follow the coding style
+guidelines for the Linux kernel [4], i.e. indent with tabs, not with spaces.
+
+
Documentation
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -244,3 +274,9 @@ 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/
+
+[4] Linux kernel coding style
+ https://github.com/torvalds/linux/blob/master/Documentation/CodingStyle
diff --git a/qemu/roms/SLOF/VERSION b/qemu/roms/SLOF/VERSION
index 20bdb2eb7..aded5537b 100644
--- a/qemu/roms/SLOF/VERSION
+++ b/qemu/roms/SLOF/VERSION
@@ -1 +1 @@
-20150429
+20160223
diff --git a/qemu/roms/SLOF/board-js2x/llfw/stage2.lds b/qemu/roms/SLOF/board-js2x/llfw/stage2.lds
index f91f0658a..e6315c3c8 100644
--- a/qemu/roms/SLOF/board-js2x/llfw/stage2.lds
+++ b/qemu/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/qemu/roms/SLOF/board-js2x/llfw/stage2_head.S b/qemu/roms/SLOF/board-js2x/llfw/stage2_head.S
index 5460bfebb..f3f5e0c8c 100644
--- a/qemu/roms/SLOF/board-js2x/llfw/stage2_head.S
+++ b/qemu/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/qemu/roms/SLOF/board-js2x/slof/Makefile b/qemu/roms/SLOF/board-js2x/slof/Makefile
index ab3e683a4..4cdd5fa36 100644
--- a/qemu/roms/SLOF/board-js2x/slof/Makefile
+++ b/qemu/roms/SLOF/board-js2x/slof/Makefile
@@ -57,6 +57,7 @@ OF_FFS_FILES = \
$(SLOFBRDDIR)/attu.fs \
$(SLOFBRDDIR)/cpu.fs \
$(SLOFBRDDIR)/ioapic.fs \
+ $(SLOFBRDDIR)/dma-function.fs \
$(SLOFBRDDIR)/pci-bridge_1022_7460.fs \
$(SLOFBRDDIR)/pci-device_1014_028c.fs \
$(SLOFBRDDIR)/pci-device_1014_02bd.fs \
diff --git a/qemu/roms/SLOF/board-js2x/slof/dma-function.fs b/qemu/roms/SLOF/board-js2x/slof/dma-function.fs
new file mode 100644
index 000000000..2e314cdaa
--- /dev/null
+++ b/qemu/roms/SLOF/board-js2x/slof/dma-function.fs
@@ -0,0 +1,31 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2011 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
+\ ****************************************************************************/
+
+: dma-alloc ( ... size -- virt )
+ \ ." dma-alloc called: " .s cr
+ alloc-mem
+;
+
+: dma-free ( virt size -- )
+ \ ." dma-free called: " .s cr
+ free-mem
+;
+
+: dma-map-in ( ... virt size cacheable? -- devaddr )
+ \ ." dma-map-in called: " .s cr
+ 2drop
+;
+
+: dma-map-out ( virt devaddr size -- )
+ \ ." dma-map-out called: " .s cr
+ 2drop drop
+;
diff --git a/qemu/roms/SLOF/board-js2x/slof/helper.fs b/qemu/roms/SLOF/board-js2x/slof/helper.fs
index 34d60da1f..1e2b03063 100644
--- a/qemu/roms/SLOF/board-js2x/slof/helper.fs
+++ b/qemu/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/qemu/roms/SLOF/board-qemu/llfw/stage2.lds b/qemu/roms/SLOF/board-qemu/llfw/stage2.lds
index e060dd189..28c9dca93 100644
--- a/qemu/roms/SLOF/board-qemu/llfw/stage2.lds
+++ b/qemu/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/qemu/roms/SLOF/board-qemu/llfw/stage2_head.S b/qemu/roms/SLOF/board-qemu/llfw/stage2_head.S
index c56b117ce..adf75547b 100644
--- a/qemu/roms/SLOF/board-qemu/llfw/stage2_head.S
+++ b/qemu/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/qemu/roms/SLOF/board-qemu/slof/Makefile b/qemu/roms/SLOF/board-qemu/slof/Makefile
index 283f77d32..a000a2519 100644
--- a/qemu/roms/SLOF/board-qemu/slof/Makefile
+++ b/qemu/roms/SLOF/board-qemu/slof/Makefile
@@ -66,9 +66,13 @@ USB_FFS_FILES = \
VIO_FFS_FILES = \
$(SLOFBRDDIR)/pci-device_1af4_1000.fs \
+ $(SLOFBRDDIR)/pci-device_1af4_1041.fs \
$(SLOFBRDDIR)/pci-device_1af4_1001.fs \
+ $(SLOFBRDDIR)/pci-device_1af4_1042.fs \
$(SLOFBRDDIR)/pci-device_1af4_1004.fs \
+ $(SLOFBRDDIR)/pci-device_1af4_1048.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 +107,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/qemu/roms/SLOF/board-qemu/slof/OF.fs b/qemu/roms/SLOF/board-qemu/slof/OF.fs
index 561d89225..69ee5c122 100644
--- a/qemu/roms/SLOF/board-qemu/slof/OF.fs
+++ b/qemu/roms/SLOF/board-qemu/slof/OF.fs
@@ -134,10 +134,6 @@ check-boot-menu
\ Grab rtas from qemu
#include "rtas.fs"
-390 cp
-
-#include "virtio.fs"
-
3f0 cp
#include "tree.fs"
diff --git a/qemu/roms/SLOF/slof/fs/archsupport.fs b/qemu/roms/SLOF/board-qemu/slof/archsupport.fs
index cc4668769..a8ace3cc5 100644
--- a/qemu/roms/SLOF/slof/fs/archsupport.fs
+++ b/qemu/roms/SLOF/board-qemu/slof/archsupport.fs
@@ -10,15 +10,16 @@
\ * IBM Corporation - initial implementation
\ ****************************************************************************/
-\ Qemu supports max 256cpus, 32K will be able to accomodate the fdt changes if
-\ needed.
-8000 VALUE size
+\ 2 MiB FDT buffer size is enough to accommodate 255 CPU cores
+\ and 16 TiB of maxmem specification.
+200000 CONSTANT cas-buffer-size
: ibm,client-architecture-support ( vec -- err? )
\ Store require parameters in nvram
\ to come back to right boot device
\ Allocate memory for H_CALL
- size alloc-mem ( vec memaddr )
- swap over size ( memaddr vec memaddr size )
+ cas-buffer-size alloc-mem ( vec memaddr )
+ dup 0= IF ." out of memory during ibm,client-architecture-support" cr THEN
+ swap over cas-buffer-size ( memaddr vec memaddr size )
\ make h_call to hypervisor
hv-cas 0= IF ( memaddr )
dup l@ 1 >= IF \ Version number >= 1
@@ -34,5 +35,5 @@
ELSE
TRUE
THEN
- >r size free-mem r>
+ >r cas-buffer-size free-mem r>
;
diff --git a/qemu/roms/SLOF/board-qemu/slof/helper.fs b/qemu/roms/SLOF/board-qemu/slof/helper.fs
index 96da49894..40d4abc3a 100644
--- a/qemu/roms/SLOF/board-qemu/slof/helper.fs
+++ b/qemu/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/qemu/roms/SLOF/board-qemu/slof/pci-device_1234_1111.fs b/qemu/roms/SLOF/board-qemu/slof/pci-device_1234_1111.fs
index a5c3584f9..22ea45d5c 100644
--- a/qemu/roms/SLOF/board-qemu/slof/pci-device_1234_1111.fs
+++ b/qemu/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/qemu/roms/SLOF/board-qemu/slof/pci-device_1af4_1001.fs b/qemu/roms/SLOF/board-qemu/slof/pci-device_1af4_1001.fs
index fb2463467..db0bb3fb8 100644
--- a/qemu/roms/SLOF/board-qemu/slof/pci-device_1af4_1001.fs
+++ b/qemu/roms/SLOF/board-qemu/slof/pci-device_1af4_1001.fs
@@ -22,13 +22,4 @@ pci-io-enable
s" virtio-block.fs" included
-\ Allocate memory for virtio queue:
-virtiodev 0 virtio-get-qsize virtio-vring-size
-1000 CLAIM VALUE queue-addr
-
-\ Write queue address into device:
-queue-addr c rshift
-virtiodev vd>base @ 8 +
-rl!-le
-
pci-device-disable
diff --git a/qemu/roms/SLOF/board-qemu/slof/pci-device_1af4_1009.fs b/qemu/roms/SLOF/board-qemu/slof/pci-device_1af4_1009.fs
index 03964a6db..9c8be249d 100644
--- a/qemu/roms/SLOF/board-qemu/slof/pci-device_1af4_1009.fs
+++ b/qemu/roms/SLOF/board-qemu/slof/pci-device_1af4_1009.fs
@@ -22,13 +22,4 @@ pci-io-enable
s" virtio-fs.fs" included
-\ Allocate memory for virtio queue:
-virtiodev 0 virtio-get-qsize virtio-vring-size
-1000 CLAIM VALUE queue-addr
-
-\ Write queue address into device:
-queue-addr c rshift
-virtiodev vd>base @ 8 +
-rl!-le
-
pci-device-disable
diff --git a/qemu/roms/SLOF/board-qemu/slof/pci-device_1af4_1041.fs b/qemu/roms/SLOF/board-qemu/slof/pci-device_1af4_1041.fs
new file mode 100644
index 000000000..552b0ef8a
--- /dev/null
+++ b/qemu/roms/SLOF/board-qemu/slof/pci-device_1af4_1041.fs
@@ -0,0 +1,15 @@
+\ *****************************************************************************
+\ * Copyright (c) 2016 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
+\ ****************************************************************************/
+
+\ Device ID 1041 is for virtio-net non-transitional device.
+\ Include the driver for virtio-net
+s" pci-device_1af4_1000.fs" included
diff --git a/qemu/roms/SLOF/board-qemu/slof/pci-device_1af4_1042.fs b/qemu/roms/SLOF/board-qemu/slof/pci-device_1af4_1042.fs
new file mode 100644
index 000000000..2b0a848d4
--- /dev/null
+++ b/qemu/roms/SLOF/board-qemu/slof/pci-device_1af4_1042.fs
@@ -0,0 +1,15 @@
+\ *****************************************************************************
+\ * Copyright (c) 2016 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
+\ ****************************************************************************/
+
+\ Device ID 1042 is for virtio-blk non-transitional device.
+\ Include the driver for virtio-blk
+s" pci-device_1af4_1001.fs" included
diff --git a/qemu/roms/SLOF/board-qemu/slof/pci-device_1af4_1048.fs b/qemu/roms/SLOF/board-qemu/slof/pci-device_1af4_1048.fs
new file mode 100644
index 000000000..055ad8960
--- /dev/null
+++ b/qemu/roms/SLOF/board-qemu/slof/pci-device_1af4_1048.fs
@@ -0,0 +1,15 @@
+\ *****************************************************************************
+\ * Copyright (c) 2016 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
+\ ****************************************************************************/
+
+\ Device ID 1048 is for virtio-scsi non-transitional device.
+\ Include the driver for virtio-scsi
+s" pci-device_1af4_1004.fs" included
diff --git a/qemu/roms/SLOF/board-qemu/slof/pci-device_1af4_1050.fs b/qemu/roms/SLOF/board-qemu/slof/pci-device_1af4_1050.fs
new file mode 100644
index 000000000..516056aad
--- /dev/null
+++ b/qemu/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/qemu/roms/SLOF/board-qemu/slof/qemu-vga.fs b/qemu/roms/SLOF/board-qemu/slof/qemu-vga.fs
new file mode 100644
index 000000000..3f4c237fc
--- /dev/null
+++ b/qemu/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/qemu/roms/SLOF/board-qemu/slof/tree.fs b/qemu/roms/SLOF/board-qemu/slof/tree.fs
index 4aba4c53f..78dafab71 100644
--- a/qemu/roms/SLOF/board-qemu/slof/tree.fs
+++ b/qemu/roms/SLOF/board-qemu/slof/tree.fs
@@ -26,6 +26,8 @@
\ 2 encode-int s" #size-cells" property
\ s" chrp" device-type
+#include "archsupport.fs"
+
480 cp
\ See 3.6.5, and the PowerPC OF binding document.
diff --git a/qemu/roms/SLOF/board-qemu/slof/virtio-block.fs b/qemu/roms/SLOF/board-qemu/slof/virtio-block.fs
index ea388fb00..bc9013eea 100644
--- a/qemu/roms/SLOF/board-qemu/slof/virtio-block.fs
+++ b/qemu/roms/SLOF/board-qemu/slof/virtio-block.fs
@@ -23,8 +23,7 @@ FALSE VALUE initialized?
INSTANCE VARIABLE deblocker
-/vd-len BUFFER: virtiodev
-virtiodev virtio-setup-vd
+virtio-setup-vd VALUE virtiodev
\ Quiesce the virtqueue of this device so that no more background
\ transactions can be pending.
diff --git a/qemu/roms/SLOF/board-qemu/slof/virtio-fs.fs b/qemu/roms/SLOF/board-qemu/slof/virtio-fs.fs
index 8632b465f..3898d0b7d 100644
--- a/qemu/roms/SLOF/board-qemu/slof/virtio-fs.fs
+++ b/qemu/roms/SLOF/board-qemu/slof/virtio-fs.fs
@@ -20,8 +20,7 @@ FALSE VALUE initialized?
2000 CONSTANT VIRTFS-BUF-SIZE \ 8k
-/vd-len BUFFER: virtiodev
-virtiodev virtio-setup-vd
+virtio-setup-vd VALUE virtiodev
\
\ Support methods.
diff --git a/qemu/roms/SLOF/board-qemu/slof/virtio-net.fs b/qemu/roms/SLOF/board-qemu/slof/virtio-net.fs
index 412b34fa6..b16fffe39 100644
--- a/qemu/roms/SLOF/board-qemu/slof/virtio-net.fs
+++ b/qemu/roms/SLOF/board-qemu/slof/virtio-net.fs
@@ -16,20 +16,28 @@ s" network" device-type
INSTANCE VARIABLE obp-tftp-package
-/vd-len BUFFER: virtiodev
-virtiodev virtio-setup-vd
+virtio-setup-vd VALUE virtiodev
0 VALUE virtio-net-priv
0 VALUE open-count
+\ Set up MAC address from config virtqueue
+6 BUFFER: local-mac
+: setup-mac ( -- )
+ s" local-mac-address" get-node get-property not IF 2drop EXIT THEN
+ 6 0 DO
+ virtiodev i 1 virtio-get-config
+ local-mac i + c!
+ LOOP
+ local-mac 6 encode-bytes s" local-mac-address" property
+;
+
: open ( -- okay? )
open-count 0= IF
open IF
\ my-unit 1 rtas-set-tce-bypass
- s" local-mac-address" get-node get-property not IF
- virtiodev virtio-net-open dup not IF ." virtio-net-open failed" EXIT THEN
- drop TO virtio-net-priv
- THEN
- true
+ virtiodev virtio-net-open not IF ." virtio-net-open failed" false EXIT THEN
+ TO virtio-net-priv
+ setup-mac true
ELSE
false
THEN
@@ -77,17 +85,6 @@ virtiodev virtio-setup-vd
s" ping" obp-tftp-package @ $call-method
;
-\ Set up MAC address from config virtqueue
-6 BUFFER: local-mac
-: setup-mac ( -- )
- 6 0 DO
- virtiodev i 1 virtio-get-config
- local-mac i + c!
- LOOP
- local-mac 6 encode-bytes s" local-mac-address" property
-;
-setup-mac
-
: setup-alias ( -- )
" net" get-next-alias ?dup IF
get-node node>path set-alias
diff --git a/qemu/roms/SLOF/board-qemu/slof/virtio-scsi.fs b/qemu/roms/SLOF/board-qemu/slof/virtio-scsi.fs
index ca5fb13aa..4fedeeeb1 100644
--- a/qemu/roms/SLOF/board-qemu/slof/virtio-scsi.fs
+++ b/qemu/roms/SLOF/board-qemu/slof/virtio-scsi.fs
@@ -22,8 +22,7 @@ FALSE CONSTANT virtio-scsi-debug
FALSE VALUE initialized?
-/vd-len BUFFER: virtiodev
-virtiodev virtio-setup-vd
+virtio-setup-vd VALUE virtiodev
STRUCT \ virtio-scsi-config
/l FIELD vs-cfg>num-queues
diff --git a/qemu/roms/SLOF/board-qemu/slof/virtio.fs b/qemu/roms/SLOF/board-qemu/slof/virtio.fs
deleted file mode 100644
index 818c1320e..000000000
--- a/qemu/roms/SLOF/board-qemu/slof/virtio.fs
+++ /dev/null
@@ -1,35 +0,0 @@
-\ *****************************************************************************
-\ * Copyright (c) 2011 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
-\ ****************************************************************************/
-
-\ This struct must match "struct virtio_device" in virtio.h!
-STRUCT
- /n FIELD vd>base
- /l FIELD vd>type
-CONSTANT /vd-len
-
-
-\ Initialize virtiodev structure for the current node
-: virtio-setup-vd ( vdstruct -- )
- >r
- \ Does it have a "class-code" property? If yes, assume we're a PCI device
- s" class-code" get-node get-property 0= IF
- \ Set up for PCI device interface
- 2drop
- s" 10 config-l@ translate-my-address 3 not AND" evaluate
- ( io-base ) r@ vd>base !
- 0 r@ vd>type l!
- ELSE
- ." unsupported virtio interface!" cr
- 1 r@ vd>type l!
- THEN
- r> drop
-;
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netapps/netboot.c b/qemu/roms/SLOF/clients/net-snk/app/netapps/netboot.c
index cf20b5915..bb1db03e3 100644
--- a/qemu/roms/SLOF/clients/net-snk/app/netapps/netboot.c
+++ b/qemu/roms/SLOF/clients/net-snk/app/netapps/netboot.c
@@ -332,7 +332,13 @@ int dhcp(char *ret_buffer, filename_ip_t * fn_ip, unsigned int retries, int flag
int i = (int) retries+1;
int rc = -1;
- printf(" ");
+ printf(" Requesting information via DHCP%s: ",
+ flags == F_IPV4 ? "v4" : flags == F_IPV6 ? "v6" : "");
+
+ if (flags != F_IPV6)
+ dhcpv4_generate_transaction_id();
+ if (flags != F_IPV4)
+ dhcpv6_generate_transaction_id();
do {
printf("\b\b\b%03d", i-1);
@@ -353,7 +359,6 @@ int dhcp(char *ret_buffer, filename_ip_t * fn_ip, unsigned int retries, int flag
set_ipv6_address(fn_ip->fd, 0);
rc = dhcpv6(ret_buffer, fn_ip);
if (rc == 0) {
- printf("\n");
memcpy(&fn_ip->own_ip6, get_ipv6_address(), 16);
break;
}
@@ -362,11 +367,23 @@ int dhcp(char *ret_buffer, filename_ip_t * fn_ip, unsigned int retries, int flag
if (rc != -1) /* either success or non-dhcp failure */
break;
} while (1);
- printf("\b\b\b\b");
+ printf("\b\b\b\bdone\n");
return rc;
}
+/**
+ * Seed the random number generator with our mac and current timestamp
+ */
+static void seed_rng(uint8_t mac[])
+{
+ unsigned int seed;
+
+ asm volatile("mftbl %0" : "=r"(seed));
+ seed ^= (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | mac[5];
+ srand(seed);
+}
+
int
netboot(int argc, char *argv[])
{
@@ -388,8 +405,7 @@ netboot(int argc, char *argv[])
int32_t block_size = strtol(argv[5], 0, 10);
uint8_t own_mac[6];
- printf("\n");
- printf(" Bootloader 1.6 \n");
+ puts("\n Initializing NIC");
memset(&fn_ip, 0, sizeof(filename_ip_t));
/***********************************************************
@@ -438,6 +454,8 @@ netboot(int argc, char *argv[])
// init ethernet layer
set_mac_address(own_mac);
+ seed_rng(own_mac);
+
if (argc > 6) {
parse_args(argv[6], &obp_tftp_args);
if(obp_tftp_args.bootp_retries - rc < DEFAULT_BOOT_RETRIES)
@@ -468,10 +486,8 @@ netboot(int argc, char *argv[])
}
}
else if (ip_version == 6) {
- if (memcmp(&obp_tftp_args.ci6addr, null_ip6, 16) != 0
- && memcmp(&obp_tftp_args.si6addr, null_ip6, 16) != 0
+ if (memcmp(&obp_tftp_args.si6addr, null_ip6, 16) != 0
&& obp_tftp_args.filename[0] != 0) {
-
memcpy(&fn_ip.server_ip6.addr[0],
&obp_tftp_args.si6addr.addr, 16);
obp_tftp_args.ip_init = IP_INIT_IPV6_MANUAL;
@@ -484,7 +500,6 @@ netboot(int argc, char *argv[])
// construction of fn_ip from parameter
switch(obp_tftp_args.ip_init) {
case IP_INIT_BOOTP:
- printf(" Requesting IP address via BOOTP: ");
// if giaddr in not specified, then we have to identify
// the BOOTP server via broadcasts
if(memcmp(obp_tftp_args.giaddr, null_ip, 4) == 0) {
@@ -499,19 +514,25 @@ netboot(int argc, char *argv[])
rc = bootp(ret_buffer, &fn_ip, obp_tftp_args.bootp_retries);
break;
case IP_INIT_DHCP:
- printf(" Requesting IP address via DHCPv4: ");
rc = dhcp(ret_buffer, &fn_ip, obp_tftp_args.bootp_retries, F_IPV4);
break;
case IP_INIT_DHCPV6_STATELESS:
- printf(" Requesting information via DHCPv6: ");
rc = dhcp(ret_buffer, &fn_ip,
obp_tftp_args.bootp_retries, F_IPV6);
break;
case IP_INIT_IPV6_MANUAL:
- set_ipv6_address(fn_ip.fd, &obp_tftp_args.ci6addr);
+ if (memcmp(&obp_tftp_args.ci6addr, null_ip6, 16)) {
+ set_ipv6_address(fn_ip.fd, &obp_tftp_args.ci6addr);
+ } else {
+ /*
+ * If no client address has been specified, then
+ * use a link-local or stateless autoconfig address
+ */
+ set_ipv6_address(fn_ip.fd, NULL);
+ memcpy(&fn_ip.own_ip6, get_ipv6_address(), 16);
+ }
break;
case IP_INIT_DEFAULT:
- printf(" Requesting IP address via DHCP: ");
rc = dhcp(ret_buffer, &fn_ip, obp_tftp_args.bootp_retries, 0);
break;
case IP_INIT_NONE:
@@ -548,10 +569,15 @@ netboot(int argc, char *argv[])
return -101;
}
- if(ip_version == 4)
- printf("%d.%d.%d.%d\n",
+ if (ip_version == 4) {
+ printf(" Using IPv4 address: %d.%d.%d.%d\n",
((fn_ip.own_ip >> 24) & 0xFF), ((fn_ip.own_ip >> 16) & 0xFF),
((fn_ip.own_ip >> 8) & 0xFF), ( fn_ip.own_ip & 0xFF));
+ } else if (ip_version == 6) {
+ char ip6_str[40];
+ ipv6_to_str(fn_ip.own_ip6.addr, ip6_str);
+ printf(" Using IPv6 address: %s\n", ip6_str);
+ }
if (rc == -2) {
sprintf(buf,
@@ -818,7 +844,7 @@ int parse_tftp_args(char buffer[], char *server_ip, char filename[], int fd,
tmp = raw + 7;
tmp[j] = '\0';
strcpy(domainname, tmp);
- if (dns_get_ip(fd, (int8_t *)domainname, server_ip6, 6) == 0) {
+ if (dns_get_ip(fd, domainname, server_ip6, 6) == 0) {
printf("\n DNS failed for IPV6\n");
return -1;
}
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/bootp.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/bootp.c
index 1bc6efe5b..6d58cef7d 100644
--- a/qemu/roms/SLOF/clients/net-snk/app/netlib/bootp.c
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/bootp.c
@@ -232,7 +232,7 @@ bootp(char *ret_buffer, filename_ip_t * fn_ip, unsigned int retries)
int i = (int) retries+1;
fn_ip->own_ip = 0;
- printf(" ");
+ printf(" Requesting IP address via BOOTP: ");
response_buffer = ret_buffer;
@@ -249,6 +249,7 @@ bootp(char *ret_buffer, filename_ip_t * fn_ip, unsigned int retries)
* in case the previous one was lost. And because we don't
* trust the network cable we keep on doing this 30 times */
} while (receive_bootp(fn_ip) != 0);
- printf("\b\b\b");
+
+ printf("\b\b\bdone\n");
return 0;
}
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcp.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcp.c
index 5f26f3afb..7e2e88ccf 100644
--- a/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcp.c
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcp.c
@@ -11,7 +11,7 @@
*****************************************************************************/
-/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ALGORITHMS <<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+/******************************* ALGORITHMS ******************************/
/** \file dhcp.c <pre>
* **************** State-transition diagram for DHCP client *************
@@ -41,13 +41,14 @@
* </pre> */
-/*>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<<<*/
+/********************** DEFINITIONS & DECLARATIONS ***********************/
#include <dhcp.h>
#include <ethernet.h>
#include <ipv4.h>
#include <udp.h>
#include <dns.h>
+#include <netapps/args.h>
#include <stdio.h>
#include <string.h>
@@ -110,11 +111,11 @@ static uint8_t dhcp_magic[] = {0x63, 0x82, 0x53, 0x63};
* If flag[i] == TRUE then field for i-th option retains valid value and
* information from this field may retrived (in case of receiving) or will
* be transmitted (in case of transmitting).
- *
+ *
*/
typedef struct {
uint8_t flag[256]; /**< Show if corresponding opt. is valid */
- uint8_t request_list[256]; /**< o.55 If i-th member is TRUE, then i-th
+ uint8_t request_list[256]; /**< o.55 If i-th member is TRUE, then i-th
option will be requested from server */
uint32_t server_ID; /**< o.54 Identifies DHCP-server */
uint32_t requested_IP; /**< o.50 Must be filled in DHCP-Request */
@@ -132,65 +133,57 @@ typedef struct {
static uint8_t dhcp_state;
-/*>>>>>>>>>>>>>>>>>>>>>>>>>>>> PROTOTYPES <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
-
-static int32_t
-dhcp_attempt(int fd);
+/***************************** PROTOTYPES ********************************/
-static int32_t
-dhcp_encode_options(uint8_t * opt_field, dhcp_options_t * opt_struct);
+static int32_t dhcp_attempt(int fd);
-static int32_t
-dhcp_decode_options(uint8_t opt_field[], uint32_t opt_len,
- dhcp_options_t * opt_struct);
+static int32_t dhcp_encode_options(uint8_t * opt_field, dhcp_options_t * opt_struct);
-static int8_t
-dhcp_merge_options(uint8_t dst_options[], uint32_t * dst_len,
- uint8_t src_options[], uint32_t src_len);
+static int32_t dhcp_decode_options(uint8_t opt_field[], uint32_t opt_len,
+ dhcp_options_t * opt_struct);
-static int8_t
-dhcp_find_option(uint8_t options[], uint32_t len,
- uint8_t op_code, uint32_t * op_offset);
-
-static void
-dhcp_append_option(uint8_t dst_options[], uint32_t * dst_len,
- uint8_t * new_option);
+static int8_t dhcp_merge_options(uint8_t dst_options[], uint32_t * dst_len,
+ uint8_t src_options[], uint32_t src_len);
-static void
-dhcp_combine_option(uint8_t dst_options[], uint32_t * dst_len,
- uint32_t dst_offset, uint8_t * new_option);
+static int8_t dhcp_find_option(uint8_t options[], uint32_t len,
+ uint8_t op_code, uint32_t * op_offset);
-static void
-dhcp_send_discover(int fd);
+static void dhcp_append_option(uint8_t dst_options[], uint32_t * dst_len,
+ uint8_t * new_option);
-static void
-dhcp_send_request(int fd);
+static void dhcp_combine_option(uint8_t dst_options[], uint32_t * dst_len,
+ uint32_t dst_offset, uint8_t * new_option);
-static uint8_t
-strtoip(int8_t * str, uint32_t * ip);
+static void dhcp_send_discover(int fd);
+static void dhcp_send_request(int fd);
-/*>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<<*/
+/***************************** LOCAL VARIABLES ***************************/
static uint8_t ether_packet[ETH_MTU_SIZE];
static uint32_t dhcp_own_ip = 0;
static uint32_t dhcp_server_ip = 0;
static uint32_t dhcp_siaddr_ip = 0;
-static int8_t dhcp_filename[256];
-static int8_t dhcp_tftp_name[256];
+static char dhcp_filename[256];
+static char dhcp_tftp_name[256];
+static uint32_t dhcp_xid;
static char * response_buffer;
-/*>>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+/***************************** IMPLEMENTATION ****************************/
-int32_t
-dhcpv4(char *ret_buffer, filename_ip_t * fn_ip) {
+void dhcpv4_generate_transaction_id(void)
+{
+ dhcp_xid = (rand() << 16) ^ rand();
+}
+int32_t dhcpv4(char *ret_buffer, filename_ip_t *fn_ip)
+{
uint32_t dhcp_tftp_ip = 0;
int fd = fn_ip->fd;
- strcpy((char *) dhcp_filename, "");
- strcpy((char *) dhcp_tftp_name, "");
+ strcpy(dhcp_filename, "");
+ strcpy(dhcp_tftp_name, "");
response_buffer = ret_buffer;
@@ -204,11 +197,11 @@ dhcpv4(char *ret_buffer, filename_ip_t * fn_ip) {
dhcp_siaddr_ip = fn_ip->server_ip;
}
if(fn_ip->filename[0] != 0) {
- strcpy((char *) dhcp_filename, (char *) fn_ip->filename);
+ strcpy(dhcp_filename, (char *) fn_ip->filename);
}
// TFTP SERVER
- if (!strlen((char *) dhcp_tftp_name)) {
+ if (!strlen(dhcp_tftp_name)) {
if (!dhcp_siaddr_ip) {
// ERROR: TFTP name is not presented
return -3;
@@ -219,9 +212,9 @@ dhcpv4(char *ret_buffer, filename_ip_t * fn_ip) {
}
else {
// TFTP server defined by its name
- if (!strtoip(dhcp_tftp_name, &(dhcp_tftp_ip))) {
- if (!dns_get_ip(fd, dhcp_tftp_name, (uint8_t *)&(dhcp_tftp_ip), 4)) {
- // DNS error - can't obtain TFTP-server name
+ if (!strtoip(dhcp_tftp_name, (char *)&dhcp_tftp_ip)) {
+ if (!dns_get_ip(fd, dhcp_tftp_name, (uint8_t *)&dhcp_tftp_ip, 4)) {
+ // DNS error - can't obtain TFTP-server name
// Use TFTP-ip from siaddr field, if presented
if (dhcp_siaddr_ip) {
dhcp_tftp_ip = dhcp_siaddr_ip;
@@ -237,7 +230,7 @@ dhcpv4(char *ret_buffer, filename_ip_t * fn_ip) {
// Store configuration info into filename_ip strucutre
fn_ip -> own_ip = dhcp_own_ip;
fn_ip -> server_ip = dhcp_tftp_ip;
- strcpy((char *) fn_ip -> filename, (char *) dhcp_filename);
+ strcpy((char *) fn_ip -> filename, dhcp_filename);
return 0;
}
@@ -245,8 +238,8 @@ dhcpv4(char *ret_buffer, filename_ip_t * fn_ip) {
/**
* DHCP: Tries o obtain DHCP parameters, refer to state-transition diagram
*/
-static int32_t
-dhcp_attempt(int fd) {
+static int32_t dhcp_attempt(int fd)
+{
int sec;
// Send DISCOVER message and switch DHCP-client to SELECT state
@@ -270,7 +263,7 @@ dhcp_attempt(int fd) {
} while (get_timer() > 0);
}
- // timeout
+ // timeout
return 0;
}
@@ -278,7 +271,7 @@ dhcp_attempt(int fd) {
* DHCP: Supplements DHCP-message with options stored in structure.
* For more information about option coding see dhcp_options_t.
*
- * @param opt_field Points to the "vend" field of DHCP-message
+ * @param opt_field Points to the "vend" field of DHCP-message
* (destination)
* @param opt_struct this structure stores info about the options which
* will be added to DHCP-message (source)
@@ -286,8 +279,8 @@ dhcp_attempt(int fd) {
* FALSE - error condition occurs.
* @see dhcp_options_t
*/
-static int32_t
-dhcp_encode_options(uint8_t * opt_field, dhcp_options_t * opt_struct) {
+static int32_t dhcp_encode_options(uint8_t * opt_field, dhcp_options_t * opt_struct)
+{
uint8_t * options = opt_field;
uint16_t i, sum; // used to define is any options set
@@ -380,7 +373,7 @@ dhcp_encode_options(uint8_t * opt_field, dhcp_options_t * opt_struct) {
* DHCP: Extracts encoded options from DHCP-message into the structure.
* For more information about option coding see dhcp_options_t.
*
- * @param opt_field Points to the "options" field of DHCP-message
+ * @param opt_field Points to the "options" field of DHCP-message
* (source).
* @param opt_len Length of "options" field.
* @param opt_struct this structure stores info about the options which
@@ -389,10 +382,10 @@ dhcp_encode_options(uint8_t * opt_field, dhcp_options_t * opt_struct) {
* FALSE - error condition occurs.
* @see dhcp_options_t
*/
-static int32_t
-dhcp_decode_options(uint8_t opt_field[], uint32_t opt_len,
- dhcp_options_t * opt_struct) {
- int32_t offset = 0;
+static int32_t dhcp_decode_options(uint8_t opt_field[], uint32_t opt_len,
+ dhcp_options_t * opt_struct)
+{
+ uint32_t offset = 0;
memset(opt_struct, 0, sizeof(dhcp_options_t));
@@ -407,30 +400,30 @@ dhcp_decode_options(uint8_t opt_field[], uint32_t opt_len,
switch(opt_field[offset]) {
case DHCP_OVERLOAD :
opt_struct -> overload = opt_field[offset + 2];
- offset += 2 + opt_field[offset + 1];
+ offset += 2 + opt_field[offset + 1];
break;
case DHCP_REQUESTED_IP :
opt_struct -> requested_IP = htonl(* (uint32_t *) (opt_field + offset + 2));
- offset += 2 + opt_field[offset + 1];
+ offset += 2 + opt_field[offset + 1];
break;
case DHCP_MASK :
opt_struct -> flag[DHCP_MASK] = 1;
opt_struct -> subnet_mask = htonl(* (uint32_t *) (opt_field + offset + 2));
- offset += 2 + opt_field[offset + 1];
+ offset += 2 + opt_field[offset + 1];
break;
case DHCP_DNS :
opt_struct -> flag[DHCP_DNS] = 1;
opt_struct -> dns_IP = htonl(* (uint32_t *) (opt_field + offset + 2));
- offset += 2 + opt_field[offset + 1];
+ offset += 2 + opt_field[offset + 1];
break;
case DHCP_ROUTER :
opt_struct -> flag[DHCP_ROUTER] = 1;
opt_struct -> router_IP = htonl(* (uint32_t *) (opt_field + offset + 2));
- offset += 2 + opt_field[offset + 1];
+ offset += 2 + opt_field[offset + 1];
break;
case DHCP_MSG_TYPE :
@@ -492,11 +485,12 @@ dhcp_decode_options(uint8_t opt_field[], uint32_t opt_len,
* FALSE - error condition occurs.
*/
static int8_t dhcp_merge_options(uint8_t dst_options[], uint32_t * dst_len,
- uint8_t src_options[], uint32_t src_len) {
- int32_t dst_offset, src_offset = 0;
+ uint8_t src_options[], uint32_t src_len)
+{
+ uint32_t dst_offset, src_offset = 0;
// remove ENDOPT if presented
- if (dhcp_find_option(dst_options, * dst_len, DHCP_ENDOPT, (uint32_t *) &dst_offset))
+ if (dhcp_find_option(dst_options, * dst_len, DHCP_ENDOPT, &dst_offset))
* dst_len = dst_offset;
while (src_offset < src_len) {
@@ -509,7 +503,7 @@ static int8_t dhcp_merge_options(uint8_t dst_options[], uint32_t * dst_len,
default:
if (dhcp_find_option(dst_options, * dst_len,
src_options[src_offset],
- (uint32_t *) &dst_offset)) {
+ &dst_offset)) {
dhcp_combine_option(dst_options, dst_len,
dst_offset,
(uint8_t *) src_options +
@@ -522,7 +516,7 @@ static int8_t dhcp_merge_options(uint8_t dst_options[], uint32_t * dst_len,
}
}
- if (src_offset == src_len)
+ if (src_offset == src_len)
return 1;
return 0;
}
@@ -540,7 +534,8 @@ static int8_t dhcp_merge_options(uint8_t dst_options[], uint32_t * dst_len,
* FALSE - option wasn't find.
*/
static int8_t dhcp_find_option(uint8_t options[], uint32_t len,
- uint8_t op_code, uint32_t * op_offset) {
+ uint8_t op_code, uint32_t * op_offset)
+{
uint32_t srch_offset = 0;
* op_offset = 0;
@@ -568,9 +563,9 @@ static int8_t dhcp_find_option(uint8_t options[], uint32_t len,
* @param dst_len length of the "options" field (modified)
* @param new_option points to an option in another list (src)
*/
-static void
-dhcp_append_option(uint8_t dst_options[], uint32_t * dst_len,
- uint8_t * new_option) {
+static void dhcp_append_option(uint8_t dst_options[], uint32_t * dst_len,
+ uint8_t * new_option)
+{
memcpy(dst_options + ( * dst_len), new_option, 2 + (* (new_option + 1)));
* dst_len += 2 + *(new_option + 1);
}
@@ -586,10 +581,9 @@ dhcp_append_option(uint8_t dst_options[], uint32_t * dst_len,
* @param dst_offset offset of the option from beginning of the list
* @param new_option points to an option in another list (src)
*/
-static void
-dhcp_combine_option(uint8_t dst_options[], uint32_t * dst_len,
- uint32_t dst_offset, uint8_t * new_option) {
-
+static void dhcp_combine_option(uint8_t dst_options[], uint32_t * dst_len,
+ uint32_t dst_offset, uint8_t * new_option)
+{
uint8_t tmp_buffer[1024]; // use to provide safe memcpy
uint32_t tail_len;
@@ -612,8 +606,8 @@ dhcp_combine_option(uint8_t dst_options[], uint32_t * dst_len,
/**
* DHCP: Sends DHCP-Discover message. Looks for DHCP servers.
*/
-static void
-dhcp_send_discover(int fd) {
+static void dhcp_send_discover(int fd)
+{
uint32_t packetsize = sizeof(struct iphdr) +
sizeof(struct udphdr) + sizeof(struct btphdr);
struct btphdr *btph;
@@ -627,6 +621,7 @@ dhcp_send_discover(int fd) {
btph -> op = 1;
btph -> htype = 1;
btph -> hlen = 6;
+ btph -> xid = dhcp_xid;
memcpy(btph -> chaddr, get_mac_address(), 6);
memset(&opt, 0, sizeof(dhcp_options_t));
@@ -655,8 +650,8 @@ dhcp_send_discover(int fd) {
/**
* DHCP: Sends DHCP-Request message. Asks for acknowledgment to occupy IP.
*/
-static void
-dhcp_send_request(int fd) {
+static void dhcp_send_request(int fd)
+{
uint32_t packetsize = sizeof(struct iphdr) +
sizeof(struct udphdr) + sizeof(struct btphdr);
struct btphdr *btph;
@@ -670,6 +665,7 @@ dhcp_send_request(int fd) {
btph -> op = 1;
btph -> htype = 1;
btph -> hlen = 6;
+ btph -> xid = dhcp_xid;
memcpy(btph -> chaddr, get_mac_address(), 6);
memset(&opt, 0, sizeof(dhcp_options_t));
@@ -704,7 +700,8 @@ dhcp_send_request(int fd) {
/**
* DHCP: Sends DHCP-Release message. Releases occupied IP.
*/
-void dhcp_send_release(int fd) {
+void dhcp_send_release(int fd)
+{
uint32_t packetsize = sizeof(struct iphdr) +
sizeof(struct udphdr) + sizeof(struct btphdr);
struct btphdr *btph;
@@ -718,6 +715,7 @@ void dhcp_send_release(int fd) {
btph -> op = 1;
btph -> htype = 1;
btph -> hlen = 6;
+ btph -> xid = dhcp_xid;
strcpy((char *) btph -> file, "");
memcpy(btph -> chaddr, get_mac_address(), 6);
btph -> ciaddr = htonl(dhcp_own_ip);
@@ -730,7 +728,7 @@ void dhcp_send_release(int fd) {
dhcp_encode_options(btph -> vend, &opt);
- fill_udphdr(&ether_packet[sizeof(struct iphdr)],
+ fill_udphdr(&ether_packet[sizeof(struct iphdr)],
sizeof(struct btphdr) + sizeof(struct udphdr),
UDPPORT_BOOTPC, UDPPORT_BOOTPS);
fill_iphdr(ether_packet, sizeof(struct btphdr) +
@@ -753,18 +751,21 @@ void dhcp_send_release(int fd) {
* @see btphdr
*/
-int8_t
-handle_dhcp(int fd, uint8_t * packet, int32_t packetsize) {
+int8_t handle_dhcp(int fd, uint8_t * packet, int32_t packetsize)
+{
struct btphdr * btph;
struct iphdr * iph;
dhcp_options_t opt;
- memset(&opt, 0, sizeof(dhcp_options_t));
+ memset(&opt, 0, sizeof(dhcp_options_t));
btph = (struct btphdr *) packet;
iph = (struct iphdr *) packet - sizeof(struct udphdr) -
sizeof(struct iphdr);
- if (btph -> op != 2)
- return -1; // it is not Boot Reply
+
+ if (btph->op != 2)
+ return -1; /* It is not a Bootp/DHCP reply */
+ if (btph->xid != dhcp_xid)
+ return -1; /* The transaction ID does not match */
if (memcmp(btph -> vend, dhcp_magic, 4)) {
// It is BootP - RFC 951
@@ -788,7 +789,7 @@ handle_dhcp(int fd, uint8_t * packet, int32_t packetsize) {
}
- // decode options
+ // decode options
if (!dhcp_decode_options(btph -> vend, packetsize -
sizeof(struct btphdr) + sizeof(btph -> vend),
&opt)) {
@@ -902,7 +903,7 @@ handle_dhcp(int fd, uint8_t * packet, int32_t packetsize) {
else {
strcpy((char *) dhcp_filename, "");
if (opt.overload != DHCP_OVERLOAD_FILE &&
- opt.overload != DHCP_OVERLOAD_BOTH &&
+ opt.overload != DHCP_OVERLOAD_BOTH &&
strlen((char *) btph -> file)) {
strncpy((char *) dhcp_filename,
(char *) btph->file,
@@ -952,47 +953,3 @@ handle_dhcp(int fd, uint8_t * packet, int32_t packetsize) {
return 0;
}
-
-/**
- * DHCP: Converts "255.255.255.255" -> 32-bit long IP
- *
- * @param str string to be converted
- * @param ip in case of SUCCESS - 32-bit long IP
- in case of FAULT - zero
- * @return TRUE - IP converted successfully;
- * FALSE - error condition occurs (e.g. bad format)
- */
-static uint8_t
-strtoip(int8_t * str, uint32_t * ip) {
- int8_t ** ptr = &str;
- int16_t i = 0, res, len;
- char octet[256];
-
- * ip = 0;
-
- while (**ptr != 0) {
- if (i > 3 || !isdigit(**ptr))
- return 0;
- if (strstr((char *) * ptr, ".") != NULL) {
- len = (int16_t) ((int8_t *) strstr((char *) * ptr, ".") -
- (int8_t *) (* ptr));
- strncpy(octet, (char *) * ptr, len); octet[len] = 0;
- * ptr += len;
- }
- else {
- strcpy(octet, (char *) * ptr);
- * ptr += strlen(octet);
- }
- res = strtol(octet, NULL, 10);
- if ((res > 255) || (res < 0))
- return 0;
- * ip = ((* ip) << 8) + res;
- i++;
- if (** ptr == '.')
- (*ptr)++;
- }
-
- if (i != 4)
- return 0;
- return 1;
-}
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcp.h b/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcp.h
index 69dd49d4a..54fb1eed3 100644
--- a/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcp.h
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcp.h
@@ -43,6 +43,7 @@ struct btphdr {
uint8_t vend[64]; /**< Optional parameters field (DHCP-options) */
};
+void dhcpv4_generate_transaction_id(void);
int bootp(char *ret_buffer, filename_ip_t *, unsigned int);
int dhcpv4(char *ret_buffer, filename_ip_t *);
void dhcp_send_release(int fd);
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.c
index 4deef30f2..d0a22d555 100644
--- a/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.c
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.c
@@ -27,13 +27,15 @@ static uint8_t tid[3];
static uint32_t dhcpv6_state = -1;
static filename_ip_t *my_fn_ip;
-static void
-generate_transaction_id(void)
+static struct ip6addr_list_entry all_dhcpv6_ll; /* All DHCPv6 servers address */
+
+void
+dhcpv6_generate_transaction_id(void)
{
- /* TODO: as per RFC 3315 transaction IDs should be generated randomly */
- tid[0] = 1;
- tid[1] = 2;
- tid[2] = 4;
+ /* As per RFC 3315 transaction IDs should be generated randomly */
+ tid[0] = rand();
+ tid[1] = rand();
+ tid[2] = rand();
}
static void
@@ -45,8 +47,6 @@ send_info_request(int fd)
memset(ether_packet, 0, ETH_MTU_SIZE);
- generate_transaction_id();
-
/* Get an IPv6 packet */
payload_length = sizeof(struct udphdr) + sizeof(struct dhcp_message_header);
fill_ip6hdr (ether_packet + sizeof(struct ethhdr),
@@ -72,16 +72,14 @@ send_info_request(int fd)
dhcph->option.el_time.length = 2;
dhcph->option.el_time.time = 0x190; /* 4000 ms */
dhcph->option.option_request_option.code = DHCPV6_OPTION_ORO;
- dhcph->option.option_request_option.length= 6;
+ dhcph->option.option_request_option.length = DHCPV6_OPTREQUEST_NUMOPTS * 2;
dhcph->option.option_request_option.option_code[0] = DHCPV6_OPTION_DNS_SERVERS;
dhcph->option.option_request_option.option_code[1] = DHCPV6_OPTION_DOMAIN_LIST;
dhcph->option.option_request_option.option_code[2] = DHCPV6_OPTION_BOOT_URL;
-
send_ipv6(fd, ether_packet + sizeof(struct ethhdr),
- sizeof(struct ethhdr)+ sizeof(struct ip6hdr)
- + sizeof(struct udphdr)
- + sizeof( struct dhcp_message_header) );
+ sizeof(struct ip6hdr) + sizeof(struct udphdr)
+ + sizeof(struct dhcp_message_header));
}
static int32_t
@@ -119,6 +117,9 @@ dhcpv6 ( char *ret_buffer, void *fn_ip)
{
int fd;
+ all_dhcpv6_ll.addr.part.prefix = 0xff02000000000000ULL;
+ all_dhcpv6_ll.addr.part.interface_id = 0x10002ULL;
+
my_fn_ip = (filename_ip_t *) fn_ip;
fd = my_fn_ip->fd;
@@ -129,8 +130,7 @@ dhcpv6 ( char *ret_buffer, void *fn_ip)
return 0;
}
-static struct dhcp6_received_options *
-dhcp6_process_options (uint8_t *option, int32_t option_length)
+static void dhcp6_process_options (uint8_t *option, int32_t option_length)
{
struct dhcp_boot_url *option_boot_url;
struct client_identifier *option_clientid;
@@ -138,24 +138,19 @@ dhcp6_process_options (uint8_t *option, int32_t option_length)
struct dhcp_dns *option_dns;
struct dhcp_dns_list *option_dns_list;
struct dhcp6_gen_option *option_gen;
- struct dhcp6_received_options *received_options;
char buffer[256];
-
- received_options = malloc (sizeof(struct dhcp6_received_options));
while (option_length > 0) {
switch ((uint16_t) *(option+1)) {
case DHCPV6_OPTION_CLIENTID:
option_clientid = (struct client_identifier *) option;
option = option + option_clientid->length + 4;
option_length = option_length - option_clientid->length - 4;
- received_options->client_id = 1;
break;
case DHCPV6_OPTION_SERVERID:
option_serverid = (struct server_identifier *) option;
option = option + option_serverid->length + 4;
option_length = option_length - option_serverid->length - 4;
- received_options->server_id = 1;
break;
case DHCPV6_OPTION_DNS_SERVERS:
option_dns = (struct dhcp_dns *) option;
@@ -184,7 +179,7 @@ dhcp6_process_options (uint8_t *option, int32_t option_length)
(char *)my_fn_ip->filename,
(int)my_fn_ip->fd,
option_boot_url->length) == -1)
- return NULL;
+ return;
break;
default:
option_gen = (struct dhcp6_gen_option *) option;
@@ -192,8 +187,6 @@ dhcp6_process_options (uint8_t *option, int32_t option_length)
option_length = option_length - option_gen->length - 4;
}
}
-
- return received_options;
}
uint32_t
@@ -205,6 +198,9 @@ handle_dhcpv6(uint8_t * packet, int32_t packetsize)
struct dhcp_message_reply *reply;
reply = (struct dhcp_message_reply *) packet;
+ if (memcmp(reply->transaction_id, tid, 3))
+ return -1; /* Wrong transaction ID */
+
if (reply->type == 7)
dhcpv6_state = DHCP_STATUSCODE_SUCCESS;
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.h b/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.h
index 078a9f11f..fb77da648 100644
--- a/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.h
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.h
@@ -77,6 +77,7 @@
#define DUID_LL 3 /* DUID based on Link-layer Address */
/* Prototypes */
+void dhcpv6_generate_transaction_id(void);
int32_t dhcpv6 ( char *ret_buffer, void *fn_ip);
uint32_t handle_dhcpv6(uint8_t * , int32_t);
@@ -102,6 +103,8 @@ struct server_identifier {
uint8_t mac[6];
};
+#define DHCPV6_OPTREQUEST_NUMOPTS 3
+
struct dhcp_info_request {
struct client_identifier client_id;
struct elapsed_time {
@@ -112,7 +115,7 @@ struct dhcp_info_request {
struct option_request {
uint16_t code;
uint16_t length;
- uint16_t option_code[5];
+ uint16_t option_code[DHCPV6_OPTREQUEST_NUMOPTS];
} option_request_option;
};
@@ -141,12 +144,6 @@ struct dhcp_boot_url {
uint8_t url[256];
};
-struct dhcp6_received_options {
- uint8_t filename;
- uint8_t ip;
- uint8_t client_id;
- uint8_t server_id;
-};
struct dhcp_message_reply {
uint8_t type; /* Message type */
uint8_t transaction_id[3]; /* Transaction id */
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/dns.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/dns.c
index 0ab1346c9..a5a36a18e 100644
--- a/qemu/roms/SLOF/clients/net-snk/app/netlib/dns.c
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/dns.c
@@ -133,7 +133,7 @@ dns_init(uint32_t _dns_server_ip, uint8_t _dns_server_ipv6[16], uint8_t ip_versi
* FALSE - error condition occurs.
*/
int8_t
-dns_get_ip(int fd, int8_t * url, uint8_t * domain_ip, uint8_t ip_version)
+dns_get_ip(int fd, char* url, uint8_t * domain_ip, uint8_t ip_version)
{
/* this counter is used so that we abort after 30 DNS request */
int32_t i;
@@ -143,7 +143,7 @@ dns_get_ip(int fd, int8_t * url, uint8_t * domain_ip, uint8_t ip_version)
(* domain_ip) = 0;
// Retrieve host name from URL
- if (!urltohost((char *) url, (char *) host_name)) {
+ if (!urltohost(url, (char *) host_name)) {
printf("\nERROR:\t\t\tBad URL!\n");
return 0;
}
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/dns.h b/qemu/roms/SLOF/clients/net-snk/app/netlib/dns.h
index 82eea4e4d..b8756afca 100644
--- a/qemu/roms/SLOF/clients/net-snk/app/netlib/dns.h
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/dns.h
@@ -20,7 +20,7 @@
extern int8_t dns_init(uint32_t _dns_server_ip, uint8_t _dns_server_ipv6[16], uint8_t ip_version);
/* For given URL retrieves IPv4 from DNS-server. */
-extern int8_t dns_get_ip(int fd, int8_t * url, uint8_t * domain_ip, uint8_t ip_version);
+extern int8_t dns_get_ip(int fd, char * url, uint8_t * domain_ip, uint8_t ip_version);
/* Handles DNS-packets, which are detected by receive_ether. */
extern int32_t handle_dns(uint8_t * packet, int32_t packetsize);
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/ethernet.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/ethernet.c
index bbfd6d1c3..1e03a0bf3 100644
--- a/qemu/roms/SLOF/clients/net-snk/app/netlib/ethernet.c
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/ethernet.c
@@ -11,7 +11,7 @@
*****************************************************************************/
-/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ALGORITHMS <<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+/******************************* ALGORITHMS ******************************/
/** \file netbase.c <pre>
* *********************** Receive-handle diagram *************************
@@ -36,12 +36,12 @@
* | APPLICATION +----------------+-----------+
* V | |
* upper DNS (handle_dns) BootP / DHCP (handle_bootp_client)
- *
+ *
* ************************************************************************
* </pre> */
-/*>>>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<*/
+/************************ DEFINITIONS & DECLARATIONS *********************/
#include <ethernet.h>
#include <string.h>
@@ -50,22 +50,22 @@
#include <ipv6.h>
-/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<*/
+/****************************** LOCAL VARIABLES **************************/
static uint8_t ether_packet[ETH_MTU_SIZE];
static uint8_t own_mac[6] = {0, 0, 0, 0, 0, 0};
static uint8_t multicast_mac[] = {0x01, 0x00, 0x5E};
static const uint8_t broadcast_mac[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
-/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<*/
+/****************************** IMPLEMENTATION ***************************/
/**
* Ethernet: Set the own MAC address to initializes ethernet layer.
*
* @param own_mac own hardware-address (MAC)
*/
-void
-set_mac_address(const uint8_t * _own_mac) {
+void set_mac_address(const uint8_t * _own_mac)
+{
if (_own_mac)
memcpy(own_mac, _own_mac, 6);
else
@@ -77,19 +77,19 @@ set_mac_address(const uint8_t * _own_mac) {
*
* @return own hardware-address (MAC)
*/
-const uint8_t *
-get_mac_address(void) {
+const uint8_t *get_mac_address(void)
+{
return own_mac;
}
/**
* Ethernet: Check if given multicast address is a multicast MAC address
- * starting with 0x3333
+ * starting with 0x3333
*
- * @return true or false
+ * @return true or false
*/
-static uint8_t
-is_multicast_mac(uint8_t * mac) {
+static uint8_t is_multicast_mac(uint8_t * mac)
+{
uint16_t mc = 0x3333;
if (memcmp(mac, &mc, 2) == 0)
@@ -98,7 +98,6 @@ is_multicast_mac(uint8_t * mac) {
return 0;
}
-
/**
* Ethernet: Receives an ethernet-packet and handles it according to
* Receive-handle diagram.
@@ -107,8 +106,8 @@ is_multicast_mac(uint8_t * mac) {
* @return ZERO - packet was handled or no packets received;
* NON ZERO - error condition occurs.
*/
-int32_t
-receive_ether(int fd) {
+int32_t receive_ether(int fd)
+{
int32_t bytes_received;
struct ethhdr * ethh;
@@ -118,7 +117,10 @@ receive_ether(int fd) {
if (!bytes_received) // No messages
return 0;
- if (bytes_received < sizeof(struct ethhdr))
+ if (bytes_received < 0)
+ return -1; /* recv() failed */
+
+ if ((size_t) bytes_received < sizeof(struct ethhdr))
return -1; // packet is too small
ethh = (struct ethhdr *) ether_packet;
@@ -176,9 +178,9 @@ send_ether(int fd, void* buffer, int len)
* @see fill_dnshdr
* @see fill_btphdr
*/
-void
-fill_ethhdr(uint8_t * packet, uint16_t eth_type,
- const uint8_t * src_mac, const uint8_t * dest_mac) {
+void fill_ethhdr(uint8_t * packet, uint16_t eth_type,
+ const uint8_t * src_mac, const uint8_t * dest_mac)
+{
struct ethhdr * ethh = (struct ethhdr *) packet;
ethh -> type = htons(eth_type);
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/icmpv6.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/icmpv6.c
index be6cc110f..c104f7015 100644
--- a/qemu/roms/SLOF/clients/net-snk/app/netlib/icmpv6.c
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/icmpv6.c
@@ -40,9 +40,8 @@ send_router_solicitation (int fd)
sizeof(struct ip6hdr));
/* Destination is "All routers multicast address" (link-local) */
- dest_addr.part.prefix = all_routers_ll.addr.part.prefix;
- dest_addr.part.interface_id = all_routers_ll.addr.part.interface_id;
-
+ dest_addr.part.prefix = 0xff02000000000000ULL;
+ dest_addr.part.interface_id = 2;
/* Fill IPv6 header */
fill_ip6hdr (ether_packet + sizeof(struct ethhdr),
@@ -78,8 +77,8 @@ handle_prefixoption (uint8_t *option)
prefix_option = (struct option_prefix *) option;
memcpy( &(prefix.addr), &(prefix_option->prefix.addr), IPV6_ADDR_LENGTH);
- /* Link-local adresses in RAs are nonsense */
- if ( (IPV6_LL_PREFIX & (prefix_option->prefix.part.prefix)) == IPV6_LL_PREFIX )
+ /* Link-local adresses in RAs are nonsense */
+ if (ip6_is_linklocal(&prefix))
return;
if (prefix_option->preferred_lifetime > prefix_option->valid_lifetime)
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv4.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv4.c
index 8185de5e1..2b92c77c4 100644
--- a/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv4.c
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv4.c
@@ -11,7 +11,7 @@
*****************************************************************************/
-/*>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<<<*/
+/********************** DEFINITIONS & DECLARATIONS ***********************/
#include <ipv4.h>
#include <udp.h>
@@ -81,32 +81,26 @@ struct icmphdr {
} payload;
};
-/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PROTOTYPES <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+/****************************** PROTOTYPES *******************************/
-static unsigned short
-checksum(unsigned short *packet, int words);
+static unsigned short checksum(unsigned short *packet, int words);
-static void
-arp_send_request(int fd, uint32_t dest_ip);
+static void arp_send_request(int fd, uint32_t dest_ip);
-static void
-arp_send_reply(int fd, uint32_t src_ip, uint8_t * src_mac);
+static void arp_send_reply(int fd, uint32_t src_ip, uint8_t * src_mac);
-static void
-fill_arphdr(uint8_t * packet, uint8_t opcode,
- const uint8_t * src_mac, uint32_t src_ip,
- const uint8_t * dest_mac, uint32_t dest_ip);
+static void fill_arphdr(uint8_t * packet, uint8_t opcode,
+ const uint8_t * src_mac, uint32_t src_ip,
+ const uint8_t * dest_mac, uint32_t dest_ip);
-static arp_entry_t*
-lookup_mac_addr(uint32_t ipv4_addr);
+static arp_entry_t *lookup_mac_addr(uint32_t ipv4_addr);
-static void
-fill_udp_checksum(struct iphdr *ipv4_hdr);
+static void fill_udp_checksum(struct iphdr *ipv4_hdr);
-static int8_t
-handle_icmp(int fd, struct iphdr * iph, uint8_t * packet, int32_t packetsize);
+static int8_t handle_icmp(int fd, struct iphdr * iph, uint8_t * packet,
+ int32_t packetsize);
-/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<*/
+/****************************** LOCAL VARIABLES **************************/
/* Routing parameters */
static uint32_t own_ip = 0;
@@ -126,18 +120,19 @@ static uint8_t multicast_mac[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
static unsigned int arp_consumer = 0;
static unsigned int arp_producer = 0;
static arp_entry_t arp_table[ARP_ENTRIES];
-static arp_entry_t pending_pkt;
+
+static uint8_t pending_pkt_frame[ETH_MTU_SIZE];
+static int pending_pkt_len;
/* Function pointer send_ip. Points either to send_ipv4() or send_ipv6() */
int (*send_ip) (int fd, void *, int);
-/*>>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+/***************************** IMPLEMENTATION ****************************/
/**
* IPv4: Initialize the environment for the IPv4 layer.
*/
-static void
-ipv4_init(void)
+static void ipv4_init(void)
{
int i;
@@ -153,7 +148,7 @@ ipv4_init(void)
arp_table[i].pkt_pending = 0;
}
- /* Set IP send function to send_ipv4() */
+ /* Set IP send function to send_ipv4() */
send_ip = &send_ipv4;
}
@@ -162,8 +157,7 @@ ipv4_init(void)
*
* @param _own_ip client IPv4 address (e.g. 127.0.0.1)
*/
-void
-set_ipv4_address(uint32_t _own_ip)
+void set_ipv4_address(uint32_t _own_ip)
{
own_ip = _own_ip;
ipv4_init();
@@ -174,8 +168,7 @@ set_ipv4_address(uint32_t _own_ip)
*
* @return client IPv4 address (e.g. 127.0.0.1)
*/
-uint32_t
-get_ipv4_address(void)
+uint32_t get_ipv4_address(void)
{
return own_ip;
}
@@ -185,8 +178,7 @@ get_ipv4_address(void)
*
* @param _own_ip multicast IPv4 address (224.0.0.0 - 239.255.255.255)
*/
-void
-set_ipv4_multicast(uint32_t _multicast_ip)
+void set_ipv4_multicast(uint32_t _multicast_ip)
{
// is this IP Multicast out of range (224.0.0.0 - 239.255.255.255)
if((htonl(_multicast_ip) < 0xE0000000)
@@ -210,8 +202,7 @@ set_ipv4_multicast(uint32_t _multicast_ip)
*
* @return multicast IPv4 address (224.0.0.0 - 239.255.255.255 or 0 if not set)
*/
-uint32_t
-get_ipv4_multicast(void)
+uint32_t get_ipv4_multicast(void)
{
return multicast_ip;
}
@@ -221,8 +212,7 @@ get_ipv4_multicast(void)
*
* @param _router_ip router IPv4 address
*/
-void
-set_ipv4_router(uint32_t _router_ip)
+void set_ipv4_router(uint32_t _router_ip)
{
router_ip = _router_ip;
ipv4_init();
@@ -233,8 +223,7 @@ set_ipv4_router(uint32_t _router_ip)
*
* @return router IPv4 address
*/
-uint32_t
-get_ipv4_router(void)
+uint32_t get_ipv4_router(void)
{
return router_ip;
}
@@ -244,8 +233,7 @@ get_ipv4_router(void)
*
* @param _subnet_mask netmask of the own IPv4 address
*/
-void
-set_ipv4_netmask(uint32_t _subnet_mask)
+void set_ipv4_netmask(uint32_t _subnet_mask)
{
subnet_mask = _subnet_mask;
ipv4_init();
@@ -256,8 +244,7 @@ set_ipv4_netmask(uint32_t _subnet_mask)
*
* @return netmask of the own IPv4 address
*/
-uint32_t
-get_ipv4_netmask(void)
+uint32_t get_ipv4_netmask(void)
{
return subnet_mask;
}
@@ -280,9 +267,9 @@ get_ipv4_netmask(void)
* @see fill_dnshdr
* @see fill_btphdr
*/
-void
-fill_iphdr(uint8_t * packet, uint16_t packetsize,
- uint8_t ip_proto, uint32_t ip_src, uint32_t ip_dst) {
+void fill_iphdr(uint8_t * packet, uint16_t packetsize,
+ uint8_t ip_proto, uint32_t ip_src, uint32_t ip_dst)
+{
struct iphdr * iph = (struct iphdr *) packet;
iph -> ip_hlv = 0x45;
@@ -308,8 +295,7 @@ fill_iphdr(uint8_t * packet, uint16_t packetsize,
* @see receive_ether
* @see iphdr
*/
-int8_t
-handle_ipv4(int fd, uint8_t * ip_packet, int32_t packetsize)
+int8_t handle_ipv4(int fd, uint8_t * ip_packet, uint32_t packetsize)
{
struct iphdr * iph;
int32_t old_sum;
@@ -422,8 +408,7 @@ handle_ipv4(int fd, uint8_t * ip_packet, int32_t packetsize)
* @see receive_ether
* @see iphdr
*/
-int
-send_ipv4(int fd, void* buffer, int len)
+int send_ipv4(int fd, void* buffer, int len)
{
arp_entry_t *arp_entry = 0;
struct iphdr *ip;
@@ -506,13 +491,11 @@ send_ipv4(int fd, void* buffer, int len)
arp_entry->pkt_pending = 1;
arp_entry->ipv4_addr = ip_dst;
memset(arp_entry->mac_addr, 0, 6);
- pending_pkt.ipv4_addr = ip_dst;
- memset(pending_pkt.mac_addr, 0, 6);
- fill_ethhdr (pending_pkt.eth_frame, htons(ETHERTYPE_IP),
+ fill_ethhdr (pending_pkt_frame, htons(ETHERTYPE_IP),
get_mac_address(), null_mac_addr);
- memcpy(&pending_pkt.eth_frame[sizeof(struct ethhdr)],
+ memcpy(&pending_pkt_frame[sizeof(struct ethhdr)],
buffer, len);
- pending_pkt.eth_len = len + sizeof(struct ethhdr);
+ pending_pkt_len = len + sizeof(struct ethhdr);
set_timer(TICKS_SEC);
do {
@@ -538,11 +521,9 @@ send_ipv4(int fd, void* buffer, int len)
*
* @param ipv4_hdr Points to the place where IPv4-header starts.
*/
-
-static void
-fill_udp_checksum(struct iphdr *ipv4_hdr)
+static void fill_udp_checksum(struct iphdr *ipv4_hdr)
{
- int i;
+ unsigned i;
unsigned long checksum = 0;
struct iphdr ip_hdr;
char *ptr;
@@ -585,8 +566,7 @@ fill_udp_checksum(struct iphdr *ipv4_hdr)
* @return Checksum
* @see iphdr
*/
-static unsigned short
-checksum(unsigned short * packet, int words)
+static unsigned short checksum(unsigned short * packet, int words)
{
unsigned long checksum;
@@ -598,8 +578,7 @@ checksum(unsigned short * packet, int words)
return ~checksum;
}
-static arp_entry_t*
-lookup_mac_addr(uint32_t ipv4_addr)
+static arp_entry_t* lookup_mac_addr(uint32_t ipv4_addr)
{
unsigned int i;
@@ -618,8 +597,7 @@ lookup_mac_addr(uint32_t ipv4_addr)
* @param fd socket fd
* @param dest_ip IP of the host which MAC should be obtained
*/
-static void
-arp_send_request(int fd, uint32_t dest_ip)
+static void arp_send_request(int fd, uint32_t dest_ip)
{
arp_entry_t *arp_entry = &arp_table[arp_producer];
@@ -642,8 +620,7 @@ arp_send_request(int fd, uint32_t dest_ip)
* @param src_ip requester IP address (foreign IP)
* @param src_mac requester MAC address (foreign MAC)
*/
-static void
-arp_send_reply(int fd, uint32_t src_ip, uint8_t * src_mac)
+static void arp_send_reply(int fd, uint32_t src_ip, uint8_t * src_mac)
{
arp_entry_t *arp_entry = &arp_table[arp_producer];
@@ -674,10 +651,9 @@ arp_send_reply(int fd, uint32_t src_ip, uint8_t * src_mac)
* @see arphdr
* @see fill_ethhdr
*/
-static void
-fill_arphdr(uint8_t * packet, uint8_t opcode,
- const uint8_t * src_mac, uint32_t src_ip,
- const uint8_t * dest_mac, uint32_t dest_ip)
+static void fill_arphdr(uint8_t * packet, uint8_t opcode,
+ const uint8_t * src_mac, uint32_t src_ip,
+ const uint8_t * dest_mac, uint32_t dest_ip)
{
struct arphdr * arph = (struct arphdr *) packet;
@@ -706,8 +682,7 @@ fill_arphdr(uint8_t * packet, uint8_t opcode,
* @see receive_ether
* @see arphdr
*/
-int8_t
-handle_arp(int fd, uint8_t * packet, int32_t packetsize)
+int8_t handle_arp(int fd, uint8_t * packet, uint32_t packetsize)
{
struct arphdr * arph = (struct arphdr *) packet;
@@ -754,11 +729,11 @@ handle_arp(int fd, uint8_t * packet, int32_t packetsize)
// do we have something to send
if (arp_table[i].pkt_pending) {
- struct ethhdr * ethh = (struct ethhdr *) pending_pkt.eth_frame;
+ struct ethhdr * ethh = (struct ethhdr *) pending_pkt_frame;
memcpy(ethh -> dest_mac, arp_table[i].mac_addr, 6);
- send_ether(fd, pending_pkt.eth_frame, pending_pkt.eth_len);
- pending_pkt.pkt_pending = 0;
+ send_ether(fd, pending_pkt_frame, pending_pkt_len);
+ arp_table[i].pkt_pending = 0;
arp_table[i].eth_len = 0;
}
return 0; // no error
@@ -780,8 +755,7 @@ handle_arp(int fd, uint8_t * packet, int32_t packetsize)
* @param fd socket descriptor
* @param _ping_dst_ip destination IPv4 address
*/
-void
-ping_ipv4(int fd, uint32_t _ping_dst_ip)
+void ping_ipv4(int fd, uint32_t _ping_dst_ip)
{
unsigned char packet[sizeof(struct iphdr) + sizeof(struct icmphdr)];
struct icmphdr *icmp;
@@ -814,8 +788,7 @@ ping_ipv4(int fd, uint32_t _ping_dst_ip)
*
* @return ping_dst_ip host IPv4 address
*/
-uint32_t
-pong_ipv4(void)
+uint32_t pong_ipv4(void)
{
return ping_dst_ip;
}
@@ -830,8 +803,8 @@ pong_ipv4(void)
* NON ZERO - packet was not handled (e.g. bad format)
* @see handle_ipv4
*/
-static int8_t
-handle_icmp(int fd, struct iphdr * iph, uint8_t * packet, int32_t packetsize)
+static int8_t handle_icmp(int fd, struct iphdr * iph, uint8_t * packet,
+ int32_t packetsize)
{
struct icmphdr *icmp = (struct icmphdr *) packet;
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv4.h b/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv4.h
index eb719f8b2..18821ea74 100644
--- a/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv4.h
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv4.h
@@ -60,7 +60,7 @@ struct arphdr {
uint32_t dest_ip; /**< Proto address of target of this packet */
} __attribute((packed));
-/*>>>>>>>>>>>>> Initialization of the IPv4 network layer. <<<<<<<<<<<<<*/
+/************** Initialization of the IPv4 network layer. **************/
extern void set_ipv4_address(uint32_t own_ip);
extern uint32_t get_ipv4_address(void);
extern void set_ipv4_multicast(uint32_t multicast_ip);
@@ -88,9 +88,9 @@ extern void ping_ipv4(int fd, uint32_t _ping_dst_ip);
extern uint32_t pong_ipv4(void);
/* Handles IPv4-packets that are detected by receive_ether. */
-extern int8_t handle_ipv4(int fd, uint8_t * packet, int32_t packetsize);
+extern int8_t handle_ipv4(int fd, uint8_t * packet, uint32_t packetsize);
/* Handles ARP-packets that are detected by receive_ether. */
-extern int8_t handle_arp(int fd, uint8_t * packet, int32_t packetsize);
+extern int8_t handle_arp(int fd, uint8_t * packet, uint32_t packetsize);
#endif
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv6.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv6.c
index 0cb0a2e7b..62d29ea86 100644
--- a/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv6.c
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv6.c
@@ -37,15 +37,23 @@ static int ip6_is_multicast (ip6_addr_t * ip);
/****************************** LOCAL VARIABLES **************************/
+/* List of Ipv6 Addresses */
+static struct ip6addr_list_entry *first_ip6;
+static struct ip6addr_list_entry *last_ip6;
+
/* Own IPv6 address */
static struct ip6addr_list_entry *own_ip6;
+/* All nodes link-local address */
+struct ip6addr_list_entry all_nodes_ll;
+
/* Null IPv6 address */
static ip6_addr_t null_ip6;
/* helper variables */
static uint8_t null_mac[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+struct ip6_config ip6_state;
/****************************** IMPLEMENTATION ***************************/
@@ -55,9 +63,10 @@ static uint8_t null_mac[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
* @param fd Socket descriptor
* @param _own_ip client IPv6 address (e.g. ::1)
*/
-void
-set_ipv6_address (int fd, ip6_addr_t *_own_ip6)
+void set_ipv6_address(int fd, ip6_addr_t *_own_ip6)
{
+ struct ip6addr_list_entry *ile;
+
own_ip6 = malloc (sizeof(struct ip6addr_list_entry));
/* If no address was passed as a parameter generate a link-local
@@ -73,6 +82,20 @@ set_ipv6_address (int fd, ip6_addr_t *_own_ip6)
ip6addr_add (own_ip6);
ipv6_init(fd);
+
+ /*
+ * Check whether we've got a non-link-local address during
+ * ipv6_init() and use that as preferred address if possible
+ */
+ if (_own_ip6 == NULL) {
+ for (ile = first_ip6; ile != NULL ; ile = ile->next) {
+ if (!ip6_is_multicast(&ile->addr) &&
+ !ip6_is_linklocal(&ile->addr)) {
+ own_ip6 = ile;
+ break;
+ }
+ }
+ }
}
/**
@@ -80,8 +103,7 @@ set_ipv6_address (int fd, ip6_addr_t *_own_ip6)
*
* @return pointer to client IPv6 address (e.g. ::1)
*/
-ip6_addr_t *
-get_ipv6_address (void)
+ip6_addr_t *get_ipv6_address(void)
{
return (ip6_addr_t *) &(own_ip6->addr);
}
@@ -92,8 +114,7 @@ get_ipv6_address (void)
* @return 0 - IPv6 address is not in list
* 1 - IPv6 address is in list
*/
-static int8_t
-find_ip6addr (ip6_addr_t *ip)
+static int8_t find_ip6addr(ip6_addr_t *ip)
{
struct ip6addr_list_entry *n = NULL;
@@ -119,8 +140,7 @@ find_ip6addr (ip6_addr_t *ip)
* @see handle_udp
* @see ip6hdr
*/
-int8_t
-handle_ipv6 (int fd, uint8_t * ip6_packet, int32_t packetsize)
+int8_t handle_ipv6(int fd, uint8_t * ip6_packet, uint32_t packetsize)
{
struct ip6hdr *ip6 = NULL;
@@ -164,11 +184,9 @@ handle_ipv6 (int fd, uint8_t * ip6_packet, int32_t packetsize)
* @see fill_dnshdr
* @see fill_btphdr
*/
-void
-fill_ip6hdr (uint8_t * packet, uint16_t packetsize,
- uint8_t ip_proto, ip6_addr_t *ip6_src, ip6_addr_t *ip6_dst)
+void fill_ip6hdr(uint8_t * packet, uint16_t packetsize,
+ uint8_t ip_proto, ip6_addr_t *ip6_src, ip6_addr_t *ip6_dst)
{
-
struct ip6hdr * ip6h = (struct ip6hdr *) packet;
ip6h->ver_tc_fl = 6 << 28; // set version to 6
@@ -184,8 +202,7 @@ fill_ip6hdr (uint8_t * packet, uint16_t packetsize,
* See RFC 4291 "IP Version 6 Addressing Architecture"
*
*/
-uint64_t
-mac2eui64 (const uint8_t *mac)
+uint64_t mac2eui64(const uint8_t *mac)
{
uint8_t eui64id[8];
uint64_t retid;
@@ -205,8 +222,7 @@ mac2eui64 (const uint8_t *mac)
* @param own_mac MAC of NIC
* @return ll_addr pointer to newly created link-local address
*/
-ip6_addr_t *
-ip6_create_ll_address (const uint8_t *own_mac)
+ip6_addr_t *ip6_create_ll_address(const uint8_t *own_mac)
{
ip6_addr_t *ll_addr;
@@ -223,8 +239,7 @@ ip6_create_ll_address (const uint8_t *own_mac)
* @param struct ip6_addr_list_entry *ip6
* @return true or false
*/
-int8_t
-unknown_prefix (ip6_addr_t *ip)
+int8_t unknown_prefix(ip6_addr_t *ip)
{
struct ip6addr_list_entry *node;
@@ -240,8 +255,7 @@ unknown_prefix (ip6_addr_t *ip)
* @return NULL - malloc failed
* ! NULL - pointer to new prefix_info
*/
-struct prefix_info *
-ip6_create_prefix_info ()
+struct prefix_info *ip6_create_prefix_info()
{
struct prefix_info *prfx_info;
@@ -259,8 +273,7 @@ ip6_create_prefix_info ()
* @param ip6_addr prefix (as received in RA)
* @return NULL - pointer to new ip6addr_list entry
*/
-void *
-ip6_prefix2addr (ip6_addr_t prefix)
+void *ip6_prefix2addr(ip6_addr_t prefix)
{
struct ip6addr_list_entry *new_address;
uint64_t interface_id;
@@ -287,8 +300,7 @@ ip6_prefix2addr (ip6_addr_t prefix)
* @return 0 - passed pointer = NULL;
* 1 - ok
*/
-int8_t
-ip6addr_add (struct ip6addr_list_entry *new_address)
+int8_t ip6addr_add(struct ip6addr_list_entry *new_address)
{
struct ip6addr_list_entry *solicited_node;
@@ -332,8 +344,7 @@ ip6addr_add (struct ip6addr_list_entry *new_address)
*
* @param fd socket fd
*/
-static void
-ipv6_init (int fd)
+static void ipv6_init(int fd)
{
int i = 0;
@@ -349,21 +360,9 @@ ipv6_init (int fd)
/* Multicast addresses */
all_nodes_ll.addr.part.prefix = 0xff02000000000000;
all_nodes_ll.addr.part.interface_id = 1;
- all_dhcpv6_ll.addr.part.prefix = 0xff02000000000000ULL;
- all_dhcpv6_ll.addr.part.interface_id = 0x10002ULL;
- all_routers_ll.addr.part.prefix = 0xff02000000000000;
- all_routers_ll.addr.part.interface_id = 2;
-
ip6addr_add(&all_nodes_ll);
- /* ... */
- /* Router list */
- first_router = NULL;
- last_router = first_router;
-
- /* Init Neighbour cache */
- first_neighbor = NULL;
- last_neighbor = first_neighbor;
+ ndp_init();
send_router_solicitation (fd);
for(i=0; i < 4 && !is_ra_received(); i++) {
@@ -382,8 +381,7 @@ ipv6_init (int fd)
* @param ip6_addr ip_1
* @param ip6_addr ip_2
*/
-int8_t
-ip6_cmp (ip6_addr_t *ip_1, ip6_addr_t *ip_2)
+int8_t ip6_cmp(ip6_addr_t *ip_1, ip6_addr_t *ip_2)
{
return ((int8_t) !memcmp( &(ip_1->addr[0]), &(ip_2->addr[0]),
IPV6_ADDR_LENGTH ));
@@ -396,11 +394,9 @@ ip6_cmp (ip6_addr_t *ip_1, ip6_addr_t *ip_2)
* @param *ip - pointer to IPv6 address
* @return true or false
*/
-int
-ip6_is_multicast (ip6_addr_t * ip)
+int ip6_is_multicast(ip6_addr_t * ip)
{
- uint8_t mc = 0xFF;
- return ! memcmp(&ip->addr[0], &mc, 1);
+ return ip->addr[0] == 0xFF;
}
/**
@@ -408,17 +404,11 @@ ip6_is_multicast (ip6_addr_t * ip)
* (e.g. UDP or ICMPv6)
*
* @param *ip - pointer to IPv6 address
+ * @param *mc_mac pointer to an array with 6 bytes (for the MAC address)
* @return pointer to Multicast MAC address
*/
-static uint8_t *
-ip6_to_multicast_mac (ip6_addr_t * ip)
+static uint8_t *ip6_to_multicast_mac(ip6_addr_t * ip, uint8_t *mc_mac)
{
- uint8_t *mc_mac;
-
- mc_mac = malloc(ETH_ALEN);
- if (!mc_mac)
- return NULL;
-
mc_mac[0] = 0x33;
mc_mac[1] = 0x33;
memcpy (mc_mac+2, (uint8_t *) &(ip->addr)+12, 4);
@@ -437,8 +427,8 @@ ip6_to_multicast_mac (ip6_addr_t * ip)
* starting from *packet
* @return checksum
*/
-static unsigned short
-ip6_checksum (struct ip6hdr *ip6h, unsigned short *packet, int words)
+static unsigned short ip6_checksum(struct ip6hdr *ip6h, unsigned short *packet,
+ int words)
{
int i=0;
unsigned long checksum;
@@ -478,8 +468,7 @@ ip6_checksum (struct ip6hdr *ip6h, unsigned short *packet, int words)
* @see receive_ether
* @see ip6hdr
*/
-int
-send_ipv6 (int fd, void* buffer, int len)
+int send_ipv6(int fd, void* buffer, int len)
{
struct neighbor *n;
struct ip6hdr *ip6h;
@@ -519,17 +508,9 @@ send_ipv6 (int fd, void* buffer, int len)
n = find_neighbor (&ip_dst);
- // If packet is a neighbor solicitation
- if (icmp6h->type == ICMPV6_NEIGHBOUR_SOLICITATION) {
- mac_addr = ip6_to_multicast_mac (&ip_dst);
- fill_ethhdr( buffer-sizeof(struct ethhdr), htons(ETHERTYPE_IPv6),
- get_mac_address(),
- mac_addr);
- }
-
// If address is a multicast address, create a proper mac address
- else if (ip6_is_multicast (&ip_dst)) {
- mac_addr = ip6_to_multicast_mac (&ip_dst);
+ if (ip6_is_multicast (&ip_dst)) {
+ mac_addr = ip6_to_multicast_mac (&ip_dst, mac);
}
else {
// Check if the MAC address is already cached
@@ -572,8 +553,7 @@ send_ipv6 (int fd, void* buffer, int len)
return send_ether (fd, n->eth_frame, len + sizeof(struct ethhdr));
}
-static int
-check_colons(const char *str)
+static int check_colons(const char *str)
{
char *pch, *prv;
int col = 0;
@@ -595,7 +575,7 @@ check_colons(const char *str)
dprintf("The number of col : %d \n",col);
dprintf("The number of dcol : %d \n",dcol);
- if((dcol > 1) || /* Cannot have 2 "::" */
+ if((dcol > 1) || /* Cannot have 2 "::" */
((dcol == 1) && (col > 5)) || /* Too many ':'s */
((dcol == 0) && (col != 7)) ) { /* Too few ':'s */
dprintf(" exiting for check_colons \n");
@@ -605,8 +585,7 @@ check_colons(const char *str)
return (col+dcol);
}
-static int
-ipv6str_to_bytes(const char *str, char *ip)
+static int ipv6str_to_bytes(const char *str, char *ip)
{
char block[5];
int res;
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv6.h b/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv6.h
index b496364f3..72c6ee22f 100644
--- a/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv6.h
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv6.h
@@ -26,6 +26,7 @@
#define IPV6_ADDR_LENGTH 16 /* Size of IPv6 adress in bytes */
#define IPV6_LL_PREFIX 0xFE80000000000000ULL
+#define IPV6_LL_PREFIX_MASK 0xFFC0000000000000ULL
#define IPV6_SOLIC_NODE_PREFIX 0xFF02000000000000ULL
#define IPV6_SOLIC_NODE_IFACE_ID 0x00000001FF000000ULL
@@ -126,32 +127,17 @@ struct ip6_config {
uint8_t managed_mode:1,
other_config:1,
reserved:6;
-} ip6_state;
+};
/******************** VARIABLES **********************************************/
/* Function pointer send_ip. Points either to send_ipv4() or send_ipv6() */
extern int (*send_ip) (int fd, void *, int);
-/* IPv6 link-local multicast addresses */
-struct ip6addr_list_entry all_routers_ll; // Routers
-struct ip6addr_list_entry all_dhcpv6_ll; // DHCPv6 servers
-struct ip6addr_list_entry all_nodes_ll; // All IPv6 nodes
-
-/* List of Ipv6 Addresses */
-struct ip6addr_list_entry *first_ip6;
-struct ip6addr_list_entry *last_ip6;
-
-/* Neighbor cache */
-struct neighbor *first_neighbor;
-struct neighbor *last_neighbor;
-
-/* Router list */
-struct router *first_router;
-struct router *last_router;
+extern struct ip6_config ip6_state;
/******************** FUNCTIONS *********************************************/
/* Handles IPv6-packets that are detected by receive_ether. */
-int8_t handle_ipv6(int fd, uint8_t * ip6_packet, int32_t packetsize);
+int8_t handle_ipv6(int fd, uint8_t * ip6_packet, uint32_t packetsize);
/* Fill IPv6 header */
void fill_ip6hdr(uint8_t * packet, uint16_t packetsize,
@@ -179,6 +165,12 @@ void * ip6_prefix2addr (ip6_addr_t prefix);
/* Compare IPv6 adresses */
int8_t ip6_cmp( ip6_addr_t *ip_1, ip6_addr_t *ip_2 );
+/* Check if it is a link-local address */
+static inline int ip6_is_linklocal(ip6_addr_t *ip)
+{
+ return (ip->part.prefix & IPV6_LL_PREFIX_MASK) == IPV6_LL_PREFIX;
+}
+
/* Check if prefix is already in our list */
int8_t unknown_prefix (ip6_addr_t *ip);
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/ndp.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/ndp.c
index ed9d61f4a..96faa8716 100644
--- a/qemu/roms/SLOF/clients/net-snk/app/netlib/ndp.c
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/ndp.c
@@ -17,6 +17,14 @@
#include <netlib/icmpv6.h>
#include <netlib/ndp.h>
+/* Neighbor cache */
+static struct neighbor *first_neighbor;
+static struct neighbor *last_neighbor;
+
+/* Router list */
+static struct router *first_router;
+static struct router *last_router;
+
/*
* NET: add new router to list
* @param struct router nghb - new router
@@ -145,3 +153,14 @@ find_neighbor (ip6_addr_t *ip)
return NULL; /* neighbor is unknown */
}
+
+void ndp_init(void)
+{
+ /* Router list */
+ first_router = NULL;
+ last_router = first_router;
+
+ /* Init Neighbour cache */
+ first_neighbor = NULL;
+ last_neighbor = first_neighbor;
+}
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/ndp.h b/qemu/roms/SLOF/clients/net-snk/app/netlib/ndp.h
index ee5235fe1..c785c4897 100644
--- a/qemu/roms/SLOF/clients/net-snk/app/netlib/ndp.h
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/ndp.h
@@ -59,6 +59,7 @@ struct neighbor {
};
/******************** FUNCTIONS *********************************************/
+void ndp_init(void);
int8_t neighbor_add (struct neighbor *);
void * neighbor_create (uint8_t *packet, struct packeth *headers);
struct neighbor * find_neighbor (ip6_addr_t *);
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/tcp.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/tcp.c
index 5511aa00a..faa0b83ac 100644
--- a/qemu/roms/SLOF/clients/net-snk/app/netlib/tcp.c
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/tcp.c
@@ -10,16 +10,14 @@
* IBM Corporation - initial implementation
*****************************************************************************/
-/*>>>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<*/
+/************************ DEFINITIONS & DECLARATIONS *********************/
#include <tcp.h>
#include <sys/socket.h>
+/****************************** LOCAL VARIABLES **************************/
-/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<*/
-
-/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<*/
-
+/****************************** IMPLEMENTATION ***************************/
/**
* TCP: Handles TCP-packets according to Receive-handle diagram.
@@ -29,13 +27,11 @@
* @return ZERO - packet handled successfully;
* NON ZERO - packet was not handled (e.g. bad format)
*/
-int8_t
-handle_tcp(uint8_t * tcp_packet, int32_t packetsize)
+int8_t handle_tcp(uint8_t * tcp_packet, int32_t packetsize)
{
return -1;
}
-
/**
* NET: This function handles situation when "Destination unreachable"
* ICMP-error occurs during sending TCP-packet.
@@ -45,6 +41,6 @@ handle_tcp(uint8_t * tcp_packet, int32_t packetsize)
* @param packetsize length of the packet
* @see handle_icmp
*/
-void
-handle_tcp_dun(uint8_t * tcp_packet, uint32_t packetsize, uint8_t err_code) {
+void handle_tcp_dun(uint8_t * tcp_packet, uint32_t packetsize, uint8_t err_code)
+{
}
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/tftp.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/tftp.c
index 0a7c0ec63..c1197cf17 100644
--- a/qemu/roms/SLOF/clients/net-snk/app/netlib/tftp.c
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/tftp.c
@@ -50,13 +50,13 @@ static unsigned short block = 0;
static unsigned short blocksize;
static char blocksize_str[6]; /* Blocksize string for read request */
static int received_len = 0;
-static int retries = 0;
+static unsigned int retries = 0;
static int huge_load;
static int len;
static int tftp_finished = 0;
static int lost_packets = 0;
-static int tftp_errno = 0;
-static int ip_version = 0;
+static int tftp_errno = 0;
+static int ip_version = 0;
static short port_number = -1;
static tftp_err_t *tftp_err;
static filename_ip_t *fn_ip;
@@ -69,8 +69,7 @@ static filename_ip_t *fn_ip;
*/
#ifdef __DEBUG__
-static void
-dump_package(unsigned char *buffer, unsigned int len)
+static void dump_package(unsigned char *buffer, unsigned int len)
{
int i;
@@ -89,8 +88,7 @@ dump_package(unsigned char *buffer, unsigned int len)
*
* @fd: Socket Descriptor
*/
-static void
-send_rrq(int fd)
+static void send_rrq(int fd)
{
int ip_len = 0;
int ip6_payload_len = 0;
@@ -121,7 +119,7 @@ send_rrq(int fd)
+ strlen("blksize") + strlen(blocksize_str) + 2;
ip_len = sizeof(struct ip6hdr) + ip6_payload_len;
fill_ip6hdr ((uint8_t *) ip6, ip6_payload_len, IPTYPE_UDP, get_ipv6_address(),
- &(fn_ip->server_ip6));
+ &(fn_ip->server_ip6));
}
udp_len = htons(sizeof(struct udphdr)
@@ -158,8 +156,7 @@ send_rrq(int fd)
* @blckno: block number
* @dport: UDP destination port
*/
-static void
-send_ack(int fd, int blckno, unsigned short dport)
+static void send_ack(int fd, int blckno, unsigned short dport)
{
int ip_len = 0;
int ip6_payload_len = 0;
@@ -182,8 +179,7 @@ send_ack(int fd, int blckno, unsigned short dport)
ip6 = (struct ip6hdr *) packet;
udph = (struct udphdr *) (ip6 + 1);
ip6_payload_len = sizeof(struct udphdr) + 4;
- ip_len = sizeof(struct ethhdr) + sizeof(struct ip6hdr) +
- ip6_payload_len;
+ ip_len = sizeof(struct ip6hdr) + ip6_payload_len;
fill_ip6hdr ((uint8_t *) ip6, ip6_payload_len, IPTYPE_UDP, get_ipv6_address(),
&(fn_ip->server_ip6));
}
@@ -210,8 +206,7 @@ send_ack(int fd, int blckno, unsigned short dport)
* @error_code: Used sub code for error packet
* @dport: UDP destination port
*/
-static void
-send_error(int fd, int error_code, unsigned short dport)
+static void send_error(int fd, int error_code, unsigned short dport)
{
int ip_len = 0;
int ip6_payload_len = 0;
@@ -234,8 +229,7 @@ send_error(int fd, int error_code, unsigned short dport)
ip6 = (struct ip6hdr *) packet;
udph = (struct udphdr *) (ip6 + 1);
ip6_payload_len = sizeof(struct udphdr) + 5;
- ip_len = sizeof(struct ethhdr) + sizeof(struct ip6hdr) +
- ip6_payload_len;
+ ip_len = sizeof(struct ip6hdr) + ip6_payload_len;
fill_ip6hdr ((uint8_t *) ip6, ip6_payload_len, IPTYPE_UDP, get_ipv6_address(),
&(fn_ip->server_ip6));
}
@@ -256,8 +250,7 @@ send_error(int fd, int error_code, unsigned short dport)
return;
}
-static void
-print_progress(int urgent, int received_bytes)
+static void print_progress(int urgent, int received_bytes)
{
static unsigned int i = 1;
static int first = -1;
@@ -265,7 +258,7 @@ print_progress(int urgent, int received_bytes)
char buffer[100];
char *ptr;
- // 1MB steps or 0x400 times or urgent
+ // 1MB steps or 0x400 times or urgent
if(((received_bytes - last_bytes) >> 20) > 0
|| (i & 0x3FF) == 0 || urgent) {
if(!first) {
@@ -295,8 +288,7 @@ print_progress(int urgent, int received_bytes)
* @param len the length of the network packet
* @return the blocksize the server supports or 0 for error
*/
-static int
-get_blksize(unsigned char *buffer, unsigned int len)
+static int get_blksize(unsigned char *buffer, unsigned int len)
{
unsigned char *orig = buffer;
/* skip all headers until tftp has been reached */
@@ -325,7 +317,7 @@ get_blksize(unsigned char *buffer, unsigned int len)
}
/**
- * Handle incoming tftp packets after read request was sent
+ * Handle incoming tftp packets after read request was sent
*
* this function also prints out some status characters
* \|-/ for each packet received
@@ -334,13 +326,12 @@ get_blksize(unsigned char *buffer, unsigned int len)
* #+* for different unexpected TFTP packets (not very good)
*
* @param fd socket descriptor
- * @param packet points to the UDP header of the packet
+ * @param packet points to the UDP header of the packet
* @param len the length of the network packet
* @return ZERO if packet was handled successfully
- * ERRORCODE if error occurred
+ * ERRORCODE if error occurred
*/
-int32_t
-handle_tftp(int fd, uint8_t *pkt, int32_t packetsize)
+int32_t handle_tftp(int fd, uint8_t *pkt, int32_t packetsize)
{
struct udphdr *udph;
struct tftphdr *tftp;
@@ -397,7 +388,7 @@ handle_tftp(int fd, uint8_t *pkt, int32_t packetsize)
case ENOUSER:
tftp_errno = -7; // ERROR: no such user
break;
- default:
+ default:
tftp_errno = -1; // ERROR: unknown error
}
goto error;
@@ -489,8 +480,7 @@ error:
*
* @param err_code Error Code (e.g. "Host unreachable")
*/
-void
-handle_tftp_dun(uint8_t err_code)
+void handle_tftp_dun(uint8_t err_code)
{
tftp_errno = - err_code - 10;
tftp_finished = 1;
@@ -510,10 +500,9 @@ handle_tftp_dun(uint8_t err_code)
* @return ZERO - error condition occurs
* NON ZERO - size of received file
*/
-int
-tftp(filename_ip_t * _fn_ip, unsigned char *_buffer, int _len,
- unsigned int _retries, tftp_err_t * _tftp_err,
- int32_t _mode, int32_t _blocksize, int _ip_version)
+int tftp(filename_ip_t * _fn_ip, unsigned char *_buffer, int _len,
+ unsigned int _retries, tftp_err_t * _tftp_err,
+ int32_t _mode, int32_t _blocksize, int _ip_version)
{
retries = _retries;
fn_ip = _fn_ip;
@@ -592,6 +581,6 @@ tftp(filename_ip_t * _fn_ip, unsigned char *_buffer, int _len,
printf("\n");
if (lost_packets)
printf("Lost ACK packets: %d\n", lost_packets);
-
+
return received_len;
}
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/udp.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/udp.c
index db29bc90f..5d16e52c6 100644
--- a/qemu/roms/SLOF/clients/net-snk/app/netlib/udp.c
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/udp.c
@@ -10,7 +10,7 @@
* IBM Corporation - initial implementation
*****************************************************************************/
-/*>>>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<*/
+/************************ DEFINITIONS & DECLARATIONS *********************/
#include <udp.h>
#include <sys/socket.h>
@@ -25,7 +25,7 @@
-/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<*/
+/****************************** LOCAL VARIABLES **************************/
#ifdef USE_MTFTP
@@ -33,17 +33,19 @@
uint16_t net_tftp_uport;
uint16_t net_mtftp_uport;
-void net_set_tftp_port(uint16_t tftp_port) {
+void net_set_tftp_port(uint16_t tftp_port)
+{
net_tftp_uport = tftp_port;
}
-void net_set_mtftp_port(uint16_t tftp_port) {
+void net_set_mtftp_port(uint16_t tftp_port)
+{
net_mtftp_uport = tftp_port;
}
#endif
-/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<*/
+/****************************** IMPLEMENTATION ***************************/
/**
@@ -56,8 +58,8 @@ void net_set_mtftp_port(uint16_t tftp_port) {
* @see receive_ether
* @see udphdr
*/
-int8_t
-handle_udp(int fd, uint8_t * udp_packet, int32_t packetsize) {
+int8_t handle_udp(int fd, uint8_t * udp_packet, uint32_t packetsize)
+{
struct udphdr * udph = (struct udphdr *) udp_packet;
if (packetsize < sizeof(struct udphdr))
@@ -108,8 +110,8 @@ handle_udp(int fd, uint8_t * udp_packet, int32_t packetsize) {
* @param packetsize length of the packet
* @see handle_icmp
*/
-void
-handle_udp_dun(uint8_t * udp_packet, uint32_t packetsize, uint8_t err_code) {
+void handle_udp_dun(uint8_t * udp_packet, uint32_t packetsize, uint8_t err_code)
+{
struct udphdr * udph = (struct udphdr *) udp_packet;
if (packetsize < sizeof(struct udphdr))
@@ -139,9 +141,9 @@ handle_udp_dun(uint8_t * udp_packet, uint32_t packetsize, uint8_t err_code) {
* @see fill_dnshdr
* @see fill_btphdr
*/
-void
-fill_udphdr(uint8_t * packet, uint16_t packetsize,
- uint16_t src_port, uint16_t dest_port) {
+void fill_udphdr(uint8_t * packet, uint16_t packetsize,
+ uint16_t src_port, uint16_t dest_port)
+{
struct udphdr * udph = (struct udphdr *) packet;
udph -> uh_sport = htons(src_port);
diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/udp.h b/qemu/roms/SLOF/clients/net-snk/app/netlib/udp.h
index 1ba9332ce..f154542dd 100644
--- a/qemu/roms/SLOF/clients/net-snk/app/netlib/udp.h
+++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/udp.h
@@ -40,7 +40,7 @@ typedef int32_t *(*handle_upper_udp_t)(uint8_t *, int32_t);
typedef void *(*handle_upper_udp_dun_t)(uint8_t);
/* Handles UDP-packets that are detected by any network layer. */
-extern int8_t handle_udp(int fd, uint8_t * udp_packet, int32_t packetsize);
+extern int8_t handle_udp(int fd, uint8_t * udp_packet, uint32_t packetsize);
/* Handles UDP related ICMP-Dest.Unreachable packets that are detected by
* the network layers. */
diff --git a/qemu/roms/SLOF/clients/net-snk/client.lds b/qemu/roms/SLOF/clients/net-snk/client.lds
index 39d04594e..c2086445b 100644
--- a/qemu/roms/SLOF/clients/net-snk/client.lds
+++ b/qemu/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/qemu/roms/SLOF/clients/net-snk/kernel/entry.S b/qemu/roms/SLOF/clients/net-snk/kernel/entry.S
index 8849fb9d1..bf10542bd 100644
--- a/qemu/roms/SLOF/clients/net-snk/kernel/entry.S
+++ b/qemu/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/qemu/roms/SLOF/clients/takeover/client.lds b/qemu/roms/SLOF/clients/takeover/client.lds
index 2701d8e1e..0ab428a01 100644
--- a/qemu/roms/SLOF/clients/takeover/client.lds
+++ b/qemu/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/qemu/roms/SLOF/clients/takeover/entry.S b/qemu/roms/SLOF/clients/takeover/entry.S
index a1030eb40..ff482732d 100644
--- a/qemu/roms/SLOF/clients/takeover/entry.S
+++ b/qemu/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/qemu/roms/SLOF/clients/takeover/main.c b/qemu/roms/SLOF/clients/takeover/main.c
index 360d8eaed..1e1b02614 100644
--- a/qemu/roms/SLOF/clients/takeover/main.c
+++ b/qemu/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/qemu/roms/SLOF/include/byteorder.h b/qemu/roms/SLOF/include/byteorder.h
index 60ca67267..d4a2c8ca7 100644
--- a/qemu/roms/SLOF/include/byteorder.h
+++ b/qemu/roms/SLOF/include/byteorder.h
@@ -19,38 +19,36 @@
#include <stdint.h>
-static inline uint16_t
-bswap_16 (uint16_t x)
+typedef uint16_t le16;
+typedef uint32_t le32;
+typedef uint64_t le64;
+
+static inline uint16_t bswap_16 (uint16_t x)
{
return __builtin_bswap16(x);
}
-static inline uint32_t
-bswap_32 (uint32_t x)
+static inline uint32_t bswap_32 (uint32_t x)
{
return __builtin_bswap32(x);
}
-static inline uint64_t
-bswap_64 (uint64_t x)
+static inline uint64_t bswap_64 (uint64_t x)
{
return __builtin_bswap64(x);
}
-static inline void
-bswap_16p (uint16_t *x)
+static inline void bswap_16p (uint16_t *x)
{
*x = __builtin_bswap16(*x);
}
-static inline void
-bswap_32p (uint32_t *x)
+static inline void bswap_32p (uint32_t *x)
{
*x = __builtin_bswap32(*x);
}
-static inline void
-bswap_64p (uint64_t *x)
+static inline void bswap_64p (uint64_t *x)
{
*x = __builtin_bswap64(*x);
}
diff --git a/qemu/roms/SLOF/include/helpers.h b/qemu/roms/SLOF/include/helpers.h
index fb105345e..5b3d711ac 100644
--- a/qemu/roms/SLOF/include/helpers.h
+++ b/qemu/roms/SLOF/include/helpers.h
@@ -30,8 +30,10 @@ extern long SLOF_dma_map_in(void *virt, long size, int cacheable);
extern void SLOF_dma_map_out(long phys, void *virt, long size);
extern long SLOF_pci_config_read32(long offset);
extern long SLOF_pci_config_read16(long offset);
+extern long SLOF_pci_config_read8(long offset);
extern void SLOF_pci_config_write32(long offset, long value);
extern void SLOF_pci_config_write16(long offset, long value);
+extern void SLOF_pci_config_write8(long offset, long value);
extern void *SLOF_translate_my_address(void *addr);
#define offset_of(type, member) ((long) &((type *)0)->member)
diff --git a/qemu/roms/SLOF/include/ppc970/cache.h b/qemu/roms/SLOF/include/ppc970/cache.h
index b74868986..500182ea6 100644
--- a/qemu/roms/SLOF/include/ppc970/cache.h
+++ b/qemu/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/qemu/roms/SLOF/include/ppcp7/cache.h b/qemu/roms/SLOF/include/ppcp7/cache.h
index dc6837196..3c02bb10d 100644
--- a/qemu/roms/SLOF/include/ppcp7/cache.h
+++ b/qemu/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,17 @@ 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)
+
+extern void fast_rfill(char *dst, long size, char pat);
+#define FAST_RFILL(dst, size, pat) fast_rfill(dst, size, pat)
+
static inline uint16_t bswap16_load(uint64_t addr)
{
unsigned int val;
diff --git a/qemu/roms/SLOF/lib/libc/include/stdlib.h b/qemu/roms/SLOF/lib/libc/include/stdlib.h
index dff57f577..5e0eda9ff 100644
--- a/qemu/roms/SLOF/lib/libc/include/stdlib.h
+++ b/qemu/roms/SLOF/lib/libc/include/stdlib.h
@@ -29,5 +29,6 @@ unsigned long int strtoul(const char *nptr, char **endptr, int base);
long int strtol(const char *nptr, char **endptr, int base);
int rand(void);
+void srand(unsigned int seed);
#endif
diff --git a/qemu/roms/SLOF/lib/libc/stdio/vsnprintf.c b/qemu/roms/SLOF/lib/libc/stdio/vsnprintf.c
index e78fb3d8e..21dd04dfe 100644
--- a/qemu/roms/SLOF/lib/libc/stdio/vsnprintf.c
+++ b/qemu/roms/SLOF/lib/libc/stdio/vsnprintf.c
@@ -10,72 +10,110 @@
* IBM Corporation - initial implementation
*****************************************************************************/
+#include <stdbool.h>
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
+#include "ctype.h"
-const static unsigned long long convert[] = {
+static const unsigned long long convert[] = {
0x0, 0xFF, 0xFFFF, 0xFFFFFF, 0xFFFFFFFF,
0xFFFFFFFFFFULL, 0xFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL
};
-
-
static int
-print_itoa(char **buffer,unsigned long value, unsigned short int base)
+print_str_fill(char **buffer, size_t bufsize, char *sizec,
+ const char *str, char c)
{
- const char zeichen[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
- static char sign = 0;
-
- if(base <= 2 || base > 16)
- return 0;
-
- if(value < 0) {
- sign = 1;
- value *= -1;
- }
+ int i, sizei, len;
+ char *bstart = *buffer;
- if(value < base) {
- if(sign) {
- **buffer = '-';
+ sizei = strtoul(sizec, NULL, 10);
+ len = strlen(str);
+ if (sizei > len) {
+ for (i = 0;
+ (i < (sizei - len)) && ((*buffer - bstart) < bufsize);
+ i++) {
+ **buffer = c;
*buffer += 1;
- sign = 0;
}
- **buffer = zeichen[value];
- *buffer += 1;
- } else {
- print_itoa(buffer, value / base, base);
- **buffer = zeichen[(value % base)];
- *buffer += 1;
}
-
return 1;
}
+static int
+print_str(char **buffer, size_t bufsize, const char *str)
+{
+ char *bstart = *buffer;
+ size_t i;
+
+ for (i = 0; (i < strlen(str)) && ((*buffer - bstart) < bufsize); i++) {
+ **buffer = str[i];
+ *buffer += 1;
+ }
+ return 1;
+}
static unsigned int
print_intlen(unsigned long value, unsigned short int base)
{
int i = 0;
- while(value > 0) {
+ while (value > 0) {
value /= base;
i++;
}
- if(i == 0) i = 1;
+ if (i == 0)
+ i = 1;
return i;
}
+static int
+print_itoa(char **buffer, size_t bufsize, unsigned long value,
+ unsigned short base, bool upper)
+{
+ const char zeichen[] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
+ char c;
+ size_t i, len;
+
+ if(base <= 2 || base > 16)
+ return 0;
+
+ len = i = print_intlen(value, base);
+
+ /* Don't print to buffer if bufsize is not enough. */
+ if (len > bufsize)
+ return 0;
+
+ do {
+ c = zeichen[value % base];
+ if (upper)
+ c = toupper(c);
+
+ (*buffer)[--i] = c;
+ value /= base;
+ } while(value);
+
+ *buffer += len;
+
+ return 1;
+}
+
+
static int
-print_fill(char **buffer, char *sizec, unsigned long size, unsigned short int base, char c, int optlen)
+print_fill(char **buffer, size_t bufsize, char *sizec, unsigned long size,
+ unsigned short int base, char c, int optlen)
{
int i, sizei, len;
+ char *bstart = *buffer;
sizei = strtoul(sizec, NULL, 10);
len = print_intlen(size, base) + optlen;
- if(sizei > len) {
- for(i = 0; i < (sizei - len); i++) {
+ if (sizei > len) {
+ for (i = 0;
+ (i < (sizei - len)) && ((*buffer - bstart) < bufsize);
+ i++) {
**buffer = c;
*buffer += 1;
}
@@ -86,17 +124,18 @@ print_fill(char **buffer, char *sizec, unsigned long size, unsigned short int ba
static int
-print_format(char **buffer, const char *format, void *var)
+print_format(char **buffer, size_t bufsize, const char *format, void *var)
{
- unsigned long start;
- unsigned int i = 0, sizei = 0, len = 0, length_mod = sizeof(int);
+ char *start;
+ unsigned int i = 0, length_mod = sizeof(int);
unsigned long value = 0;
unsigned long signBit;
char *form, sizec[32];
char sign = ' ';
+ bool upper = false;
form = (char *) format;
- start = (unsigned long) *buffer;
+ start = *buffer;
form++;
if(*form == '0' || *form == '.') {
@@ -104,7 +143,7 @@ print_format(char **buffer, const char *format, void *var)
form++;
}
- while(*form != '\0') {
+ while ((*form != '\0') && ((*buffer - start) < bufsize)) {
switch(*form) {
case 'u':
case 'd':
@@ -112,57 +151,59 @@ print_format(char **buffer, const char *format, void *var)
sizec[i] = '\0';
value = (unsigned long) var;
signBit = 0x1ULL << (length_mod * 8 - 1);
- if (signBit & value) {
+ if ((*form != 'u') && (signBit & value)) {
**buffer = '-';
*buffer += 1;
value = (-(unsigned long)value) & convert[length_mod];
}
- print_fill(buffer, sizec, value, 10, sign, 0);
- print_itoa(buffer, value, 10);
+ print_fill(buffer, bufsize - (*buffer - start),
+ sizec, value, 10, sign, 0);
+ print_itoa(buffer, bufsize - (*buffer - start),
+ value, 10, upper);
break;
case 'X':
+ upper = true;
case 'x':
sizec[i] = '\0';
value = (unsigned long) var & convert[length_mod];
- print_fill(buffer, sizec, value, 16, sign, 0);
- print_itoa(buffer, value, 16);
+ print_fill(buffer, bufsize - (*buffer - start),
+ sizec, value, 16, sign, 0);
+ print_itoa(buffer, bufsize - (*buffer - start),
+ value, 16, upper);
break;
case 'O':
case 'o':
sizec[i] = '\0';
value = (long int) var & convert[length_mod];
- print_fill(buffer, sizec, value, 8, sign, 0);
- print_itoa(buffer, value, 8);
+ print_fill(buffer, bufsize - (*buffer - start),
+ sizec, value, 8, sign, 0);
+ print_itoa(buffer, bufsize - (*buffer - start),
+ value, 8, upper);
break;
case 'p':
sizec[i] = '\0';
- print_fill(buffer, sizec, (unsigned long) var, 16, ' ', 2);
- **buffer = '0';
- *buffer += 1;
- **buffer = 'x';
- *buffer += 1;
- print_itoa(buffer,(unsigned long) var, 16);
+ print_fill(buffer, bufsize - (*buffer - start),
+ sizec, (unsigned long) var, 16, ' ', 2);
+ print_str(buffer, bufsize - (*buffer - start),
+ "0x");
+ print_itoa(buffer, bufsize - (*buffer - start),
+ (unsigned long) var, 16, upper);
break;
case 'c':
sizec[i] = '\0';
- print_fill(buffer, sizec, 1, 10, ' ', 0);
+ print_fill(buffer, bufsize - (*buffer - start),
+ sizec, 1, 10, ' ', 0);
**buffer = (unsigned long) var;
*buffer += 1;
break;
case 's':
sizec[i] = '\0';
- sizei = strtoul(sizec, NULL, 10);
- len = strlen((char *) var);
- if(sizei > len) {
- for(i = 0; i < (sizei - len); i++) {
- **buffer = ' ';
- *buffer += 1;
- }
- }
- for(i = 0; i < strlen((char *) var); i++) {
- **buffer = ((char *) var)[i];
- *buffer += 1;
- }
+ print_str_fill(buffer,
+ bufsize - (*buffer - start), sizec,
+ (char *) var, ' ');
+
+ print_str(buffer, bufsize - (*buffer - start),
+ (char *) var);
break;
case 'l':
form++;
@@ -182,6 +223,9 @@ print_format(char **buffer, const char *format, void *var)
length_mod = sizeof(short int);
}
break;
+ case 'z':
+ length_mod = sizeof(size_t);
+ break;
default:
if(*form >= '0' && *form <= '9')
sizec[i++] = *form;
@@ -206,6 +250,16 @@ vsnprintf(char *buffer, size_t bufsize, const char *format, va_list arg)
bstart = buffer;
ptr = (char *) format;
+ /*
+ * Return from here if size passed is zero, otherwise we would
+ * overrun buffer while setting NULL character at the end.
+ */
+ if (!buffer || !bufsize)
+ return 0;
+
+ /* Leave one space for NULL character */
+ bufsize--;
+
while(*ptr != '\0' && (buffer - bstart) < bufsize)
{
if(*ptr == '%') {
@@ -224,7 +278,9 @@ vsnprintf(char *buffer, size_t bufsize, const char *format, va_list arg)
if(*ptr == '%') {
*buffer++ = '%';
} else {
- print_format(&buffer, formstr, va_arg(arg, void *));
+ print_format(&buffer,
+ bufsize - (buffer - bstart),
+ formstr, va_arg(arg, void *));
}
ptr++;
} else {
diff --git a/qemu/roms/SLOF/lib/libc/stdlib/rand.c b/qemu/roms/SLOF/lib/libc/stdlib/rand.c
index 87e3efd29..39f5a9a2c 100644
--- a/qemu/roms/SLOF/lib/libc/stdlib/rand.c
+++ b/qemu/roms/SLOF/lib/libc/stdlib/rand.c
@@ -18,7 +18,12 @@ static unsigned long _rand = 1;
int
rand(void)
{
- _rand = _rand * 25364735 + 34563;
+ _rand = _rand * 1237732973 + 34563;
- return ((unsigned int) (_rand << 16) & RAND_MAX);
+ return ((unsigned int) (_rand >> 16) & RAND_MAX);
+}
+
+void srand(unsigned int seed)
+{
+ _rand = seed;
}
diff --git a/qemu/roms/SLOF/lib/libhvcall/Makefile b/qemu/roms/SLOF/lib/libhvcall/Makefile
index 2a9b2d7d1..def532509 100644
--- a/qemu/roms/SLOF/lib/libhvcall/Makefile
+++ b/qemu/roms/SLOF/lib/libhvcall/Makefile
@@ -24,7 +24,7 @@ TARGET = ../libhvcall.a
all: $(TARGET)
-SRCS = brokensc1.c
+SRCS = brokensc1.c rfill.c
SRCSS = hvcall.S
diff --git a/qemu/roms/SLOF/lib/libhvcall/rfill.c b/qemu/roms/SLOF/lib/libhvcall/rfill.c
new file mode 100644
index 000000000..5407cd2a6
--- /dev/null
+++ b/qemu/roms/SLOF/lib/libhvcall/rfill.c
@@ -0,0 +1,38 @@
+/*****************************************************************************
+ * Fast function for filling cache-inhibited memory regions via h-call.
+ *
+ * Copyright 2015 Red Hat, Inc.
+ *
+ * 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:
+ * Thomas Huth, Red Hat Inc. - initial implementation
+ *****************************************************************************/
+
+#include <cache.h>
+#include <string.h>
+
+typedef unsigned long type_u;
+
+/**
+ * fast_rfill is the implementation of the FAST_RFILL macro with h-calls.
+ * This is defined here instead of cache.h since we need a temporary
+ * local buffer - and that caused stack size problems in engine() when
+ * we used it directly in the FAST_RFILL macro.
+ */
+void fast_rfill(char *dst, long size, char pat)
+{
+ type_u buf[64];
+
+ memset(buf, pat, size < sizeof(buf) ? size : sizeof(buf));
+
+ while (size > sizeof(buf)) {
+ FAST_MRMOVE(buf, dst, sizeof(buf));
+ dst += sizeof(buf);
+ size -= sizeof(buf);
+ }
+ FAST_MRMOVE(buf, dst, size);
+}
diff --git a/qemu/roms/SLOF/lib/libnvram/envvar.c b/qemu/roms/SLOF/lib/libnvram/envvar.c
index 87aaf27a0..ee943fce5 100644
--- a/qemu/roms/SLOF/lib/libnvram/envvar.c
+++ b/qemu/roms/SLOF/lib/libnvram/envvar.c
@@ -17,7 +17,7 @@
#include "nvram.h"
/* returns the offset of the first byte after the searched envvar */
-static int get_past_env_pos(partition_t part, char *envvar)
+static int get_past_env_pos(partition_t part, char *envvar, int evlen)
{
int offset, len;
static char temp[256];
@@ -32,7 +32,7 @@ static int get_past_env_pos(partition_t part, char *envvar)
while((data=nvram_read_byte(offset++)) && len < 256) {
temp[len++]=data;
}
- if (!strncmp(envvar, temp, strlen(envvar))) {
+ if (!strncmp(envvar, temp, evlen)) {
return offset;
}
} while (len);
@@ -43,16 +43,16 @@ static int get_past_env_pos(partition_t part, char *envvar)
/**
* @param partition name of the envvar partition
* @param envvar name of the environment variable
+ * @param evlen string length of the envvar parameter
* @return pointer to temporary string containing the value of envvar
*/
-
-char *get_env(partition_t part, char *envvar)
+char *nvram_get_env(partition_t part, char *envvar, int evlen)
{
static char temp[256+1];
int len, offset;
uint8_t data;
- DEBUG("get_env %s... ", envvar);
+ DEBUG("nvram_get_env %p... ", envvar);
if(!part.addr) {
/* ERROR: No environment variable partition */
DEBUG("invalid partition.\n");
@@ -68,7 +68,7 @@ char *get_env(partition_t part, char *envvar)
}
temp[len]=0;
- if (!strncmp(envvar, temp, strlen(envvar))) {
+ if (!strncmp(envvar, temp, evlen)) {
int pos=0;
while (temp[pos]!='=' && pos < len) pos++;
// DEBUG("value='%s'\n", temp+pos+1);
@@ -100,7 +100,7 @@ static int find_last_envvar(partition_t part)
return -1;
}
-int add_env(partition_t part, char *envvar, char *value)
+int nvram_add_env(partition_t part, char *envvar, int evlen, char *value, int vallen)
{
int freespace, last, len, offset;
unsigned int i;
@@ -112,7 +112,7 @@ int add_env(partition_t part, char *envvar, char *value)
freespace = part.addr+part.len-last;
/* how long is the entry we want to write? */
- len = strlen(envvar) + strlen(value) + 2;
+ len = evlen + vallen + 2;
if(freespace<len) {
// TODO try to increase partition size
@@ -121,18 +121,18 @@ int add_env(partition_t part, char *envvar, char *value)
offset=last;
- for(i=0; i<strlen(envvar); i++)
+ for (i = 0; i < evlen; i++)
nvram_write_byte(offset++, envvar[i]);
nvram_write_byte(offset++, '=');
- for(i=0; i<strlen(value); i++)
+ for (i = 0; i < vallen; i++)
nvram_write_byte(offset++, value[i]);
return 0;
}
-int del_env(partition_t part, char *envvar)
+int nvram_del_env(partition_t part, char *envvar, int evlen)
{
int last, current, pos, i;
char *buffer;
@@ -141,7 +141,7 @@ int del_env(partition_t part, char *envvar)
return -1;
last=find_last_envvar(part);
- current = pos = get_past_env_pos(part, envvar);
+ current = pos = get_past_env_pos(part, envvar, evlen);
// TODO is this really required?
/* go back to non-0 value */
@@ -168,25 +168,25 @@ int del_env(partition_t part, char *envvar)
return 0;
}
-int set_env(partition_t part, char *envvar, char *value)
+int nvram_set_env(partition_t part, char *envvar, int evlen, char *value, int vallen)
{
char *oldvalue, *buffer;
int last, current, buffersize, i;
- DEBUG("set_env %lx[%lx]: %s=%s\n", part.addr, part.len, envvar, value);
+ DEBUG("nvram_set_env %lx[%lx]: %p=>%p\n", part.addr, part.len, envvar, value);
if(!part.addr)
return -1;
/* Check whether the environment variable exists already */
- oldvalue = get_env(part, envvar);
+ oldvalue = nvram_get_env(part, envvar, evlen);
- if(oldvalue==NULL)
- return add_env(part, envvar, value);
+ if (oldvalue == NULL)
+ return nvram_add_env(part, envvar, evlen, value, vallen);
/* The value did not change. So we succeeded! */
- if(!strncmp(oldvalue, value, strlen(value)+1))
+ if (strlen(oldvalue) == vallen && !strncmp(oldvalue, value, vallen))
return 0;
/* we need to overwrite environment variables, back them up first */
@@ -195,7 +195,7 @@ int set_env(partition_t part, char *envvar, char *value)
/* allocate a buffer */
last=find_last_envvar(part);
- current=get_past_env_pos(part, envvar);
+ current = get_past_env_pos(part, envvar, evlen);
buffersize = last - current;
buffer=get_nvram_buffer(buffersize);
if(!buffer)
@@ -214,7 +214,7 @@ int set_env(partition_t part, char *envvar, char *value)
current++;
/* Write the new value */
- for(i=0; i<(int)strlen(value); i++) {
+ for(i = 0; i < vallen; i++) {
nvram_write_byte(current++, value[i]);
}
diff --git a/qemu/roms/SLOF/lib/libnvram/libnvram.code b/qemu/roms/SLOF/lib/libnvram/libnvram.code
index 723941d3e..8481f57f5 100644
--- a/qemu/roms/SLOF/lib/libnvram/libnvram.code
+++ b/qemu/roms/SLOF/lib/libnvram/libnvram.code
@@ -11,17 +11,6 @@
*****************************************************************************/
#include <nvram.h>
-#define STRING_INIT(str) \
- char str[255]; \
- char * str##_address; \
- int str##_length;
-
-#define STRING_FROM_STACK(str) \
- str##_length = TOS.u; POP; \
- str##_address = TOS.a; POP; \
- memcpy(str, str##_address, str##_length); \
- memset(str + str##_length, 0, 255 - str##_length);
-
PRIM(nvram_X2d_c_X40)
unsigned int offset = TOS.u;
TOS.u=nvram_read_byte(offset);
@@ -80,21 +69,18 @@ MIRP
/* get-named-nvram-partition ( name.addr name.len -- addr len FAILED? ) */
PRIM(get_X2d_named_X2d_nvram_X2d_partition)
- STRING_INIT(name)
partition_t partition;
+ int namelen = TOS.n; POP;
- STRING_FROM_STACK(name)
- partition = get_partition(-1, name);
+ partition = get_partition_fs(TOS.a, namelen);
if(partition.len && partition.len != -1) {
- PUSH;
TOS.u = partition.addr;
PUSH;
TOS.u = partition.len;
PUSH;
TOS.u = 0; // FALSE
} else {
- PUSH;
TOS.u = -1; // TRUE
}
MIRP
@@ -103,23 +89,16 @@ MIRP
/* new-nvram-partition ( type name.addr name.len len -- part.offs part.len FALSE | TRUE) */
PRIM(new_X2d_nvram_X2d_partition)
- int type, len, i, slen;
- char name[12], *addr;
+ int type, len, namelen;
partition_t partition;
+ char *name;
len = TOS.u; POP;
- slen = TOS.u; POP;
- addr = (char *)TOS.u; POP;
+ namelen = TOS.u; POP;
+ name = (char *)TOS.u; POP;
type = TOS.u; POP;
- for (i=0; i<12; i++) {
- if(slen>i)
- name[i]=addr[i];
- else
- name[i]=0;
- }
-
- partition=new_nvram_partition(type, name, len);
+ partition = new_nvram_partition_fs(type, name, namelen, len);
if(!partition.len) {
PUSH; TOS.u = -1; // TRUE
@@ -165,15 +144,17 @@ MIRP
// ( part.start part.len name.addr name.len -- var.addr var.len TRUE | false )
PRIM(internal_X2d_get_X2d_env)
- STRING_INIT(name)
+ char *name;
+ int namelen;
partition_t part;
char *val;
- STRING_FROM_STACK(name)
+ namelen = TOS.u; POP;
+ name = TOS.a; POP;
part.len = TOS.u; POP;
part.addr = TOS.u; POP;
- val=get_env(part, name);
+ val = nvram_get_env(part, name, namelen);
if(val) {
PUSH; TOS.a = val;
PUSH; TOS.u = strlen(val);
@@ -185,17 +166,19 @@ MIRP
// ( part.start part.len name.addr name.len val.addr val.len -- FALSE|TRUE)
PRIM(internal_X2d_add_X2d_env)
- STRING_INIT(name)
- STRING_INIT(value)
+ char *name, *val;
+ int namelen, vallen;
partition_t part;
int ret;
- STRING_FROM_STACK(value)
- STRING_FROM_STACK(name)
+ vallen = TOS.u; POP;
+ val = TOS.a; POP;
+ namelen = TOS.u; POP;
+ name = TOS.a; POP;
part.len = TOS.u; POP;
part.addr = TOS.u; POP;
- ret=add_env(part, name, value);
+ ret = nvram_add_env(part, name, namelen, val, vallen);
if(ret) {
PUSH; TOS.u = -1; // TRUE
} else {
@@ -205,15 +188,17 @@ MIRP
// ( part.addr part.len name.addr name.len -- FALSE|TRUE)
PRIM(internal_X2d_del_X2d_env)
- STRING_INIT(name)
+ char *name;
+ int namelen;
partition_t part;
int ret;
- STRING_FROM_STACK(name);
+ namelen = TOS.u; POP;
+ name = TOS.a; POP;
part.len = TOS.u; POP;
part.addr = TOS.u; POP;
- ret=del_env(part, name);
+ ret = nvram_del_env(part, name, namelen);
if(ret) {
PUSH; TOS.u = -1; // TRUE
} else {
@@ -224,17 +209,19 @@ MIRP
// internal-set-env ( part.addr part.len name.addr name.len val.addr val.len -- FALSE|TRUE)
PRIM(internal_X2d_set_X2d_env)
- STRING_INIT(name)
- STRING_INIT(value)
+ char *name, *value;
+ int namelen, valuelen;
partition_t part;
int ret;
- STRING_FROM_STACK(value)
- STRING_FROM_STACK(name)
+ valuelen = TOS.u; POP;
+ value = TOS.a; POP;
+ namelen = TOS.u; POP;
+ name = TOS.a; POP;
part.len = TOS.u; POP;
part.addr = TOS.u; POP;
- ret=set_env(part, name, value);
+ ret = nvram_set_env(part, name, namelen, value, valuelen);
if(ret) {
PUSH; TOS.u = -1; // TRUE
} else {
diff --git a/qemu/roms/SLOF/lib/libnvram/nvram.c b/qemu/roms/SLOF/lib/libnvram/nvram.c
index 5c1137669..473814e5c 100644
--- a/qemu/roms/SLOF/lib/libnvram/nvram.c
+++ b/qemu/roms/SLOF/lib/libnvram/nvram.c
@@ -358,6 +358,17 @@ partition_t get_partition(unsigned int type, char *name)
return ret;
}
+/* Get partition specified by a Forth string */
+partition_t get_partition_fs(char *name, int namelen)
+{
+ char buf[namelen + 1];
+
+ memcpy(buf, name, namelen);
+ buf[namelen] = 0;
+
+ return get_partition(-1, buf);
+}
+
void erase_nvram(int offset, int len)
{
int i;
@@ -466,6 +477,22 @@ partition_t new_nvram_partition(int type, char *name, int len)
return new_part;
}
+partition_t new_nvram_partition_fs(int type, char *name, int namelen, int len)
+{
+ char buf[13];
+ int i;
+
+ for (i = 0; i < 12; i++) {
+ if (i < namelen)
+ buf[i] = name[i];
+ else
+ buf[i] = 0;
+ }
+ buf[12] = 0;
+
+ return new_nvram_partition(type, buf, len);
+}
+
/**
* @param partition partition structure pointing to the partition to wipe.
*/
diff --git a/qemu/roms/SLOF/lib/libnvram/nvram.h b/qemu/roms/SLOF/lib/libnvram/nvram.h
index fa6bdd425..73fe44424 100644
--- a/qemu/roms/SLOF/lib/libnvram/nvram.h
+++ b/qemu/roms/SLOF/lib/libnvram/nvram.h
@@ -51,9 +51,11 @@ char *get_nvram_buffer(int len);
void free_nvram_buffer(char *buffer);
int nvramlog_printf(const char* fmt, ...);
partition_t get_partition(unsigned int type, char *name);
+partition_t get_partition_fs(char *name, int namelen);
void erase_nvram(int offset, int len);
int wipe_partition(partition_t partition, int header_only);
partition_t new_nvram_partition(int type, char *name, int len);
+partition_t new_nvram_partition_fs(int type, char *name, int namelen, int len);
int increase_nvram_partition_size(partition_t partition, int newsize);
int clear_nvram_partition(partition_t part);
int delete_nvram_partition(partition_t part);
@@ -65,9 +67,9 @@ void nvram_init(uint32_t store_token, uint32_t fetch_token,
unsigned int get_nvram_size(void);
/* envvar.c */
-char *get_env(partition_t part, char *envvar);
-int add_env(partition_t part, char *envvar, char *value);
-int del_env(partition_t part, char *envvar);
-int set_env(partition_t part, char *envvar, char *value);
+char *nvram_get_env(partition_t part, char *envvar, int evlen);
+int nvram_add_env(partition_t part, char *envvar, int evlen, char *value, int vallen);
+int nvram_del_env(partition_t part, char *envvar, int evlen);
+int nvram_set_env(partition_t part, char *envvar, int evlen, char *val, int vlen);
#endif
diff --git a/qemu/roms/SLOF/lib/libusb/usb-core.c b/qemu/roms/SLOF/lib/libusb/usb-core.c
index 6719c5726..4c720ce2f 100644
--- a/qemu/roms/SLOF/lib/libusb/usb-core.c
+++ b/qemu/roms/SLOF/lib/libusb/usb-core.c
@@ -383,8 +383,6 @@ int usb_hid_exit(void *vdev)
return true;
}
-#define usb_get_intf_class(x) ((x & 0x00FF0000) >> 16)
-
int usb_msc_init(void *vdev)
{
struct usb_dev *dev;
@@ -420,7 +418,7 @@ int usb_msc_exit(void *vdev)
return true;
}
-static int usb_msc_reset(struct usb_dev *dev)
+int usb_msc_reset(struct usb_dev *dev)
{
struct usb_dev_req req;
@@ -477,7 +475,7 @@ static int usb_handle_device(struct usb_dev *dev, struct usb_dev_config_descr *c
case DESCR_TYPE_HUB:
break;
default:
- printf("ptr %p desc_type %d\n", ptr, desc_type);
+ dprintf("ptr %p desc_type %d\n", ptr, desc_type);
}
ptr += desc_len;
len -= desc_len;
@@ -485,7 +483,7 @@ static int usb_handle_device(struct usb_dev *dev, struct usb_dev_config_descr *c
return true;
}
-int setup_new_device(struct usb_dev *dev, unsigned int port)
+int usb_setup_new_device(struct usb_dev *dev, unsigned int port)
{
struct usb_dev_descr descr;
struct usb_dev_config_descr cfg;
@@ -552,35 +550,6 @@ int setup_new_device(struct usb_dev *dev, unsigned int port)
if (!usb_handle_device(dev, &cfg, data, len))
goto fail_mem_free;
- switch (usb_get_intf_class(dev->class)) {
- case 3:
- dprintf("HID found %06X\n", dev->class);
- slof_usb_handle(dev);
- break;
- case 8:
- dprintf("MASS STORAGE found %d %06X\n", dev->intf_num,
- dev->class);
- if ((dev->class & 0x50) != 0x50) { /* Bulk-only supported */
- printf("Device not supported %06X\n", dev->class);
- goto fail_mem_free;
- }
-
- if (!usb_msc_reset(dev)) {
- printf("%s: bulk reset failed\n", __func__);
- goto fail_mem_free;
- }
- SLOF_msleep(100);
- slof_usb_handle(dev);
- break;
- case 9:
- dprintf("HUB found\n");
- slof_usb_handle(dev);
- break;
- default:
- printf("USB Interface class -%x- Not supported\n", dev->class);
- break;
- }
-
SLOF_dma_free(data, len);
return true;
fail_mem_free:
diff --git a/qemu/roms/SLOF/lib/libusb/usb-core.h b/qemu/roms/SLOF/lib/libusb/usb-core.h
index 7441979e9..a35df3485 100644
--- a/qemu/roms/SLOF/lib/libusb/usb-core.h
+++ b/qemu/roms/SLOF/lib/libusb/usb-core.h
@@ -261,6 +261,8 @@ struct usb_hcd_ops {
unsigned int usb_type;
};
+#define usb_get_intf_class(x) ((x & 0x00FF0000) >> 16)
+
extern void usb_hcd_register(struct usb_hcd_ops *ops);
extern struct usb_pipe *usb_get_pipe(struct usb_dev *dev, struct usb_ep_descr *ep,
char *buf, size_t len);
@@ -269,11 +271,12 @@ extern int usb_poll_intr(struct usb_pipe *pipe, uint8_t *buf);
extern int usb_send_ctrl(struct usb_pipe *pipe, struct usb_dev_req *req, void *data);
extern struct usb_dev *usb_devpool_get(void);
extern void usb_devpool_put(struct usb_dev *);
-extern int setup_new_device(struct usb_dev *dev, unsigned int port);
-extern int slof_usb_handle(struct usb_dev *dev);
+extern int usb_setup_new_device(struct usb_dev *dev, unsigned int port);
+extern void usb_slof_populate_new_device(struct usb_dev *dev);
extern int usb_dev_populate_pipe(struct usb_dev *dev, struct usb_ep_descr *ep,
void *buf, size_t len);
extern int usb_hid_kbd_init(struct usb_dev *dev);
extern int usb_hid_kbd_exit(struct usb_dev *dev);
+extern int usb_msc_reset(struct usb_dev *dev);
extern void usb_msc_resetrecovery(struct usb_dev *dev);
#endif
diff --git a/qemu/roms/SLOF/lib/libusb/usb-ehci.c b/qemu/roms/SLOF/lib/libusb/usb-ehci.c
index 4cca0da15..60af9e101 100644
--- a/qemu/roms/SLOF/lib/libusb/usb-ehci.c
+++ b/qemu/roms/SLOF/lib/libusb/usb-ehci.c
@@ -79,7 +79,9 @@ static int ehci_hub_check_ports(struct ehci_hcd *ehcd)
dprintf("usb-ehci: allocated device %p\n", dev);
dev->hcidev = ehcd->hcidev;
dev->speed = USB_HIGH_SPEED; /* TODO: Check for Low/Full speed device */
- if (!setup_new_device(dev, i))
+ if (usb_setup_new_device(dev, i))
+ usb_slof_populate_new_device(dev);
+ else
printf("usb-ehci: unable to setup device on port %d\n", i);
}
}
diff --git a/qemu/roms/SLOF/lib/libusb/usb-hid.c b/qemu/roms/SLOF/lib/libusb/usb-hid.c
index f0cab8a69..ac6616aba 100644
--- a/qemu/roms/SLOF/lib/libusb/usb-hid.c
+++ b/qemu/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/qemu/roms/SLOF/lib/libusb/usb-hub.c b/qemu/roms/SLOF/lib/libusb/usb-hub.c
index 7059cd019..bb8a30915 100644
--- a/qemu/roms/SLOF/lib/libusb/usb-hub.c
+++ b/qemu/roms/SLOF/lib/libusb/usb-hub.c
@@ -175,7 +175,9 @@ unsigned int usb_hub_init(void *hubdev)
newdev = usb_devpool_get();
dprintf("usb-hub: allocated device %p\n", newdev);
newdev->hcidev = dev->hcidev;
- if (!setup_new_device(newdev, i))
+ if (usb_setup_new_device(newdev, i))
+ usb_slof_populate_new_device(newdev);
+ else
printf("usb-hub: unable to setup device on port %d\n", i);
}
}
diff --git a/qemu/roms/SLOF/lib/libusb/usb-ohci.c b/qemu/roms/SLOF/lib/libusb/usb-ohci.c
index 0e8400481..d06c754d1 100644
--- a/qemu/roms/SLOF/lib/libusb/usb-ohci.c
+++ b/qemu/roms/SLOF/lib/libusb/usb-ohci.c
@@ -192,7 +192,9 @@ static void ohci_hub_check_ports(struct ohci_hcd *ohcd)
dev = usb_devpool_get();
dprintf("usb-ohci: Device reset, setting up %p\n", dev);
dev->hcidev = ohcd->hcidev;
- if (!setup_new_device(dev, i))
+ if (usb_setup_new_device(dev, i))
+ usb_slof_populate_new_device(dev);
+ else
printf("usb-ohci: unable to setup device on port %d\n", i);
}
if (port_status & RH_PS_PESC) {
@@ -252,7 +254,7 @@ static int ohci_alloc_pipe_pool(struct ohci_hcd *ohcd)
return false;
ohcd->pool_phys = opipe_phys = SLOF_dma_map_in(opipe, OHCI_PIPE_POOL_SIZE, true);
- dprintf("usb-ohci: %s opipe %x, opipe_phys %x size %d count %d\n",
+ dprintf("usb-ohci: %s opipe %p, opipe_phys %lx size %ld count %d\n",
__func__, opipe, opipe_phys, sizeof(*opipe), count);
/* Although an array, link them*/
for (i = 0, curr = opipe, prev = NULL; i < count; i++, curr++) {
@@ -446,7 +448,7 @@ again:
/* Interrupt is there, read from done_head pointer */
td_phys = (struct ohci_td *)(uint64_t) le32_to_cpu(hcca->done_head);
if (!td_phys) {
- dprintf("Again td_phys null %ld\n");
+ dprintf("Again td_phys null\n");
goto again;
}
hcca->done_head = 0;
@@ -553,7 +555,7 @@ static int ohci_send_ctrl(struct usb_pipe *pipe, struct usb_dev_req *req, void *
attr = EDA_FADDR(pipe->dev->addr) | EDA_MPS(pipe->mps) | EDA_SKIP;
ohci_fill_ed(ed, PTR_U32(td_phys), td_next, attr, 0);
ed->tailp = 0; /* HACK */
- dprintf("usb-ohci: %s - td_start %x td_end %x req %x\n", __func__,
+ dprintf("usb-ohci: %s - td_start %p td_end %lx req %lx\n", __func__,
td_phys, td_next, req_phys);
mb();
ed->attr &= cpu_to_le32(~EDA_SKIP);
@@ -642,7 +644,7 @@ static int ohci_transfer_bulk(struct usb_pipe *pipe, void *td_ptr,
td = tds = (struct ohci_td *) td_ptr;
td_phys = (long)td_phys_ptr;
- dprintf("usb-ohci: %s pipe %p data_phys %p len %d DIR_IN %d td %p td_phys %p\n",
+ dprintf("usb-ohci: %s pipe %p data_phys %p len %d DIR_IN %d td %p td_phys %lx\n",
__func__, pipe, data_phys, datalen, dir, td, td_phys);
if (!tds) {
@@ -672,7 +674,7 @@ static int ohci_transfer_bulk(struct usb_pipe *pipe, void *td_ptr,
| EDA_SKIP | pipe->dev->speed | EDA_EP(pipe->epno);
td_next = ohci_get_td_phys(td, tds, td_phys);
ohci_fill_ed(ed, td_phys, td_next, attr, 0);
- dprintf("usb-ohci: %s - tds %p td %p\n", __func__, td_phys, td_next);
+ dprintf("usb-ohci: %s - tds %lx td %lx\n", __func__, td_phys, td_next);
mb();
ed->attr &= cpu_to_le32(~EDA_SKIP);
@@ -778,7 +780,7 @@ static int ohci_get_pipe_intr(struct usb_pipe *pipe, struct ohci_hcd *ohcd,
td->attr = cpu_to_le32(TDA_DP_IN | TDA_ROUNDING | TDA_CC);
td->next_td = cpu_to_le32(td_next);
td->be = cpu_to_le32(PTR_U32(ptr) + mps - 1);
- dprintf("td %x td++ %x ptr %x be %x\n",
+ dprintf("td %p td++ %x ptr %p be %x\n",
td, le32_to_cpu(td->next_td),
ptr, (PTR_U32(ptr) + mps - 1));
}
diff --git a/qemu/roms/SLOF/lib/libusb/usb-slof.c b/qemu/roms/SLOF/lib/libusb/usb-slof.c
index de841f0fb..ff070559a 100644
--- a/qemu/roms/SLOF/lib/libusb/usb-slof.c
+++ b/qemu/roms/SLOF/lib/libusb/usb-slof.c
@@ -26,7 +26,7 @@
#define dprintf(_x ...)
#endif
-int slof_usb_handle(struct usb_dev *dev)
+static int slof_usb_handle(struct usb_dev *dev)
{
struct slof_usb_dev sdev;
sdev.port = dev->port;
@@ -59,3 +59,35 @@ int slof_usb_handle(struct usb_dev *dev)
}
return true;
}
+
+void usb_slof_populate_new_device(struct usb_dev *dev)
+{
+ switch (usb_get_intf_class(dev->class)) {
+ case 3:
+ dprintf("HID found %06X\n", dev->class);
+ slof_usb_handle(dev);
+ break;
+ case 8:
+ dprintf("MASS STORAGE found %d %06X\n", dev->intf_num,
+ dev->class);
+ if ((dev->class & 0x50) != 0x50) { /* Bulk-only supported */
+ printf("Device not supported %06X\n", dev->class);
+ break;
+ }
+
+ if (!usb_msc_reset(dev)) {
+ printf("%s: bulk reset failed\n", __func__);
+ break;
+ }
+ SLOF_msleep(100);
+ slof_usb_handle(dev);
+ break;
+ case 9:
+ dprintf("HUB found\n");
+ slof_usb_handle(dev);
+ break;
+ default:
+ printf("USB Interface class -%x- Not supported\n", dev->class);
+ break;
+ }
+}
diff --git a/qemu/roms/SLOF/lib/libusb/usb-xhci.c b/qemu/roms/SLOF/lib/libusb/usb-xhci.c
index 0c3d6e47f..858cd12f9 100644
--- a/qemu/roms/SLOF/lib/libusb/usb-xhci.c
+++ b/qemu/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;
}
@@ -601,8 +608,10 @@ static bool xhci_alloc_dev(struct xhci_hcd *xhcd, uint32_t slot_id, uint32_t por
dev->port = newport;
dev->priv = xdev;
xdev->dev = dev;
- if (setup_new_device(dev, newport))
+ if (usb_setup_new_device(dev, newport)) {
+ usb_slof_populate_new_device(dev);
return true;
+ }
xhci_free_ctx(&xdev->out_ctx, XHCI_CTX_BUF_SIZE);
fail_control_seg:
@@ -616,6 +625,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 +647,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 +673,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 +686,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 +703,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 +727,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 +899,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 +1122,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 +1147,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 +1162,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 +1188,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 +1276,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 +1298,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 +1382,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 +1408,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 +1426,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 +1478,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/qemu/roms/SLOF/lib/libusb/usb-xhci.h b/qemu/roms/SLOF/lib/libusb/usb-xhci.h
index faeb07ead..3fc7e7889 100644
--- a/qemu/roms/SLOF/lib/libusb/usb-xhci.h
+++ b/qemu/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/qemu/roms/SLOF/lib/libvirtio/p9.c b/qemu/roms/SLOF/lib/libvirtio/p9.c
index a55662994..0e5953031 100644
--- a/qemu/roms/SLOF/lib/libvirtio/p9.c
+++ b/qemu/roms/SLOF/lib/libvirtio/p9.c
@@ -143,7 +143,7 @@ int p9_transaction(p9_connection_t *connection)
{
int rc;
int tx_size = GET_SIZE;
- int rx_size = connection->message_size;
+ uint32_t rx_size = connection->message_size;
if (transact == NULL) {
return P9_NO_TRANSPORT;
diff --git a/qemu/roms/SLOF/lib/libvirtio/p9.h b/qemu/roms/SLOF/lib/libvirtio/p9.h
index 7df9ef441..3a35e80ed 100644
--- a/qemu/roms/SLOF/lib/libvirtio/p9.h
+++ b/qemu/roms/SLOF/lib/libvirtio/p9.h
@@ -33,7 +33,7 @@
#define P9_PARTIAL_WALK 1
typedef int (*p9_transact_t)(void *opaque, uint8_t *tx, int tx_size,
- uint8_t *rx, int *rx_size);
+ uint8_t *rx, uint32_t *rx_size);
typedef struct {
uint32_t message_size;
diff --git a/qemu/roms/SLOF/lib/libvirtio/virtio-9p.c b/qemu/roms/SLOF/lib/libvirtio/virtio-9p.c
index 5a5fd01da..fc5db9154 100644
--- a/qemu/roms/SLOF/lib/libvirtio/virtio-9p.c
+++ b/qemu/roms/SLOF/lib/libvirtio/virtio-9p.c
@@ -19,6 +19,7 @@
#include "virtio-9p.h"
#include "p9.h"
+static struct vqs vq;
/**
* Notes for 9P Server config:
@@ -86,7 +87,7 @@ static void dprint_buffer(const char *name, uint8_t *buffer, int length)
* @return 0 = success, -ve = error.
*/
static int virtio_9p_transact(void *opaque, uint8_t *tx, int tx_size, uint8_t *rx,
- int *rx_size)
+ uint32_t *rx_size)
{
struct virtio_device *dev = opaque;
struct vring_desc *desc;
@@ -165,6 +166,7 @@ int virtio_9p_init(struct virtio_device *dev, void *tx_buf, void *rx_buf,
int buf_size)
{
struct vring_avail *vq_avail;
+ int status = VIRTIO_STAT_ACKNOWLEDGE;
/* Check for double open */
if (__buf_size)
@@ -174,28 +176,31 @@ int virtio_9p_init(struct virtio_device *dev, void *tx_buf, void *rx_buf,
dprintf("%s : device at %p\n", __func__, dev->base);
dprintf("%s : type is %04x\n", __func__, dev->type);
- /* Reset device */
- // XXX That will clear the virtq base. We need to move
- // initializing it to here anyway
- //
- // virtio_reset_device(dev);
+ /* Keep it disabled until the driver is 1.0 capable */
+ dev->is_modern = false;
+
+ virtio_reset_device(dev);
/* Acknowledge device. */
- virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE);
+ virtio_set_status(dev, status);
/* Tell HV that we know how to drive the device. */
- virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE | VIRTIO_STAT_DRIVER);
+ status |= VIRTIO_STAT_DRIVER;
+ virtio_set_status(dev, status);
/* Device specific setup - we do not support special features */
virtio_set_guest_features(dev, 0);
+ if (virtio_queue_init_vq(dev, &vq, 0))
+ goto dev_error;
+
vq_avail = virtio_get_vring_avail(dev, 0);
vq_avail->flags = VRING_AVAIL_F_NO_INTERRUPT;
vq_avail->idx = 0;
/* Tell HV that setup succeeded */
- virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE | VIRTIO_STAT_DRIVER
- |VIRTIO_STAT_DRIVER_OK);
+ status |= VIRTIO_STAT_DRIVER_OK;
+ virtio_set_status(dev, status);
/* Setup 9P library. */
p9_reg_transport(virtio_9p_transact, dev,(uint8_t *)tx_buf,
@@ -203,6 +208,12 @@ int virtio_9p_init(struct virtio_device *dev, void *tx_buf, void *rx_buf,
dprintf("%s : complete\n", __func__);
return 0;
+
+dev_error:
+ printf("%s: failed\n", __func__);
+ status |= VIRTIO_STAT_FAILED;
+ virtio_set_status(dev, status);
+ return -1;
}
/**
@@ -228,7 +239,7 @@ void virtio_9p_shutdown(struct virtio_device *dev)
* @param buffer[out] Where to read the file to.
* @return +ve = amount of data read, -ve = error.
*/
-int virtio_9p_load(struct virtio_device *dev, const char *file_name, uint8_t *buffer)
+long virtio_9p_load(struct virtio_device *dev, const char *file_name, uint8_t *buffer)
{
int rc;
uint16_t tag_len;
@@ -332,5 +343,5 @@ cleanup_connection:
dprintf("%s : complete, read %llu bytes\n", __func__, offset);
- return rc == 0 ? offset : rc;
+ return rc == 0 ? (long)offset : rc;
}
diff --git a/qemu/roms/SLOF/lib/libvirtio/virtio-9p.h b/qemu/roms/SLOF/lib/libvirtio/virtio-9p.h
index 4bf47d078..db2cf6f11 100644
--- a/qemu/roms/SLOF/lib/libvirtio/virtio-9p.h
+++ b/qemu/roms/SLOF/lib/libvirtio/virtio-9p.h
@@ -26,7 +26,7 @@ typedef struct {
int virtio_9p_init(struct virtio_device *dev, void *tx_buf, void *rx_buf,
int buf_size);
void virtio_9p_shutdown(struct virtio_device *dev);
-int virtio_9p_load(struct virtio_device *dev, const char *file_name, uint8_t *buffer);
+long virtio_9p_load(struct virtio_device *dev, const char *file_name, uint8_t *buffer);
#endif /* VIRTIO_9P_H_ */
diff --git a/qemu/roms/SLOF/lib/libvirtio/virtio-blk.c b/qemu/roms/SLOF/lib/libvirtio/virtio-blk.c
index 826f2ea0e..07ec1048f 100644
--- a/qemu/roms/SLOF/lib/libvirtio/virtio-blk.c
+++ b/qemu/roms/SLOF/lib/libvirtio/virtio-blk.c
@@ -13,10 +13,15 @@
#include <stdio.h>
#include <cpu.h>
#include <helpers.h>
+#include <byteorder.h>
#include "virtio.h"
#include "virtio-blk.h"
+#include "virtio-internal.h"
#define DEFAULT_SECTOR_SIZE 512
+#define DRIVER_FEATURE_SUPPORT (VIRTIO_BLK_F_BLK_SIZE | VIRTIO_F_VERSION_1)
+
+static struct vqs vq;
/**
* Initialize virtio-block device.
@@ -27,39 +32,54 @@ virtioblk_init(struct virtio_device *dev)
{
struct vring_avail *vq_avail;
int blk_size = DEFAULT_SECTOR_SIZE;
- int features;
+ uint64_t features;
+ int status = VIRTIO_STAT_ACKNOWLEDGE;
/* Reset device */
- // XXX That will clear the virtq base. We need to move
- // initializing it to here anyway
- //
- // virtio_reset_device(dev);
+ virtio_reset_device(dev);
/* Acknowledge device. */
- virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE);
+ virtio_set_status(dev, status);
/* Tell HV that we know how to drive the device. */
- virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER);
+ status |= VIRTIO_STAT_DRIVER;
+ virtio_set_status(dev, status);
+
+ if (dev->is_modern) {
+ /* Negotiate features and sets FEATURES_OK if successful */
+ if (virtio_negotiate_guest_features(dev, DRIVER_FEATURE_SUPPORT))
+ goto dev_error;
+
+ virtio_get_status(dev, &status);
+ } else {
+ /* Device specific setup - we support F_BLK_SIZE */
+ virtio_set_guest_features(dev, VIRTIO_BLK_F_BLK_SIZE);
+ }
- /* Device specific setup - we support F_BLK_SIZE */
- virtio_set_guest_features(dev, VIRTIO_BLK_F_BLK_SIZE);
+ if (virtio_queue_init_vq(dev, &vq, 0))
+ goto dev_error;
vq_avail = virtio_get_vring_avail(dev, 0);
- vq_avail->flags = VRING_AVAIL_F_NO_INTERRUPT;
+ vq_avail->flags = virtio_cpu_to_modern16(dev, VRING_AVAIL_F_NO_INTERRUPT);
vq_avail->idx = 0;
/* Tell HV that setup succeeded */
- virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER
- |VIRTIO_STAT_DRIVER_OK);
+ status |= VIRTIO_STAT_DRIVER_OK;
+ virtio_set_status(dev, status);
- virtio_get_host_features(dev, &features);
+ features = virtio_get_host_features(dev);
if (features & VIRTIO_BLK_F_BLK_SIZE) {
blk_size = virtio_get_config(dev,
- offset_of(struct virtio_blk_cfg, blk_size),
- sizeof(blk_size));
+ offset_of(struct virtio_blk_cfg, blk_size),
+ sizeof(blk_size));
}
return blk_size;
+dev_error:
+ printf("%s: failed\n", __func__);
+ status |= VIRTIO_STAT_FAILED;
+ virtio_set_status(dev, status);
+ return 0;
}
@@ -77,6 +97,19 @@ virtioblk_shutdown(struct virtio_device *dev)
virtio_reset_device(dev);
}
+static void fill_blk_hdr(struct virtio_blk_req *blkhdr, bool is_modern,
+ uint32_t type, uint32_t ioprio, uint32_t sector)
+{
+ if (is_modern) {
+ blkhdr->type = cpu_to_le32(type);
+ blkhdr->ioprio = cpu_to_le32(ioprio);
+ blkhdr->sector = cpu_to_le64(sector);
+ } else {
+ blkhdr->type = type;
+ blkhdr->ioprio = ioprio;
+ blkhdr->sector = sector;
+ }
+}
/**
* Read blocks
@@ -87,7 +120,7 @@ virtioblk_shutdown(struct virtio_device *dev)
* @return number of blocks that have been read successfully
*/
int
-virtioblk_read(struct virtio_device *dev, char *buf, long blocknum, long cnt)
+virtioblk_read(struct virtio_device *dev, char *buf, uint64_t blocknum, long cnt)
{
struct vring_desc *desc;
int id;
@@ -100,7 +133,7 @@ virtioblk_read(struct virtio_device *dev, char *buf, long blocknum, long cnt)
struct vring_used *vq_used; /* "Used" vring */
volatile uint8_t status = -1;
volatile uint16_t *current_used_idx;
- uint16_t last_used_idx;
+ uint16_t last_used_idx, avail_idx;
int blk_size = DEFAULT_SECTOR_SIZE;
//printf("virtioblk_read: dev=%p buf=%p blocknum=%li count=%li\n",
@@ -128,41 +161,38 @@ virtioblk_read(struct virtio_device *dev, char *buf, long blocknum, long cnt)
vq_avail = virtio_get_vring_avail(dev, 0);
vq_used = virtio_get_vring_used(dev, 0);
+ avail_idx = virtio_modern16_to_cpu(dev, vq_avail->idx);
+
last_used_idx = vq_used->idx;
current_used_idx = &vq_used->idx;
/* Set up header */
- blkhdr.type = VIRTIO_BLK_T_IN | VIRTIO_BLK_T_BARRIER;
- blkhdr.ioprio = 1;
- blkhdr.sector = blocknum * blk_size / DEFAULT_SECTOR_SIZE;
+ fill_blk_hdr(&blkhdr, dev->is_modern, VIRTIO_BLK_T_IN | VIRTIO_BLK_T_BARRIER,
+ 1, blocknum * blk_size / DEFAULT_SECTOR_SIZE);
/* Determine descriptor index */
- id = (vq_avail->idx * 3) % vq_size;
+ id = (avail_idx * 3) % vq_size;
/* Set up virtqueue descriptor for header */
desc = &vq_desc[id];
- desc->addr = (uint64_t)&blkhdr;
- desc->len = sizeof(struct virtio_blk_req);
- desc->flags = VRING_DESC_F_NEXT;
- desc->next = (id + 1) % vq_size;
+ virtio_fill_desc(desc, dev->is_modern, (uint64_t)&blkhdr,
+ sizeof(struct virtio_blk_req),
+ VRING_DESC_F_NEXT, (id + 1) % vq_size);
/* Set up virtqueue descriptor for data */
desc = &vq_desc[(id + 1) % vq_size];
- desc->addr = (uint64_t)buf;
- desc->len = cnt * blk_size;
- desc->flags = VRING_DESC_F_NEXT | VRING_DESC_F_WRITE;
- desc->next = (id + 2) % vq_size;
+ virtio_fill_desc(desc, dev->is_modern, (uint64_t)buf, cnt * blk_size,
+ VRING_DESC_F_NEXT | VRING_DESC_F_WRITE,
+ (id + 2) % vq_size);
/* Set up virtqueue descriptor for status */
desc = &vq_desc[(id + 2) % vq_size];
- desc->addr = (uint64_t)&status;
- desc->len = 1;
- desc->flags = VRING_DESC_F_WRITE;
- desc->next = 0;
+ virtio_fill_desc(desc, dev->is_modern, (uint64_t)&status, 1,
+ VRING_DESC_F_WRITE, 0);
- vq_avail->ring[vq_avail->idx % vq_size] = id;
+ vq_avail->ring[avail_idx % vq_size] = virtio_cpu_to_modern16 (dev, id);
mb();
- vq_avail->idx += 1;
+ vq_avail->idx = virtio_cpu_to_modern16(dev, avail_idx + 1);
/* Tell HV that the queue is ready */
virtio_queue_notify(dev, 0);
diff --git a/qemu/roms/SLOF/lib/libvirtio/virtio-blk.h b/qemu/roms/SLOF/lib/libvirtio/virtio-blk.h
index ac8bf2896..2e7b5926b 100644
--- a/qemu/roms/SLOF/lib/libvirtio/virtio-blk.h
+++ b/qemu/roms/SLOF/lib/libvirtio/virtio-blk.h
@@ -55,6 +55,6 @@ struct virtio_blk_req {
extern int virtioblk_init(struct virtio_device *dev);
extern void virtioblk_shutdown(struct virtio_device *dev);
-extern int virtioblk_read(struct virtio_device *dev, char *buf, long blocknum, long cnt);
+extern int virtioblk_read(struct virtio_device *dev, char *buf, uint64_t blocknum, long cnt);
#endif /* _VIRTIO_BLK_H */
diff --git a/qemu/roms/SLOF/lib/libvirtio/virtio-internal.h b/qemu/roms/SLOF/lib/libvirtio/virtio-internal.h
new file mode 100644
index 000000000..08662eab7
--- /dev/null
+++ b/qemu/roms/SLOF/lib/libvirtio/virtio-internal.h
@@ -0,0 +1,48 @@
+/******************************************************************************
+ * Copyright (c) 2016 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
+ *****************************************************************************/
+
+#ifndef _LIBVIRTIO_INTERNAL_H
+#define _LIBVIRTIO_INTERNAL_H
+
+#include <byteorder.h>
+
+static inline uint16_t virtio_cpu_to_modern16(struct virtio_device *dev, uint16_t val)
+{
+ return dev->is_modern ? cpu_to_le16(val) : val;
+}
+
+static inline uint32_t virtio_cpu_to_modern32(struct virtio_device *dev, uint32_t val)
+{
+ return dev->is_modern ? cpu_to_le32(val) : val;
+}
+
+static inline uint64_t virtio_cpu_to_modern64(struct virtio_device *dev, uint64_t val)
+{
+ return dev->is_modern ? cpu_to_le64(val) : val;
+}
+
+static inline uint16_t virtio_modern16_to_cpu(struct virtio_device *dev, uint16_t val)
+{
+ return dev->is_modern ? le16_to_cpu(val) : val;
+}
+
+static inline uint32_t virtio_modern32_to_cpu(struct virtio_device *dev, uint32_t val)
+{
+ return dev->is_modern ? le32_to_cpu(val) : val;
+}
+
+static inline uint64_t virtio_modern64_to_cpu(struct virtio_device *dev, uint64_t val)
+{
+ return dev->is_modern ? le64_to_cpu(val) : val;
+}
+
+#endif /* _LIBVIRTIO_INTERNAL_H */
diff --git a/qemu/roms/SLOF/lib/libvirtio/virtio-net.c b/qemu/roms/SLOF/lib/libvirtio/virtio-net.c
index 99c19d952..fc620a201 100644
--- a/qemu/roms/SLOF/lib/libvirtio/virtio-net.c
+++ b/qemu/roms/SLOF/lib/libvirtio/virtio-net.c
@@ -26,6 +26,7 @@
#include <byteorder.h>
#include "virtio.h"
#include "virtio-net.h"
+#include "virtio-internal.h"
#undef DEBUG
//#define DEBUG
@@ -37,22 +38,13 @@
#define sync() asm volatile (" sync \n" ::: "memory")
-/* PCI virtio header offsets */
-#define VIRTIOHDR_DEVICE_FEATURES 0
-#define VIRTIOHDR_GUEST_FEATURES 4
-#define VIRTIOHDR_QUEUE_ADDRESS 8
-#define VIRTIOHDR_QUEUE_SIZE 12
-#define VIRTIOHDR_QUEUE_SELECT 14
-#define VIRTIOHDR_QUEUE_NOTIFY 16
-#define VIRTIOHDR_DEVICE_STATUS 18
-#define VIRTIOHDR_ISR_STATUS 19
-#define VIRTIOHDR_DEVICE_CONFIG 20
-#define VIRTIOHDR_MAC_ADDRESS 20
+#define DRIVER_FEATURE_SUPPORT (VIRTIO_NET_F_MAC | VIRTIO_F_VERSION_1)
struct virtio_device virtiodev;
-struct vqs vq[2]; /* Information about virtqueues */
+static struct vqs vq_rx; /* Information about receive virtqueues */
+static struct vqs vq_tx; /* Information about transmit virtqueues */
-/* See Virtio Spec, appendix C, "Device Operation" */
+/* See Virtio Spec, appendix C, "Device Operation" */
struct virtio_net_hdr {
uint8_t flags;
uint8_t gso_type;
@@ -63,6 +55,18 @@ struct virtio_net_hdr {
// uint16_t num_buffers; /* Only if VIRTIO_NET_F_MRG_RXBUF */
};
+static unsigned int net_hdr_size;
+
+struct virtio_net_hdr_v1 {
+ uint8_t flags;
+ uint8_t gso_type;
+ le16 hdr_len;
+ le16 gso_size;
+ le16 csum_start;
+ le16 csum_offset;
+ le16 num_buffers;
+};
+
static uint16_t last_rx_idx; /* Last index in RX "used" ring */
/**
@@ -72,15 +76,13 @@ static uint16_t last_rx_idx; /* Last index in RX "used" ring */
*/
static int virtionet_init_pci(struct virtio_device *dev)
{
- int i;
-
dprintf("virtionet: doing virtionet_init_pci!\n");
if (!dev)
return -1;
- virtiodev.base = dev->base;
- virtiodev.type = dev->type;
+ /* make a copy of the device structure */
+ memcpy(&virtiodev, dev, sizeof(struct virtio_device));
/* Reset device */
virtio_reset_device(&virtiodev);
@@ -90,29 +92,11 @@ static int virtionet_init_pci(struct virtio_device *dev)
* second the transmit queue, and the forth is the control queue for
* networking options.
* We are only interested in the receive and transmit queue here. */
-
- for (i=VQ_RX; i<=VQ_TX; i++) {
- /* Select ring (0=RX, 1=TX): */
- vq[i].id = i-VQ_RX;
- ci_write_16(virtiodev.base+VIRTIOHDR_QUEUE_SELECT,
- cpu_to_le16(vq[i].id));
-
- vq[i].size = le16_to_cpu(ci_read_16(virtiodev.base+VIRTIOHDR_QUEUE_SIZE));
- vq[i].desc = SLOF_alloc_mem_aligned(virtio_vring_size(vq[i].size), 4096);
- if (!vq[i].desc) {
- printf("memory allocation failed!\n");
- return -1;
- }
- memset(vq[i].desc, 0, virtio_vring_size(vq[i].size));
- ci_write_32(virtiodev.base+VIRTIOHDR_QUEUE_ADDRESS,
- cpu_to_le32((long)vq[i].desc / 4096));
- vq[i].avail = (void*)vq[i].desc
- + vq[i].size * sizeof(struct vring_desc);
- vq[i].used = (void*)VQ_ALIGN((long)vq[i].avail
- + vq[i].size * sizeof(struct vring_avail));
-
- dprintf("%i: vq.id = %llx\nvq.size =%x\n vq.avail =%p\nvq.used=%p\n",
- i, vq[i].id, vq[i].size, vq[i].avail, vq[i].used);
+ if (virtio_queue_init_vq(dev, &vq_rx, VQ_RX) ||
+ virtio_queue_init_vq(dev, &vq_tx, VQ_TX)) {
+ virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER
+ |VIRTIO_STAT_FAILED);
+ return -1;
}
/* Acknowledge device. */
@@ -129,6 +113,7 @@ static int virtionet_init_pci(struct virtio_device *dev)
static int virtionet_init(net_driver_t *driver)
{
int i;
+ int status = VIRTIO_STAT_ACKNOWLEDGE | VIRTIO_STAT_DRIVER;
dprintf("virtionet_init(%02x:%02x:%02x:%02x:%02x:%02x)\n",
driver->mac_addr[0], driver->mac_addr[1],
@@ -139,60 +124,69 @@ static int virtionet_init(net_driver_t *driver)
return 0;
/* Tell HV that we know how to drive the device. */
- virtio_set_status(&virtiodev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER);
-
- /* Device specific setup - we do not support special features right now */
- virtio_set_guest_features(&virtiodev, 0);
+ virtio_set_status(&virtiodev, status);
+
+ /* Device specific setup */
+ if (virtiodev.is_modern) {
+ if (virtio_negotiate_guest_features(&virtiodev, DRIVER_FEATURE_SUPPORT))
+ goto dev_error;
+ net_hdr_size = sizeof(struct virtio_net_hdr_v1);
+ virtio_get_status(&virtiodev, &status);
+ } else {
+ net_hdr_size = sizeof(struct virtio_net_hdr);
+ virtio_set_guest_features(&virtiodev, 0);
+ }
/* Allocate memory for one transmit an multiple receive buffers */
- vq[VQ_RX].buf_mem = SLOF_alloc_mem((BUFFER_ENTRY_SIZE+sizeof(struct virtio_net_hdr))
+ vq_rx.buf_mem = SLOF_alloc_mem((BUFFER_ENTRY_SIZE+net_hdr_size)
* RX_QUEUE_SIZE);
- if (!vq[VQ_RX].buf_mem) {
+ if (!vq_rx.buf_mem) {
printf("virtionet: Failed to allocate buffers!\n");
- virtio_set_status(&virtiodev, VIRTIO_STAT_FAILED);
- return -1;
+ goto dev_error;
}
/* Prepare receive buffer queue */
for (i = 0; i < RX_QUEUE_SIZE; i++) {
- struct vring_desc *desc;
+ uint64_t addr = (uint64_t)vq_rx.buf_mem
+ + i * (BUFFER_ENTRY_SIZE+net_hdr_size);
+ uint32_t id = i*2;
/* Descriptor for net_hdr: */
- desc = &vq[VQ_RX].desc[i*2];
- desc->addr = (uint64_t)vq[VQ_RX].buf_mem
- + i * (BUFFER_ENTRY_SIZE+sizeof(struct virtio_net_hdr));
- desc->len = sizeof(struct virtio_net_hdr);
- desc->flags = VRING_DESC_F_NEXT | VRING_DESC_F_WRITE;
- desc->next = i*2+1;
+ virtio_fill_desc(&vq_rx.desc[id], virtiodev.is_modern, addr, net_hdr_size,
+ VRING_DESC_F_NEXT | VRING_DESC_F_WRITE, id + 1);
/* Descriptor for data: */
- desc = &vq[VQ_RX].desc[i*2+1];
- desc->addr = vq[VQ_RX].desc[i*2].addr + sizeof(struct virtio_net_hdr);
- desc->len = BUFFER_ENTRY_SIZE;
- desc->flags = VRING_DESC_F_WRITE;
- desc->next = 0;
+ virtio_fill_desc(&vq_rx.desc[id+1], virtiodev.is_modern, addr + net_hdr_size,
+ BUFFER_ENTRY_SIZE, VRING_DESC_F_WRITE, 0);
- vq[VQ_RX].avail->ring[i] = i*2;
+ vq_rx.avail->ring[i] = virtio_cpu_to_modern16(&virtiodev, id);
}
sync();
- vq[VQ_RX].avail->flags = VRING_AVAIL_F_NO_INTERRUPT;
- vq[VQ_RX].avail->idx = RX_QUEUE_SIZE;
- last_rx_idx = vq[VQ_RX].used->idx;
+ vq_rx.avail->flags = virtio_cpu_to_modern16(&virtiodev, VRING_AVAIL_F_NO_INTERRUPT);
+ vq_rx.avail->idx = virtio_cpu_to_modern16(&virtiodev, RX_QUEUE_SIZE);
+
+ last_rx_idx = virtio_modern16_to_cpu(&virtiodev, vq_rx.used->idx);
- vq[VQ_TX].avail->flags = VRING_AVAIL_F_NO_INTERRUPT;
- vq[VQ_TX].avail->idx = 0;
+ vq_tx.avail->flags = virtio_cpu_to_modern16(&virtiodev, VRING_AVAIL_F_NO_INTERRUPT);
+ vq_tx.avail->idx = 0;
/* Tell HV that setup succeeded */
- virtio_set_status(&virtiodev, VIRTIO_STAT_ACKNOWLEDGE
- |VIRTIO_STAT_DRIVER
- |VIRTIO_STAT_DRIVER_OK);
+ status |= VIRTIO_STAT_DRIVER_OK;
+ virtio_set_status(&virtiodev, status);
/* Tell HV that RX queues are ready */
virtio_queue_notify(&virtiodev, VQ_RX);
driver->running = 1;
-
+ for(i = 0; i < (int)sizeof(driver->mac_addr); i++) {
+ driver->mac_addr[i] = virtio_get_config(&virtiodev, i, 1);
+ }
return 0;
+
+dev_error:
+ status |= VIRTIO_STAT_FAILED;
+ virtio_set_status(&virtiodev, status);
+ return -1;
}
@@ -225,9 +219,10 @@ static int virtionet_term(net_driver_t *driver)
*/
static int virtionet_xmit(char *buf, int len)
{
- struct vring_desc *desc;
- int id;
- static struct virtio_net_hdr nethdr;
+ int id, idx;
+ static struct virtio_net_hdr_v1 nethdr_v1;
+ static struct virtio_net_hdr nethdr_legacy;
+ void *nethdr = &nethdr_legacy;
if (len > BUFFER_ENTRY_SIZE) {
printf("virtionet: Packet too big!\n");
@@ -236,28 +231,25 @@ static int virtionet_xmit(char *buf, int len)
dprintf("\nvirtionet_xmit(packet at %p, %d bytes)\n", buf, len);
- memset(&nethdr, 0, sizeof(nethdr));
+ if (virtiodev.is_modern)
+ nethdr = &nethdr_v1;
+
+ memset(nethdr, 0, net_hdr_size);
/* Determine descriptor index */
- id = (vq[VQ_TX].avail->idx * 2) % vq[VQ_TX].size;
+ idx = virtio_modern16_to_cpu(&virtiodev, vq_tx.avail->idx);
+ id = (idx * 2) % vq_tx.size;
/* Set up virtqueue descriptor for header */
- desc = &vq[VQ_TX].desc[id];
- desc->addr = (uint64_t)&nethdr;
- desc->len = sizeof(struct virtio_net_hdr);
- desc->flags = VRING_DESC_F_NEXT;
- desc->next = id + 1;
+ virtio_fill_desc(&vq_tx.desc[id], virtiodev.is_modern, (uint64_t)nethdr,
+ net_hdr_size, VRING_DESC_F_NEXT, id + 1);
/* Set up virtqueue descriptor for data */
- desc = &vq[VQ_TX].desc[id+1];
- desc->addr = (uint64_t)buf;
- desc->len = len;
- desc->flags = 0;
- desc->next = 0;
+ virtio_fill_desc(&vq_tx.desc[id+1], virtiodev.is_modern, (uint64_t)buf, len, 0, 0);
- vq[VQ_TX].avail->ring[vq[VQ_TX].avail->idx % vq[VQ_TX].size] = id;
+ vq_tx.avail->ring[idx % vq_tx.size] = virtio_cpu_to_modern16(&virtiodev, id);
sync();
- vq[VQ_TX].avail->idx += 1;
+ vq_tx.avail->idx = virtio_cpu_to_modern16(&virtiodev, idx + 1);
sync();
/* Tell HV that TX queue is ready */
@@ -272,23 +264,24 @@ static int virtionet_xmit(char *buf, int len)
*/
static int virtionet_receive(char *buf, int maxlen)
{
- int len = 0;
- int id;
+ uint32_t len = 0;
+ uint32_t id, idx;
- if (last_rx_idx == vq[VQ_RX].used->idx) {
+ idx = virtio_modern16_to_cpu(&virtiodev, vq_rx.used->idx);
+
+ if (last_rx_idx == idx) {
/* Nothing received yet */
return 0;
}
- id = (vq[VQ_RX].used->ring[last_rx_idx % vq[VQ_RX].size].id + 1)
- % vq[VQ_RX].size;
- len = vq[VQ_RX].used->ring[last_rx_idx % vq[VQ_RX].size].len
- - sizeof(struct virtio_net_hdr);
-
- dprintf("virtionet_receive() last_rx_idx=%i, vq[VQ_RX].used->idx=%i,"
- " id=%i len=%i\n", last_rx_idx, vq[VQ_RX].used->idx, id, len);
+ id = (virtio_modern32_to_cpu(&virtiodev, vq_rx.used->ring[last_rx_idx % vq_rx.size].id) + 1)
+ % vq_rx.size;
+ len = virtio_modern32_to_cpu(&virtiodev, vq_rx.used->ring[last_rx_idx % vq_rx.size].len)
+ - net_hdr_size;
+ dprintf("virtionet_receive() last_rx_idx=%i, vq_rx.used->idx=%i,"
+ " id=%i len=%i\n", last_rx_idx, vq_rx.used->idx, id, len);
- if (len > maxlen) {
+ if (len > (uint32_t)maxlen) {
printf("virtio-net: Receive buffer not big enough!\n");
len = maxlen;
}
@@ -298,7 +291,7 @@ static int virtionet_receive(char *buf, int maxlen)
printf("\n");
int i;
for (i=0; i<64; i++) {
- printf(" %02x", *(uint8_t*)(vq[VQ_RX].desc[id].addr+i));
+ printf(" %02x", *(uint8_t*)(vq_rx.desc[id].addr+i));
if ((i%16)==15)
printf("\n");
}
@@ -306,14 +299,14 @@ static int virtionet_receive(char *buf, int maxlen)
#endif
/* Copy data to destination buffer */
- memcpy(buf, (void*)vq[VQ_RX].desc[id].addr, len);
+ memcpy(buf, (void *)virtio_modern64_to_cpu(&virtiodev, vq_rx.desc[id].addr), len);
/* Move indices to next entries */
last_rx_idx = last_rx_idx + 1;
- vq[VQ_RX].avail->ring[vq[VQ_RX].avail->idx % vq[VQ_RX].size] = id - 1;
+ vq_rx.avail->ring[idx % vq_rx.size] = virtio_cpu_to_modern16(&virtiodev, id - 1);
sync();
- vq[VQ_RX].avail->idx += 1;
+ vq_rx.avail->idx = virtio_cpu_to_modern16(&virtiodev, idx + 1);
/* Tell HV that RX queue entry is ready */
virtio_queue_notify(&virtiodev, VQ_RX);
@@ -321,7 +314,7 @@ static int virtionet_receive(char *buf, int maxlen)
return len;
}
-net_driver_t *virtionet_open(char *mac_addr, int len, struct virtio_device *dev)
+net_driver_t *virtionet_open(struct virtio_device *dev)
{
net_driver_t *driver;
@@ -331,7 +324,6 @@ net_driver_t *virtionet_open(char *mac_addr, int len, struct virtio_device *dev)
return NULL;
}
- memcpy(driver->mac_addr, mac_addr, 6);
driver->running = 0;
if (virtionet_init_pci(dev))
diff --git a/qemu/roms/SLOF/lib/libvirtio/virtio-net.h b/qemu/roms/SLOF/lib/libvirtio/virtio-net.h
index bc7a189f7..c2d8ee336 100644
--- a/qemu/roms/SLOF/lib/libvirtio/virtio-net.h
+++ b/qemu/roms/SLOF/lib/libvirtio/virtio-net.h
@@ -23,19 +23,10 @@ enum {
VQ_TX = 1, /* Transmit Queue */
};
-struct vqs {
- uint64_t id; /* Queue ID */
- uint32_t size;
- void *buf_mem;
- struct vring_desc *desc;
- struct vring_avail *avail;
- struct vring_used *used;
-};
-
-/* Device is identified by RX queue ID: */
-#define DEVICE_ID vq[0].id
+/* VIRTIO_NET Feature bits */
+#define VIRTIO_NET_F_MAC (1 << 5)
-extern net_driver_t *virtionet_open(char *mac_addr, int len, struct virtio_device *dev);
+extern net_driver_t *virtionet_open(struct virtio_device *dev);
extern void virtionet_close(net_driver_t *driver);
extern int virtionet_read(char *buf, int len);
extern int virtionet_write(char *buf, int len);
diff --git a/qemu/roms/SLOF/lib/libvirtio/virtio-scsi.c b/qemu/roms/SLOF/lib/libvirtio/virtio-scsi.c
index 48289289a..04181b06c 100644
--- a/qemu/roms/SLOF/lib/libvirtio/virtio-scsi.c
+++ b/qemu/roms/SLOF/lib/libvirtio/virtio-scsi.c
@@ -15,6 +15,7 @@
#include <cpu.h>
#include <helpers.h>
#include "virtio.h"
+#include "virtio-internal.h"
#include "virtio-scsi.h"
int virtioscsi_send(struct virtio_device *dev,
@@ -22,58 +23,54 @@ int virtioscsi_send(struct virtio_device *dev,
struct virtio_scsi_resp_cmd *resp,
int is_read, void *buf, uint64_t buf_len)
{
- struct vring_desc *desc;
- struct vring_desc *vq_desc; /* Descriptor vring */
- struct vring_avail *vq_avail; /* "Available" vring */
- struct vring_used *vq_used; /* "Used" vring */
-
- volatile uint16_t *current_used_idx;
- uint16_t last_used_idx;
- int id;
- uint32_t vq_size, time;
-
- int vq = VIRTIO_SCSI_REQUEST_VQ;
-
- vq_size = virtio_get_qsize(dev, vq);
- vq_desc = virtio_get_vring_desc(dev, vq);
- vq_avail = virtio_get_vring_avail(dev, vq);
- vq_used = virtio_get_vring_used(dev, vq);
-
- last_used_idx = vq_used->idx;
- current_used_idx = &vq_used->idx;
-
- /* Determine descriptor index */
- id = (vq_avail->idx * 3) % vq_size;
-
- desc = &vq_desc[id];
- desc->addr = (uint64_t)req;
- desc->len = sizeof(*req);
- desc->flags = VRING_DESC_F_NEXT;
- desc->next = (id + 1) % vq_size;
-
- /* Set up virtqueue descriptor for data */
- desc = &vq_desc[(id + 1) % vq_size];
- desc->addr = (uint64_t)resp;
- desc->len = sizeof(*resp);
- desc->flags = VRING_DESC_F_NEXT | VRING_DESC_F_WRITE;
- desc->next = (id + 2) % vq_size;
-
- if (buf && buf_len) {
- /* Set up virtqueue descriptor for status */
- desc = &vq_desc[(id + 2) % vq_size];
- desc->addr = (uint64_t)buf;
- desc->len = buf_len;
- desc->flags = is_read ? VRING_DESC_F_WRITE : 0;
- desc->next = 0;
- } else
- desc->flags &= ~VRING_DESC_F_NEXT;
-
- vq_avail->ring[vq_avail->idx % vq_size] = id;
- mb();
- vq_avail->idx += 1;
-
- /* Tell HV that the vq is ready */
- virtio_queue_notify(dev, vq);
+ struct vring_desc *vq_desc; /* Descriptor vring */
+ struct vring_avail *vq_avail; /* "Available" vring */
+ struct vring_used *vq_used; /* "Used" vring */
+
+ volatile uint16_t *current_used_idx;
+ uint16_t last_used_idx, avail_idx;
+ int id;
+ uint32_t vq_size, time;
+
+ int vq = VIRTIO_SCSI_REQUEST_VQ;
+
+ vq_size = virtio_get_qsize(dev, vq);
+ vq_desc = virtio_get_vring_desc(dev, vq);
+ vq_avail = virtio_get_vring_avail(dev, vq);
+ vq_used = virtio_get_vring_used(dev, vq);
+
+ avail_idx = virtio_modern16_to_cpu(dev, vq_avail->idx);
+
+ last_used_idx = vq_used->idx;
+ current_used_idx = &vq_used->idx;
+
+ /* Determine descriptor index */
+ id = (avail_idx * 3) % vq_size;
+ virtio_fill_desc(&vq_desc[id], dev->is_modern, (uint64_t)req, sizeof(*req), VRING_DESC_F_NEXT,
+ (id + 1) % vq_size);
+
+ /* Set up virtqueue descriptor for data */
+ if (buf && buf_len) {
+ virtio_fill_desc(&vq_desc[(id + 1) % vq_size], dev->is_modern,
+ (uint64_t)resp, sizeof(*resp),
+ VRING_DESC_F_NEXT | VRING_DESC_F_WRITE,
+ (id + 2) % vq_size);
+ /* Set up virtqueue descriptor for status */
+ virtio_fill_desc(&vq_desc[(id + 2) % vq_size], dev->is_modern,
+ (uint64_t)buf, buf_len,
+ (is_read ? VRING_DESC_F_WRITE : 0), 0);
+ } else {
+ virtio_fill_desc(&vq_desc[(id + 1) % vq_size], dev->is_modern,
+ (uint64_t)resp, sizeof(*resp),
+ VRING_DESC_F_WRITE, 0);
+ }
+
+ vq_avail->ring[avail_idx % vq_size] = virtio_cpu_to_modern16(dev, id);
+ mb();
+ vq_avail->idx = virtio_cpu_to_modern16(dev, avail_idx + 1);
+
+ /* Tell HV that the vq is ready */
+ virtio_queue_notify(dev, vq);
/* Wait for host to consume the descriptor */
time = SLOF_GetTimer() + VIRTIO_TIMEOUT;
@@ -84,7 +81,7 @@ int virtioscsi_send(struct virtio_device *dev,
break;
}
- return 0;
+ return 0;
}
/**
@@ -93,42 +90,55 @@ int virtioscsi_send(struct virtio_device *dev,
*/
int virtioscsi_init(struct virtio_device *dev)
{
- struct vring_avail *vq_avail;
- unsigned int idx = 0;
- int qsize = 0;
-
- /* Reset device */
- // XXX That will clear the virtq base. We need to move
- // initializing it to here anyway
- //
- // virtio_reset_device(dev);
-
- /* Acknowledge device. */
- virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE);
+ struct vring_avail *vq_avail;
+ unsigned int idx = 0;
+ int qsize = 0;
+ int status = VIRTIO_STAT_ACKNOWLEDGE;
- /* Tell HV that we know how to drive the device. */
- virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER);
-
- /* Device specific setup - we do not support special features right now */
- virtio_set_guest_features(dev, 0);
+ /* Reset device */
+ // XXX That will clear the virtq base. We need to move
+ // initializing it to here anyway
+ //
+ // virtio_reset_device(dev);
+
+ /* Acknowledge device. */
+ virtio_set_status(dev, status);
+
+ /* Tell HV that we know how to drive the device. */
+ status |= VIRTIO_STAT_DRIVER;
+ virtio_set_status(dev, status);
+
+ /* Device specific setup - we do not support special features right now */
+ if (dev->is_modern) {
+ if (virtio_negotiate_guest_features(dev, VIRTIO_F_VERSION_1))
+ goto dev_error;
+ virtio_get_status(dev, &status);
+ } else {
+ virtio_set_guest_features(dev, 0);
+ }
- while(1) {
- qsize = virtio_get_qsize(dev, idx);
- if (!qsize)
- break;
- virtio_vring_size(qsize);
+ while(1) {
+ qsize = virtio_get_qsize(dev, idx);
+ if (!qsize)
+ break;
+ virtio_vring_size(qsize);
- vq_avail = virtio_get_vring_avail(dev, 0);
- vq_avail->flags = VRING_AVAIL_F_NO_INTERRUPT;
- vq_avail->idx = 0;
- idx++;
- }
+ vq_avail = virtio_get_vring_avail(dev, idx);
+ vq_avail->flags = virtio_cpu_to_modern16(dev, VRING_AVAIL_F_NO_INTERRUPT);
+ vq_avail->idx = 0;
+ idx++;
+ }
/* Tell HV that setup succeeded */
- virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER
- |VIRTIO_STAT_DRIVER_OK);
+ status |= VIRTIO_STAT_DRIVER_OK;
+ virtio_set_status(dev, status);
return 0;
+dev_error:
+ printf("%s: failed\n", __func__);
+ status |= VIRTIO_STAT_FAILED;
+ virtio_set_status(dev, status);
+ return -1;
}
/**
diff --git a/qemu/roms/SLOF/lib/libvirtio/virtio.c b/qemu/roms/SLOF/lib/libvirtio/virtio.c
index f9c00a67a..f189941c7 100644
--- a/qemu/roms/SLOF/lib/libvirtio/virtio.c
+++ b/qemu/roms/SLOF/lib/libvirtio/virtio.c
@@ -10,10 +10,16 @@
* IBM Corporation - initial implementation
*****************************************************************************/
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
#include <cpu.h>
#include <cache.h>
#include <byteorder.h>
#include "virtio.h"
+#include "helpers.h"
/* PCI virtio header offsets */
#define VIRTIOHDR_DEVICE_FEATURES 0
@@ -26,6 +32,166 @@
#define VIRTIOHDR_ISR_STATUS 19
#define VIRTIOHDR_DEVICE_CONFIG 20
+/* PCI defines */
+#define PCI_BASE_ADDR_SPACE_IO 0x01
+#define PCI_BASE_ADDR_SPACE_64BIT 0x04
+#define PCI_BASE_ADDR_MEM_MASK (~0x0fUL)
+#define PCI_BASE_ADDR_IO_MASK (~0x03UL)
+
+#define PCI_BASE_ADDR_REG_0 0x10
+#define PCI_CONFIG_CAP_REG 0x34
+
+#define PCI_CAP_ID_VNDR 0x9
+
+/* Common configuration */
+#define VIRTIO_PCI_CAP_COMMON_CFG 1
+/* Notifications */
+#define VIRTIO_PCI_CAP_NOTIFY_CFG 2
+/* ISR access */
+#define VIRTIO_PCI_CAP_ISR_CFG 3
+/* Device specific configuration */
+#define VIRTIO_PCI_CAP_DEVICE_CFG 4
+/* PCI configuration access */
+#define VIRTIO_PCI_CAP_PCI_CFG 5
+
+#define VIRTIO_PCI_CAP_VNDR 0 /* Generic PCI field: PCI_CAP_ID_VNDR */
+#define VIRTIO_PCI_CAP_NEXT 1 /* Generic PCI field: next ptr. */
+#define VIRTIO_PCI_CAP_LEN 2 /* Generic PCI field: capability length */
+#define VIRTIO_PCI_CAP_CFG_TYPE 3 /* Identifies the structure. */
+#define VIRTIO_PCI_CAP_BAR 4 /* Where to find it. */
+#define VIRTIO_PCI_CAP_OFFSET 8 /* Offset within bar. */
+#define VIRTIO_PCI_CAP_LENGTH 12 /* Length of the structure, in bytes. */
+
+struct virtio_dev_common {
+ le32 dev_features_sel;
+ le32 dev_features;
+ le32 drv_features_sel;
+ le32 drv_features;
+ le16 msix_config;
+ le16 num_queues;
+ uint8_t dev_status;
+ uint8_t cfg_generation;
+
+ le16 q_select;
+ le16 q_size;
+ le16 q_msix_vec;
+ le16 q_enable;
+ le16 q_notify_off;
+ le64 q_desc;
+ le64 q_avail;
+ le64 q_used;
+} __attribute__ ((packed));
+
+/* virtio 1.0 Spec: 4.1.3 PCI Device Layout
+ *
+ * Fields of different sizes are present in the device configuration regions.
+ * All 64-bit, 32-bit and 16-bit fields are little-endian. 64-bit fields are to
+ * be treated as two 32-bit fields, with low 32 bit part followed by the high 32
+ * bit part.
+ */
+static void virtio_pci_write64(void *addr, uint64_t val)
+{
+ uint32_t hi = (val >> 32) & 0xFFFFFFFF;
+ uint32_t lo = val & 0xFFFFFFFF;
+
+ ci_write_32(addr, cpu_to_le32(lo));
+ ci_write_32(addr + 4, cpu_to_le32(hi));
+}
+
+static uint64_t virtio_pci_read64(void *addr)
+{
+ uint64_t hi, lo;
+
+ lo = le32_to_cpu(ci_read_32(addr));
+ hi = le32_to_cpu(ci_read_32(addr + 4));
+ return (hi << 32) | lo;
+}
+
+static void virtio_cap_set_base_addr(struct virtio_cap *cap, uint32_t offset)
+{
+ uint64_t addr;
+
+ addr = SLOF_pci_config_read32(PCI_BASE_ADDR_REG_0 + 4 * cap->bar);
+ if (addr & PCI_BASE_ADDR_SPACE_IO) {
+ addr = addr & PCI_BASE_ADDR_IO_MASK;
+ cap->is_io = 1;
+ } else {
+ if (addr & PCI_BASE_ADDR_SPACE_64BIT)
+ addr |= SLOF_pci_config_read32(PCI_BASE_ADDR_REG_0 + 4 * (cap->bar + 1)) << 32;
+ addr = addr & PCI_BASE_ADDR_MEM_MASK;
+ cap->is_io = 0;
+ }
+ addr = (uint64_t)SLOF_translate_my_address((void *)addr);
+ cap->addr = (void *)addr + offset;
+}
+
+static void virtio_process_cap(struct virtio_device *dev, uint8_t cap_ptr)
+{
+ struct virtio_cap *cap;
+ uint8_t cfg_type, bar;
+ uint32_t offset;
+
+ cfg_type = SLOF_pci_config_read8(cap_ptr + VIRTIO_PCI_CAP_CFG_TYPE);
+ bar = SLOF_pci_config_read8(cap_ptr + VIRTIO_PCI_CAP_BAR);
+ offset = SLOF_pci_config_read32(cap_ptr + VIRTIO_PCI_CAP_OFFSET);
+
+ switch(cfg_type) {
+ case VIRTIO_PCI_CAP_COMMON_CFG:
+ cap = &dev->common;
+ break;
+ case VIRTIO_PCI_CAP_NOTIFY_CFG:
+ cap = &dev->notify;
+ dev->notify_off_mul = SLOF_pci_config_read32(cap_ptr + sizeof(struct virtio_cap));
+ break;
+ case VIRTIO_PCI_CAP_ISR_CFG:
+ cap = &dev->isr;
+ break;
+ case VIRTIO_PCI_CAP_DEVICE_CFG:
+ cap = &dev->device;
+ break;
+ default:
+ return;
+ }
+
+ cap->bar = bar;
+ virtio_cap_set_base_addr(cap, offset);
+ cap->cap_id = cfg_type;
+}
+
+/**
+ * Reads the virtio device capabilities, gets called from SLOF routines The
+ * function determines legacy or modern device and sets up driver registers
+ */
+struct virtio_device *virtio_setup_vd(void)
+{
+ uint8_t cap_ptr, cap_vndr;
+ struct virtio_device *dev;
+
+ dev = SLOF_alloc_mem(sizeof(struct virtio_device));
+ if (!dev) {
+ printf("Failed to allocate memory");
+ return NULL;
+ }
+
+ cap_ptr = SLOF_pci_config_read8(PCI_CONFIG_CAP_REG);
+ while (cap_ptr != 0) {
+ cap_vndr = SLOF_pci_config_read8(cap_ptr + VIRTIO_PCI_CAP_VNDR);
+ if (cap_vndr == PCI_CAP_ID_VNDR)
+ virtio_process_cap(dev, cap_ptr);
+ cap_ptr = SLOF_pci_config_read8(cap_ptr+VIRTIO_PCI_CAP_NEXT);
+ }
+
+ if (dev->common.cap_id && dev->notify.cap_id &&
+ dev->isr.cap_id && dev->device.cap_id) {
+ dev->is_modern = 1;
+ } else {
+ dev->is_modern = 0;
+ dev->legacy.cap_id = 0;
+ dev->legacy.bar = 0;
+ virtio_cap_set_base_addr(&dev->legacy, 0);
+ }
+ return dev;
+}
/**
* Calculate ring size according to queue size number
@@ -33,9 +199,9 @@
unsigned long virtio_vring_size(unsigned int qsize)
{
return VQ_ALIGN(sizeof(struct vring_desc) * qsize +
- sizeof(struct vring_avail) + sizeof(uint16_t) * qsize) +
- VQ_ALIGN(sizeof(struct vring_used) +
- sizeof(struct vring_used_elem) * qsize);
+ sizeof(struct vring_avail) + sizeof(uint16_t) * qsize) +
+ VQ_ALIGN(sizeof(struct vring_used) +
+ sizeof(struct vring_used_elem) * qsize);
}
@@ -45,15 +211,22 @@ unsigned long virtio_vring_size(unsigned int qsize)
* @param queue virtio queue number
* @return number of elements
*/
-int virtio_get_qsize(struct virtio_device *dev, int queue)
+unsigned int virtio_get_qsize(struct virtio_device *dev, int queue)
{
- int size = 0;
+ unsigned int size = 0;
- if (dev->type == VIRTIO_TYPE_PCI) {
- ci_write_16(dev->base+VIRTIOHDR_QUEUE_SELECT,
+ if (dev->is_modern) {
+ void *addr = dev->common.addr + offset_of(struct virtio_dev_common, q_select);
+ ci_write_16(addr, cpu_to_le16(queue));
+ eieio();
+ addr = dev->common.addr + offset_of(struct virtio_dev_common, q_size);
+ size = le16_to_cpu(ci_read_16(addr));
+ }
+ else {
+ ci_write_16(dev->legacy.addr+VIRTIOHDR_QUEUE_SELECT,
cpu_to_le16(queue));
eieio();
- size = le16_to_cpu(ci_read_16(dev->base+VIRTIOHDR_QUEUE_SIZE));
+ size = le16_to_cpu(ci_read_16(dev->legacy.addr+VIRTIOHDR_QUEUE_SIZE));
}
return size;
@@ -70,12 +243,19 @@ struct vring_desc *virtio_get_vring_desc(struct virtio_device *dev, int queue)
{
struct vring_desc *desc = 0;
- if (dev->type == VIRTIO_TYPE_PCI) {
- ci_write_16(dev->base+VIRTIOHDR_QUEUE_SELECT,
+ if (dev->is_modern) {
+ void *q_sel = dev->common.addr + offset_of(struct virtio_dev_common, q_select);
+ void *q_desc = dev->common.addr + offset_of(struct virtio_dev_common, q_desc);
+
+ ci_write_16(q_sel, cpu_to_le16(queue));
+ eieio();
+ desc = (void *)(virtio_pci_read64(q_desc));
+ } else {
+ ci_write_16(dev->legacy.addr+VIRTIOHDR_QUEUE_SELECT,
cpu_to_le16(queue));
eieio();
desc = (void*)(4096L *
- le32_to_cpu(ci_read_32(dev->base+VIRTIOHDR_QUEUE_ADDRESS)));
+ le32_to_cpu(ci_read_32(dev->legacy.addr+VIRTIOHDR_QUEUE_ADDRESS)));
}
return desc;
@@ -90,8 +270,18 @@ struct vring_desc *virtio_get_vring_desc(struct virtio_device *dev, int queue)
*/
struct vring_avail *virtio_get_vring_avail(struct virtio_device *dev, int queue)
{
- return (void*)((uint64_t)virtio_get_vring_desc(dev, queue)
- + virtio_get_qsize(dev, queue) * sizeof(struct vring_desc));
+ if (dev->is_modern) {
+ void *q_sel = dev->common.addr + offset_of(struct virtio_dev_common, q_select);
+ void *q_avail = dev->common.addr + offset_of(struct virtio_dev_common, q_avail);
+
+ ci_write_16(q_sel, cpu_to_le16(queue));
+ eieio();
+ return (void *)(virtio_pci_read64(q_avail));
+ }
+ else {
+ return (void*)((uint64_t)virtio_get_vring_desc(dev, queue) +
+ virtio_get_qsize(dev, queue) * sizeof(struct vring_desc));
+ }
}
@@ -103,20 +293,46 @@ struct vring_avail *virtio_get_vring_avail(struct virtio_device *dev, int queue)
*/
struct vring_used *virtio_get_vring_used(struct virtio_device *dev, int queue)
{
- return (void*)VQ_ALIGN((uint64_t)virtio_get_vring_avail(dev, queue)
- + virtio_get_qsize(dev, queue)
- * sizeof(struct vring_avail));
+ if (dev->is_modern) {
+ void *q_sel = dev->common.addr + offset_of(struct virtio_dev_common, q_select);
+ void *q_used = dev->common.addr + offset_of(struct virtio_dev_common, q_used);
+
+ ci_write_16(q_sel, cpu_to_le16(queue));
+ eieio();
+ return (void *)(virtio_pci_read64(q_used));
+ } else {
+ return (void*)VQ_ALIGN((uint64_t)virtio_get_vring_avail(dev, queue)
+ + virtio_get_qsize(dev, queue)
+ * sizeof(struct vring_avail));
+ }
}
+/**
+ * Fill the virtio ring descriptor depending on the legacy mode or virtio 1.0
+ */
+void virtio_fill_desc(struct vring_desc *desc, bool is_modern,
+ uint64_t addr, uint32_t len,
+ uint16_t flags, uint16_t next)
+{
+ if (is_modern) {
+ desc->addr = cpu_to_le64(addr);
+ desc->len = cpu_to_le32(len);
+ desc->flags = cpu_to_le16(flags);
+ desc->next = cpu_to_le16(next);
+ } else {
+ desc->addr = addr;
+ desc->len = len;
+ desc->flags = flags;
+ desc->next = next;
+ }
+}
/**
* Reset virtio device
*/
void virtio_reset_device(struct virtio_device *dev)
{
- if (dev->type == VIRTIO_TYPE_PCI) {
- ci_write_8(dev->base+VIRTIOHDR_DEVICE_STATUS, 0);
- }
+ virtio_set_status(dev, 0);
}
@@ -125,25 +341,64 @@ void virtio_reset_device(struct virtio_device *dev)
*/
void virtio_queue_notify(struct virtio_device *dev, int queue)
{
- if (dev->type == VIRTIO_TYPE_PCI) {
- ci_write_16(dev->base+VIRTIOHDR_QUEUE_NOTIFY, cpu_to_le16(queue));
+ if (dev->is_modern) {
+ void *q_sel = dev->common.addr + offset_of(struct virtio_dev_common, q_select);
+ void *q_ntfy = dev->common.addr + offset_of(struct virtio_dev_common, q_notify_off);
+ void *addr;
+ uint16_t q_notify_off;
+
+ ci_write_16(q_sel, cpu_to_le16(queue));
+ eieio();
+ q_notify_off = le16_to_cpu(ci_read_16(q_ntfy));
+ addr = dev->notify.addr + q_notify_off * dev->notify_off_mul;
+ ci_write_16(addr, cpu_to_le16(queue));
+ } else {
+ ci_write_16(dev->legacy.addr+VIRTIOHDR_QUEUE_NOTIFY, cpu_to_le16(queue));
}
}
/**
* Set queue address
*/
-void virtio_set_qaddr(struct virtio_device *dev, int queue, unsigned int qaddr)
+void virtio_set_qaddr(struct virtio_device *dev, int queue, unsigned long qaddr)
+{
+ if (dev->is_modern) {
+ uint64_t q_desc = qaddr;
+ uint64_t q_avail;
+ uint64_t q_used;
+ uint32_t q_size = virtio_get_qsize(dev, queue);
+
+ virtio_pci_write64(dev->common.addr + offset_of(struct virtio_dev_common, q_desc), q_desc);
+ q_avail = q_desc + q_size * sizeof(struct vring_desc);
+ virtio_pci_write64(dev->common.addr + offset_of(struct virtio_dev_common, q_avail), q_avail);
+ q_used = VQ_ALIGN(q_avail + sizeof(struct vring_avail) + sizeof(uint16_t) * q_size);
+ virtio_pci_write64(dev->common.addr + offset_of(struct virtio_dev_common, q_used), q_used);
+ ci_write_16(dev->common.addr + offset_of(struct virtio_dev_common, q_enable), cpu_to_le16(1));
+ } else {
+ uint32_t val = qaddr;
+ val = val >> 12;
+ ci_write_16(dev->legacy.addr+VIRTIOHDR_QUEUE_SELECT,
+ cpu_to_le16(queue));
+ eieio();
+ ci_write_32(dev->legacy.addr+VIRTIOHDR_QUEUE_ADDRESS,
+ cpu_to_le32(val));
+ }
+}
+
+int virtio_queue_init_vq(struct virtio_device *dev, struct vqs *vq, unsigned int id)
{
- if (dev->type == VIRTIO_TYPE_PCI) {
- uint32_t val = qaddr;
- val = val >> 12;
- ci_write_16(dev->base+VIRTIOHDR_QUEUE_SELECT,
- cpu_to_le16(queue));
- eieio();
- ci_write_32(dev->base+VIRTIOHDR_QUEUE_ADDRESS,
- cpu_to_le32(val));
- }
+ vq->size = virtio_get_qsize(dev, id);
+ vq->desc = SLOF_alloc_mem_aligned(virtio_vring_size(vq->size), 4096);
+ if (!vq->desc) {
+ printf("memory allocation failed!\n");
+ return -1;
+ }
+ memset(vq->desc, 0, virtio_vring_size(vq->size));
+ virtio_set_qaddr(dev, id, (unsigned long)vq->desc);
+ vq->avail = virtio_get_vring_avail(dev, id);
+ vq->used = virtio_get_vring_used(dev, id);
+ vq->id = id;
+ return 0;
}
/**
@@ -151,34 +406,109 @@ void virtio_set_qaddr(struct virtio_device *dev, int queue, unsigned int qaddr)
*/
void virtio_set_status(struct virtio_device *dev, int status)
{
- if (dev->type == VIRTIO_TYPE_PCI) {
- ci_write_8(dev->base+VIRTIOHDR_DEVICE_STATUS, status);
+ if (dev->is_modern) {
+ ci_write_8(dev->common.addr +
+ offset_of(struct virtio_dev_common, dev_status), status);
+ } else {
+ ci_write_8(dev->legacy.addr+VIRTIOHDR_DEVICE_STATUS, status);
}
}
+/**
+ * Get device status bits
+ */
+void virtio_get_status(struct virtio_device *dev, int *status)
+{
+ if (dev->is_modern) {
+ *status = ci_read_8(dev->common.addr +
+ offset_of(struct virtio_dev_common, dev_status));
+ } else {
+ *status = ci_read_8(dev->legacy.addr+VIRTIOHDR_DEVICE_STATUS);
+ }
+}
/**
* Set guest feature bits
*/
-void virtio_set_guest_features(struct virtio_device *dev, int features)
+void virtio_set_guest_features(struct virtio_device *dev, uint64_t features)
{
- if (dev->type == VIRTIO_TYPE_PCI) {
- ci_write_32(dev->base+VIRTIOHDR_GUEST_FEATURES, bswap_32(features));
+ if (dev->is_modern) {
+ uint32_t f1 = (features >> 32) & 0xFFFFFFFF;
+ uint32_t f0 = features & 0xFFFFFFFF;
+ void *addr = dev->common.addr;
+
+ ci_write_32(addr + offset_of(struct virtio_dev_common, drv_features_sel),
+ cpu_to_le32(1));
+ ci_write_32(addr + offset_of(struct virtio_dev_common, drv_features),
+ cpu_to_le32(f1));
+
+ ci_write_32(addr + offset_of(struct virtio_dev_common, drv_features_sel),
+ cpu_to_le32(0));
+ ci_write_32(addr + offset_of(struct virtio_dev_common, drv_features),
+ cpu_to_le32(f0));
+ } else {
+ ci_write_32(dev->legacy.addr+VIRTIOHDR_GUEST_FEATURES, cpu_to_le32(features));
}
}
/**
* Get host feature bits
*/
-void virtio_get_host_features(struct virtio_device *dev, int *features)
+uint64_t virtio_get_host_features(struct virtio_device *dev)
{
- if (dev->type == VIRTIO_TYPE_PCI && features) {
- *features = bswap_32(ci_read_32(dev->base+VIRTIOHDR_DEVICE_FEATURES));
+ uint64_t features = 0;
+ if (dev->is_modern) {
+ uint32_t f0 = 0, f1 = 0;
+ void *addr = dev->common.addr;
+
+ ci_write_32(addr + offset_of(struct virtio_dev_common, dev_features_sel),
+ cpu_to_le32(1));
+ f1 = ci_read_32(addr +
+ offset_of(struct virtio_dev_common, dev_features));
+ ci_write_32(addr + offset_of(struct virtio_dev_common, dev_features_sel),
+ cpu_to_le32(0));
+ f0 = ci_read_32(addr +
+ offset_of(struct virtio_dev_common, dev_features));
+
+ features = ((uint64_t)le32_to_cpu(f1) << 32) | le32_to_cpu(f0);
+ } else {
+ features = le32_to_cpu(ci_read_32(dev->legacy.addr+VIRTIOHDR_DEVICE_FEATURES));
}
+ return features;
}
+int virtio_negotiate_guest_features(struct virtio_device *dev, uint64_t features)
+{
+ uint64_t host_features = 0;
+ int status;
+
+ /* Negotiate features */
+ host_features = virtio_get_host_features(dev);
+ if (!(host_features & VIRTIO_F_VERSION_1)) {
+ fprintf(stderr, "Device does not support virtio 1.0 %llx\n", host_features);
+ return -1;
+ }
+
+ virtio_set_guest_features(dev, features);
+ host_features = virtio_get_host_features(dev);
+ if ((host_features & features) != features) {
+ fprintf(stderr, "Features error %llx\n", features);
+ return -1;
+ }
+
+ virtio_get_status(dev, &status);
+ status |= VIRTIO_STAT_FEATURES_OK;
+ virtio_set_status(dev, status);
+
+ /* Read back to verify the FEATURES_OK bit */
+ virtio_get_status(dev, &status);
+ if ((status & VIRTIO_STAT_FEATURES_OK) != VIRTIO_STAT_FEATURES_OK)
+ return -1;
+
+ return 0;
+}
/**
* Get additional config values
@@ -186,32 +516,38 @@ void virtio_get_host_features(struct virtio_device *dev, int *features)
uint64_t virtio_get_config(struct virtio_device *dev, int offset, int size)
{
uint64_t val = ~0ULL;
+ uint32_t hi, lo;
void *confbase;
- switch (dev->type) {
- case VIRTIO_TYPE_PCI:
- confbase = dev->base+VIRTIOHDR_DEVICE_CONFIG;
- break;
- default:
- return ~0ULL;
- }
+ if (dev->is_modern)
+ confbase = dev->device.addr;
+ else
+ confbase = dev->legacy.addr+VIRTIOHDR_DEVICE_CONFIG;
+
switch (size) {
- case 1:
+ case 1:
val = ci_read_8(confbase+offset);
break;
- case 2:
+ case 2:
val = ci_read_16(confbase+offset);
+ if (dev->is_modern)
+ val = le16_to_cpu(val);
break;
- case 4:
+ case 4:
val = ci_read_32(confbase+offset);
+ if (dev->is_modern)
+ val = le32_to_cpu(val);
break;
- case 8:
+ case 8:
/* We don't support 8 bytes PIO accesses
* in qemu and this is all PIO
*/
- val = ci_read_32(confbase+offset);
- val <<= 32;
- val |= ci_read_32(confbase+offset+4);
+ lo = ci_read_32(confbase+offset);
+ hi = ci_read_32(confbase+offset+4);
+ if (dev->is_modern)
+ val = (uint64_t)le32_to_cpu(hi) << 32 | le32_to_cpu(lo);
+ else
+ val = (uint64_t)hi << 32 | lo;
break;
}
@@ -222,20 +558,19 @@ uint64_t virtio_get_config(struct virtio_device *dev, int offset, int size)
* Get config blob
*/
int __virtio_read_config(struct virtio_device *dev, void *dst,
- int offset, int len)
+ int offset, int len)
{
void *confbase;
unsigned char *buf = dst;
int i;
- switch (dev->type) {
- case VIRTIO_TYPE_PCI:
- confbase = dev->base+VIRTIOHDR_DEVICE_CONFIG;
- break;
- default:
- return 0;
- }
+ if (dev->is_modern)
+ confbase = dev->device.addr;
+ else
+ confbase = dev->legacy.addr+VIRTIOHDR_DEVICE_CONFIG;
+
for (i = 0; i < len; i++)
buf[i] = ci_read_8(confbase + offset + i);
+
return len;
}
diff --git a/qemu/roms/SLOF/lib/libvirtio/virtio.code b/qemu/roms/SLOF/lib/libvirtio/virtio.code
index 258b9bbda..8eec8f055 100644
--- a/qemu/roms/SLOF/lib/libvirtio/virtio.code
+++ b/qemu/roms/SLOF/lib/libvirtio/virtio.code
@@ -18,6 +18,11 @@
/******** core virtio ********/
+// : virtio-setup-vd ( -- dev )
+PRIM(virtio_X2d_setup_X2d_vd)
+ PUSH; TOS.a = virtio_setup_vd();
+MIRP
+
// : virtio-vring-size ( queuesize -- ringsize )
PRIM(virtio_X2d_vring_X2d_size)
TOS.u = virtio_vring_size(TOS.u);
@@ -122,20 +127,18 @@ MIRP
/******** virtio-net ********/
-// : virtio-net-open ( mac-addr-str len dev -- false | [ driver true ] )
+// : virtio-net-open ( dev -- false | [ driver true ] )
PRIM(virtio_X2d_net_X2d_open)
{
- void *dev = TOS.a; POP;
- int len = TOS.u; POP;
- char *mac_addr = TOS.a;
+ void *dev = TOS.a;
- net_driver_t *net_driver = virtionet_open(mac_addr, len, dev);
+ net_driver_t *net_driver = virtionet_open(dev);
- if (net_driver) {
- TOS.u = (unsigned long)net_driver; PUSH;
- TOS.n = -1;
- } else
- TOS.n = 0;
+ if (net_driver) {
+ TOS.u = (unsigned long)net_driver; PUSH;
+ TOS.n = -1;
+ } else
+ TOS.n = 0;
}
MIRP
diff --git a/qemu/roms/SLOF/lib/libvirtio/virtio.h b/qemu/roms/SLOF/lib/libvirtio/virtio.h
index d5759b45a..0fee4baec 100644
--- a/qemu/roms/SLOF/lib/libvirtio/virtio.h
+++ b/qemu/roms/SLOF/lib/libvirtio/virtio.h
@@ -14,13 +14,23 @@
#define _LIBVIRTIO_H
#include <stdint.h>
+#include <stdbool.h>
/* Device status bits */
#define VIRTIO_STAT_ACKNOWLEDGE 1
#define VIRTIO_STAT_DRIVER 2
#define VIRTIO_STAT_DRIVER_OK 4
+#define VIRTIO_STAT_FEATURES_OK 8
+#define VIRTIO_STAT_NEEDS_RESET 64
#define VIRTIO_STAT_FAILED 128
+#define BIT(x) (1UL << (x))
+
+/* VIRTIO 1.0 Device independent feature bits */
+#define VIRTIO_F_RING_INDIRECT_DESC BIT(28)
+#define VIRTIO_F_RING_EVENT_IDX BIT(29)
+#define VIRTIO_F_VERSION_1 BIT(32)
+
#define VIRTIO_TIMEOUT 5000 /* 5 sec timeout */
/* Definitions for vring_desc.flags */
@@ -34,7 +44,7 @@ struct vring_desc {
uint32_t len; /* Length */
uint16_t flags; /* The flags as indicated above */
uint16_t next; /* Next field if flags & NEXT */
-};
+};
/* Definitions for vring_avail.flags */
#define VRING_AVAIL_F_NO_INTERRUPT 1
@@ -44,8 +54,7 @@ struct vring_avail {
uint16_t flags;
uint16_t idx;
uint16_t ring[];
-};
-
+};
/* Definitions for vring_used.flags */
#define VRING_USED_F_NO_NOTIFY 1
@@ -61,27 +70,56 @@ struct vring_used {
struct vring_used_elem ring[];
};
-#define VIRTIO_TYPE_PCI 0 /* For virtio-pci interface */
+/* Structure shared with SLOF and is 16bytes */
+struct virtio_cap {
+ void *addr;
+ uint8_t bar;
+ uint8_t is_io;
+ uint8_t cap_id;
+};
+
struct virtio_device {
- void *base; /* base address */
- int type; /* VIRTIO_TYPE_PCI or VIRTIO_TYPE_VIO */
+ uint32_t is_modern; /* Indicates whether to use virtio 1.0 */
+ struct virtio_cap legacy;
+ struct virtio_cap common;
+ struct virtio_cap notify;
+ struct virtio_cap isr;
+ struct virtio_cap device;
+ struct virtio_cap pci;
+ uint32_t notify_off_mul;
+};
+
+struct vqs {
+ uint64_t id; /* Queue ID */
+ uint32_t size;
+ void *buf_mem;
+ struct vring_desc *desc;
+ struct vring_avail *avail;
+ struct vring_used *used;
};
/* Parts of the virtqueue are aligned on a 4096 byte page boundary */
#define VQ_ALIGN(addr) (((addr) + 0xfff) & ~0xfff)
extern unsigned long virtio_vring_size(unsigned int qsize);
-extern int virtio_get_qsize(struct virtio_device *dev, int queue);
+extern unsigned int virtio_get_qsize(struct virtio_device *dev, int queue);
extern struct vring_desc *virtio_get_vring_desc(struct virtio_device *dev, int queue);
extern struct vring_avail *virtio_get_vring_avail(struct virtio_device *dev, int queue);
extern struct vring_used *virtio_get_vring_used(struct virtio_device *dev, int queue);
+extern void virtio_fill_desc(struct vring_desc *desc, bool is_modern,
+ uint64_t addr, uint32_t len,
+ uint16_t flags, uint16_t next);
+extern int virtio_queue_init_vq(struct virtio_device *dev, struct vqs *vq, unsigned int id);
+extern struct virtio_device *virtio_setup_vd(void);
extern void virtio_reset_device(struct virtio_device *dev);
extern void virtio_queue_notify(struct virtio_device *dev, int queue);
extern void virtio_set_status(struct virtio_device *dev, int status);
-extern void virtio_set_qaddr(struct virtio_device *dev, int queue, unsigned int qaddr);
-extern void virtio_set_guest_features(struct virtio_device *dev, int features);
-extern void virtio_get_host_features(struct virtio_device *dev, int *features);
+extern void virtio_get_status(struct virtio_device *dev, int *status);
+extern void virtio_set_qaddr(struct virtio_device *dev, int queue, unsigned long qaddr);
+extern void virtio_set_guest_features(struct virtio_device *dev, uint64_t features);
+extern uint64_t virtio_get_host_features(struct virtio_device *dev);
+extern int virtio_negotiate_guest_features(struct virtio_device *dev, uint64_t features);
extern uint64_t virtio_get_config(struct virtio_device *dev, int offset, int size);
extern int __virtio_read_config(struct virtio_device *dev, void *dst,
int offset, int len);
diff --git a/qemu/roms/SLOF/lib/libvirtio/virtio.in b/qemu/roms/SLOF/lib/libvirtio/virtio.in
index c36d127c7..195840e0f 100644
--- a/qemu/roms/SLOF/lib/libvirtio/virtio.in
+++ b/qemu/roms/SLOF/lib/libvirtio/virtio.in
@@ -10,6 +10,8 @@
* IBM Corporation - initial implementation
*****************************************************************************/
+cod(virtio-setup-vd)
+
cod(virtio-vring-size)
cod(virtio-get-qsize)
cod(virtio-get-config)
diff --git a/qemu/roms/SLOF/make.rules b/qemu/roms/SLOF/make.rules
index aebc4e360..cbc63530a 100644
--- a/qemu/roms/SLOF/make.rules
+++ b/qemu/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/qemu/roms/SLOF/rtas/reloc.S b/qemu/roms/SLOF/rtas/reloc.S
index e24d293d4..1b5b59a68 100644
--- a/qemu/roms/SLOF/rtas/reloc.S
+++ b/qemu/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/qemu/roms/SLOF/rtas/rtas.lds b/qemu/roms/SLOF/rtas/rtas.lds
index a5ba1daaf..30b18dd26 100644
--- a/qemu/roms/SLOF/rtas/rtas.lds
+++ b/qemu/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/qemu/roms/SLOF/rtas/rtas_entry.S b/qemu/roms/SLOF/rtas/rtas_entry.S
index 74693aa48..424137bf5 100644
--- a/qemu/roms/SLOF/rtas/rtas_entry.S
+++ b/qemu/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/qemu/roms/SLOF/slof/entry.S b/qemu/roms/SLOF/slof/entry.S
index dcff57ba0..5372de357 100644
--- a/qemu/roms/SLOF/slof/entry.S
+++ b/qemu/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
+
+.global the_system_stack
.lcomm the_system_stack, STACKSIZE, 16
diff --git a/qemu/roms/SLOF/slof/fs/base.fs b/qemu/roms/SLOF/slof/fs/base.fs
index e71e087eb..03e77e54f 100644
--- a/qemu/roms/SLOF/slof/fs/base.fs
+++ b/qemu/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/qemu/roms/SLOF/slof/fs/boot.fs b/qemu/roms/SLOF/slof/fs/boot.fs
index 9a0ded0c2..e0b628140 100644
--- a/qemu/roms/SLOF/slof/fs/boot.fs
+++ b/qemu/roms/SLOF/slof/fs/boot.fs
@@ -181,17 +181,13 @@ defer go ( -- )
\ with watchdog timeout.
4ec set-watchdog
THEN
+ 2dup " HALT" str= IF 2drop 0 EXIT THEN
my-self >r current-node @ >r \ Save my-self
." Trying to load: " $bootargs type ." from: " 2dup type ." ... "
2dup open-dev dup IF
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 +207,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/qemu/roms/SLOF/slof/fs/client.fs b/qemu/roms/SLOF/slof/fs/client.fs
index 1b2bb0326..7d537a668 100644
--- a/qemu/roms/SLOF/slof/fs/client.fs
+++ b/qemu/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/qemu/roms/SLOF/slof/fs/fbuffer.fs b/qemu/roms/SLOF/slof/fs/fbuffer.fs
index 756f05a95..47046087d 100644
--- a/qemu/roms/SLOF/slof/fs/fbuffer.fs
+++ b/qemu/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/qemu/roms/SLOF/slof/fs/little-endian.fs b/qemu/roms/SLOF/slof/fs/little-endian.fs
index f2e4e8d42..6b4779ee0 100644
--- a/qemu/roms/SLOF/slof/fs/little-endian.fs
+++ b/qemu/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/qemu/roms/SLOF/slof/fs/packages/disk-label.fs b/qemu/roms/SLOF/slof/fs/packages/disk-label.fs
index fe1c25e7a..e034d6408 100644
--- a/qemu/roms/SLOF/slof/fs/packages/disk-label.fs
+++ b/qemu/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/qemu/roms/SLOF/slof/fs/packages/fat-files.fs b/qemu/roms/SLOF/slof/fs/packages/fat-files.fs
index 0cec3664e..d9194527e 100644
--- a/qemu/roms/SLOF/slof/fs/packages/fat-files.fs
+++ b/qemu/roms/SLOF/slof/fs/packages/fat-files.fs
@@ -18,6 +18,7 @@ INSTANCE VARIABLE sectors/cluster
INSTANCE VARIABLE #reserved-sectors
INSTANCE VARIABLE #fats
INSTANCE VARIABLE #root-entries
+INSTANCE VARIABLE fat32-root-cluster
INSTANCE VARIABLE total-#sectors
INSTANCE VARIABLE media-descriptor
INSTANCE VARIABLE sectors/fat
@@ -59,9 +60,18 @@ INSTANCE VARIABLE next-cluster
: read-cluster ( cluster# -- )
dup bytes/cluster @ * cluster-offset @ + bytes/cluster @ read-data
read-fat dup #clusters @ >= IF drop 0 THEN next-cluster ! ;
+
: read-dir ( cluster# -- )
- ?dup 0= IF root-offset @ #root-entries @ 20 * read-data 0 next-cluster !
- ELSE read-cluster THEN ;
+ ?dup 0= IF
+ #root-entries @ 0= IF
+ fat32-root-cluster @ read-cluster
+ ELSE
+ root-offset @ #root-entries @ 20 * read-data 0 next-cluster !
+ THEN
+ ELSE
+ read-cluster
+ THEN
+;
: .time ( x -- )
base @ >r decimal
@@ -137,6 +147,7 @@ CREATE dos-name b allot
\ For FAT32:
sectors/fat @ 0= IF data @ 24 + 4c@ bljoin sectors/fat ! THEN
+ #root-entries @ 0= IF data @ 2c + 4c@ bljoin ELSE 0 THEN fat32-root-cluster !
\ XXX add other FAT32 stuff (offsets 28, 2c, 30)
diff --git a/qemu/roms/SLOF/slof/fs/pci-config-bridge.fs b/qemu/roms/SLOF/slof/fs/pci-config-bridge.fs
index 689325318..1efbcd804 100644
--- a/qemu/roms/SLOF/slof/fs/pci-config-bridge.fs
+++ b/qemu/roms/SLOF/slof/fs/pci-config-bridge.fs
@@ -81,26 +81,6 @@
2drop
;
-: dma-alloc ( ... size -- virt )
- \ ." dma-alloc called: " .s cr
- alloc-mem
-;
-
-: dma-free ( virt size -- )
- \ ." dma-free called: " .s cr
- free-mem
-;
-
-: dma-map-in ( ... virt size cacheable? -- devaddr )
- \ ." dma-map-in called: " .s cr
- 2drop
-;
-
-: dma-map-out ( virt devaddr size -- )
- \ ." dma-map-out called: " .s cr
- 2drop drop
-;
-
: dma-sync ( virt devaddr size -- )
\ XXX should we add at least a memory barrier here?
\ ." dma-sync called: " .s cr
diff --git a/qemu/roms/SLOF/slof/fs/pci-scan.fs b/qemu/roms/SLOF/slof/fs/pci-scan.fs
index b8b9fe61f..2fdf0e8f5 100644
--- a/qemu/roms/SLOF/slof/fs/pci-scan.fs
+++ b/qemu/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/qemu/roms/SLOF/slof/fs/rmove.fs b/qemu/roms/SLOF/slof/fs/rmove.fs
deleted file mode 100644
index c28dba9c4..000000000
--- a/qemu/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/qemu/roms/SLOF/slof/fs/root.fs b/qemu/roms/SLOF/slof/fs/root.fs
index 21c710951..952b00e75 100644
--- a/qemu/roms/SLOF/slof/fs/root.fs
+++ b/qemu/roms/SLOF/slof/fs/root.fs
@@ -77,7 +77,6 @@ finish-device
: open true ;
: close ;
-#include <archsupport.fs>
\ Finish root
finish-device
diff --git a/qemu/roms/SLOF/slof/fs/terminal.fs b/qemu/roms/SLOF/slof/fs/terminal.fs
index 582bedeb3..dc82e7bf4 100644
--- a/qemu/roms/SLOF/slof/fs/terminal.fs
+++ b/qemu/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/qemu/roms/SLOF/slof/helpers.c b/qemu/roms/SLOF/slof/helpers.c
index d7c1888b4..48c34a65c 100644
--- a/qemu/roms/SLOF/slof/helpers.c
+++ b/qemu/roms/SLOF/slof/helpers.c
@@ -114,6 +114,13 @@ long SLOF_pci_config_read16(long offset)
return forth_pop();
}
+long SLOF_pci_config_read8(long offset)
+{
+ forth_push(offset);
+ forth_eval("config-b@");
+ return forth_pop();
+}
+
void SLOF_pci_config_write32(long offset, long value)
{
forth_push(value);
@@ -128,6 +135,13 @@ void SLOF_pci_config_write16(long offset, long value)
forth_eval("config-w!");
}
+void SLOF_pci_config_write8(long offset, long value)
+{
+ forth_push(value);
+ forth_push(offset);
+ forth_eval("config-b!");
+}
+
void *SLOF_translate_my_address(void *addr)
{
forth_push((long)addr);
diff --git a/qemu/roms/SLOF/slof/paflof.c b/qemu/roms/SLOF/slof/paflof.c
index 624955fba..2fc25c81e 100644
--- a/qemu/roms/SLOF/slof/paflof.c
+++ b/qemu/roms/SLOF/slof/paflof.c
@@ -19,6 +19,7 @@
#undef unix
#include "paflof.h"
+#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <ctype.h>
@@ -43,6 +44,9 @@ unsigned char hash_table[HASHSIZE*CELLSIZE];
#include ISTR(TARG,c)
+static int did_stackwarning;
+extern char the_system_stack[];
+
// the actual engine
long engine(int mode, long param_1, long param_2)
{
@@ -84,6 +88,11 @@ long engine(int mode, long param_1, long param_2)
c_return[1].a = &dummy;
}
+ if ((char *)&ip < the_system_stack && !did_stackwarning) {
+ puts("ERROR: stack overflow in engine()!");
+ did_stackwarning = 1;
+ }
+
if (mode & ENGINE_MODE_PARAM_2) {
(++dp)->n = param_2;
}
diff --git a/qemu/roms/SLOF/slof/ppc64.c b/qemu/roms/SLOF/slof/ppc64.c
index 20d927069..619d95ec7 100644
--- a/qemu/roms/SLOF/slof/ppc64.c
+++ b/qemu/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/qemu/roms/SLOF/slof/prim.code b/qemu/roms/SLOF/slof/prim.code
index 9fbed7168..bb9e036a9 100644
--- a/qemu/roms/SLOF/slof/prim.code
+++ b/qemu/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/qemu/roms/SLOF/slof/prim.in b/qemu/roms/SLOF/slof/prim.in
index 7a0d6a2ed..855f59262 100644
--- a/qemu/roms/SLOF/slof/prim.in
+++ b/qemu/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/qemu/roms/config.ipxe.general.h b/qemu/roms/config.ipxe.general.h
deleted file mode 100644
index 619ee4c15..000000000
--- a/qemu/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/qemu/roms/config.seabios-128k b/qemu/roms/config.seabios-128k
index c719ba689..0a9da77a5 100644
--- a/qemu/roms/config.seabios-128k
+++ b/qemu/roms/config.seabios-128k
@@ -3,6 +3,8 @@
CONFIG_QEMU=y
CONFIG_ROM_SIZE=128
CONFIG_XEN=n
+CONFIG_USB_OHCI=n
CONFIG_USB_XHCI=n
CONFIG_USB_UAS=n
CONFIG_SDCARD=n
+CONFIG_TCGBIOS=n
diff --git a/qemu/roms/ipxe/COPYING b/qemu/roms/ipxe/COPYING
index a43ea2126..342330bb9 100644
--- a/qemu/roms/ipxe/COPYING
+++ b/qemu/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/qemu/roms/ipxe/COPYING.GPLv2 b/qemu/roms/ipxe/COPYING.GPLv2
new file mode 100644
index 000000000..d159169d1
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/COPYING.UBDL b/qemu/roms/ipxe/COPYING.UBDL
new file mode 100644
index 000000000..780ddcd77
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/COPYRIGHTS b/qemu/roms/ipxe/COPYRIGHTS
deleted file mode 100644
index 342330bb9..000000000
--- a/qemu/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/qemu/roms/ipxe/src/Makefile b/qemu/roms/ipxe/src/Makefile
index b742d1283..2a9cc9e8f 100644
--- a/qemu/roms/ipxe/src/Makefile
+++ b/qemu/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/qemu/roms/ipxe/src/Makefile.housekeeping b/qemu/roms/ipxe/src/Makefile.housekeeping
index 1a75d3939..03800c8ef 100644
--- a/qemu/roms/ipxe/src/Makefile.housekeeping
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/Makefile b/qemu/roms/ipxe/src/arch/i386/Makefile
index 4925cc4e6..99f875314 100644
--- a/qemu/roms/ipxe/src/arch/i386/Makefile
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/core/basemem_packet.c b/qemu/roms/ipxe/src/arch/i386/core/basemem_packet.c
index 06ffa3bbd..9f5fbf330 100644
--- a/qemu/roms/ipxe/src/arch/i386/core/basemem_packet.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/core/cachedhcp.c b/qemu/roms/ipxe/src/arch/i386/core/cachedhcp.c
index 3cac28e7d..a5c624035 100644
--- a/qemu/roms/ipxe/src/arch/i386/core/cachedhcp.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/core/gdbmach.c b/qemu/roms/ipxe/src/arch/i386/core/gdbmach.c
index 4d6897f7d..d92a4ac08 100644
--- a/qemu/roms/ipxe/src/arch/i386/core/gdbmach.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/core/patch_cf.S b/qemu/roms/ipxe/src/arch/i386/core/patch_cf.S
index 97a62f494..4365563fe 100644
--- a/qemu/roms/ipxe/src/arch/i386/core/patch_cf.S
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/core/pci_autoboot.c b/qemu/roms/ipxe/src/arch/i386/core/pci_autoboot.c
index a3eb1f97d..337598091 100644
--- a/qemu/roms/ipxe/src/arch/i386/core/pci_autoboot.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/core/rdtsc_timer.c b/qemu/roms/ipxe/src/arch/i386/core/rdtsc_timer.c
index 2f31afc66..e720a239c 100644
--- a/qemu/roms/ipxe/src/arch/i386/core/rdtsc_timer.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/core/relocate.c b/qemu/roms/ipxe/src/arch/i386/core/relocate.c
index 5fbf2d2c2..54ad387e4 100644
--- a/qemu/roms/ipxe/src/arch/i386/core/relocate.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/core/runtime.c b/qemu/roms/ipxe/src/arch/i386/core/runtime.c
index 18ca7936e..d160fee04 100644
--- a/qemu/roms/ipxe/src/arch/i386/core/runtime.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/core/setjmp.S b/qemu/roms/ipxe/src/arch/i386/core/setjmp.S
index 03727148c..81d3b4911 100644
--- a/qemu/roms/ipxe/src/arch/i386/core/setjmp.S
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/core/stack.S b/qemu/roms/ipxe/src/arch/i386/core/stack.S
index 737ec0eed..98f1cd9b9 100644
--- a/qemu/roms/ipxe/src/arch/i386/core/stack.S
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/core/stack16.S b/qemu/roms/ipxe/src/arch/i386/core/stack16.S
index 523f0288b..4bc6f081a 100644
--- a/qemu/roms/ipxe/src/arch/i386/core/stack16.S
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/core/timer2.c b/qemu/roms/ipxe/src/arch/i386/core/timer2.c
deleted file mode 100644
index 077866562..000000000
--- a/qemu/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/qemu/roms/ipxe/src/arch/i386/core/virtaddr.S b/qemu/roms/ipxe/src/arch/i386/core/virtaddr.S
index 5e5d77352..425591570 100644
--- a/qemu/roms/ipxe/src/arch/i386/core/virtaddr.S
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/drivers/net/undi.c b/qemu/roms/ipxe/src/arch/i386/drivers/net/undi.c
index 2bc54824c..9820cf629 100644
--- a/qemu/roms/ipxe/src/arch/i386/drivers/net/undi.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/drivers/net/undiload.c b/qemu/roms/ipxe/src/arch/i386/drivers/net/undiload.c
index 77134dcb8..7160ee384 100644
--- a/qemu/roms/ipxe/src/arch/i386/drivers/net/undiload.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/drivers/net/undionly.c b/qemu/roms/ipxe/src/arch/i386/drivers/net/undionly.c
index 028fac5d9..70dbe4bfd 100644
--- a/qemu/roms/ipxe/src/arch/i386/drivers/net/undionly.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/drivers/net/undipreload.c b/qemu/roms/ipxe/src/arch/i386/drivers/net/undipreload.c
index 81d7a80eb..fca771843 100644
--- a/qemu/roms/ipxe/src/arch/i386/drivers/net/undipreload.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/firmware/pcbios/basemem.c b/qemu/roms/ipxe/src/arch/i386/firmware/pcbios/basemem.c
index b23f2c356..6a46081aa 100644
--- a/qemu/roms/ipxe/src/arch/i386/firmware/pcbios/basemem.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/firmware/pcbios/bios_console.c b/qemu/roms/ipxe/src/arch/i386/firmware/pcbios/bios_console.c
index bd73838b5..63413cdc1 100644
--- a/qemu/roms/ipxe/src/arch/i386/firmware/pcbios/bios_console.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/firmware/pcbios/e820mangler.S b/qemu/roms/ipxe/src/arch/i386/firmware/pcbios/e820mangler.S
index cea17ef8e..d5d97b482 100644
--- a/qemu/roms/ipxe/src/arch/i386/firmware/pcbios/e820mangler.S
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/firmware/pcbios/fakee820.c b/qemu/roms/ipxe/src/arch/i386/firmware/pcbios/fakee820.c
index e5f713728..15f4d772f 100644
--- a/qemu/roms/ipxe/src/arch/i386/firmware/pcbios/fakee820.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/firmware/pcbios/hidemem.c b/qemu/roms/ipxe/src/arch/i386/firmware/pcbios/hidemem.c
index 8f3069e18..253c601ff 100644
--- a/qemu/roms/ipxe/src/arch/i386/firmware/pcbios/hidemem.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/firmware/pcbios/memmap.c b/qemu/roms/ipxe/src/arch/i386/firmware/pcbios/memmap.c
index 0937a7ce2..bcacecd6a 100644
--- a/qemu/roms/ipxe/src/arch/i386/firmware/pcbios/memmap.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/firmware/pcbios/pnpbios.c b/qemu/roms/ipxe/src/arch/i386/firmware/pcbios/pnpbios.c
index 5c74b0431..20ec35d75 100644
--- a/qemu/roms/ipxe/src/arch/i386/firmware/pcbios/pnpbios.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/hci/commands/pxe_cmd.c b/qemu/roms/ipxe/src/arch/i386/hci/commands/pxe_cmd.c
index 523724ab0..473b97f97 100644
--- a/qemu/roms/ipxe/src/arch/i386/hci/commands/pxe_cmd.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/image/bootsector.c b/qemu/roms/ipxe/src/arch/i386/image/bootsector.c
index 9a089e6bb..dba87613c 100644
--- a/qemu/roms/ipxe/src/arch/i386/image/bootsector.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/image/bzimage.c b/qemu/roms/ipxe/src/arch/i386/image/bzimage.c
index 4865c394c..a64206cd3 100644
--- a/qemu/roms/ipxe/src/arch/i386/image/bzimage.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/image/elfboot.c b/qemu/roms/ipxe/src/arch/i386/image/elfboot.c
index 0f6957f02..dc3568929 100644
--- a/qemu/roms/ipxe/src/arch/i386/image/elfboot.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/image/initrd.c b/qemu/roms/ipxe/src/arch/i386/image/initrd.c
index eaba3a645..80c197417 100644
--- a/qemu/roms/ipxe/src/arch/i386/image/initrd.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/image/multiboot.c b/qemu/roms/ipxe/src/arch/i386/image/multiboot.c
index 86b0bc12d..0c85df708 100644
--- a/qemu/roms/ipxe/src/arch/i386/image/multiboot.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/image/pxe_image.c b/qemu/roms/ipxe/src/arch/i386/image/pxe_image.c
index dc28f6082..5b0f6eb89 100644
--- a/qemu/roms/ipxe/src/arch/i386/image/pxe_image.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/image/sdi.c b/qemu/roms/ipxe/src/arch/i386/image/sdi.c
index df1c3a868..fa2d0b73f 100644
--- a/qemu/roms/ipxe/src/arch/i386/image/sdi.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/basemem.h b/qemu/roms/ipxe/src/arch/i386/include/basemem.h
index c477c7fe2..01c2ea917 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/basemem.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/basemem_packet.h b/qemu/roms/ipxe/src/arch/i386/include/basemem_packet.h
index 3cb477671..def6dee31 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/basemem_packet.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/bios.h b/qemu/roms/ipxe/src/arch/i386/include/bios.h
index 0754b1168..988bbc62b 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/bios.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/biosint.h b/qemu/roms/ipxe/src/arch/i386/include/biosint.h
index ab466af3c..67d6a3811 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/biosint.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/bits/byteswap.h b/qemu/roms/ipxe/src/arch/i386/include/bits/byteswap.h
index 0d9cb967c..53b6a454d 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/bits/byteswap.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/bits/compiler.h b/qemu/roms/ipxe/src/arch/i386/include/bits/compiler.h
index d48b4b385..87201135f 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/bits/compiler.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/bits/endian.h b/qemu/roms/ipxe/src/arch/i386/include/bits/endian.h
deleted file mode 100644
index 841885424..000000000
--- a/qemu/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/qemu/roms/ipxe/src/arch/i386/include/bits/entropy.h b/qemu/roms/ipxe/src/arch/i386/include/bits/entropy.h
index 6dcceec6d..bfeb5e3b5 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/bits/entropy.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/bits/hyperv.h b/qemu/roms/ipxe/src/arch/i386/include/bits/hyperv.h
new file mode 100644
index 000000000..3565c8a83
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/bits/nap.h b/qemu/roms/ipxe/src/arch/i386/include/bits/nap.h
index 64066e6ab..e8bcfd13b 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/bits/nap.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/bits/profile.h b/qemu/roms/ipxe/src/arch/i386/include/bits/profile.h
index f3ee54ae9..e184d7b51 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/bits/profile.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/bits/reboot.h b/qemu/roms/ipxe/src/arch/i386/include/bits/reboot.h
index 5b09e95f7..803dacfe4 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/bits/reboot.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/bits/sanboot.h b/qemu/roms/ipxe/src/arch/i386/include/bits/sanboot.h
index 9c77a4d42..f02d2e649 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/bits/sanboot.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/bits/smbios.h b/qemu/roms/ipxe/src/arch/i386/include/bits/smbios.h
index cc79eec51..2ab31e74b 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/bits/smbios.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/bits/stdint.h b/qemu/roms/ipxe/src/arch/i386/include/bits/stdint.h
index 8edf13192..fe1f9946a 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/bits/stdint.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/bits/strings.h b/qemu/roms/ipxe/src/arch/i386/include/bits/strings.h
index 092bcb593..453545f00 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/bits/strings.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/bits/time.h b/qemu/roms/ipxe/src/arch/i386/include/bits/time.h
index 24dd020e9..6a5d63d32 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/bits/time.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/bits/timer.h b/qemu/roms/ipxe/src/arch/i386/include/bits/timer.h
index 50b676b77..f7d86d78c 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/bits/timer.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/bits/uaccess.h b/qemu/roms/ipxe/src/arch/i386/include/bits/uaccess.h
index 2bb52e021..aac09ba95 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/bits/uaccess.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/bits/umalloc.h b/qemu/roms/ipxe/src/arch/i386/include/bits/umalloc.h
index 54fb006f0..113f16fd1 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/bits/umalloc.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/bootsector.h b/qemu/roms/ipxe/src/arch/i386/include/bootsector.h
index 8730fbfcc..c5d35aae3 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/bootsector.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/bzimage.h b/qemu/roms/ipxe/src/arch/i386/include/bzimage.h
index 7e42e3188..4933ce5b1 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/bzimage.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/efi/ipxe/dhcp_arch.h b/qemu/roms/ipxe/src/arch/i386/include/efi/ipxe/dhcp_arch.h
index 184177219..c17c1ea5e 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/efi/ipxe/dhcp_arch.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/fakee820.h b/qemu/roms/ipxe/src/arch/i386/include/fakee820.h
index 9d00fb670..552b1e48d 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/fakee820.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/initrd.h b/qemu/roms/ipxe/src/arch/i386/include/initrd.h
index a5659f43c..ddb3e5a45 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/initrd.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/int13.h b/qemu/roms/ipxe/src/arch/i386/include/int13.h
index e337ca1d1..f82a583c6 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/int13.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/ipxe/bios_nap.h b/qemu/roms/ipxe/src/arch/i386/include/ipxe/bios_nap.h
index 5b684c041..c9b82c1e5 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/ipxe/bios_nap.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/ipxe/bios_reboot.h b/qemu/roms/ipxe/src/arch/i386/include/ipxe/bios_reboot.h
index a0845328d..3f6df9073 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/ipxe/bios_reboot.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/ipxe/bios_sanboot.h b/qemu/roms/ipxe/src/arch/i386/include/ipxe/bios_sanboot.h
index 689227b70..1a86b7d57 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/ipxe/bios_sanboot.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/ipxe/bios_smbios.h b/qemu/roms/ipxe/src/arch/i386/include/ipxe/bios_smbios.h
index d8c7f648a..9f7f9c8ff 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/ipxe/bios_smbios.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/ipxe/bios_timer.h b/qemu/roms/ipxe/src/arch/i386/include/ipxe/bios_timer.h
index f9fc80412..6b88a623c 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/ipxe/bios_timer.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/ipxe/errno/pcbios.h b/qemu/roms/ipxe/src/arch/i386/include/ipxe/errno/pcbios.h
index 3a9eb2495..6312adaa4 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/ipxe/errno/pcbios.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/ipxe/guestrpc.h b/qemu/roms/ipxe/src/arch/i386/include/ipxe/guestrpc.h
index 72a0f714f..bc3d85506 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/ipxe/guestrpc.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/ipxe/memtop_umalloc.h b/qemu/roms/ipxe/src/arch/i386/include/ipxe/memtop_umalloc.h
index 001648fe5..dee055d16 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/ipxe/memtop_umalloc.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/ipxe/msr.h b/qemu/roms/ipxe/src/arch/i386/include/ipxe/msr.h
index c88e26a39..5705318fd 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/ipxe/msr.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/ipxe/rdtsc_timer.h b/qemu/roms/ipxe/src/arch/i386/include/ipxe/rdtsc_timer.h
index 472e14007..598f4bb08 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/ipxe/rdtsc_timer.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/ipxe/rtc_entropy.h b/qemu/roms/ipxe/src/arch/i386/include/ipxe/rtc_entropy.h
index 6c3cf2104..e214745d0 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/ipxe/rtc_entropy.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/ipxe/rtc_time.h b/qemu/roms/ipxe/src/arch/i386/include/ipxe/rtc_time.h
index c0dfe3f88..cb8c7f49e 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/ipxe/rtc_time.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/ipxe/timer2.h b/qemu/roms/ipxe/src/arch/i386/include/ipxe/timer2.h
deleted file mode 100644
index 322a3ed59..000000000
--- a/qemu/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/qemu/roms/ipxe/src/arch/i386/include/ipxe/vesafb.h b/qemu/roms/ipxe/src/arch/i386/include/ipxe/vesafb.h
index 48cd6a7b7..efc8f2cb8 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/ipxe/vesafb.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/ipxe/vmware.h b/qemu/roms/ipxe/src/arch/i386/include/ipxe/vmware.h
index 2ac65f436..24f60a03a 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/ipxe/vmware.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/librm.h b/qemu/roms/ipxe/src/arch/i386/include/librm.h
index c8ba72b53..a8a578a39 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/librm.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/limits.h b/qemu/roms/ipxe/src/arch/i386/include/limits.h
index 031b6c57a..bb48b75ab 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/limits.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/memsizes.h b/qemu/roms/ipxe/src/arch/i386/include/memsizes.h
index 7b217494a..f115f7574 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/memsizes.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/multiboot.h b/qemu/roms/ipxe/src/arch/i386/include/multiboot.h
index 44614c73a..ae09df6c7 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/multiboot.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/pcbios/ipxe/dhcp_arch.h b/qemu/roms/ipxe/src/arch/i386/include/pcbios/ipxe/dhcp_arch.h
index a36d9cfa1..e07e4c192 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/pcbios/ipxe/dhcp_arch.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/pnpbios.h b/qemu/roms/ipxe/src/arch/i386/include/pnpbios.h
index 4c20e73ed..d14873700 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/pnpbios.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/pxe.h b/qemu/roms/ipxe/src/arch/i386/include/pxe.h
index b95b0cce5..66d752683 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/pxe.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/pxe_api.h b/qemu/roms/ipxe/src/arch/i386/include/pxe_api.h
index e4396efb2..3110d26da 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/pxe_api.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/pxe_call.h b/qemu/roms/ipxe/src/arch/i386/include/pxe_call.h
index 45af46549..cbd548318 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/pxe_call.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/pxe_error.h b/qemu/roms/ipxe/src/arch/i386/include/pxe_error.h
index a1398cbd4..51298e665 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/pxe_error.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/pxe_types.h b/qemu/roms/ipxe/src/arch/i386/include/pxe_types.h
index db8214591..483666e33 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/pxe_types.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/realmode.h b/qemu/roms/ipxe/src/arch/i386/include/realmode.h
index dafc5a32a..4defd3b97 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/realmode.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/registers.h b/qemu/roms/ipxe/src/arch/i386/include/registers.h
index 06d236524..d9aa3c376 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/registers.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/rtc.h b/qemu/roms/ipxe/src/arch/i386/include/rtc.h
index 2a6abbae5..6294b63e3 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/rtc.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/sdi.h b/qemu/roms/ipxe/src/arch/i386/include/sdi.h
index fc486402d..806c3f194 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/sdi.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/setjmp.h b/qemu/roms/ipxe/src/arch/i386/include/setjmp.h
index 5d3c11b69..fe1a9ef4d 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/setjmp.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/undi.h b/qemu/roms/ipxe/src/arch/i386/include/undi.h
index 325fcbbf9..7a5624f93 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/undi.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/undiload.h b/qemu/roms/ipxe/src/arch/i386/include/undiload.h
index 426830e8d..235e7a79e 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/undiload.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/undinet.h b/qemu/roms/ipxe/src/arch/i386/include/undinet.h
index c3c17c11a..2798c4466 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/undinet.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/undipreload.h b/qemu/roms/ipxe/src/arch/i386/include/undipreload.h
index de9b8fb52..57f493cec 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/undipreload.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/undirom.h b/qemu/roms/ipxe/src/arch/i386/include/undirom.h
index 86d7077b5..1c530118d 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/undirom.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/interface/pcbios/apm.c b/qemu/roms/ipxe/src/arch/i386/interface/pcbios/apm.c
index 3b13e1cd0..50b19cb81 100644
--- a/qemu/roms/ipxe/src/arch/i386/interface/pcbios/apm.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/interface/pcbios/bios_nap.c b/qemu/roms/ipxe/src/arch/i386/interface/pcbios/bios_nap.c
index 1e7de756b..f1ba8297b 100644
--- a/qemu/roms/ipxe/src/arch/i386/interface/pcbios/bios_nap.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/interface/pcbios/bios_reboot.c b/qemu/roms/ipxe/src/arch/i386/interface/pcbios/bios_reboot.c
index 68546b2e5..10a1ecb89 100644
--- a/qemu/roms/ipxe/src/arch/i386/interface/pcbios/bios_reboot.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/interface/pcbios/bios_smbios.c b/qemu/roms/ipxe/src/arch/i386/interface/pcbios/bios_smbios.c
index dd7897e29..a8c0fc325 100644
--- a/qemu/roms/ipxe/src/arch/i386/interface/pcbios/bios_smbios.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/interface/pcbios/bios_timer.c b/qemu/roms/ipxe/src/arch/i386/interface/pcbios/bios_timer.c
index 65bbf9e01..3299c9aae 100644
--- a/qemu/roms/ipxe/src/arch/i386/interface/pcbios/bios_timer.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/interface/pcbios/biosint.c b/qemu/roms/ipxe/src/arch/i386/interface/pcbios/biosint.c
index a193defa3..3b8e80438 100644
--- a/qemu/roms/ipxe/src/arch/i386/interface/pcbios/biosint.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/interface/pcbios/int13.c b/qemu/roms/ipxe/src/arch/i386/interface/pcbios/int13.c
index 1c7a8128f..f0450da90 100644
--- a/qemu/roms/ipxe/src/arch/i386/interface/pcbios/int13.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/interface/pcbios/int13con.c b/qemu/roms/ipxe/src/arch/i386/interface/pcbios/int13con.c
new file mode 100644
index 000000000..2414c6909
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/interface/pcbios/memtop_umalloc.c b/qemu/roms/ipxe/src/arch/i386/interface/pcbios/memtop_umalloc.c
index c382e3c36..957f8e324 100644
--- a/qemu/roms/ipxe/src/arch/i386/interface/pcbios/memtop_umalloc.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/interface/pcbios/pcibios.c b/qemu/roms/ipxe/src/arch/i386/interface/pcbios/pcibios.c
index 61873039f..34efa0b39 100644
--- a/qemu/roms/ipxe/src/arch/i386/interface/pcbios/pcibios.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/interface/pcbios/rtc_entropy.c b/qemu/roms/ipxe/src/arch/i386/interface/pcbios/rtc_entropy.c
index fad421c2a..9aab03c03 100644
--- a/qemu/roms/ipxe/src/arch/i386/interface/pcbios/rtc_entropy.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/interface/pcbios/rtc_time.c b/qemu/roms/ipxe/src/arch/i386/interface/pcbios/rtc_time.c
index 67041d4ca..cdbeac8d5 100644
--- a/qemu/roms/ipxe/src/arch/i386/interface/pcbios/rtc_time.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/interface/pcbios/vesafb.c b/qemu/roms/ipxe/src/arch/i386/interface/pcbios/vesafb.c
index 2adc7b040..9cf2bf29e 100644
--- a/qemu/roms/ipxe/src/arch/i386/interface/pcbios/vesafb.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/interface/pxe/pxe_call.c b/qemu/roms/ipxe/src/arch/i386/interface/pxe/pxe_call.c
index 657d47b6c..104313666 100644
--- a/qemu/roms/ipxe/src/arch/i386/interface/pxe/pxe_call.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/interface/pxe/pxe_entry.S b/qemu/roms/ipxe/src/arch/i386/interface/pxe/pxe_entry.S
index 6274264ff..07852cd50 100644
--- a/qemu/roms/ipxe/src/arch/i386/interface/pxe/pxe_entry.S
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/interface/pxe/pxe_exit_hook.c b/qemu/roms/ipxe/src/arch/i386/interface/pxe/pxe_exit_hook.c
index 9d1896507..f92dae0d1 100644
--- a/qemu/roms/ipxe/src/arch/i386/interface/pxe/pxe_exit_hook.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/interface/pxe/pxe_file.c b/qemu/roms/ipxe/src/arch/i386/interface/pxe/pxe_file.c
index 6e9610294..456ffb5fd 100644
--- a/qemu/roms/ipxe/src/arch/i386/interface/pxe/pxe_file.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/interface/pxe/pxe_loader.c b/qemu/roms/ipxe/src/arch/i386/interface/pxe/pxe_loader.c
index 695af3b93..e6a2e072a 100644
--- a/qemu/roms/ipxe/src/arch/i386/interface/pxe/pxe_loader.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/interface/pxe/pxe_preboot.c b/qemu/roms/ipxe/src/arch/i386/interface/pxe/pxe_preboot.c
index 534352b2b..6e09080bc 100644
--- a/qemu/roms/ipxe/src/arch/i386/interface/pxe/pxe_preboot.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/interface/pxe/pxe_tftp.c b/qemu/roms/ipxe/src/arch/i386/interface/pxe/pxe_tftp.c
index f4801bad0..068d8a7b2 100644
--- a/qemu/roms/ipxe/src/arch/i386/interface/pxe/pxe_tftp.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/interface/pxe/pxe_udp.c b/qemu/roms/ipxe/src/arch/i386/interface/pxe/pxe_udp.c
index 32bc39c8e..071cb59db 100644
--- a/qemu/roms/ipxe/src/arch/i386/interface/pxe/pxe_udp.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/interface/pxe/pxe_undi.c b/qemu/roms/ipxe/src/arch/i386/interface/pxe/pxe_undi.c
index 29e586ed2..2eb68178a 100644
--- a/qemu/roms/ipxe/src/arch/i386/interface/pxe/pxe_undi.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/interface/syslinux/comboot_call.c b/qemu/roms/ipxe/src/arch/i386/interface/syslinux/comboot_call.c
index 1854501de..69d94c407 100644
--- a/qemu/roms/ipxe/src/arch/i386/interface/syslinux/comboot_call.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/interface/vmware/guestrpc.c b/qemu/roms/ipxe/src/arch/i386/interface/vmware/guestrpc.c
index 390fc5545..ef7ee8151 100644
--- a/qemu/roms/ipxe/src/arch/i386/interface/vmware/guestrpc.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/interface/vmware/vmconsole.c b/qemu/roms/ipxe/src/arch/i386/interface/vmware/vmconsole.c
index c6b9fff12..f7df4f75b 100644
--- a/qemu/roms/ipxe/src/arch/i386/interface/vmware/vmconsole.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/interface/vmware/vmware.c b/qemu/roms/ipxe/src/arch/i386/interface/vmware/vmware.c
index 8074e6118..a415465fb 100644
--- a/qemu/roms/ipxe/src/arch/i386/interface/vmware/vmware.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/prefix/bootpart.S b/qemu/roms/ipxe/src/arch/i386/prefix/bootpart.S
index 968da1a38..6d0c6034a 100644
--- a/qemu/roms/ipxe/src/arch/i386/prefix/bootpart.S
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/prefix/exeprefix.S b/qemu/roms/ipxe/src/arch/i386/prefix/exeprefix.S
index cb61287d3..5c648d51d 100644
--- a/qemu/roms/ipxe/src/arch/i386/prefix/exeprefix.S
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/prefix/hdprefix.S b/qemu/roms/ipxe/src/arch/i386/prefix/hdprefix.S
index 876bfe1be..1d012d80b 100644
--- a/qemu/roms/ipxe/src/arch/i386/prefix/hdprefix.S
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/prefix/isaromprefix.S b/qemu/roms/ipxe/src/arch/i386/prefix/isaromprefix.S
index e28208089..fb49819ee 100644
--- a/qemu/roms/ipxe/src/arch/i386/prefix/isaromprefix.S
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/prefix/kkkpxeprefix.S b/qemu/roms/ipxe/src/arch/i386/prefix/kkkpxeprefix.S
index 27ed231e7..6e43cd26a 100644
--- a/qemu/roms/ipxe/src/arch/i386/prefix/kkkpxeprefix.S
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/prefix/kkpxeprefix.S b/qemu/roms/ipxe/src/arch/i386/prefix/kkpxeprefix.S
index d177d7d62..3c17dbdb1 100644
--- a/qemu/roms/ipxe/src/arch/i386/prefix/kkpxeprefix.S
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/prefix/kpxeprefix.S b/qemu/roms/ipxe/src/arch/i386/prefix/kpxeprefix.S
index c75608172..200006d83 100644
--- a/qemu/roms/ipxe/src/arch/i386/prefix/kpxeprefix.S
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/prefix/libprefix.S b/qemu/roms/ipxe/src/arch/i386/prefix/libprefix.S
index 7c1ece791..7d5c1ed53 100644
--- a/qemu/roms/ipxe/src/arch/i386/prefix/libprefix.S
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/prefix/lkrnprefix.S b/qemu/roms/ipxe/src/arch/i386/prefix/lkrnprefix.S
index 259bc6ba5..64135e14b 100644
--- a/qemu/roms/ipxe/src/arch/i386/prefix/lkrnprefix.S
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/prefix/mbr.S b/qemu/roms/ipxe/src/arch/i386/prefix/mbr.S
index adfe20410..a1e237de8 100644
--- a/qemu/roms/ipxe/src/arch/i386/prefix/mbr.S
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/prefix/mromprefix.S b/qemu/roms/ipxe/src/arch/i386/prefix/mromprefix.S
index 4c94457c2..b636b92af 100644
--- a/qemu/roms/ipxe/src/arch/i386/prefix/mromprefix.S
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/prefix/nbiprefix.S b/qemu/roms/ipxe/src/arch/i386/prefix/nbiprefix.S
index 06e7df5b7..16c79566c 100644
--- a/qemu/roms/ipxe/src/arch/i386/prefix/nbiprefix.S
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/prefix/nullprefix.S b/qemu/roms/ipxe/src/arch/i386/prefix/nullprefix.S
index 032d41e0f..bd0ff339e 100644
--- a/qemu/roms/ipxe/src/arch/i386/prefix/nullprefix.S
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/prefix/pciromprefix.S b/qemu/roms/ipxe/src/arch/i386/prefix/pciromprefix.S
index 45ba31f50..5a5a49647 100644
--- a/qemu/roms/ipxe/src/arch/i386/prefix/pciromprefix.S
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/prefix/pxeprefix.S b/qemu/roms/ipxe/src/arch/i386/prefix/pxeprefix.S
index 6e29c7949..465ce4345 100644
--- a/qemu/roms/ipxe/src/arch/i386/prefix/pxeprefix.S
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/prefix/romprefix.S b/qemu/roms/ipxe/src/arch/i386/prefix/romprefix.S
index 7bc4fe8cd..18dda2b37 100644
--- a/qemu/roms/ipxe/src/arch/i386/prefix/romprefix.S
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/prefix/undiloader.S b/qemu/roms/ipxe/src/arch/i386/prefix/undiloader.S
index 74bb59041..5cace44b7 100644
--- a/qemu/roms/ipxe/src/arch/i386/prefix/undiloader.S
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/prefix/unlzma.S b/qemu/roms/ipxe/src/arch/i386/prefix/unlzma.S
new file mode 100644
index 000000000..8d4b3c1a8
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/prefix/unnrv2b16.S b/qemu/roms/ipxe/src/arch/i386/prefix/unlzma16.S
index b24c2846f..32b43f0dc 100644
--- a/qemu/roms/ipxe/src/arch/i386/prefix/unnrv2b16.S
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/prefix/unnrv2b.S b/qemu/roms/ipxe/src/arch/i386/prefix/unnrv2b.S
deleted file mode 100644
index f5724c134..000000000
--- a/qemu/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/qemu/roms/ipxe/src/arch/i386/prefix/usbdisk.S b/qemu/roms/ipxe/src/arch/i386/prefix/usbdisk.S
index fa7d1956e..9676406e2 100644
--- a/qemu/roms/ipxe/src/arch/i386/prefix/usbdisk.S
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/scripts/i386.lds b/qemu/roms/ipxe/src/arch/i386/scripts/i386.lds
index 98f95cb23..38c89e14b 100644
--- a/qemu/roms/ipxe/src/arch/i386/scripts/i386.lds
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/transitions/liba20.S b/qemu/roms/ipxe/src/arch/i386/transitions/liba20.S
index 684697525..6c1e1f62f 100644
--- a/qemu/roms/ipxe/src/arch/i386/transitions/liba20.S
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/transitions/libkir.S b/qemu/roms/ipxe/src/arch/i386/transitions/libkir.S
index 1176fcced..fa9459d52 100644
--- a/qemu/roms/ipxe/src/arch/i386/transitions/libkir.S
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/transitions/librm.S b/qemu/roms/ipxe/src/arch/i386/transitions/librm.S
index 2e447b030..863e22415 100644
--- a/qemu/roms/ipxe/src/arch/i386/transitions/librm.S
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/transitions/librm_mgmt.c b/qemu/roms/ipxe/src/arch/i386/transitions/librm_mgmt.c
index cc4765de2..becb02677 100644
--- a/qemu/roms/ipxe/src/arch/i386/transitions/librm_mgmt.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/transitions/librm_test.c b/qemu/roms/ipxe/src/arch/i386/transitions/librm_test.c
index e07cfccdd..f1a517eda 100644
--- a/qemu/roms/ipxe/src/arch/i386/transitions/librm_test.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/Makefile b/qemu/roms/ipxe/src/arch/x86/Makefile
index e555587df..98c49b98d 100644
--- a/qemu/roms/ipxe/src/arch/x86/Makefile
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/Makefile.efi b/qemu/roms/ipxe/src/arch/x86/Makefile.efi
index 13a69d9f7..f73bc7d5d 100644
--- a/qemu/roms/ipxe/src/arch/x86/Makefile.efi
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/core/cpuid.c b/qemu/roms/ipxe/src/arch/x86/core/cpuid.c
index 5908f4419..bc5a6c68c 100644
--- a/qemu/roms/ipxe/src/arch/x86/core/cpuid.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/core/cpuid_settings.c b/qemu/roms/ipxe/src/arch/x86/core/cpuid_settings.c
index 42dea9336..08bd3918a 100644
--- a/qemu/roms/ipxe/src/arch/x86/core/cpuid_settings.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/core/debugcon.c b/qemu/roms/ipxe/src/arch/x86/core/debugcon.c
index 263cb4af1..60de61f55 100644
--- a/qemu/roms/ipxe/src/arch/x86/core/debugcon.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/core/pcidirect.c b/qemu/roms/ipxe/src/arch/x86/core/pcidirect.c
index dbc8317b8..9b8e6b1d9 100644
--- a/qemu/roms/ipxe/src/arch/x86/core/pcidirect.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/core/pic8259.c b/qemu/roms/ipxe/src/arch/x86/core/pic8259.c
index 0a9ea2e03..0a9ea2e03 100644
--- a/qemu/roms/ipxe/src/arch/i386/core/pic8259.c
+++ b/qemu/roms/ipxe/src/arch/x86/core/pic8259.c
diff --git a/qemu/roms/ipxe/src/arch/x86/core/pit8254.c b/qemu/roms/ipxe/src/arch/x86/core/pit8254.c
new file mode 100644
index 000000000..da2099263
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/core/vram_settings.c b/qemu/roms/ipxe/src/arch/x86/core/vram_settings.c
new file mode 100644
index 000000000..9c169b40c
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/core/x86_bigint.c b/qemu/roms/ipxe/src/arch/x86/core/x86_bigint.c
index 418ac2309..6413b2fa8 100644
--- a/qemu/roms/ipxe/src/arch/x86/core/x86_bigint.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/core/x86_io.c b/qemu/roms/ipxe/src/arch/x86/core/x86_io.c
index 9b2d2d935..3081fa8b9 100644
--- a/qemu/roms/ipxe/src/arch/x86/core/x86_io.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/core/x86_string.c b/qemu/roms/ipxe/src/arch/x86/core/x86_string.c
index d48347c96..7d5e4a5f1 100644
--- a/qemu/roms/ipxe/src/arch/x86/core/x86_string.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/core/x86_tcpip.c b/qemu/roms/ipxe/src/arch/x86/core/x86_tcpip.c
index 8a4ce5152..88042f5f7 100644
--- a/qemu/roms/ipxe/src/arch/x86/core/x86_tcpip.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/core/x86_uart.c b/qemu/roms/ipxe/src/arch/x86/core/x86_uart.c
new file mode 100644
index 000000000..e455775bf
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/drivers/hyperv/hyperv.c b/qemu/roms/ipxe/src/arch/x86/drivers/hyperv/hyperv.c
new file mode 100644
index 000000000..f73829bd5
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/drivers/hyperv/hyperv.h b/qemu/roms/ipxe/src/arch/x86/drivers/hyperv/hyperv.h
new file mode 100644
index 000000000..0d09beb44
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/drivers/xen/hvm.c b/qemu/roms/ipxe/src/arch/x86/drivers/xen/hvm.c
index 7406ca68d..7ac32d54c 100644
--- a/qemu/roms/ipxe/src/arch/x86/drivers/xen/hvm.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/drivers/xen/hvm.h b/qemu/roms/ipxe/src/arch/x86/drivers/xen/hvm.h
index 325d20d66..72ed94f6d 100644
--- a/qemu/roms/ipxe/src/arch/x86/drivers/xen/hvm.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/hci/commands/cpuid_cmd.c b/qemu/roms/ipxe/src/arch/x86/hci/commands/cpuid_cmd.c
index c4e35d179..d73ce2a3e 100644
--- a/qemu/roms/ipxe/src/arch/x86/hci/commands/cpuid_cmd.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/include/bits/bigint.h b/qemu/roms/ipxe/src/arch/x86/include/bits/bigint.h
index d3449af5a..c9bb6ea45 100644
--- a/qemu/roms/ipxe/src/arch/x86/include/bits/bigint.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/include/bits/endian.h b/qemu/roms/ipxe/src/arch/x86/include/bits/endian.h
new file mode 100644
index 000000000..85718cfdd
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/include/bits/errfile.h b/qemu/roms/ipxe/src/arch/x86/include/bits/errfile.h
index 624575621..0d1617d20 100644
--- a/qemu/roms/ipxe/src/arch/x86/include/bits/errfile.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/include/bits/io.h b/qemu/roms/ipxe/src/arch/x86/include/bits/io.h
index cb1b67a6f..60c2e3edf 100644
--- a/qemu/roms/ipxe/src/arch/x86/include/bits/io.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/include/bits/pci_io.h b/qemu/roms/ipxe/src/arch/x86/include/bits/pci_io.h
index 01b12326e..b41e562ee 100644
--- a/qemu/roms/ipxe/src/arch/x86/include/bits/pci_io.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/include/bits/string.h b/qemu/roms/ipxe/src/arch/x86/include/bits/string.h
index dce994983..c26fe30d5 100644
--- a/qemu/roms/ipxe/src/arch/x86/include/bits/string.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/include/bits/tcpip.h b/qemu/roms/ipxe/src/arch/x86/include/bits/tcpip.h
index a4b335eb1..5c2baffcf 100644
--- a/qemu/roms/ipxe/src/arch/x86/include/bits/tcpip.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/include/bits/uart.h b/qemu/roms/ipxe/src/arch/x86/include/bits/uart.h
new file mode 100644
index 000000000..e09cd3f4c
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/include/bits/xen.h b/qemu/roms/ipxe/src/arch/x86/include/bits/xen.h
index dbccf1b77..fc065ea38 100644
--- a/qemu/roms/ipxe/src/arch/x86/include/bits/xen.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/include/ipxe/cpuid.h b/qemu/roms/ipxe/src/arch/x86/include/ipxe/cpuid.h
index 2f78dfca1..da85d0b88 100644
--- a/qemu/roms/ipxe/src/arch/x86/include/ipxe/cpuid.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/include/ipxe/efi/efix86_nap.h b/qemu/roms/ipxe/src/arch/x86/include/ipxe/efi/efix86_nap.h
index e85a272b3..1a391c9b6 100644
--- a/qemu/roms/ipxe/src/arch/x86/include/ipxe/efi/efix86_nap.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/include/ipxe/pcibios.h b/qemu/roms/ipxe/src/arch/x86/include/ipxe/pcibios.h
index 36af7fcde..7e1bcd814 100644
--- a/qemu/roms/ipxe/src/arch/x86/include/ipxe/pcibios.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/include/ipxe/pcidirect.h b/qemu/roms/ipxe/src/arch/x86/include/ipxe/pcidirect.h
index 7fa7c4fa7..d924f2f20 100644
--- a/qemu/roms/ipxe/src/arch/x86/include/ipxe/pcidirect.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/include/ipxe/pit8254.h b/qemu/roms/ipxe/src/arch/x86/include/ipxe/pit8254.h
new file mode 100644
index 000000000..00b0ab164
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/include/ipxe/x86_io.h b/qemu/roms/ipxe/src/arch/x86/include/ipxe/x86_io.h
index 9e68f4e78..5214e9fbb 100644
--- a/qemu/roms/ipxe/src/arch/x86/include/ipxe/x86_io.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/include/linux/ipxe/dhcp_arch.h b/qemu/roms/ipxe/src/arch/x86/include/linux/ipxe/dhcp_arch.h
index e83fd9d87..d60905f22 100644
--- a/qemu/roms/ipxe/src/arch/x86/include/linux/ipxe/dhcp_arch.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/i386/include/pic8259.h b/qemu/roms/ipxe/src/arch/x86/include/pic8259.h
index a07e97d30..f02e62909 100644
--- a/qemu/roms/ipxe/src/arch/i386/include/pic8259.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/interface/efi/efi_entropy.c b/qemu/roms/ipxe/src/arch/x86/interface/efi/efi_entropy.c
new file mode 100644
index 000000000..a54bd12e6
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/interface/efi/efix86_nap.c b/qemu/roms/ipxe/src/arch/x86/interface/efi/efix86_nap.c
index b05421fab..3ebf0bd68 100644
--- a/qemu/roms/ipxe/src/arch/x86/interface/efi/efix86_nap.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/prefix/efidrvprefix.c b/qemu/roms/ipxe/src/arch/x86/prefix/efidrvprefix.c
index 3daefd00a..4fbb19ff7 100644
--- a/qemu/roms/ipxe/src/arch/x86/prefix/efidrvprefix.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/prefix/efiprefix.c b/qemu/roms/ipxe/src/arch/x86/prefix/efiprefix.c
index b0bf99c65..18b931e68 100644
--- a/qemu/roms/ipxe/src/arch/x86/prefix/efiprefix.c
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86_64/Makefile b/qemu/roms/ipxe/src/arch/x86_64/Makefile
index b687f3407..48c0aa1af 100644
--- a/qemu/roms/ipxe/src/arch/x86_64/Makefile
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86_64/core/setjmp.S b/qemu/roms/ipxe/src/arch/x86_64/core/setjmp.S
new file mode 100644
index 000000000..e43200d7b
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86_64/include/bits/byteswap.h b/qemu/roms/ipxe/src/arch/x86_64/include/bits/byteswap.h
index 2e472d98a..d8c5098ef 100644
--- a/qemu/roms/ipxe/src/arch/x86_64/include/bits/byteswap.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86_64/include/bits/compiler.h b/qemu/roms/ipxe/src/arch/x86_64/include/bits/compiler.h
index 51a7eaae2..f70b2e517 100644
--- a/qemu/roms/ipxe/src/arch/x86_64/include/bits/compiler.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86_64/include/bits/endian.h b/qemu/roms/ipxe/src/arch/x86_64/include/bits/endian.h
deleted file mode 100644
index 413e702db..000000000
--- a/qemu/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/qemu/roms/ipxe/src/arch/x86_64/include/bits/entropy.h b/qemu/roms/ipxe/src/arch/x86_64/include/bits/entropy.h
index 9c64c833b..a9b3bc10e 100644
--- a/qemu/roms/ipxe/src/arch/x86_64/include/bits/entropy.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86_64/include/bits/hyperv.h b/qemu/roms/ipxe/src/arch/x86_64/include/bits/hyperv.h
new file mode 100644
index 000000000..845c182f7
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86_64/include/bits/profile.h b/qemu/roms/ipxe/src/arch/x86_64/include/bits/profile.h
index 6fc16d84b..b7c74fbe7 100644
--- a/qemu/roms/ipxe/src/arch/x86_64/include/bits/profile.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86_64/include/bits/reboot.h b/qemu/roms/ipxe/src/arch/x86_64/include/bits/reboot.h
index f1bce0540..f9bcd6a7b 100644
--- a/qemu/roms/ipxe/src/arch/x86_64/include/bits/reboot.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86_64/include/bits/sanboot.h b/qemu/roms/ipxe/src/arch/x86_64/include/bits/sanboot.h
index d33d03cbe..dcab830f6 100644
--- a/qemu/roms/ipxe/src/arch/x86_64/include/bits/sanboot.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86_64/include/bits/strings.h b/qemu/roms/ipxe/src/arch/x86_64/include/bits/strings.h
index 6ee99a500..3b7911f3b 100644
--- a/qemu/roms/ipxe/src/arch/x86_64/include/bits/strings.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86_64/include/bits/time.h b/qemu/roms/ipxe/src/arch/x86_64/include/bits/time.h
index 59b355359..aa74fac8c 100644
--- a/qemu/roms/ipxe/src/arch/x86_64/include/bits/time.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86_64/include/efi/ipxe/dhcp_arch.h b/qemu/roms/ipxe/src/arch/x86_64/include/efi/ipxe/dhcp_arch.h
index 9a4790fdc..6511c1ad3 100644
--- a/qemu/roms/ipxe/src/arch/x86_64/include/efi/ipxe/dhcp_arch.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86_64/include/ipxe/msr.h b/qemu/roms/ipxe/src/arch/x86_64/include/ipxe/msr.h
index a5816ac35..316243b69 100644
--- a/qemu/roms/ipxe/src/arch/x86_64/include/ipxe/msr.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86_64/include/setjmp.h b/qemu/roms/ipxe/src/arch/x86_64/include/setjmp.h
new file mode 100644
index 000000000..69835d9fa
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/config/.gitignore b/qemu/roms/ipxe/src/config/.gitignore
deleted file mode 100644
index 8e94f32fe..000000000
--- a/qemu/roms/ipxe/src/config/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-.buildserial.*
diff --git a/qemu/roms/ipxe/src/config/branding.h b/qemu/roms/ipxe/src/config/branding.h
new file mode 100644
index 000000000..73f00af95
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/config/colour.h b/qemu/roms/ipxe/src/config/colour.h
index 57d20c1db..98198f12f 100644
--- a/qemu/roms/ipxe/src/config/colour.h
+++ b/qemu/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/qemu/roms/ipxe/src/config/config.c b/qemu/roms/ipxe/src/config/config.c
index 6c8b9551a..1dd912c1d 100644
--- a/qemu/roms/ipxe/src/config/config.c
+++ b/qemu/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/qemu/roms/ipxe/src/config/config_crypto.c b/qemu/roms/ipxe/src/config/config_crypto.c
new file mode 100644
index 000000000..1e125d8ab
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/config/config_ethernet.c b/qemu/roms/ipxe/src/config/config_ethernet.c
index d13bd6144..de7a07c57 100644
--- a/qemu/roms/ipxe/src/config/config_ethernet.c
+++ b/qemu/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/qemu/roms/ipxe/src/config/config_fc.c b/qemu/roms/ipxe/src/config/config_fc.c
index 414646994..33fc9462a 100644
--- a/qemu/roms/ipxe/src/config/config_fc.c
+++ b/qemu/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/qemu/roms/ipxe/src/config/config_http.c b/qemu/roms/ipxe/src/config/config_http.c
new file mode 100644
index 000000000..3f198d228
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/config/config_infiniband.c b/qemu/roms/ipxe/src/config/config_infiniband.c
index 432e621d0..a742e7559 100644
--- a/qemu/roms/ipxe/src/config/config_infiniband.c
+++ b/qemu/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/qemu/roms/ipxe/src/config/config_net80211.c b/qemu/roms/ipxe/src/config/config_net80211.c
index b33c363b1..343617548 100644
--- a/qemu/roms/ipxe/src/config/config_net80211.c
+++ b/qemu/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/qemu/roms/ipxe/src/config/config_romprefix.c b/qemu/roms/ipxe/src/config/config_romprefix.c
index 85f1e78ab..21921b867 100644
--- a/qemu/roms/ipxe/src/config/config_romprefix.c
+++ b/qemu/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/qemu/roms/ipxe/src/config/config_route.c b/qemu/roms/ipxe/src/config/config_route.c
index 33e18cdd3..c0b4ee91d 100644
--- a/qemu/roms/ipxe/src/config/config_route.c
+++ b/qemu/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/qemu/roms/ipxe/src/config/config_usb.c b/qemu/roms/ipxe/src/config/config_usb.c
new file mode 100644
index 000000000..dc0e6e6af
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/config/console.h b/qemu/roms/ipxe/src/config/console.h
index 908ec5a0b..ffa5cf50d 100644
--- a/qemu/roms/ipxe/src/config/console.h
+++ b/qemu/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/qemu/roms/ipxe/src/config/crypto.h b/qemu/roms/ipxe/src/config/crypto.h
index 1e021b0fb..bccfc04b8 100644
--- a/qemu/roms/ipxe/src/config/crypto.h
+++ b/qemu/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/qemu/roms/ipxe/src/config/defaults.h b/qemu/roms/ipxe/src/config/defaults.h
index 389c0b07b..32d6dbcce 100644
--- a/qemu/roms/ipxe/src/config/defaults.h
+++ b/qemu/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/qemu/roms/ipxe/src/config/defaults/efi.h b/qemu/roms/ipxe/src/config/defaults/efi.h
index 4276d9366..cdf41c54d 100644
--- a/qemu/roms/ipxe/src/config/defaults/efi.h
+++ b/qemu/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/qemu/roms/ipxe/src/config/defaults/pcbios.h b/qemu/roms/ipxe/src/config/defaults/pcbios.h
index 7debc8d2f..3ed8343ce 100644
--- a/qemu/roms/ipxe/src/config/defaults/pcbios.h
+++ b/qemu/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/qemu/roms/ipxe/src/config/dhcp.h b/qemu/roms/ipxe/src/config/dhcp.h
new file mode 100644
index 000000000..49fe16b92
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/config/entropy.h b/qemu/roms/ipxe/src/config/entropy.h
index 7de2f6737..c79060fd5 100644
--- a/qemu/roms/ipxe/src/config/entropy.h
+++ b/qemu/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/qemu/roms/ipxe/src/config/fault.h b/qemu/roms/ipxe/src/config/fault.h
new file mode 100644
index 000000000..5024a8ff3
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/config/general.h b/qemu/roms/ipxe/src/config/general.h
index 539203457..ee15f6bf1 100644
--- a/qemu/roms/ipxe/src/config/general.h
+++ b/qemu/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/qemu/roms/ipxe/src/config/ioapi.h b/qemu/roms/ipxe/src/config/ioapi.h
index ce19c6d71..abe5a50ce 100644
--- a/qemu/roms/ipxe/src/config/ioapi.h
+++ b/qemu/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/qemu/roms/ipxe/src/config/named.h b/qemu/roms/ipxe/src/config/named.h
index 36efdabdd..ddde6f0a6 100644
--- a/qemu/roms/ipxe/src/config/named.h
+++ b/qemu/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/qemu/roms/ipxe/src/config/nap.h b/qemu/roms/ipxe/src/config/nap.h
index 187af4289..e4fe97964 100644
--- a/qemu/roms/ipxe/src/config/nap.h
+++ b/qemu/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/qemu/roms/ipxe/src/config/qemu/colour.h b/qemu/roms/ipxe/src/config/qemu/colour.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/qemu/roms/ipxe/src/config/qemu/colour.h
diff --git a/qemu/roms/ipxe/src/config/qemu/console.h b/qemu/roms/ipxe/src/config/qemu/console.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/qemu/roms/ipxe/src/config/qemu/console.h
diff --git a/qemu/roms/ipxe/src/config/qemu/crypto.h b/qemu/roms/ipxe/src/config/qemu/crypto.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/qemu/roms/ipxe/src/config/qemu/crypto.h
diff --git a/qemu/roms/ipxe/src/config/qemu/general.h b/qemu/roms/ipxe/src/config/qemu/general.h
new file mode 100644
index 000000000..30f60d3f7
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/config/qemu/serial.h b/qemu/roms/ipxe/src/config/qemu/serial.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/qemu/roms/ipxe/src/config/qemu/serial.h
diff --git a/qemu/roms/ipxe/src/config/qemu/settings.h b/qemu/roms/ipxe/src/config/qemu/settings.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/qemu/roms/ipxe/src/config/qemu/settings.h
diff --git a/qemu/roms/ipxe/src/config/qemu/sideband.h b/qemu/roms/ipxe/src/config/qemu/sideband.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/qemu/roms/ipxe/src/config/qemu/sideband.h
diff --git a/qemu/roms/ipxe/src/config/qemu/usb.h b/qemu/roms/ipxe/src/config/qemu/usb.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/qemu/roms/ipxe/src/config/qemu/usb.h
diff --git a/qemu/roms/ipxe/src/config/reboot.h b/qemu/roms/ipxe/src/config/reboot.h
index 240ef87be..2d1648e7b 100644
--- a/qemu/roms/ipxe/src/config/reboot.h
+++ b/qemu/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/qemu/roms/ipxe/src/config/sanboot.h b/qemu/roms/ipxe/src/config/sanboot.h
index 1d7f5f177..ccc4bda1f 100644
--- a/qemu/roms/ipxe/src/config/sanboot.h
+++ b/qemu/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/qemu/roms/ipxe/src/config/serial.h b/qemu/roms/ipxe/src/config/serial.h
index 08368efdb..27040dc54 100644
--- a/qemu/roms/ipxe/src/config/serial.h
+++ b/qemu/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/qemu/roms/ipxe/src/config/settings.h b/qemu/roms/ipxe/src/config/settings.h
index 42fe9cc81..01feaaa87 100644
--- a/qemu/roms/ipxe/src/config/settings.h
+++ b/qemu/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/qemu/roms/ipxe/src/config/sideband.h b/qemu/roms/ipxe/src/config/sideband.h
index 039bb5d09..dd704f9bb 100644
--- a/qemu/roms/ipxe/src/config/sideband.h
+++ b/qemu/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/qemu/roms/ipxe/src/config/time.h b/qemu/roms/ipxe/src/config/time.h
index 0576211fd..678f6f864 100644
--- a/qemu/roms/ipxe/src/config/time.h
+++ b/qemu/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/qemu/roms/ipxe/src/config/timer.h b/qemu/roms/ipxe/src/config/timer.h
index abd669851..5a54d398c 100644
--- a/qemu/roms/ipxe/src/config/timer.h
+++ b/qemu/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/qemu/roms/ipxe/src/config/umalloc.h b/qemu/roms/ipxe/src/config/umalloc.h
index 245c6b4aa..832dd21d1 100644
--- a/qemu/roms/ipxe/src/config/umalloc.h
+++ b/qemu/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/qemu/roms/ipxe/src/config/usb.h b/qemu/roms/ipxe/src/config/usb.h
new file mode 100644
index 000000000..52e82eaad
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/config/vbox/general.h b/qemu/roms/ipxe/src/config/vbox/general.h
index 27d15daf2..06b45f1a8 100644
--- a/qemu/roms/ipxe/src/config/vbox/general.h
+++ b/qemu/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/qemu/roms/ipxe/src/config/vbox/usb.h b/qemu/roms/ipxe/src/config/vbox/usb.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/qemu/roms/ipxe/src/config/vbox/usb.h
diff --git a/qemu/roms/ipxe/src/core/acpi.c b/qemu/roms/ipxe/src/core/acpi.c
index 330f50631..b0ccfa78d 100644
--- a/qemu/roms/ipxe/src/core/acpi.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/ansicol.c b/qemu/roms/ipxe/src/core/ansicol.c
index 142a00f8d..ddf9ba77c 100644
--- a/qemu/roms/ipxe/src/core/ansicol.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/ansicoldef.c b/qemu/roms/ipxe/src/core/ansicoldef.c
index dd89f3b70..6d8598e11 100644
--- a/qemu/roms/ipxe/src/core/ansicoldef.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/ansiesc.c b/qemu/roms/ipxe/src/core/ansiesc.c
index ca9a73ce0..7f545db0e 100644
--- a/qemu/roms/ipxe/src/core/ansiesc.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/asprintf.c b/qemu/roms/ipxe/src/core/asprintf.c
index 03cf45cfc..00edf8e11 100644
--- a/qemu/roms/ipxe/src/core/asprintf.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/assert.c b/qemu/roms/ipxe/src/core/assert.c
index 0791ea7b9..294e766be 100644
--- a/qemu/roms/ipxe/src/core/assert.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/base16.c b/qemu/roms/ipxe/src/core/base16.c
index bf9cc21bb..f9e0f3364 100644
--- a/qemu/roms/ipxe/src/core/base16.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/base64.c b/qemu/roms/ipxe/src/core/base64.c
index bdaf70957..e452f7d41 100644
--- a/qemu/roms/ipxe/src/core/base64.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/basename.c b/qemu/roms/ipxe/src/core/basename.c
index b534a7886..f4f929517 100644
--- a/qemu/roms/ipxe/src/core/basename.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/bitmap.c b/qemu/roms/ipxe/src/core/bitmap.c
index 0d1152327..2aac33870 100644
--- a/qemu/roms/ipxe/src/core/bitmap.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/blockdev.c b/qemu/roms/ipxe/src/core/blockdev.c
index 9d118cb2f..c219d9673 100644
--- a/qemu/roms/ipxe/src/core/blockdev.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/blocktrans.c b/qemu/roms/ipxe/src/core/blocktrans.c
new file mode 100644
index 000000000..3f32f9cf8
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/core/console.c b/qemu/roms/ipxe/src/core/console.c
index 141d8f0f0..7fd00036f 100644
--- a/qemu/roms/ipxe/src/core/console.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/cpio.c b/qemu/roms/ipxe/src/core/cpio.c
index 3a5f4d2b6..080c72daf 100644
--- a/qemu/roms/ipxe/src/core/cpio.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/ctype.c b/qemu/roms/ipxe/src/core/ctype.c
index c812346a0..891af71ea 100644
--- a/qemu/roms/ipxe/src/core/ctype.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/cwuri.c b/qemu/roms/ipxe/src/core/cwuri.c
index 5865552a0..612f0b179 100644
--- a/qemu/roms/ipxe/src/core/cwuri.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/debug.c b/qemu/roms/ipxe/src/core/debug.c
index 7ded47089..def5d8b09 100644
--- a/qemu/roms/ipxe/src/core/debug.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/debug_md5.c b/qemu/roms/ipxe/src/core/debug_md5.c
index f049ac757..d0dbad9ed 100644
--- a/qemu/roms/ipxe/src/core/debug_md5.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/device.c b/qemu/roms/ipxe/src/core/device.c
index 330f95c5a..77d7b719b 100644
--- a/qemu/roms/ipxe/src/core/device.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/downloader.c b/qemu/roms/ipxe/src/core/downloader.c
index ec69db6b1..d745f3617 100644
--- a/qemu/roms/ipxe/src/core/downloader.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/edd.c b/qemu/roms/ipxe/src/core/edd.c
index d574ea6c0..a50b74ab1 100644
--- a/qemu/roms/ipxe/src/core/edd.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/errno.c b/qemu/roms/ipxe/src/core/errno.c
index 06905561f..5de15bb92 100644
--- a/qemu/roms/ipxe/src/core/errno.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/exec.c b/qemu/roms/ipxe/src/core/exec.c
index 1c85705ae..2c2ade0a5 100644
--- a/qemu/roms/ipxe/src/core/exec.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/fault.c b/qemu/roms/ipxe/src/core/fault.c
new file mode 100644
index 000000000..63d3ccacf
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/core/fbcon.c b/qemu/roms/ipxe/src/core/fbcon.c
index 72d6a6789..6d8b0086d 100644
--- a/qemu/roms/ipxe/src/core/fbcon.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/fnrec.c b/qemu/roms/ipxe/src/core/fnrec.c
index 3453c8b6a..0430817f8 100644
--- a/qemu/roms/ipxe/src/core/fnrec.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/gdbserial.c b/qemu/roms/ipxe/src/core/gdbserial.c
index 6f78c88bf..0983f2557 100644
--- a/qemu/roms/ipxe/src/core/gdbserial.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/gdbstub.c b/qemu/roms/ipxe/src/core/gdbstub.c
index af06118b2..6ad52d1a6 100644
--- a/qemu/roms/ipxe/src/core/gdbstub.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/gdbudp.c b/qemu/roms/ipxe/src/core/gdbudp.c
index 5977547c8..e4613d137 100644
--- a/qemu/roms/ipxe/src/core/gdbudp.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/getkey.c b/qemu/roms/ipxe/src/core/getkey.c
index d69cfb44b..0f0f8b7c3 100644
--- a/qemu/roms/ipxe/src/core/getkey.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/getopt.c b/qemu/roms/ipxe/src/core/getopt.c
index abc1edd6c..e6c3948d1 100644
--- a/qemu/roms/ipxe/src/core/getopt.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/image.c b/qemu/roms/ipxe/src/core/image.c
index ec4480238..529e3d72c 100644
--- a/qemu/roms/ipxe/src/core/image.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/init.c b/qemu/roms/ipxe/src/core/init.c
index 7ea0730fa..d91e44669 100644
--- a/qemu/roms/ipxe/src/core/init.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/interface.c b/qemu/roms/ipxe/src/core/interface.c
index 62f4621db..ba148c13d 100644
--- a/qemu/roms/ipxe/src/core/interface.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/iobuf.c b/qemu/roms/ipxe/src/core/iobuf.c
index afc91d150..3e52ada4f 100644
--- a/qemu/roms/ipxe/src/core/iobuf.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/isqrt.c b/qemu/roms/ipxe/src/core/isqrt.c
index 35c918d19..c4d0571e7 100644
--- a/qemu/roms/ipxe/src/core/isqrt.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/job.c b/qemu/roms/ipxe/src/core/job.c
index 674bec8b5..65df80056 100644
--- a/qemu/roms/ipxe/src/core/job.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/linebuf.c b/qemu/roms/ipxe/src/core/linebuf.c
index 8fb2f86a7..c197e383c 100644
--- a/qemu/roms/ipxe/src/core/linebuf.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/lineconsole.c b/qemu/roms/ipxe/src/core/lineconsole.c
index 1b6791cf3..bb3bfafc9 100644
--- a/qemu/roms/ipxe/src/core/lineconsole.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/list.c b/qemu/roms/ipxe/src/core/list.c
index 77579d69a..5175c84ec 100644
--- a/qemu/roms/ipxe/src/core/list.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/log.c b/qemu/roms/ipxe/src/core/log.c
index f160b4fc8..c08e4bb9b 100644
--- a/qemu/roms/ipxe/src/core/log.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/main.c b/qemu/roms/ipxe/src/core/main.c
index db09e4c39..638dea9cf 100644
--- a/qemu/roms/ipxe/src/core/main.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/malloc.c b/qemu/roms/ipxe/src/core/malloc.c
index d9c07495d..b120c0325 100644
--- a/qemu/roms/ipxe/src/core/malloc.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/memblock.c b/qemu/roms/ipxe/src/core/memblock.c
index 1fd89b871..aecddc22c 100644
--- a/qemu/roms/ipxe/src/core/memblock.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/memmap_settings.c b/qemu/roms/ipxe/src/core/memmap_settings.c
index 0f6d0abf5..fab3e5f3a 100644
--- a/qemu/roms/ipxe/src/core/memmap_settings.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/menu.c b/qemu/roms/ipxe/src/core/menu.c
index 8d42e1f83..ab5b0c7f5 100644
--- a/qemu/roms/ipxe/src/core/menu.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/misc.c b/qemu/roms/ipxe/src/core/misc.c
deleted file mode 100644
index eaceddfea..000000000
--- a/qemu/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/qemu/roms/ipxe/src/core/monojob.c b/qemu/roms/ipxe/src/core/monojob.c
index 820fa31dc..817f21b2c 100644
--- a/qemu/roms/ipxe/src/core/monojob.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/null_reboot.c b/qemu/roms/ipxe/src/core/null_reboot.c
index a3d5b2ef8..7be5612a3 100644
--- a/qemu/roms/ipxe/src/core/null_reboot.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/null_sanboot.c b/qemu/roms/ipxe/src/core/null_sanboot.c
index 18c0dea84..2f7522c6c 100644
--- a/qemu/roms/ipxe/src/core/null_sanboot.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/null_time.c b/qemu/roms/ipxe/src/core/null_time.c
index 506c70b52..90041a456 100644
--- a/qemu/roms/ipxe/src/core/null_time.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/nvo.c b/qemu/roms/ipxe/src/core/nvo.c
index e135d2b41..d2c9b5e73 100644
--- a/qemu/roms/ipxe/src/core/nvo.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/open.c b/qemu/roms/ipxe/src/core/open.c
index b479c2975..9d665ffda 100644
--- a/qemu/roms/ipxe/src/core/open.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/params.c b/qemu/roms/ipxe/src/core/params.c
index 93b834419..e1f66acca 100644
--- a/qemu/roms/ipxe/src/core/params.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/parseopt.c b/qemu/roms/ipxe/src/core/parseopt.c
index d268c0594..66f60158c 100644
--- a/qemu/roms/ipxe/src/core/parseopt.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/pending.c b/qemu/roms/ipxe/src/core/pending.c
index 7bb0c2e00..96d0cf197 100644
--- a/qemu/roms/ipxe/src/core/pending.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/pinger.c b/qemu/roms/ipxe/src/core/pinger.c
index 31ea2ce1c..0ff7bb9f2 100644
--- a/qemu/roms/ipxe/src/core/pinger.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/pixbuf.c b/qemu/roms/ipxe/src/core/pixbuf.c
index 48f8e9f9a..41e18f8dc 100644
--- a/qemu/roms/ipxe/src/core/pixbuf.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/pool.c b/qemu/roms/ipxe/src/core/pool.c
new file mode 100644
index 000000000..0163405f7
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/core/posix_io.c b/qemu/roms/ipxe/src/core/posix_io.c
index 8460d0f51..35b52beeb 100644
--- a/qemu/roms/ipxe/src/core/posix_io.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/process.c b/qemu/roms/ipxe/src/core/process.c
index d341a2c37..69852c416 100644
--- a/qemu/roms/ipxe/src/core/process.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/profile.c b/qemu/roms/ipxe/src/core/profile.c
index 150e6b273..1075047b9 100644
--- a/qemu/roms/ipxe/src/core/profile.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/random.c b/qemu/roms/ipxe/src/core/random.c
index 8824dca3a..a74175a79 100644
--- a/qemu/roms/ipxe/src/core/random.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/refcnt.c b/qemu/roms/ipxe/src/core/refcnt.c
index 68a86120e..47c975a0b 100644
--- a/qemu/roms/ipxe/src/core/refcnt.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/resolv.c b/qemu/roms/ipxe/src/core/resolv.c
index d59a8c0ad..1e3182b0b 100644
--- a/qemu/roms/ipxe/src/core/resolv.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/serial.c b/qemu/roms/ipxe/src/core/serial.c
index 7e4460ab9..4ce025519 100644
--- a/qemu/roms/ipxe/src/core/serial.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/serial_console.c b/qemu/roms/ipxe/src/core/serial_console.c
deleted file mode 100644
index de9b84ca7..000000000
--- a/qemu/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/qemu/roms/ipxe/src/core/settings.c b/qemu/roms/ipxe/src/core/settings.c
index 5e16b27d0..12e6c7d61 100644
--- a/qemu/roms/ipxe/src/core/settings.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/string.c b/qemu/roms/ipxe/src/core/string.c
index e53c283c2..3e658e54e 100644
--- a/qemu/roms/ipxe/src/core/string.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/stringextra.c b/qemu/roms/ipxe/src/core/stringextra.c
index 0a509852e..18ffc6301 100644
--- a/qemu/roms/ipxe/src/core/stringextra.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/strtoull.c b/qemu/roms/ipxe/src/core/strtoull.c
deleted file mode 100644
index 00986eef0..000000000
--- a/qemu/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/qemu/roms/ipxe/src/core/time.c b/qemu/roms/ipxe/src/core/time.c
index f70e1981d..29a924ebe 100644
--- a/qemu/roms/ipxe/src/core/time.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/timer.c b/qemu/roms/ipxe/src/core/timer.c
index 18c2b2849..dbd89f12b 100644
--- a/qemu/roms/ipxe/src/core/timer.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/uart.c b/qemu/roms/ipxe/src/core/uart.c
new file mode 100644
index 000000000..b85fe0767
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/core/uri.c b/qemu/roms/ipxe/src/core/uri.c
index 9ec21cee4..3b5f270fe 100644
--- a/qemu/roms/ipxe/src/core/uri.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/uuid.c b/qemu/roms/ipxe/src/core/uuid.c
index 27a249da8..b8d21de17 100644
--- a/qemu/roms/ipxe/src/core/uuid.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/version.c b/qemu/roms/ipxe/src/core/version.c
index 1e1e9daca..c984335c2 100644
--- a/qemu/roms/ipxe/src/core/version.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/vsprintf.c b/qemu/roms/ipxe/src/core/vsprintf.c
index 54811b11b..cb3bec5dd 100644
--- a/qemu/roms/ipxe/src/core/vsprintf.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/wchar.c b/qemu/roms/ipxe/src/core/wchar.c
index 7fabca470..860322820 100644
--- a/qemu/roms/ipxe/src/core/wchar.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/xfer.c b/qemu/roms/ipxe/src/core/xfer.c
index 8d4bc9f53..112fee1bf 100644
--- a/qemu/roms/ipxe/src/core/xfer.c
+++ b/qemu/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/qemu/roms/ipxe/src/core/xferbuf.c b/qemu/roms/ipxe/src/core/xferbuf.c
index a0457feee..240118557 100644
--- a/qemu/roms/ipxe/src/core/xferbuf.c
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/aes.c b/qemu/roms/ipxe/src/crypto/aes.c
new file mode 100644
index 000000000..b9e206bfb
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/asn1.c b/qemu/roms/ipxe/src/crypto/asn1.c
index 6d880704f..aca12bf30 100644
--- a/qemu/roms/ipxe/src/crypto/asn1.c
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/axtls/aes.c b/qemu/roms/ipxe/src/crypto/axtls/aes.c
deleted file mode 100644
index bd99a7097..000000000
--- a/qemu/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/qemu/roms/ipxe/src/crypto/axtls/bigint.h b/qemu/roms/ipxe/src/crypto/axtls/bigint.h
deleted file mode 100644
index 1f38c53d6..000000000
--- a/qemu/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/qemu/roms/ipxe/src/crypto/axtls/bigint_impl.h b/qemu/roms/ipxe/src/crypto/axtls/bigint_impl.h
deleted file mode 100644
index 09d8550ea..000000000
--- a/qemu/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/qemu/roms/ipxe/src/crypto/axtls/config.h b/qemu/roms/ipxe/src/crypto/axtls/config.h
deleted file mode 100644
index 32fa3bf03..000000000
--- a/qemu/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/qemu/roms/ipxe/src/crypto/axtls/crypto.h b/qemu/roms/ipxe/src/crypto/axtls/crypto.h
deleted file mode 100644
index 2c4cda4de..000000000
--- a/qemu/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/qemu/roms/ipxe/src/crypto/axtls/os_port.h b/qemu/roms/ipxe/src/crypto/axtls/os_port.h
deleted file mode 100644
index 76313e204..000000000
--- a/qemu/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/qemu/roms/ipxe/src/crypto/axtls_aes.c b/qemu/roms/ipxe/src/crypto/axtls_aes.c
deleted file mode 100644
index 7f93c0ed7..000000000
--- a/qemu/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/qemu/roms/ipxe/src/crypto/bigint.c b/qemu/roms/ipxe/src/crypto/bigint.c
index 340128e2f..50f320302 100644
--- a/qemu/roms/ipxe/src/crypto/bigint.c
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/cbc.c b/qemu/roms/ipxe/src/crypto/cbc.c
index 9bf0e8b49..0ba17ee48 100644
--- a/qemu/roms/ipxe/src/crypto/cbc.c
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/certstore.c b/qemu/roms/ipxe/src/crypto/certstore.c
index 77cf6ebb6..503ce499e 100644
--- a/qemu/roms/ipxe/src/crypto/certstore.c
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/chap.c b/qemu/roms/ipxe/src/crypto/chap.c
index db64371c7..c90c16def 100644
--- a/qemu/roms/ipxe/src/crypto/chap.c
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/cms.c b/qemu/roms/ipxe/src/crypto/cms.c
index b4a41de6c..bc2148e8a 100644
--- a/qemu/roms/ipxe/src/crypto/cms.c
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/crypto_null.c b/qemu/roms/ipxe/src/crypto/crypto_null.c
index ba05f7269..15a1c538b 100644
--- a/qemu/roms/ipxe/src/crypto/crypto_null.c
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/deflate.c b/qemu/roms/ipxe/src/crypto/deflate.c
index 91a489961..e1c87d5fe 100644
--- a/qemu/roms/ipxe/src/crypto/deflate.c
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/drbg.c b/qemu/roms/ipxe/src/crypto/drbg.c
index 9e0175d25..5c8b5e612 100644
--- a/qemu/roms/ipxe/src/crypto/drbg.c
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/ecb.c b/qemu/roms/ipxe/src/crypto/ecb.c
new file mode 100644
index 000000000..3c9cf340c
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/entropy.c b/qemu/roms/ipxe/src/crypto/entropy.c
index c7045840e..5acbc0258 100644
--- a/qemu/roms/ipxe/src/crypto/entropy.c
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/hash_df.c b/qemu/roms/ipxe/src/crypto/hash_df.c
index adf1d87e4..c1417e683 100644
--- a/qemu/roms/ipxe/src/crypto/hash_df.c
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/hmac.c b/qemu/roms/ipxe/src/crypto/hmac.c
index e9459198c..95a46195c 100644
--- a/qemu/roms/ipxe/src/crypto/hmac.c
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/hmac_drbg.c b/qemu/roms/ipxe/src/crypto/hmac_drbg.c
index 1e5f732e2..6c1d5deb2 100644
--- a/qemu/roms/ipxe/src/crypto/hmac_drbg.c
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/md5.c b/qemu/roms/ipxe/src/crypto/md5.c
index 122c7d59e..f9738b0ac 100644
--- a/qemu/roms/ipxe/src/crypto/md5.c
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/mishmash/rsa_aes_cbc_sha1.c b/qemu/roms/ipxe/src/crypto/mishmash/rsa_aes_cbc_sha1.c
new file mode 100644
index 000000000..06722c0e1
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/mishmash/rsa_aes_cbc_sha256.c b/qemu/roms/ipxe/src/crypto/mishmash/rsa_aes_cbc_sha256.c
new file mode 100644
index 000000000..c609eacea
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/mishmash/rsa_md5.c b/qemu/roms/ipxe/src/crypto/mishmash/rsa_md5.c
new file mode 100644
index 000000000..ac828ac11
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/mishmash/rsa_sha1.c b/qemu/roms/ipxe/src/crypto/mishmash/rsa_sha1.c
new file mode 100644
index 000000000..39424bf2d
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/mishmash/rsa_sha224.c b/qemu/roms/ipxe/src/crypto/mishmash/rsa_sha224.c
new file mode 100644
index 000000000..5e8755aab
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/mishmash/rsa_sha256.c b/qemu/roms/ipxe/src/crypto/mishmash/rsa_sha256.c
new file mode 100644
index 000000000..b44af5f19
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/mishmash/rsa_sha384.c b/qemu/roms/ipxe/src/crypto/mishmash/rsa_sha384.c
new file mode 100644
index 000000000..af22a2bf0
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/mishmash/rsa_sha512.c b/qemu/roms/ipxe/src/crypto/mishmash/rsa_sha512.c
new file mode 100644
index 000000000..29ee15493
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/null_entropy.c b/qemu/roms/ipxe/src/crypto/null_entropy.c
index c56d5e76f..d1e1a6f73 100644
--- a/qemu/roms/ipxe/src/crypto/null_entropy.c
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/ocsp.c b/qemu/roms/ipxe/src/crypto/ocsp.c
index 66e47c57e..5df55bc96 100644
--- a/qemu/roms/ipxe/src/crypto/ocsp.c
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/privkey.c b/qemu/roms/ipxe/src/crypto/privkey.c
index e010649c0..a6043bd1e 100644
--- a/qemu/roms/ipxe/src/crypto/privkey.c
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/random_nz.c b/qemu/roms/ipxe/src/crypto/random_nz.c
index f1d2e187d..5fe576e05 100644
--- a/qemu/roms/ipxe/src/crypto/random_nz.c
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/rbg.c b/qemu/roms/ipxe/src/crypto/rbg.c
index e2d06978c..943b288c3 100644
--- a/qemu/roms/ipxe/src/crypto/rbg.c
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/rootcert.c b/qemu/roms/ipxe/src/crypto/rootcert.c
index ae28905ac..00ea1647e 100644
--- a/qemu/roms/ipxe/src/crypto/rootcert.c
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/rsa.c b/qemu/roms/ipxe/src/crypto/rsa.c
index 0ab7b2ad3..36109280d 100644
--- a/qemu/roms/ipxe/src/crypto/rsa.c
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/sha1.c b/qemu/roms/ipxe/src/crypto/sha1.c
index e1bef669e..51866f4b7 100644
--- a/qemu/roms/ipxe/src/crypto/sha1.c
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/sha224.c b/qemu/roms/ipxe/src/crypto/sha224.c
new file mode 100644
index 000000000..be25f24e9
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/sha256.c b/qemu/roms/ipxe/src/crypto/sha256.c
index 36e02b3c2..0360d8d16 100644
--- a/qemu/roms/ipxe/src/crypto/sha256.c
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/sha384.c b/qemu/roms/ipxe/src/crypto/sha384.c
new file mode 100644
index 000000000..017751826
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/sha512.c b/qemu/roms/ipxe/src/crypto/sha512.c
new file mode 100644
index 000000000..814f44563
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/sha512_224.c b/qemu/roms/ipxe/src/crypto/sha512_224.c
new file mode 100644
index 000000000..8c37b566b
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/sha512_256.c b/qemu/roms/ipxe/src/crypto/sha512_256.c
new file mode 100644
index 000000000..f8afaf3e3
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/crypto/x509.c b/qemu/roms/ipxe/src/crypto/x509.c
index 4a02dad14..43a4ca17a 100644
--- a/qemu/roms/ipxe/src/crypto/x509.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/bitbash/bitbash.c b/qemu/roms/ipxe/src/drivers/bitbash/bitbash.c
index 23ca30356..9b24f716c 100644
--- a/qemu/roms/ipxe/src/drivers/bitbash/bitbash.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/bitbash/i2c_bit.c b/qemu/roms/ipxe/src/drivers/bitbash/i2c_bit.c
index decc8d80e..707d9447d 100644
--- a/qemu/roms/ipxe/src/drivers/bitbash/i2c_bit.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/bitbash/spi_bit.c b/qemu/roms/ipxe/src/drivers/bitbash/spi_bit.c
index 1b39d72fa..04fddc20b 100644
--- a/qemu/roms/ipxe/src/drivers/bitbash/spi_bit.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/block/ata.c b/qemu/roms/ipxe/src/drivers/block/ata.c
index c9b87c20c..b1c6855a0 100644
--- a/qemu/roms/ipxe/src/drivers/block/ata.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/block/scsi.c b/qemu/roms/ipxe/src/drivers/block/scsi.c
index 64d692986..fd5f82b9f 100644
--- a/qemu/roms/ipxe/src/drivers/block/scsi.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/bus/cdc.c b/qemu/roms/ipxe/src/drivers/bus/cdc.c
new file mode 100644
index 000000000..373a03072
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/bus/pci.c b/qemu/roms/ipxe/src/drivers/bus/pci.c
index 4a8d00b54..6fbedd940 100644
--- a/qemu/roms/ipxe/src/drivers/bus/pci.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/bus/pci_settings.c b/qemu/roms/ipxe/src/drivers/bus/pci_settings.c
index db20452e0..1cb9fa5a3 100644
--- a/qemu/roms/ipxe/src/drivers/bus/pci_settings.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/bus/pcibackup.c b/qemu/roms/ipxe/src/drivers/bus/pcibackup.c
index 6b592e893..fecad8192 100644
--- a/qemu/roms/ipxe/src/drivers/bus/pcibackup.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/bus/pciextra.c b/qemu/roms/ipxe/src/drivers/bus/pciextra.c
index c4417e0cb..82287fb86 100644
--- a/qemu/roms/ipxe/src/drivers/bus/pciextra.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/bus/pcivpd.c b/qemu/roms/ipxe/src/drivers/bus/pcivpd.c
index 0b7a879fe..243b1f779 100644
--- a/qemu/roms/ipxe/src/drivers/bus/pcivpd.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/bus/usb.c b/qemu/roms/ipxe/src/drivers/bus/usb.c
new file mode 100644
index 000000000..2019e3341
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/infiniband/arbel.c b/qemu/roms/ipxe/src/drivers/infiniband/arbel.c
index 1a56ff9af..2a6c32dec 100644
--- a/qemu/roms/ipxe/src/drivers/infiniband/arbel.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/infiniband/arbel.h b/qemu/roms/ipxe/src/drivers/infiniband/arbel.h
index c0303f1bc..73394cd9a 100644
--- a/qemu/roms/ipxe/src/drivers/infiniband/arbel.h
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/infiniband/linda.c b/qemu/roms/ipxe/src/drivers/infiniband/linda.c
index 4afda1208..a6ae9f529 100644
--- a/qemu/roms/ipxe/src/drivers/infiniband/linda.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/infiniband/linda.h b/qemu/roms/ipxe/src/drivers/infiniband/linda.h
index 72ce70868..46a920a17 100644
--- a/qemu/roms/ipxe/src/drivers/infiniband/linda.h
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/infiniband/qib7322.c b/qemu/roms/ipxe/src/drivers/infiniband/qib7322.c
index 9979b346e..e22f2349a 100644
--- a/qemu/roms/ipxe/src/drivers/infiniband/qib7322.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/infiniband/qib7322.h b/qemu/roms/ipxe/src/drivers/infiniband/qib7322.h
index 63abe221b..72797b240 100644
--- a/qemu/roms/ipxe/src/drivers/infiniband/qib7322.h
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/amd8111e.h b/qemu/roms/ipxe/src/drivers/net/amd8111e.h
index 2000df158..8ecd159af 100644
--- a/qemu/roms/ipxe/src/drivers/net/amd8111e.h
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/ath/ath9k/ani.h b/qemu/roms/ipxe/src/drivers/net/ath/ath9k/ani.h
index dbd4d4d5b..ba87ba0fd 100644
--- a/qemu/roms/ipxe/src/drivers/net/ath/ath9k/ani.h
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ani.c b/qemu/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ani.c
index ff7df497f..76ca79cba 100644
--- a/qemu/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ani.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar5008_phy.c b/qemu/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar5008_phy.c
index 60e87e9e2..2b6c133cb 100644
--- a/qemu/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar5008_phy.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9003_phy.c b/qemu/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9003_phy.c
index 6103040ab..2244b775a 100644
--- a/qemu/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9003_phy.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/atl1e.c b/qemu/roms/ipxe/src/drivers/net/atl1e.c
index 1ff0f0d10..d010d8c4a 100644
--- a/qemu/roms/ipxe/src/drivers/net/atl1e.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/davicom.c b/qemu/roms/ipxe/src/drivers/net/davicom.c
index a4870a729..9d3d8b915 100644
--- a/qemu/roms/ipxe/src/drivers/net/davicom.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/dm96xx.c b/qemu/roms/ipxe/src/drivers/net/dm96xx.c
new file mode 100644
index 000000000..58d8dd964
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/dm96xx.h b/qemu/roms/ipxe/src/drivers/net/dm96xx.h
new file mode 100644
index 000000000..43a1a4e30
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/dmfe.c b/qemu/roms/ipxe/src/drivers/net/dmfe.c
index aae40fce7..2ea0d2b2b 100644
--- a/qemu/roms/ipxe/src/drivers/net/dmfe.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/ecm.c b/qemu/roms/ipxe/src/drivers/net/ecm.c
new file mode 100644
index 000000000..8c84ea9e9
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/ecm.h b/qemu/roms/ipxe/src/drivers/net/ecm.h
new file mode 100644
index 000000000..83d324bdc
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/eepro.c b/qemu/roms/ipxe/src/drivers/net/eepro.c
index 909482bcc..97b4c4061 100644
--- a/qemu/roms/ipxe/src/drivers/net/eepro.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/eepro100.c b/qemu/roms/ipxe/src/drivers/net/eepro100.c
index ede0a1a4b..1046cda39 100644
--- a/qemu/roms/ipxe/src/drivers/net/eepro100.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/efi/nii.c b/qemu/roms/ipxe/src/drivers/net/efi/nii.c
index d0d7da95a..b91848f5c 100644
--- a/qemu/roms/ipxe/src/drivers/net/efi/nii.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/efi/nii.h b/qemu/roms/ipxe/src/drivers/net/efi/nii.h
index de0ac687b..c10be9db5 100644
--- a/qemu/roms/ipxe/src/drivers/net/efi/nii.h
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/efi/snp.c b/qemu/roms/ipxe/src/drivers/net/efi/snp.c
index 2b5fc8618..acfcfba9f 100644
--- a/qemu/roms/ipxe/src/drivers/net/efi/snp.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/efi/snponly.c b/qemu/roms/ipxe/src/drivers/net/efi/snponly.c
index 99f264bca..73abfdbf4 100644
--- a/qemu/roms/ipxe/src/drivers/net/efi/snponly.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/etherfabric.c b/qemu/roms/ipxe/src/drivers/net/etherfabric.c
index 5e0efb1e1..29d117443 100644
--- a/qemu/roms/ipxe/src/drivers/net/etherfabric.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/forcedeth.c b/qemu/roms/ipxe/src/drivers/net/forcedeth.c
index d8ece9a7a..79938cbbb 100644
--- a/qemu/roms/ipxe/src/drivers/net/forcedeth.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/igbvf/igbvf_main.c b/qemu/roms/ipxe/src/drivers/net/igbvf/igbvf_main.c
index aace5ad56..fc7021c38 100644
--- a/qemu/roms/ipxe/src/drivers/net/igbvf/igbvf_main.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/intel.c b/qemu/roms/ipxe/src/drivers/net/intel.c
index a89f947b2..6309e9aa5 100644
--- a/qemu/roms/ipxe/src/drivers/net/intel.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/intel.h b/qemu/roms/ipxe/src/drivers/net/intel.h
index 8c4479bb4..ce9e3f467 100644
--- a/qemu/roms/ipxe/src/drivers/net/intel.h
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/intelvf.c b/qemu/roms/ipxe/src/drivers/net/intelvf.c
new file mode 100644
index 000000000..ac6fea745
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/intelvf.h b/qemu/roms/ipxe/src/drivers/net/intelvf.h
new file mode 100644
index 000000000..d2f98d874
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/intelx.c b/qemu/roms/ipxe/src/drivers/net/intelx.c
index d69900e41..982b74f12 100644
--- a/qemu/roms/ipxe/src/drivers/net/intelx.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/intelx.h b/qemu/roms/ipxe/src/drivers/net/intelx.h
index 60bb294d5..6383dfcad 100644
--- a/qemu/roms/ipxe/src/drivers/net/intelx.h
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/intelxvf.c b/qemu/roms/ipxe/src/drivers/net/intelxvf.c
new file mode 100644
index 000000000..05e34c127
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/intelxvf.h b/qemu/roms/ipxe/src/drivers/net/intelxvf.h
new file mode 100644
index 000000000..ad046a65c
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/ipoib.c b/qemu/roms/ipxe/src/drivers/net/ipoib.c
index 1b5391776..6552d764e 100644
--- a/qemu/roms/ipxe/src/drivers/net/ipoib.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/legacy.c b/qemu/roms/ipxe/src/drivers/net/legacy.c
index 4edbef162..73a80194f 100644
--- a/qemu/roms/ipxe/src/drivers/net/legacy.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/mii.c b/qemu/roms/ipxe/src/drivers/net/mii.c
index c4d32514d..9b297029a 100644
--- a/qemu/roms/ipxe/src/drivers/net/mii.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/myson.c b/qemu/roms/ipxe/src/drivers/net/myson.c
index 6abb55660..84a550596 100644
--- a/qemu/roms/ipxe/src/drivers/net/myson.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/myson.h b/qemu/roms/ipxe/src/drivers/net/myson.h
index 8d7cc5855..05a6b8a58 100644
--- a/qemu/roms/ipxe/src/drivers/net/myson.h
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/ncm.c b/qemu/roms/ipxe/src/drivers/net/ncm.c
new file mode 100644
index 000000000..10728d2a1
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/ncm.h b/qemu/roms/ipxe/src/drivers/net/ncm.h
new file mode 100644
index 000000000..a9565a56b
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/netfront.c b/qemu/roms/ipxe/src/drivers/net/netfront.c
index 4b816329e..2f4bbf2a0 100644
--- a/qemu/roms/ipxe/src/drivers/net/netfront.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/netfront.h b/qemu/roms/ipxe/src/drivers/net/netfront.h
index b3f899f3c..38fd0a77e 100644
--- a/qemu/roms/ipxe/src/drivers/net/netfront.h
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/netvsc.c b/qemu/roms/ipxe/src/drivers/net/netvsc.c
new file mode 100644
index 000000000..d269cd63e
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/netvsc.h b/qemu/roms/ipxe/src/drivers/net/netvsc.h
new file mode 100644
index 000000000..39eeb891c
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/phantom/nx_bitops.h b/qemu/roms/ipxe/src/drivers/net/phantom/nx_bitops.h
index 15f3d3767..1687b6952 100644
--- a/qemu/roms/ipxe/src/drivers/net/phantom/nx_bitops.h
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/phantom/phantom.c b/qemu/roms/ipxe/src/drivers/net/phantom/phantom.c
index e70ded08c..38b66743c 100644
--- a/qemu/roms/ipxe/src/drivers/net/phantom/phantom.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/phantom/phantom.h b/qemu/roms/ipxe/src/drivers/net/phantom/phantom.h
index 1647168ba..967603409 100644
--- a/qemu/roms/ipxe/src/drivers/net/phantom/phantom.h
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/phantom/phantom_hw.h b/qemu/roms/ipxe/src/drivers/net/phantom/phantom_hw.h
index 7dfff52b2..016730de3 100644
--- a/qemu/roms/ipxe/src/drivers/net/phantom/phantom_hw.h
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/pnic.c b/qemu/roms/ipxe/src/drivers/net/pnic.c
index 4170cc640..ca64299ea 100644
--- a/qemu/roms/ipxe/src/drivers/net/pnic.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/prism2.c b/qemu/roms/ipxe/src/drivers/net/prism2.c
index ab974264c..4331f2cd0 100644
--- a/qemu/roms/ipxe/src/drivers/net/prism2.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/prism2_pci.c b/qemu/roms/ipxe/src/drivers/net/prism2_pci.c
index 72549babf..69ddf0fb0 100644
--- a/qemu/roms/ipxe/src/drivers/net/prism2_pci.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/prism2_plx.c b/qemu/roms/ipxe/src/drivers/net/prism2_plx.c
index 2098f7f09..a73b0e087 100644
--- a/qemu/roms/ipxe/src/drivers/net/prism2_plx.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/realtek.c b/qemu/roms/ipxe/src/drivers/net/realtek.c
index 0aca8c77f..022b59324 100644
--- a/qemu/roms/ipxe/src/drivers/net/realtek.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/realtek.h b/qemu/roms/ipxe/src/drivers/net/realtek.h
index ac33405e8..b1ce7f98f 100644
--- a/qemu/roms/ipxe/src/drivers/net/realtek.h
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/rtl818x/rtl8180.c b/qemu/roms/ipxe/src/drivers/net/rtl818x/rtl8180.c
index 8851d1bfb..5f97480fa 100644
--- a/qemu/roms/ipxe/src/drivers/net/rtl818x/rtl8180.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/rtl818x/rtl8185.c b/qemu/roms/ipxe/src/drivers/net/rtl818x/rtl8185.c
index fd27e5c8c..234978cea 100644
--- a/qemu/roms/ipxe/src/drivers/net/rtl818x/rtl8185.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/rtl818x/rtl818x.c b/qemu/roms/ipxe/src/drivers/net/rtl818x/rtl818x.c
index cf4c7556f..8b3c206d4 100644
--- a/qemu/roms/ipxe/src/drivers/net/rtl818x/rtl818x.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/rtl818x/rtl818x.h b/qemu/roms/ipxe/src/drivers/net/rtl818x/rtl818x.h
index 4e57d0bd3..ae4b8a96f 100644
--- a/qemu/roms/ipxe/src/drivers/net/rtl818x/rtl818x.h
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/skeleton.c b/qemu/roms/ipxe/src/drivers/net/skeleton.c
index 365111b8d..0435b9d0e 100644
--- a/qemu/roms/ipxe/src/drivers/net/skeleton.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/skeleton.h b/qemu/roms/ipxe/src/drivers/net/skeleton.h
index 3de2afa5b..2ab01bd56 100644
--- a/qemu/roms/ipxe/src/drivers/net/skeleton.h
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/smsc75xx.c b/qemu/roms/ipxe/src/drivers/net/smsc75xx.c
new file mode 100644
index 000000000..017e02a59
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/smsc75xx.h b/qemu/roms/ipxe/src/drivers/net/smsc75xx.h
new file mode 100644
index 000000000..2463b72a1
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/sundance.c b/qemu/roms/ipxe/src/drivers/net/sundance.c
index eef7c9c7c..9127fa2cd 100644
--- a/qemu/roms/ipxe/src/drivers/net/sundance.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/tg3/tg3.c b/qemu/roms/ipxe/src/drivers/net/tg3/tg3.c
index 32ca1609c..42bfa2d99 100644
--- a/qemu/roms/ipxe/src/drivers/net/tg3/tg3.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/tg3/tg3.h b/qemu/roms/ipxe/src/drivers/net/tg3/tg3.h
index 660368394..2b85b065b 100644
--- a/qemu/roms/ipxe/src/drivers/net/tg3/tg3.h
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/tg3/tg3_hw.c b/qemu/roms/ipxe/src/drivers/net/tg3/tg3_hw.c
index 3a481aba3..50353cf36 100644
--- a/qemu/roms/ipxe/src/drivers/net/tg3/tg3_hw.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/virtio-net.c b/qemu/roms/ipxe/src/drivers/net/virtio-net.c
index d5fd81979..533ccb0c6 100644
--- a/qemu/roms/ipxe/src/drivers/net/virtio-net.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/vmxnet3.c b/qemu/roms/ipxe/src/drivers/net/vmxnet3.c
index 31082bf6f..8d4f4b843 100644
--- a/qemu/roms/ipxe/src/drivers/net/vmxnet3.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/vmxnet3.h b/qemu/roms/ipxe/src/drivers/net/vmxnet3.h
index db313d4b8..a1671d9dd 100644
--- a/qemu/roms/ipxe/src/drivers/net/vmxnet3.h
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/vxge/vxge.c b/qemu/roms/ipxe/src/drivers/net/vxge/vxge.c
index bf20ec43c..d50ac05b5 100644
--- a/qemu/roms/ipxe/src/drivers/net/vxge/vxge.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/vxge/vxge_main.c b/qemu/roms/ipxe/src/drivers/net/vxge/vxge_main.c
index 130eab617..8b099c0e2 100644
--- a/qemu/roms/ipxe/src/drivers/net/vxge/vxge_main.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/net/w89c840.c b/qemu/roms/ipxe/src/drivers/net/w89c840.c
index ce638ab99..d8144a8ce 100644
--- a/qemu/roms/ipxe/src/drivers/net/w89c840.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/nvs/nvs.c b/qemu/roms/ipxe/src/drivers/nvs/nvs.c
index ccb2145bd..af7c466c4 100644
--- a/qemu/roms/ipxe/src/drivers/nvs/nvs.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/nvs/nvsvpd.c b/qemu/roms/ipxe/src/drivers/nvs/nvsvpd.c
index 33148d5b9..3e88531c7 100644
--- a/qemu/roms/ipxe/src/drivers/nvs/nvsvpd.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/nvs/spi.c b/qemu/roms/ipxe/src/drivers/nvs/spi.c
index 84613b9dd..dcfe1af91 100644
--- a/qemu/roms/ipxe/src/drivers/nvs/spi.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/nvs/threewire.c b/qemu/roms/ipxe/src/drivers/nvs/threewire.c
index 53f1ad8de..547f35382 100644
--- a/qemu/roms/ipxe/src/drivers/nvs/threewire.c
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/usb/ehci.c b/qemu/roms/ipxe/src/drivers/usb/ehci.c
new file mode 100644
index 000000000..4124692a6
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/usb/ehci.h b/qemu/roms/ipxe/src/drivers/usb/ehci.h
new file mode 100644
index 000000000..42e282e92
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/usb/uhci.c b/qemu/roms/ipxe/src/drivers/usb/uhci.c
new file mode 100644
index 000000000..b6bb92560
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/usb/uhci.h b/qemu/roms/ipxe/src/drivers/usb/uhci.h
new file mode 100644
index 000000000..ba4c28f7e
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/usb/usbhid.c b/qemu/roms/ipxe/src/drivers/usb/usbhid.c
new file mode 100644
index 000000000..c74535a05
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/usb/usbhub.c b/qemu/roms/ipxe/src/drivers/usb/usbhub.c
new file mode 100644
index 000000000..bf2a20005
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/usb/usbhub.h b/qemu/roms/ipxe/src/drivers/usb/usbhub.h
new file mode 100644
index 000000000..d7d8f9610
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/usb/usbkbd.c b/qemu/roms/ipxe/src/drivers/usb/usbkbd.c
new file mode 100644
index 000000000..ea94f2e63
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/usb/usbkbd.h b/qemu/roms/ipxe/src/drivers/usb/usbkbd.h
new file mode 100644
index 000000000..7eab24e46
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/usb/usbnet.c b/qemu/roms/ipxe/src/drivers/usb/usbnet.c
new file mode 100644
index 000000000..b92336d05
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/usb/xhci.c b/qemu/roms/ipxe/src/drivers/usb/xhci.c
new file mode 100644
index 000000000..49e67316b
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/drivers/usb/xhci.h b/qemu/roms/ipxe/src/drivers/usb/xhci.h
new file mode 100644
index 000000000..83bf71e7e
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/hci/commands/autoboot_cmd.c b/qemu/roms/ipxe/src/hci/commands/autoboot_cmd.c
index 62235a278..56f39a1ce 100644
--- a/qemu/roms/ipxe/src/hci/commands/autoboot_cmd.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/commands/config_cmd.c b/qemu/roms/ipxe/src/hci/commands/config_cmd.c
index b81c866ff..ad415e045 100644
--- a/qemu/roms/ipxe/src/hci/commands/config_cmd.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/commands/console_cmd.c b/qemu/roms/ipxe/src/hci/commands/console_cmd.c
index d2eae59f0..ba472b9f6 100644
--- a/qemu/roms/ipxe/src/hci/commands/console_cmd.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/commands/dhcp_cmd.c b/qemu/roms/ipxe/src/hci/commands/dhcp_cmd.c
index feeb55ee5..45a922b51 100644
--- a/qemu/roms/ipxe/src/hci/commands/dhcp_cmd.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/commands/fcmgmt_cmd.c b/qemu/roms/ipxe/src/hci/commands/fcmgmt_cmd.c
index 1c199b5dc..97f10f4dd 100644
--- a/qemu/roms/ipxe/src/hci/commands/fcmgmt_cmd.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/commands/gdbstub_cmd.c b/qemu/roms/ipxe/src/hci/commands/gdbstub_cmd.c
index 33890aebc..c4a831e7a 100644
--- a/qemu/roms/ipxe/src/hci/commands/gdbstub_cmd.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/commands/ifmgmt_cmd.c b/qemu/roms/ipxe/src/hci/commands/ifmgmt_cmd.c
index 5307c9423..c89af2e81 100644
--- a/qemu/roms/ipxe/src/hci/commands/ifmgmt_cmd.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/commands/image_cmd.c b/qemu/roms/ipxe/src/hci/commands/image_cmd.c
index a9e831bf5..4a7c500a4 100644
--- a/qemu/roms/ipxe/src/hci/commands/image_cmd.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/commands/image_trust_cmd.c b/qemu/roms/ipxe/src/hci/commands/image_trust_cmd.c
index ca59a858a..f9d6b5b3e 100644
--- a/qemu/roms/ipxe/src/hci/commands/image_trust_cmd.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/commands/ipstat_cmd.c b/qemu/roms/ipxe/src/hci/commands/ipstat_cmd.c
index d565dc0ae..763e4dfd6 100644
--- a/qemu/roms/ipxe/src/hci/commands/ipstat_cmd.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/commands/login_cmd.c b/qemu/roms/ipxe/src/hci/commands/login_cmd.c
index f5db427d5..c9e196437 100644
--- a/qemu/roms/ipxe/src/hci/commands/login_cmd.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/commands/lotest_cmd.c b/qemu/roms/ipxe/src/hci/commands/lotest_cmd.c
index 0fa031bcb..a989932d4 100644
--- a/qemu/roms/ipxe/src/hci/commands/lotest_cmd.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/commands/menu_cmd.c b/qemu/roms/ipxe/src/hci/commands/menu_cmd.c
index 66a6262e6..76bce8695 100644
--- a/qemu/roms/ipxe/src/hci/commands/menu_cmd.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/commands/neighbour_cmd.c b/qemu/roms/ipxe/src/hci/commands/neighbour_cmd.c
index a1e052439..816e87357 100644
--- a/qemu/roms/ipxe/src/hci/commands/neighbour_cmd.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/commands/nvo_cmd.c b/qemu/roms/ipxe/src/hci/commands/nvo_cmd.c
index e63dab08e..ac0d60651 100644
--- a/qemu/roms/ipxe/src/hci/commands/nvo_cmd.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/commands/param_cmd.c b/qemu/roms/ipxe/src/hci/commands/param_cmd.c
index 6cf096d00..bff04f2ff 100644
--- a/qemu/roms/ipxe/src/hci/commands/param_cmd.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/commands/pci_cmd.c b/qemu/roms/ipxe/src/hci/commands/pci_cmd.c
index f5145fb35..a2a811aa0 100644
--- a/qemu/roms/ipxe/src/hci/commands/pci_cmd.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/commands/ping_cmd.c b/qemu/roms/ipxe/src/hci/commands/ping_cmd.c
index 34807696f..ab271e75a 100644
--- a/qemu/roms/ipxe/src/hci/commands/ping_cmd.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/commands/poweroff_cmd.c b/qemu/roms/ipxe/src/hci/commands/poweroff_cmd.c
index 9d487d330..afdf12dde 100644
--- a/qemu/roms/ipxe/src/hci/commands/poweroff_cmd.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/commands/profstat_cmd.c b/qemu/roms/ipxe/src/hci/commands/profstat_cmd.c
index e4c9e5a24..dc6f649e3 100644
--- a/qemu/roms/ipxe/src/hci/commands/profstat_cmd.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/commands/reboot_cmd.c b/qemu/roms/ipxe/src/hci/commands/reboot_cmd.c
index 485939e42..45d54cc2c 100644
--- a/qemu/roms/ipxe/src/hci/commands/reboot_cmd.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/commands/route_cmd.c b/qemu/roms/ipxe/src/hci/commands/route_cmd.c
index cc5ffc2f2..8aa535363 100644
--- a/qemu/roms/ipxe/src/hci/commands/route_cmd.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/commands/sanboot_cmd.c b/qemu/roms/ipxe/src/hci/commands/sanboot_cmd.c
index 5954b6326..24ec8bc4e 100644
--- a/qemu/roms/ipxe/src/hci/commands/sanboot_cmd.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/commands/sync_cmd.c b/qemu/roms/ipxe/src/hci/commands/sync_cmd.c
index adf7e3cc6..54799d422 100644
--- a/qemu/roms/ipxe/src/hci/commands/sync_cmd.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/commands/vlan_cmd.c b/qemu/roms/ipxe/src/hci/commands/vlan_cmd.c
index 5d7298220..8a2f0c749 100644
--- a/qemu/roms/ipxe/src/hci/commands/vlan_cmd.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/editstring.c b/qemu/roms/ipxe/src/hci/editstring.c
index 5f6f04d51..8cbce0767 100644
--- a/qemu/roms/ipxe/src/hci/editstring.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/jumpscroll.c b/qemu/roms/ipxe/src/hci/jumpscroll.c
new file mode 100644
index 000000000..dd6bcac2b
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/hci/mucurses/alert.c b/qemu/roms/ipxe/src/hci/mucurses/alert.c
index 00e959a89..7dc61c222 100644
--- a/qemu/roms/ipxe/src/hci/mucurses/alert.c
+++ b/qemu/roms/ipxe/src/hci/mucurses/alert.c
@@ -7,6 +7,8 @@
*
*/
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
/**
* Audible signal
*
diff --git a/qemu/roms/ipxe/src/hci/mucurses/ansi_screen.c b/qemu/roms/ipxe/src/hci/mucurses/ansi_screen.c
index 1d3143f89..1cf3309dd 100644
--- a/qemu/roms/ipxe/src/hci/mucurses/ansi_screen.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/mucurses/clear.c b/qemu/roms/ipxe/src/hci/mucurses/clear.c
index f5e52ca20..2054f72cc 100644
--- a/qemu/roms/ipxe/src/hci/mucurses/clear.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/mucurses/colour.c b/qemu/roms/ipxe/src/hci/mucurses/colour.c
index c1359c868..b0c480b1f 100644
--- a/qemu/roms/ipxe/src/hci/mucurses/colour.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/mucurses/cursor.h b/qemu/roms/ipxe/src/hci/mucurses/cursor.h
index 16b7d27c2..2e0c896a6 100644
--- a/qemu/roms/ipxe/src/hci/mucurses/cursor.h
+++ b/qemu/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/qemu/roms/ipxe/src/hci/mucurses/edging.c b/qemu/roms/ipxe/src/hci/mucurses/edging.c
index eccd32422..e938d338b 100644
--- a/qemu/roms/ipxe/src/hci/mucurses/edging.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/mucurses/kb.c b/qemu/roms/ipxe/src/hci/mucurses/kb.c
index b38c8c146..8face14d8 100644
--- a/qemu/roms/ipxe/src/hci/mucurses/kb.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/mucurses/mucurses.c b/qemu/roms/ipxe/src/hci/mucurses/mucurses.c
index b67445baf..98a8a2c59 100644
--- a/qemu/roms/ipxe/src/hci/mucurses/mucurses.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/mucurses/mucurses.h b/qemu/roms/ipxe/src/hci/mucurses/mucurses.h
index 7ac1086ac..270394787 100644
--- a/qemu/roms/ipxe/src/hci/mucurses/mucurses.h
+++ b/qemu/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/qemu/roms/ipxe/src/hci/mucurses/print.c b/qemu/roms/ipxe/src/hci/mucurses/print.c
index 9c682588b..e8831c58f 100644
--- a/qemu/roms/ipxe/src/hci/mucurses/print.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/mucurses/print_nadv.c b/qemu/roms/ipxe/src/hci/mucurses/print_nadv.c
index ee472e685..3a44e5bd2 100644
--- a/qemu/roms/ipxe/src/hci/mucurses/print_nadv.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/mucurses/slk.c b/qemu/roms/ipxe/src/hci/mucurses/slk.c
index 600658e75..660eb65c0 100644
--- a/qemu/roms/ipxe/src/hci/mucurses/slk.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/mucurses/widgets/editbox.c b/qemu/roms/ipxe/src/hci/mucurses/widgets/editbox.c
index 630a66e0b..210de4481 100644
--- a/qemu/roms/ipxe/src/hci/mucurses/widgets/editbox.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/mucurses/winattrs.c b/qemu/roms/ipxe/src/hci/mucurses/winattrs.c
index f549d7519..97a5a18b3 100644
--- a/qemu/roms/ipxe/src/hci/mucurses/winattrs.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/mucurses/windows.c b/qemu/roms/ipxe/src/hci/mucurses/windows.c
index 63d0af08c..7f39bdea2 100644
--- a/qemu/roms/ipxe/src/hci/mucurses/windows.c
+++ b/qemu/roms/ipxe/src/hci/mucurses/windows.c
@@ -9,6 +9,8 @@
*
*/
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
/**
* Delete a window
*
diff --git a/qemu/roms/ipxe/src/hci/mucurses/wininit.c b/qemu/roms/ipxe/src/hci/mucurses/wininit.c
index b75abba44..dd84d2f1d 100644
--- a/qemu/roms/ipxe/src/hci/mucurses/wininit.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/readline.c b/qemu/roms/ipxe/src/hci/readline.c
index 40aa59787..83a2e0b90 100644
--- a/qemu/roms/ipxe/src/hci/readline.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/shell.c b/qemu/roms/ipxe/src/hci/shell.c
index c1a543849..276eb3527 100644
--- a/qemu/roms/ipxe/src/hci/shell.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/strerror.c b/qemu/roms/ipxe/src/hci/strerror.c
index 9356e9e0a..1bba8c620 100644
--- a/qemu/roms/ipxe/src/hci/strerror.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/tui/login_ui.c b/qemu/roms/ipxe/src/hci/tui/login_ui.c
index 996b68a0a..3c55325d5 100644
--- a/qemu/roms/ipxe/src/hci/tui/login_ui.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/tui/menu_ui.c b/qemu/roms/ipxe/src/hci/tui/menu_ui.c
index 0a9566def..f9dd9d100 100644
--- a/qemu/roms/ipxe/src/hci/tui/menu_ui.c
+++ b/qemu/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/qemu/roms/ipxe/src/hci/tui/settings_ui.c b/qemu/roms/ipxe/src/hci/tui/settings_ui.c
index 221839730..be421cc0a 100644
--- a/qemu/roms/ipxe/src/hci/tui/settings_ui.c
+++ b/qemu/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/qemu/roms/ipxe/src/image/elf.c b/qemu/roms/ipxe/src/image/elf.c
index 51636a8e9..5c2f9db25 100644
--- a/qemu/roms/ipxe/src/image/elf.c
+++ b/qemu/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/qemu/roms/ipxe/src/image/embedded.c b/qemu/roms/ipxe/src/image/embedded.c
index 6358378fb..48dd86851 100644
--- a/qemu/roms/ipxe/src/image/embedded.c
+++ b/qemu/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/qemu/roms/ipxe/src/image/png.c b/qemu/roms/ipxe/src/image/png.c
index c14608553..5c4bcb3a0 100644
--- a/qemu/roms/ipxe/src/image/png.c
+++ b/qemu/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/qemu/roms/ipxe/src/image/pnm.c b/qemu/roms/ipxe/src/image/pnm.c
index af9e571a2..f24b28841 100644
--- a/qemu/roms/ipxe/src/image/pnm.c
+++ b/qemu/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/qemu/roms/ipxe/src/image/script.c b/qemu/roms/ipxe/src/image/script.c
index 5328da8b4..28050868a 100644
--- a/qemu/roms/ipxe/src/image/script.c
+++ b/qemu/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/qemu/roms/ipxe/src/image/segment.c b/qemu/roms/ipxe/src/image/segment.c
index 86fe42662..2d0f2f0fc 100644
--- a/qemu/roms/ipxe/src/image/segment.c
+++ b/qemu/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/qemu/roms/ipxe/src/include/.gitignore b/qemu/roms/ipxe/src/include/.gitignore
deleted file mode 100644
index de1598ef3..000000000
--- a/qemu/roms/ipxe/src/include/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-.buildserial.h
diff --git a/qemu/roms/ipxe/src/include/assert.h b/qemu/roms/ipxe/src/include/assert.h
index a33f6017c..07f3ecb8c 100644
--- a/qemu/roms/ipxe/src/include/assert.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/big_bswap.h b/qemu/roms/ipxe/src/include/big_bswap.h
deleted file mode 100644
index 6c375a573..000000000
--- a/qemu/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/qemu/roms/ipxe/src/include/byteswap.h b/qemu/roms/ipxe/src/include/byteswap.h
index 466759cf8..d1028c579 100644
--- a/qemu/roms/ipxe/src/include/byteswap.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/compiler.h b/qemu/roms/ipxe/src/include/compiler.h
index 3f5c913a0..ca82f9523 100644
--- a/qemu/roms/ipxe/src/include/compiler.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ctype.h b/qemu/roms/ipxe/src/include/ctype.h
index e92ecb1c0..0d79ecd19 100644
--- a/qemu/roms/ipxe/src/include/ctype.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/curses.h b/qemu/roms/ipxe/src/include/curses.h
index f16f9d7d0..04060fe27 100644
--- a/qemu/roms/ipxe/src/include/curses.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/elf.h b/qemu/roms/ipxe/src/include/elf.h
index 04022b687..18f755a21 100644
--- a/qemu/roms/ipxe/src/include/elf.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/endian.h b/qemu/roms/ipxe/src/include/endian.h
index 9682cf9b4..79c3163ee 100644
--- a/qemu/roms/ipxe/src/include/endian.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/errno.h b/qemu/roms/ipxe/src/include/errno.h
index bcc4a8816..036479aff 100644
--- a/qemu/roms/ipxe/src/include/errno.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/getopt.h b/qemu/roms/ipxe/src/include/getopt.h
index 0fe43567e..db3de1786 100644
--- a/qemu/roms/ipxe/src/include/getopt.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/hci/ifmgmt_cmd.h b/qemu/roms/ipxe/src/include/hci/ifmgmt_cmd.h
index 913b911d8..5debf85c2 100644
--- a/qemu/roms/ipxe/src/include/hci/ifmgmt_cmd.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/acpi.h b/qemu/roms/ipxe/src/include/ipxe/acpi.h
index 282b6d92d..2ccd691ed 100644
--- a/qemu/roms/ipxe/src/include/ipxe/acpi.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/aes.h b/qemu/roms/ipxe/src/include/ipxe/aes.h
index 4e44f9853..0432e43ee 100644
--- a/qemu/roms/ipxe/src/include/ipxe/aes.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/ansicol.h b/qemu/roms/ipxe/src/include/ipxe/ansicol.h
index 707d1599d..2b54ecaca 100644
--- a/qemu/roms/ipxe/src/include/ipxe/ansicol.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/ansiesc.h b/qemu/roms/ipxe/src/include/ipxe/ansiesc.h
index c1c74481d..80bc83308 100644
--- a/qemu/roms/ipxe/src/include/ipxe/ansiesc.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/aoe.h b/qemu/roms/ipxe/src/include/ipxe/aoe.h
index 60f3bd959..0c656e7c2 100644
--- a/qemu/roms/ipxe/src/include/ipxe/aoe.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/api.h b/qemu/roms/ipxe/src/include/ipxe/api.h
index 838b8936e..d05d3b07a 100644
--- a/qemu/roms/ipxe/src/include/ipxe/api.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/arp.h b/qemu/roms/ipxe/src/include/ipxe/arp.h
index e30ae6b76..5822fa095 100644
--- a/qemu/roms/ipxe/src/include/ipxe/arp.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/asn1.h b/qemu/roms/ipxe/src/include/ipxe/asn1.h
index d12524ddb..5fbd58281 100644
--- a/qemu/roms/ipxe/src/include/ipxe/asn1.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/ata.h b/qemu/roms/ipxe/src/include/ipxe/ata.h
index b7f02d655..a10cfafcc 100644
--- a/qemu/roms/ipxe/src/include/ipxe/ata.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/base16.h b/qemu/roms/ipxe/src/include/ipxe/base16.h
index 60e3f2315..8c44da17e 100644
--- a/qemu/roms/ipxe/src/include/ipxe/base16.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/base64.h b/qemu/roms/ipxe/src/include/ipxe/base64.h
index 5fe134dc8..0c70d8382 100644
--- a/qemu/roms/ipxe/src/include/ipxe/base64.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/bigint.h b/qemu/roms/ipxe/src/include/ipxe/bigint.h
index 97fbce245..2f99f8445 100644
--- a/qemu/roms/ipxe/src/include/ipxe/bigint.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/bitbash.h b/qemu/roms/ipxe/src/include/ipxe/bitbash.h
index 69d5d9e3e..2a2e475d0 100644
--- a/qemu/roms/ipxe/src/include/ipxe/bitbash.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/bitmap.h b/qemu/roms/ipxe/src/include/ipxe/bitmap.h
index b18584c1f..38aca694b 100644
--- a/qemu/roms/ipxe/src/include/ipxe/bitmap.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/bitops.h b/qemu/roms/ipxe/src/include/ipxe/bitops.h
index 73e859f41..220ab0fe7 100644
--- a/qemu/roms/ipxe/src/include/ipxe/bitops.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/blockdev.h b/qemu/roms/ipxe/src/include/ipxe/blockdev.h
index 9f0a9f787..418c43004 100644
--- a/qemu/roms/ipxe/src/include/ipxe/blockdev.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/blocktrans.h b/qemu/roms/ipxe/src/include/ipxe/blocktrans.h
new file mode 100644
index 000000000..fee71b96c
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/bofm.h b/qemu/roms/ipxe/src/include/ipxe/bofm.h
index 1da47f651..bc994ea8b 100644
--- a/qemu/roms/ipxe/src/include/ipxe/bofm.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/cbc.h b/qemu/roms/ipxe/src/include/ipxe/cbc.h
index fae376577..18a94e144 100644
--- a/qemu/roms/ipxe/src/include/ipxe/cbc.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/cdc.h b/qemu/roms/ipxe/src/include/ipxe/cdc.h
new file mode 100644
index 000000000..f1799cd9a
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/certstore.h b/qemu/roms/ipxe/src/include/ipxe/certstore.h
index 7456db621..49b3b512c 100644
--- a/qemu/roms/ipxe/src/include/ipxe/certstore.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/chap.h b/qemu/roms/ipxe/src/include/ipxe/chap.h
index fce48f3ea..7c693e29d 100644
--- a/qemu/roms/ipxe/src/include/ipxe/chap.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/cms.h b/qemu/roms/ipxe/src/include/ipxe/cms.h
index e026ebd2f..7adf724b2 100644
--- a/qemu/roms/ipxe/src/include/ipxe/cms.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/command.h b/qemu/roms/ipxe/src/include/ipxe/command.h
index 432da1abb..a208e7d8f 100644
--- a/qemu/roms/ipxe/src/include/ipxe/command.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/console.h b/qemu/roms/ipxe/src/include/ipxe/console.h
index 4b90c9cec..1b764aaca 100644
--- a/qemu/roms/ipxe/src/include/ipxe/console.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/cpio.h b/qemu/roms/ipxe/src/include/ipxe/cpio.h
index 277232808..0637c531d 100644
--- a/qemu/roms/ipxe/src/include/ipxe/cpio.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/crc32.h b/qemu/roms/ipxe/src/include/ipxe/crc32.h
index 38ac1b31f..30d2fe66c 100644
--- a/qemu/roms/ipxe/src/include/ipxe/crc32.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/crypto.h b/qemu/roms/ipxe/src/include/ipxe/crypto.h
index 3eda5ec6e..fc0d8b22b 100644
--- a/qemu/roms/ipxe/src/include/ipxe/crypto.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/deflate.h b/qemu/roms/ipxe/src/include/ipxe/deflate.h
index 19c5125eb..b751aa9a3 100644
--- a/qemu/roms/ipxe/src/include/ipxe/deflate.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/device.h b/qemu/roms/ipxe/src/include/ipxe/device.h
index 7202a6966..d81417e8e 100644
--- a/qemu/roms/ipxe/src/include/ipxe/device.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/dhcp.h b/qemu/roms/ipxe/src/include/ipxe/dhcp.h
index bcfb85cc1..a11db3497 100644
--- a/qemu/roms/ipxe/src/include/ipxe/dhcp.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/dhcpopts.h b/qemu/roms/ipxe/src/include/ipxe/dhcpopts.h
index c5af5d749..707fda4a8 100644
--- a/qemu/roms/ipxe/src/include/ipxe/dhcpopts.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/dhcppkt.h b/qemu/roms/ipxe/src/include/ipxe/dhcppkt.h
index 3179a6bb0..f13dfc93d 100644
--- a/qemu/roms/ipxe/src/include/ipxe/dhcppkt.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/dhcpv6.h b/qemu/roms/ipxe/src/include/ipxe/dhcpv6.h
index 2636b8ab2..9307b6cae 100644
--- a/qemu/roms/ipxe/src/include/ipxe/dhcpv6.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/dns.h b/qemu/roms/ipxe/src/include/ipxe/dns.h
index 4f6cab3a4..738dea6e4 100644
--- a/qemu/roms/ipxe/src/include/ipxe/dns.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/downloader.h b/qemu/roms/ipxe/src/include/ipxe/downloader.h
index de1a2e75e..ccb1abfef 100644
--- a/qemu/roms/ipxe/src/include/ipxe/downloader.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/drbg.h b/qemu/roms/ipxe/src/include/ipxe/drbg.h
index 6374e7787..ed2b3757a 100644
--- a/qemu/roms/ipxe/src/include/ipxe/drbg.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/ecb.h b/qemu/roms/ipxe/src/include/ipxe/ecb.h
new file mode 100644
index 000000000..4e6aa3c81
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/edd.h b/qemu/roms/ipxe/src/include/ipxe/edd.h
index 0c25593d5..1914fd0b0 100644
--- a/qemu/roms/ipxe/src/include/ipxe/edd.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/editbox.h b/qemu/roms/ipxe/src/include/ipxe/editbox.h
index 9122dbbf3..2c70e0b6b 100644
--- a/qemu/roms/ipxe/src/include/ipxe/editbox.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/editstring.h b/qemu/roms/ipxe/src/include/ipxe/editstring.h
index 2ef546a63..a00a8adaa 100644
--- a/qemu/roms/ipxe/src/include/ipxe/editstring.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/efi/ProcessorBind.h b/qemu/roms/ipxe/src/include/ipxe/efi/ProcessorBind.h
index 1294459f9..7466814fa 100644
--- a/qemu/roms/ipxe/src/include/ipxe/efi/ProcessorBind.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/efi/Protocol/Rng.h b/qemu/roms/ipxe/src/include/ipxe/efi/Protocol/Rng.h
new file mode 100644
index 000000000..f04efbb03
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/efi/efi_autoboot.h b/qemu/roms/ipxe/src/include/ipxe/efi/efi_autoboot.h
index d4a26850c..1d5ddc8c3 100644
--- a/qemu/roms/ipxe/src/include/ipxe/efi/efi_autoboot.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/efi/efi_driver.h b/qemu/roms/ipxe/src/include/ipxe/efi/efi_driver.h
index e16a24daa..f497df3e3 100644
--- a/qemu/roms/ipxe/src/include/ipxe/efi/efi_driver.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/efi/efi_entropy.h b/qemu/roms/ipxe/src/include/ipxe/efi/efi_entropy.h
new file mode 100644
index 000000000..39a667355
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/efi/efi_hii.h b/qemu/roms/ipxe/src/include/ipxe/efi/efi_hii.h
index 8e94bbe7e..bbec31194 100644
--- a/qemu/roms/ipxe/src/include/ipxe/efi/efi_hii.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/efi/efi_pci.h b/qemu/roms/ipxe/src/include/ipxe/efi/efi_pci.h
index af36613d9..6dd945f05 100644
--- a/qemu/roms/ipxe/src/include/ipxe/efi/efi_pci.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/efi/efi_pci_api.h b/qemu/roms/ipxe/src/include/ipxe/efi/efi_pci_api.h
index 498a0388b..887d5ee14 100644
--- a/qemu/roms/ipxe/src/include/ipxe/efi/efi_pci_api.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/efi/efi_reboot.h b/qemu/roms/ipxe/src/include/ipxe/efi/efi_reboot.h
index 33921b913..249cae8c5 100644
--- a/qemu/roms/ipxe/src/include/ipxe/efi/efi_reboot.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/efi/efi_smbios.h b/qemu/roms/ipxe/src/include/ipxe/efi/efi_smbios.h
index 7642e5bc5..d890d5460 100644
--- a/qemu/roms/ipxe/src/include/ipxe/efi/efi_smbios.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/efi/efi_snp.h b/qemu/roms/ipxe/src/include/ipxe/efi/efi_snp.h
index a18bced5f..1e5c66626 100644
--- a/qemu/roms/ipxe/src/include/ipxe/efi/efi_snp.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/efi/efi_strings.h b/qemu/roms/ipxe/src/include/ipxe/efi/efi_strings.h
index 023ccda07..2f241537e 100644
--- a/qemu/roms/ipxe/src/include/ipxe/efi/efi_strings.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/efi/efi_time.h b/qemu/roms/ipxe/src/include/ipxe/efi/efi_time.h
new file mode 100644
index 000000000..099994b57
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/efi/efi_timer.h b/qemu/roms/ipxe/src/include/ipxe/efi/efi_timer.h
index b10543d6c..c03765393 100644
--- a/qemu/roms/ipxe/src/include/ipxe/efi/efi_timer.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/efi/efi_uaccess.h b/qemu/roms/ipxe/src/include/ipxe/efi/efi_uaccess.h
index 870a089b2..3cc750405 100644
--- a/qemu/roms/ipxe/src/include/ipxe/efi/efi_uaccess.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/efi/efi_umalloc.h b/qemu/roms/ipxe/src/include/ipxe/efi/efi_umalloc.h
index 911e69a96..4eb2a5f9b 100644
--- a/qemu/roms/ipxe/src/include/ipxe/efi/efi_umalloc.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/efi/efi_utils.h b/qemu/roms/ipxe/src/include/ipxe/efi/efi_utils.h
index 9164be190..57268daf7 100644
--- a/qemu/roms/ipxe/src/include/ipxe/efi/efi_utils.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/efi/efi_watchdog.h b/qemu/roms/ipxe/src/include/ipxe/efi/efi_watchdog.h
new file mode 100644
index 000000000..4a56b9a29
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/efi/efi_wrap.h b/qemu/roms/ipxe/src/include/ipxe/efi/efi_wrap.h
index 7579e0fe9..d8ed1a5cc 100644
--- a/qemu/roms/ipxe/src/include/ipxe/efi/efi_wrap.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/eisa.h b/qemu/roms/ipxe/src/include/ipxe/eisa.h
index 22a1ed94e..e7dac1f39 100644
--- a/qemu/roms/ipxe/src/include/ipxe/eisa.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/elf.h b/qemu/roms/ipxe/src/include/ipxe/elf.h
index ec675c047..033c3f7a8 100644
--- a/qemu/roms/ipxe/src/include/ipxe/elf.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/eltorito.h b/qemu/roms/ipxe/src/include/ipxe/eltorito.h
index 3302b38b6..27e361b16 100644
--- a/qemu/roms/ipxe/src/include/ipxe/eltorito.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/entropy.h b/qemu/roms/ipxe/src/include/ipxe/entropy.h
index adf325e79..beeb3abfa 100644
--- a/qemu/roms/ipxe/src/include/ipxe/entropy.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/errfile.h b/qemu/roms/ipxe/src/include/ipxe/errfile.h
index f809337ff..e21c95938 100644
--- a/qemu/roms/ipxe/src/include/ipxe/errfile.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/errno/efi.h b/qemu/roms/ipxe/src/include/ipxe/errno/efi.h
index 2d2c50176..9f010f5fb 100644
--- a/qemu/roms/ipxe/src/include/ipxe/errno/efi.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/errno/linux.h b/qemu/roms/ipxe/src/include/ipxe/errno/linux.h
index 11309b4ad..99133c816 100644
--- a/qemu/roms/ipxe/src/include/ipxe/errno/linux.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/errortab.h b/qemu/roms/ipxe/src/include/ipxe/errortab.h
index a2f6a70f5..4fe81a6be 100644
--- a/qemu/roms/ipxe/src/include/ipxe/errortab.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/eth_slow.h b/qemu/roms/ipxe/src/include/ipxe/eth_slow.h
index 00509197d..f6d731b3b 100644
--- a/qemu/roms/ipxe/src/include/ipxe/eth_slow.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/ethernet.h b/qemu/roms/ipxe/src/include/ipxe/ethernet.h
index d1263d7c3..dd04e00ce 100644
--- a/qemu/roms/ipxe/src/include/ipxe/ethernet.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/fakedhcp.h b/qemu/roms/ipxe/src/include/ipxe/fakedhcp.h
index ea06b06dc..d016b5237 100644
--- a/qemu/roms/ipxe/src/include/ipxe/fakedhcp.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/fault.h b/qemu/roms/ipxe/src/include/ipxe/fault.h
new file mode 100644
index 000000000..356296c35
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/fbcon.h b/qemu/roms/ipxe/src/include/ipxe/fbcon.h
index 0538449ac..d442bb918 100644
--- a/qemu/roms/ipxe/src/include/ipxe/fbcon.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/fc.h b/qemu/roms/ipxe/src/include/ipxe/fc.h
index 6fdef092d..840d11f62 100644
--- a/qemu/roms/ipxe/src/include/ipxe/fc.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/fcels.h b/qemu/roms/ipxe/src/include/ipxe/fcels.h
index 45fa69a4a..02f755115 100644
--- a/qemu/roms/ipxe/src/include/ipxe/fcels.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/fcns.h b/qemu/roms/ipxe/src/include/ipxe/fcns.h
index e25d9b9d5..9011a7be7 100644
--- a/qemu/roms/ipxe/src/include/ipxe/fcns.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/fcoe.h b/qemu/roms/ipxe/src/include/ipxe/fcoe.h
index 6ba5b406a..b61e82fea 100644
--- a/qemu/roms/ipxe/src/include/ipxe/fcoe.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/fcp.h b/qemu/roms/ipxe/src/include/ipxe/fcp.h
index f6922bc7c..853ca13f6 100644
--- a/qemu/roms/ipxe/src/include/ipxe/fcp.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/features.h b/qemu/roms/ipxe/src/include/ipxe/features.h
index d8b8b2184..e86a2d226 100644
--- a/qemu/roms/ipxe/src/include/ipxe/features.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/fragment.h b/qemu/roms/ipxe/src/include/ipxe/fragment.h
index e311ad1e4..0069e5e08 100644
--- a/qemu/roms/ipxe/src/include/ipxe/fragment.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/ftp.h b/qemu/roms/ipxe/src/include/ipxe/ftp.h
index cbab12d2c..3180f1631 100644
--- a/qemu/roms/ipxe/src/include/ipxe/ftp.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/gdbserial.h b/qemu/roms/ipxe/src/include/ipxe/gdbserial.h
index a3b56173c..e1040c94e 100644
--- a/qemu/roms/ipxe/src/include/ipxe/gdbserial.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/gdbstub.h b/qemu/roms/ipxe/src/include/ipxe/gdbstub.h
index 319606747..13ca33ddb 100644
--- a/qemu/roms/ipxe/src/include/ipxe/gdbstub.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/gdbudp.h b/qemu/roms/ipxe/src/include/ipxe/gdbudp.h
index db7a451c9..a1c091522 100644
--- a/qemu/roms/ipxe/src/include/ipxe/gdbudp.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/hash_df.h b/qemu/roms/ipxe/src/include/ipxe/hash_df.h
index 607a4a610..e57682446 100644
--- a/qemu/roms/ipxe/src/include/ipxe/hash_df.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/hidemem.h b/qemu/roms/ipxe/src/include/ipxe/hidemem.h
index ddc9cd8b3..cc8d5ee37 100644
--- a/qemu/roms/ipxe/src/include/ipxe/hidemem.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/hmac.h b/qemu/roms/ipxe/src/include/ipxe/hmac.h
index d5ec0868d..09d3e273d 100644
--- a/qemu/roms/ipxe/src/include/ipxe/hmac.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/hmac_drbg.h b/qemu/roms/ipxe/src/include/ipxe/hmac_drbg.h
index 8dfd2924f..a0f22da75 100644
--- a/qemu/roms/ipxe/src/include/ipxe/hmac_drbg.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/http.h b/qemu/roms/ipxe/src/include/ipxe/http.h
index cf8c0c7fa..a0dff7d00 100644
--- a/qemu/roms/ipxe/src/include/ipxe/http.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/hyperv.h b/qemu/roms/ipxe/src/include/ipxe/hyperv.h
new file mode 100644
index 000000000..c61e2a083
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/i2c.h b/qemu/roms/ipxe/src/include/ipxe/i2c.h
index c1f5a9bbd..46970515c 100644
--- a/qemu/roms/ipxe/src/include/ipxe/i2c.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/ib_cm.h b/qemu/roms/ipxe/src/include/ipxe/ib_cm.h
index 7d08cd9b1..4913eebae 100644
--- a/qemu/roms/ipxe/src/include/ipxe/ib_cm.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/ib_mad.h b/qemu/roms/ipxe/src/include/ipxe/ib_mad.h
index b8694833e..ae1eea7e4 100644
--- a/qemu/roms/ipxe/src/include/ipxe/ib_mad.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/ib_mcast.h b/qemu/roms/ipxe/src/include/ipxe/ib_mcast.h
index a5c22a03e..564066975 100644
--- a/qemu/roms/ipxe/src/include/ipxe/ib_mcast.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/ib_mi.h b/qemu/roms/ipxe/src/include/ipxe/ib_mi.h
index 5c5415b71..c7c8143ba 100644
--- a/qemu/roms/ipxe/src/include/ipxe/ib_mi.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/ib_packet.h b/qemu/roms/ipxe/src/include/ipxe/ib_packet.h
index a959967cb..f275fcb09 100644
--- a/qemu/roms/ipxe/src/include/ipxe/ib_packet.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/ib_pathrec.h b/qemu/roms/ipxe/src/include/ipxe/ib_pathrec.h
index 1fe67f87d..a4e11ebe3 100644
--- a/qemu/roms/ipxe/src/include/ipxe/ib_pathrec.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/ib_sma.h b/qemu/roms/ipxe/src/include/ipxe/ib_sma.h
index fa355c652..74003d045 100644
--- a/qemu/roms/ipxe/src/include/ipxe/ib_sma.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/ib_smc.h b/qemu/roms/ipxe/src/include/ipxe/ib_smc.h
index 259d2cde1..f9b96b1bd 100644
--- a/qemu/roms/ipxe/src/include/ipxe/ib_smc.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/icmp.h b/qemu/roms/ipxe/src/include/ipxe/icmp.h
index 0480ddfaf..803f8e019 100644
--- a/qemu/roms/ipxe/src/include/ipxe/icmp.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/icmpv6.h b/qemu/roms/ipxe/src/include/ipxe/icmpv6.h
index b5ea54eab..0474ddca8 100644
--- a/qemu/roms/ipxe/src/include/ipxe/icmpv6.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/if_arp.h b/qemu/roms/ipxe/src/include/ipxe/if_arp.h
index fd36e9c67..4eb1f80b7 100644
--- a/qemu/roms/ipxe/src/include/ipxe/if_arp.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/if_ether.h b/qemu/roms/ipxe/src/include/ipxe/if_ether.h
index a7e237349..58d91b976 100644
--- a/qemu/roms/ipxe/src/include/ipxe/if_ether.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/image.h b/qemu/roms/ipxe/src/include/ipxe/image.h
index 5d7080a75..6abd7a2d2 100644
--- a/qemu/roms/ipxe/src/include/ipxe/image.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/in.h b/qemu/roms/ipxe/src/include/ipxe/in.h
index de96ca22a..0ebf441c2 100644
--- a/qemu/roms/ipxe/src/include/ipxe/in.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/infiniband.h b/qemu/roms/ipxe/src/include/ipxe/infiniband.h
index f546ea61b..87cfe5082 100644
--- a/qemu/roms/ipxe/src/include/ipxe/infiniband.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/init.h b/qemu/roms/ipxe/src/include/ipxe/init.h
index 19c5925bf..025cfaf37 100644
--- a/qemu/roms/ipxe/src/include/ipxe/init.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/interface.h b/qemu/roms/ipxe/src/include/ipxe/interface.h
index a474aaad0..a8d823775 100644
--- a/qemu/roms/ipxe/src/include/ipxe/interface.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/io.h b/qemu/roms/ipxe/src/include/ipxe/io.h
index 29ccfd1fa..af767915d 100644
--- a/qemu/roms/ipxe/src/include/ipxe/io.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/iobuf.h b/qemu/roms/ipxe/src/include/ipxe/iobuf.h
index b2b0cb440..27d285d44 100644
--- a/qemu/roms/ipxe/src/include/ipxe/iobuf.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/ip.h b/qemu/roms/ipxe/src/include/ipxe/ip.h
index 1a93a552e..285be6dcd 100644
--- a/qemu/roms/ipxe/src/include/ipxe/ip.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/ipoib.h b/qemu/roms/ipxe/src/include/ipxe/ipoib.h
index 68ff8df49..b34dd32d0 100644
--- a/qemu/roms/ipxe/src/include/ipxe/ipoib.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/ipstat.h b/qemu/roms/ipxe/src/include/ipxe/ipstat.h
index c554c1859..b34ed5fcf 100644
--- a/qemu/roms/ipxe/src/include/ipxe/ipstat.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/ipv6.h b/qemu/roms/ipxe/src/include/ipxe/ipv6.h
index 48aaf677e..b500382c1 100644
--- a/qemu/roms/ipxe/src/include/ipxe/ipv6.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/isa_ids.h b/qemu/roms/ipxe/src/include/ipxe/isa_ids.h
index 1faf1148d..d815bda34 100644
--- a/qemu/roms/ipxe/src/include/ipxe/isa_ids.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/isapnp.h b/qemu/roms/ipxe/src/include/ipxe/isapnp.h
index b0b0e98d6..59beac986 100644
--- a/qemu/roms/ipxe/src/include/ipxe/isapnp.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/iscsi.h b/qemu/roms/ipxe/src/include/ipxe/iscsi.h
index be71360a0..c75ff4188 100644
--- a/qemu/roms/ipxe/src/include/ipxe/iscsi.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/iso9660.h b/qemu/roms/ipxe/src/include/ipxe/iso9660.h
index 02c2ae377..34cb8f0a1 100644
--- a/qemu/roms/ipxe/src/include/ipxe/iso9660.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/isqrt.h b/qemu/roms/ipxe/src/include/ipxe/isqrt.h
index 58ed42f0c..68255d1bc 100644
--- a/qemu/roms/ipxe/src/include/ipxe/isqrt.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/job.h b/qemu/roms/ipxe/src/include/ipxe/job.h
index a2369f7c2..7e1bd8109 100644
--- a/qemu/roms/ipxe/src/include/ipxe/job.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/jumpscroll.h b/qemu/roms/ipxe/src/include/ipxe/jumpscroll.h
new file mode 100644
index 000000000..7a5b111c1
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/keymap.h b/qemu/roms/ipxe/src/include/ipxe/keymap.h
index 9ac42a6b1..0f1b0c656 100644
--- a/qemu/roms/ipxe/src/include/ipxe/keymap.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/keys.h b/qemu/roms/ipxe/src/include/ipxe/keys.h
index 8b13550b9..d15267a1f 100644
--- a/qemu/roms/ipxe/src/include/ipxe/keys.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/linebuf.h b/qemu/roms/ipxe/src/include/ipxe/linebuf.h
index 706ef2554..630278a04 100644
--- a/qemu/roms/ipxe/src/include/ipxe/linebuf.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/lineconsole.h b/qemu/roms/ipxe/src/include/ipxe/lineconsole.h
index 925c0accc..31117e73c 100644
--- a/qemu/roms/ipxe/src/include/ipxe/lineconsole.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/linux/linux_entropy.h b/qemu/roms/ipxe/src/include/ipxe/linux/linux_entropy.h
index bd89bd52f..afef6fe19 100644
--- a/qemu/roms/ipxe/src/include/ipxe/linux/linux_entropy.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/linux/linux_nap.h b/qemu/roms/ipxe/src/include/ipxe/linux/linux_nap.h
index 5bac7242f..d072886c7 100644
--- a/qemu/roms/ipxe/src/include/ipxe/linux/linux_nap.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/linux/linux_pci.h b/qemu/roms/ipxe/src/include/ipxe/linux/linux_pci.h
index 439166733..22ae7f1bc 100644
--- a/qemu/roms/ipxe/src/include/ipxe/linux/linux_pci.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/linux/linux_smbios.h b/qemu/roms/ipxe/src/include/ipxe/linux/linux_smbios.h
index 6d51e13ba..16c6d8acd 100644
--- a/qemu/roms/ipxe/src/include/ipxe/linux/linux_smbios.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/linux/linux_time.h b/qemu/roms/ipxe/src/include/ipxe/linux/linux_time.h
index 93a257730..872ef5ade 100644
--- a/qemu/roms/ipxe/src/include/ipxe/linux/linux_time.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/linux/linux_timer.h b/qemu/roms/ipxe/src/include/ipxe/linux/linux_timer.h
index 379507417..7f46e36b2 100644
--- a/qemu/roms/ipxe/src/include/ipxe/linux/linux_timer.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/linux/linux_uaccess.h b/qemu/roms/ipxe/src/include/ipxe/linux/linux_uaccess.h
index e4d16d9e0..acd919a85 100644
--- a/qemu/roms/ipxe/src/include/ipxe/linux/linux_uaccess.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/linux/linux_umalloc.h b/qemu/roms/ipxe/src/include/ipxe/linux/linux_umalloc.h
index 4de55ecf3..1811d0bc6 100644
--- a/qemu/roms/ipxe/src/include/ipxe/linux/linux_umalloc.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/linux_compat.h b/qemu/roms/ipxe/src/include/ipxe/linux_compat.h
index 6f6ed97d7..4704c4817 100644
--- a/qemu/roms/ipxe/src/include/ipxe/linux_compat.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/list.h b/qemu/roms/ipxe/src/include/ipxe/list.h
index 581ec9806..6a9b76f91 100644
--- a/qemu/roms/ipxe/src/include/ipxe/list.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/login_ui.h b/qemu/roms/ipxe/src/include/ipxe/login_ui.h
index 01e5479f7..313e07349 100644
--- a/qemu/roms/ipxe/src/include/ipxe/login_ui.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/malloc.h b/qemu/roms/ipxe/src/include/ipxe/malloc.h
index bbd6cb898..dd158b8e6 100644
--- a/qemu/roms/ipxe/src/include/ipxe/malloc.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/mca.h b/qemu/roms/ipxe/src/include/ipxe/mca.h
index d86dab195..11470ec93 100644
--- a/qemu/roms/ipxe/src/include/ipxe/mca.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/md5.h b/qemu/roms/ipxe/src/include/ipxe/md5.h
index 860bc4769..05c3974c8 100644
--- a/qemu/roms/ipxe/src/include/ipxe/md5.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/memblock.h b/qemu/roms/ipxe/src/include/ipxe/memblock.h
index 13af3e433..2bb38c460 100644
--- a/qemu/roms/ipxe/src/include/ipxe/memblock.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/menu.h b/qemu/roms/ipxe/src/include/ipxe/menu.h
index f2b3caccc..3cc99be48 100644
--- a/qemu/roms/ipxe/src/include/ipxe/menu.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/mii.h b/qemu/roms/ipxe/src/include/ipxe/mii.h
index f53ad4a62..c2245b49e 100644
--- a/qemu/roms/ipxe/src/include/ipxe/mii.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/monojob.h b/qemu/roms/ipxe/src/include/ipxe/monojob.h
index aedc37eca..1661d91c2 100644
--- a/qemu/roms/ipxe/src/include/ipxe/monojob.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/mount.h b/qemu/roms/ipxe/src/include/ipxe/mount.h
index ca958117a..2d42ba080 100644
--- a/qemu/roms/ipxe/src/include/ipxe/mount.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/nap.h b/qemu/roms/ipxe/src/include/ipxe/nap.h
index afc887910..f4de778c4 100644
--- a/qemu/roms/ipxe/src/include/ipxe/nap.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/ndp.h b/qemu/roms/ipxe/src/include/ipxe/ndp.h
index 7388f938e..1815236f5 100644
--- a/qemu/roms/ipxe/src/include/ipxe/ndp.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/neighbour.h b/qemu/roms/ipxe/src/include/ipxe/neighbour.h
index f2a3946f1..1c1d1b6ca 100644
--- a/qemu/roms/ipxe/src/include/ipxe/neighbour.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/net80211_err.h b/qemu/roms/ipxe/src/include/ipxe/net80211_err.h
index 7df3d0d85..32ccc257f 100644
--- a/qemu/roms/ipxe/src/include/ipxe/net80211_err.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/netdevice.h b/qemu/roms/ipxe/src/include/ipxe/netdevice.h
index 95ad1cf1b..a1d207ffc 100644
--- a/qemu/roms/ipxe/src/include/ipxe/netdevice.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/nfs.h b/qemu/roms/ipxe/src/include/ipxe/nfs.h
index 498ed5a27..69b8b5381 100644
--- a/qemu/roms/ipxe/src/include/ipxe/nfs.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/nfs_open.h b/qemu/roms/ipxe/src/include/ipxe/nfs_open.h
index caba977f7..8572c41b3 100644
--- a/qemu/roms/ipxe/src/include/ipxe/nfs_open.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/nfs_uri.h b/qemu/roms/ipxe/src/include/ipxe/nfs_uri.h
index d88bd6f65..aaa6d3749 100644
--- a/qemu/roms/ipxe/src/include/ipxe/nfs_uri.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/null_entropy.h b/qemu/roms/ipxe/src/include/ipxe/null_entropy.h
index 646d1a17e..91adefa69 100644
--- a/qemu/roms/ipxe/src/include/ipxe/null_entropy.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/null_nap.h b/qemu/roms/ipxe/src/include/ipxe/null_nap.h
index 0c0704bc7..17145b48b 100644
--- a/qemu/roms/ipxe/src/include/ipxe/null_nap.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/null_reboot.h b/qemu/roms/ipxe/src/include/ipxe/null_reboot.h
index 3de36c5b3..5de38afc0 100644
--- a/qemu/roms/ipxe/src/include/ipxe/null_reboot.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/null_sanboot.h b/qemu/roms/ipxe/src/include/ipxe/null_sanboot.h
index 2b3a2c74d..58f03339f 100644
--- a/qemu/roms/ipxe/src/include/ipxe/null_sanboot.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/null_time.h b/qemu/roms/ipxe/src/include/ipxe/null_time.h
index 2b72cdf50..d2b15194b 100644
--- a/qemu/roms/ipxe/src/include/ipxe/null_time.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/nvo.h b/qemu/roms/ipxe/src/include/ipxe/nvo.h
index 1a629da78..7a3c7a3db 100644
--- a/qemu/roms/ipxe/src/include/ipxe/nvo.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/nvs.h b/qemu/roms/ipxe/src/include/ipxe/nvs.h
index 4733123cf..5789f4c0d 100644
--- a/qemu/roms/ipxe/src/include/ipxe/nvs.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/nvsvpd.h b/qemu/roms/ipxe/src/include/ipxe/nvsvpd.h
index 3450e5c71..4c50daf85 100644
--- a/qemu/roms/ipxe/src/include/ipxe/nvsvpd.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/ocsp.h b/qemu/roms/ipxe/src/include/ipxe/ocsp.h
index 387e28f81..71fa41dc9 100644
--- a/qemu/roms/ipxe/src/include/ipxe/ocsp.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/oncrpc.h b/qemu/roms/ipxe/src/include/ipxe/oncrpc.h
index 76c1260f2..071468711 100644
--- a/qemu/roms/ipxe/src/include/ipxe/oncrpc.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/oncrpc_iob.h b/qemu/roms/ipxe/src/include/ipxe/oncrpc_iob.h
index 4858d96b5..b55043770 100644
--- a/qemu/roms/ipxe/src/include/ipxe/oncrpc_iob.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/open.h b/qemu/roms/ipxe/src/include/ipxe/open.h
index a522f0cd1..43d4cdc66 100644
--- a/qemu/roms/ipxe/src/include/ipxe/open.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/params.h b/qemu/roms/ipxe/src/include/ipxe/params.h
index c2d82d9cf..dd3292efc 100644
--- a/qemu/roms/ipxe/src/include/ipxe/params.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/parseopt.h b/qemu/roms/ipxe/src/include/ipxe/parseopt.h
index 840de7497..829b3431c 100644
--- a/qemu/roms/ipxe/src/include/ipxe/parseopt.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/pccrc.h b/qemu/roms/ipxe/src/include/ipxe/pccrc.h
new file mode 100644
index 000000000..7f0963428
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/pccrd.h b/qemu/roms/ipxe/src/include/ipxe/pccrd.h
new file mode 100644
index 000000000..3daa92f29
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/pccrr.h b/qemu/roms/ipxe/src/include/ipxe/pccrr.h
new file mode 100644
index 000000000..1ea86c40d
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/pci.h b/qemu/roms/ipxe/src/include/ipxe/pci.h
index 692771ebe..a841e00ff 100644
--- a/qemu/roms/ipxe/src/include/ipxe/pci.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/pci_ids.h b/qemu/roms/ipxe/src/include/ipxe/pci_ids.h
deleted file mode 100644
index 25c7782bc..000000000
--- a/qemu/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/qemu/roms/ipxe/src/include/ipxe/pci_io.h b/qemu/roms/ipxe/src/include/ipxe/pci_io.h
index 781b77fe1..10e69763e 100644
--- a/qemu/roms/ipxe/src/include/ipxe/pci_io.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/pcibackup.h b/qemu/roms/ipxe/src/include/ipxe/pcibackup.h
index b9f55cf71..159d25392 100644
--- a/qemu/roms/ipxe/src/include/ipxe/pcibackup.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/pcivpd.h b/qemu/roms/ipxe/src/include/ipxe/pcivpd.h
index 0abf8a956..fefb69740 100644
--- a/qemu/roms/ipxe/src/include/ipxe/pcivpd.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/peerblk.h b/qemu/roms/ipxe/src/include/ipxe/peerblk.h
new file mode 100644
index 000000000..6fc9172f6
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/peerdisc.h b/qemu/roms/ipxe/src/include/ipxe/peerdisc.h
new file mode 100644
index 000000000..f08ccaae2
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/peermux.h b/qemu/roms/ipxe/src/include/ipxe/peermux.h
new file mode 100644
index 000000000..44cbdb9d6
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/pending.h b/qemu/roms/ipxe/src/include/ipxe/pending.h
index e6a369813..be6ed05a1 100644
--- a/qemu/roms/ipxe/src/include/ipxe/pending.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/ping.h b/qemu/roms/ipxe/src/include/ipxe/ping.h
index 6cd376b6f..c55bd1ab2 100644
--- a/qemu/roms/ipxe/src/include/ipxe/ping.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/pinger.h b/qemu/roms/ipxe/src/include/ipxe/pinger.h
index 9932df6b0..227f002dc 100644
--- a/qemu/roms/ipxe/src/include/ipxe/pinger.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/pixbuf.h b/qemu/roms/ipxe/src/include/ipxe/pixbuf.h
index 106b666e6..615744812 100644
--- a/qemu/roms/ipxe/src/include/ipxe/pixbuf.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/png.h b/qemu/roms/ipxe/src/include/ipxe/png.h
index f51d1e6fe..3505eefc8 100644
--- a/qemu/roms/ipxe/src/include/ipxe/png.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/pnm.h b/qemu/roms/ipxe/src/include/ipxe/pnm.h
index 536c14d5f..860968cbc 100644
--- a/qemu/roms/ipxe/src/include/ipxe/pnm.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/pool.h b/qemu/roms/ipxe/src/include/ipxe/pool.h
new file mode 100644
index 000000000..27066e9b3
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/portmap.h b/qemu/roms/ipxe/src/include/ipxe/portmap.h
index 9b735bbca..681ca2ec2 100644
--- a/qemu/roms/ipxe/src/include/ipxe/portmap.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/posix_io.h b/qemu/roms/ipxe/src/include/ipxe/posix_io.h
index 11f3bb5c9..1a73b5e86 100644
--- a/qemu/roms/ipxe/src/include/ipxe/posix_io.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/privkey.h b/qemu/roms/ipxe/src/include/ipxe/privkey.h
index 39049ac9f..81108b6bf 100644
--- a/qemu/roms/ipxe/src/include/ipxe/privkey.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/process.h b/qemu/roms/ipxe/src/include/ipxe/process.h
index 2c76ff260..d600508e7 100644
--- a/qemu/roms/ipxe/src/include/ipxe/process.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/profile.h b/qemu/roms/ipxe/src/include/ipxe/profile.h
index 3a745fcfa..b6d2b19e0 100644
--- a/qemu/roms/ipxe/src/include/ipxe/profile.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/random_nz.h b/qemu/roms/ipxe/src/include/ipxe/random_nz.h
index 6bb80d2ab..4c433fa38 100644
--- a/qemu/roms/ipxe/src/include/ipxe/random_nz.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/rarp.h b/qemu/roms/ipxe/src/include/ipxe/rarp.h
index f84301a43..9054db21a 100644
--- a/qemu/roms/ipxe/src/include/ipxe/rarp.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/rbg.h b/qemu/roms/ipxe/src/include/ipxe/rbg.h
index 9689142f8..758238a65 100644
--- a/qemu/roms/ipxe/src/include/ipxe/rbg.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/reboot.h b/qemu/roms/ipxe/src/include/ipxe/reboot.h
index 97e0d5fb6..33606d9d5 100644
--- a/qemu/roms/ipxe/src/include/ipxe/reboot.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/refcnt.h b/qemu/roms/ipxe/src/include/ipxe/refcnt.h
index 0e8b8658c..7f489abc9 100644
--- a/qemu/roms/ipxe/src/include/ipxe/refcnt.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/resolv.h b/qemu/roms/ipxe/src/include/ipxe/resolv.h
index d9868a5d7..ff48d35ca 100644
--- a/qemu/roms/ipxe/src/include/ipxe/resolv.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/retry.h b/qemu/roms/ipxe/src/include/ipxe/retry.h
index c514822b2..76d45fbd0 100644
--- a/qemu/roms/ipxe/src/include/ipxe/retry.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/rndis.h b/qemu/roms/ipxe/src/include/ipxe/rndis.h
new file mode 100644
index 000000000..bcb6d8e6a
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/rootcert.h b/qemu/roms/ipxe/src/include/ipxe/rootcert.h
index 6525df87a..d4be2e1bc 100644
--- a/qemu/roms/ipxe/src/include/ipxe/rootcert.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/rotate.h b/qemu/roms/ipxe/src/include/ipxe/rotate.h
index ba271ca74..b5693e3ca 100644
--- a/qemu/roms/ipxe/src/include/ipxe/rotate.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/rsa.h b/qemu/roms/ipxe/src/include/ipxe/rsa.h
index 1a5ad8bab..d947eec73 100644
--- a/qemu/roms/ipxe/src/include/ipxe/rsa.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/sanboot.h b/qemu/roms/ipxe/src/include/ipxe/sanboot.h
index 14c8a5da4..57025f2c6 100644
--- a/qemu/roms/ipxe/src/include/ipxe/sanboot.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/script.h b/qemu/roms/ipxe/src/include/ipxe/script.h
index 33420dae4..7e7a9a3a4 100644
--- a/qemu/roms/ipxe/src/include/ipxe/script.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/scsi.h b/qemu/roms/ipxe/src/include/ipxe/scsi.h
index 4428daac3..28b55b2d5 100644
--- a/qemu/roms/ipxe/src/include/ipxe/scsi.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/segment.h b/qemu/roms/ipxe/src/include/ipxe/segment.h
index 37bed0e19..9d5ecbd9b 100644
--- a/qemu/roms/ipxe/src/include/ipxe/segment.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/serial.h b/qemu/roms/ipxe/src/include/ipxe/serial.h
index b47b1d125..83be59c31 100644
--- a/qemu/roms/ipxe/src/include/ipxe/serial.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/settings.h b/qemu/roms/ipxe/src/include/ipxe/settings.h
index d6929ecd0..95a553cc8 100644
--- a/qemu/roms/ipxe/src/include/ipxe/settings.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/settings_ui.h b/qemu/roms/ipxe/src/include/ipxe/settings_ui.h
index 5f7be30cc..0bf21935d 100644
--- a/qemu/roms/ipxe/src/include/ipxe/settings_ui.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/sha256.h b/qemu/roms/ipxe/src/include/ipxe/sha256.h
index 9aa9f3e57..e234cce33 100644
--- a/qemu/roms/ipxe/src/include/ipxe/sha256.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/sha512.h b/qemu/roms/ipxe/src/include/ipxe/sha512.h
new file mode 100644
index 000000000..8e22d8357
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/shell.h b/qemu/roms/ipxe/src/include/ipxe/shell.h
index faa32f422..0d574e028 100644
--- a/qemu/roms/ipxe/src/include/ipxe/shell.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/smbios.h b/qemu/roms/ipxe/src/include/ipxe/smbios.h
index ef5892a21..24b05ed62 100644
--- a/qemu/roms/ipxe/src/include/ipxe/smbios.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/socket.h b/qemu/roms/ipxe/src/include/ipxe/socket.h
index 7cb3912f4..8c70ea4c0 100644
--- a/qemu/roms/ipxe/src/include/ipxe/socket.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/spi.h b/qemu/roms/ipxe/src/include/ipxe/spi.h
index d92d1aec9..83b53bce3 100644
--- a/qemu/roms/ipxe/src/include/ipxe/spi.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/spi_bit.h b/qemu/roms/ipxe/src/include/ipxe/spi_bit.h
index 9cfa7b825..049d30a22 100644
--- a/qemu/roms/ipxe/src/include/ipxe/spi_bit.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/stp.h b/qemu/roms/ipxe/src/include/ipxe/stp.h
new file mode 100644
index 000000000..3d85e5ba4
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/string.h b/qemu/roms/ipxe/src/include/ipxe/string.h
new file mode 100644
index 000000000..a8cbe8faa
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/syslog.h b/qemu/roms/ipxe/src/include/ipxe/syslog.h
index 131692654..138440d66 100644
--- a/qemu/roms/ipxe/src/include/ipxe/syslog.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/tables.h b/qemu/roms/ipxe/src/include/ipxe/tables.h
index e35ce8220..60f8efdea 100644
--- a/qemu/roms/ipxe/src/include/ipxe/tables.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/tcp.h b/qemu/roms/ipxe/src/include/ipxe/tcp.h
index 9baa6391c..063ebaa4b 100644
--- a/qemu/roms/ipxe/src/include/ipxe/tcp.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/tcpip.h b/qemu/roms/ipxe/src/include/ipxe/tcpip.h
index 200630d6b..3cfc8e3ac 100644
--- a/qemu/roms/ipxe/src/include/ipxe/tcpip.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/test.h b/qemu/roms/ipxe/src/include/ipxe/test.h
index 028ee29fb..0b65c299c 100644
--- a/qemu/roms/ipxe/src/include/ipxe/test.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/tftp.h b/qemu/roms/ipxe/src/include/ipxe/tftp.h
index aecafa2ae..e3661e1ac 100644
--- a/qemu/roms/ipxe/src/include/ipxe/tftp.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/time.h b/qemu/roms/ipxe/src/include/ipxe/time.h
index 673fe098a..4c5bb2a00 100644
--- a/qemu/roms/ipxe/src/include/ipxe/time.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/timer.h b/qemu/roms/ipxe/src/include/ipxe/timer.h
index d0309655d..82fbb6764 100644
--- a/qemu/roms/ipxe/src/include/ipxe/timer.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/tls.h b/qemu/roms/ipxe/src/include/ipxe/tls.h
index 586da26ec..7d982c326 100644
--- a/qemu/roms/ipxe/src/include/ipxe/tls.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/uaccess.h b/qemu/roms/ipxe/src/include/ipxe/uaccess.h
index 055bb2ca7..a3f78566a 100644
--- a/qemu/roms/ipxe/src/include/ipxe/uaccess.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/uart.h b/qemu/roms/ipxe/src/include/ipxe/uart.h
new file mode 100644
index 000000000..c63eae615
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/udp.h b/qemu/roms/ipxe/src/include/ipxe/udp.h
index 5717ef213..7b0de4dc0 100644
--- a/qemu/roms/ipxe/src/include/ipxe/udp.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/umalloc.h b/qemu/roms/ipxe/src/include/ipxe/umalloc.h
index 4b25e182a..3892ef53b 100644
--- a/qemu/roms/ipxe/src/include/ipxe/umalloc.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/uri.h b/qemu/roms/ipxe/src/include/ipxe/uri.h
index 7613d578d..00e5a24c4 100644
--- a/qemu/roms/ipxe/src/include/ipxe/uri.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/usb.h b/qemu/roms/ipxe/src/include/ipxe/usb.h
new file mode 100644
index 000000000..ab060b8f4
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/usbhid.h b/qemu/roms/ipxe/src/include/ipxe/usbhid.h
new file mode 100644
index 000000000..fe9d84455
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/usbnet.h b/qemu/roms/ipxe/src/include/ipxe/usbnet.h
new file mode 100644
index 000000000..33a8f3f58
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/uuid.h b/qemu/roms/ipxe/src/include/ipxe/uuid.h
index ad515d0cb..6c45eb9aa 100644
--- a/qemu/roms/ipxe/src/include/ipxe/uuid.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/validator.h b/qemu/roms/ipxe/src/include/ipxe/validator.h
index 23bdab423..0aee56eb0 100644
--- a/qemu/roms/ipxe/src/include/ipxe/validator.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/version.h b/qemu/roms/ipxe/src/include/ipxe/version.h
index ae4275db1..a43a33425 100644
--- a/qemu/roms/ipxe/src/include/ipxe/version.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/vlan.h b/qemu/roms/ipxe/src/include/ipxe/vlan.h
index 083c21916..439e0c16d 100644
--- a/qemu/roms/ipxe/src/include/ipxe/vlan.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/vmbus.h b/qemu/roms/ipxe/src/include/ipxe/vmbus.h
new file mode 100644
index 000000000..26fc578c6
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/vsprintf.h b/qemu/roms/ipxe/src/include/ipxe/vsprintf.h
index c48c97a87..9e6297715 100644
--- a/qemu/roms/ipxe/src/include/ipxe/vsprintf.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/x509.h b/qemu/roms/ipxe/src/include/ipxe/x509.h
index 802480e54..0daaf5e59 100644
--- a/qemu/roms/ipxe/src/include/ipxe/x509.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/xen.h b/qemu/roms/ipxe/src/include/ipxe/xen.h
index 60aabe03e..eac1145ad 100644
--- a/qemu/roms/ipxe/src/include/ipxe/xen.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/xenbus.h b/qemu/roms/ipxe/src/include/ipxe/xenbus.h
index ef2b5496f..ec5782eed 100644
--- a/qemu/roms/ipxe/src/include/ipxe/xenbus.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/xenevent.h b/qemu/roms/ipxe/src/include/ipxe/xenevent.h
index 1dd6a0c0b..f0bd3465e 100644
--- a/qemu/roms/ipxe/src/include/ipxe/xenevent.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/xengrant.h b/qemu/roms/ipxe/src/include/ipxe/xengrant.h
index f9b3beb21..451a3ceee 100644
--- a/qemu/roms/ipxe/src/include/ipxe/xengrant.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/xenmem.h b/qemu/roms/ipxe/src/include/ipxe/xenmem.h
index 9b9aeda9c..dcc38d460 100644
--- a/qemu/roms/ipxe/src/include/ipxe/xenmem.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/xenstore.h b/qemu/roms/ipxe/src/include/ipxe/xenstore.h
index f25f15704..892640755 100644
--- a/qemu/roms/ipxe/src/include/ipxe/xenstore.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/xenver.h b/qemu/roms/ipxe/src/include/ipxe/xenver.h
index 5d678c5a3..b29dfb321 100644
--- a/qemu/roms/ipxe/src/include/ipxe/xenver.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/xfer.h b/qemu/roms/ipxe/src/include/ipxe/xfer.h
index 1167e5cba..3a35fa924 100644
--- a/qemu/roms/ipxe/src/include/ipxe/xfer.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/ipxe/xferbuf.h b/qemu/roms/ipxe/src/include/ipxe/xferbuf.h
index 2ca871e59..cb0b1a0e8 100644
--- a/qemu/roms/ipxe/src/include/ipxe/xferbuf.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/libgen.h b/qemu/roms/ipxe/src/include/libgen.h
index 7e94881a9..ae0861270 100644
--- a/qemu/roms/ipxe/src/include/libgen.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/little_bswap.h b/qemu/roms/ipxe/src/include/little_bswap.h
deleted file mode 100644
index 92dd26ba1..000000000
--- a/qemu/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/qemu/roms/ipxe/src/include/nic.h b/qemu/roms/ipxe/src/include/nic.h
index 9aaede8a7..4c91f57a6 100644
--- a/qemu/roms/ipxe/src/include/nic.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/readline/readline.h b/qemu/roms/ipxe/src/include/readline/readline.h
index 0449a3f98..afafbbdf5 100644
--- a/qemu/roms/ipxe/src/include/readline/readline.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/stdarg.h b/qemu/roms/ipxe/src/include/stdarg.h
index f317238a9..89e94ce22 100644
--- a/qemu/roms/ipxe/src/include/stdarg.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/stddef.h b/qemu/roms/ipxe/src/include/stddef.h
index bf792771f..3c056294f 100644
--- a/qemu/roms/ipxe/src/include/stddef.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/stdint.h b/qemu/roms/ipxe/src/include/stdint.h
index 8cc9b84a5..0a239a517 100644
--- a/qemu/roms/ipxe/src/include/stdint.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/stdio.h b/qemu/roms/ipxe/src/include/stdio.h
index 91840af5b..a618482ce 100644
--- a/qemu/roms/ipxe/src/include/stdio.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/stdlib.h b/qemu/roms/ipxe/src/include/stdlib.h
index 2951522b8..d7748a07e 100644
--- a/qemu/roms/ipxe/src/include/stdlib.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/string.h b/qemu/roms/ipxe/src/include/string.h
index 3482e1b22..0fab6c74b 100644
--- a/qemu/roms/ipxe/src/include/string.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/strings.h b/qemu/roms/ipxe/src/include/strings.h
index 6912a1e45..fab26dc28 100644
--- a/qemu/roms/ipxe/src/include/strings.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/sys/time.h b/qemu/roms/ipxe/src/include/sys/time.h
index 2647d3588..6e2a24447 100644
--- a/qemu/roms/ipxe/src/include/sys/time.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/syslog.h b/qemu/roms/ipxe/src/include/syslog.h
index 93f32f867..748a4faec 100644
--- a/qemu/roms/ipxe/src/include/syslog.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/time.h b/qemu/roms/ipxe/src/include/time.h
index 452a544bb..462ac6999 100644
--- a/qemu/roms/ipxe/src/include/time.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/unistd.h b/qemu/roms/ipxe/src/include/unistd.h
index 3a50a2521..d09e1ae30 100644
--- a/qemu/roms/ipxe/src/include/unistd.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/usr/autoboot.h b/qemu/roms/ipxe/src/include/usr/autoboot.h
index bc51aae79..4db226b9c 100644
--- a/qemu/roms/ipxe/src/include/usr/autoboot.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/usr/dhcpmgmt.h b/qemu/roms/ipxe/src/include/usr/dhcpmgmt.h
index af1eceb17..ed669eb9d 100644
--- a/qemu/roms/ipxe/src/include/usr/dhcpmgmt.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/usr/fcmgmt.h b/qemu/roms/ipxe/src/include/usr/fcmgmt.h
index 9441cefb4..eb568fd20 100644
--- a/qemu/roms/ipxe/src/include/usr/fcmgmt.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/usr/ifmgmt.h b/qemu/roms/ipxe/src/include/usr/ifmgmt.h
index db77f1f1b..5c386327b 100644
--- a/qemu/roms/ipxe/src/include/usr/ifmgmt.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/usr/imgmgmt.h b/qemu/roms/ipxe/src/include/usr/imgmgmt.h
index 5e25c562b..806df0bfb 100644
--- a/qemu/roms/ipxe/src/include/usr/imgmgmt.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/usr/imgtrust.h b/qemu/roms/ipxe/src/include/usr/imgtrust.h
index f47105af0..414e07a80 100644
--- a/qemu/roms/ipxe/src/include/usr/imgtrust.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/usr/ipstat.h b/qemu/roms/ipxe/src/include/usr/ipstat.h
index 5ff8b40c3..803254bcb 100644
--- a/qemu/roms/ipxe/src/include/usr/ipstat.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/usr/lotest.h b/qemu/roms/ipxe/src/include/usr/lotest.h
index aa4bbac4d..ce0fe5eda 100644
--- a/qemu/roms/ipxe/src/include/usr/lotest.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/usr/neighmgmt.h b/qemu/roms/ipxe/src/include/usr/neighmgmt.h
index 3c2b704af..06f03716e 100644
--- a/qemu/roms/ipxe/src/include/usr/neighmgmt.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/usr/pingmgmt.h b/qemu/roms/ipxe/src/include/usr/pingmgmt.h
index d4c2d6cd5..c7a8434be 100644
--- a/qemu/roms/ipxe/src/include/usr/pingmgmt.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/usr/profstat.h b/qemu/roms/ipxe/src/include/usr/profstat.h
index 06ea251a0..b7812ca7f 100644
--- a/qemu/roms/ipxe/src/include/usr/profstat.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/usr/prompt.h b/qemu/roms/ipxe/src/include/usr/prompt.h
index 57e43d2dc..8d3eeee3c 100644
--- a/qemu/roms/ipxe/src/include/usr/prompt.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/usr/route.h b/qemu/roms/ipxe/src/include/usr/route.h
index b914f4b84..7ec4a3509 100644
--- a/qemu/roms/ipxe/src/include/usr/route.h
+++ b/qemu/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/qemu/roms/ipxe/src/include/usr/sync.h b/qemu/roms/ipxe/src/include/usr/sync.h
index 0047d4ed9..b6f12ad6e 100644
--- a/qemu/roms/ipxe/src/include/usr/sync.h
+++ b/qemu/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/qemu/roms/ipxe/src/arch/x86/include/valgrind/memcheck.h b/qemu/roms/ipxe/src/include/valgrind/memcheck.h
index 7d4b56d31..7d4b56d31 100644
--- a/qemu/roms/ipxe/src/arch/x86/include/valgrind/memcheck.h
+++ b/qemu/roms/ipxe/src/include/valgrind/memcheck.h
diff --git a/qemu/roms/ipxe/src/arch/x86/include/valgrind/valgrind.h b/qemu/roms/ipxe/src/include/valgrind/valgrind.h
index d48bbccae..d48bbccae 100644
--- a/qemu/roms/ipxe/src/arch/x86/include/valgrind/valgrind.h
+++ b/qemu/roms/ipxe/src/include/valgrind/valgrind.h
diff --git a/qemu/roms/ipxe/src/include/wchar.h b/qemu/roms/ipxe/src/include/wchar.h
index ba349aae8..d054b8d5b 100644
--- a/qemu/roms/ipxe/src/include/wchar.h
+++ b/qemu/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/qemu/roms/ipxe/src/interface/bofm/bofm.c b/qemu/roms/ipxe/src/interface/bofm/bofm.c
index b0e92b27c..545088dc6 100644
--- a/qemu/roms/ipxe/src/interface/bofm/bofm.c
+++ b/qemu/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/qemu/roms/ipxe/src/interface/efi/efi_autoboot.c b/qemu/roms/ipxe/src/interface/efi/efi_autoboot.c
index ab0f36541..a9e807e23 100644
--- a/qemu/roms/ipxe/src/interface/efi/efi_autoboot.c
+++ b/qemu/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/qemu/roms/ipxe/src/interface/efi/efi_bofm.c b/qemu/roms/ipxe/src/interface/efi/efi_bofm.c
index bdb705196..ea0e15f7f 100644
--- a/qemu/roms/ipxe/src/interface/efi/efi_bofm.c
+++ b/qemu/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/qemu/roms/ipxe/src/interface/efi/efi_debug.c b/qemu/roms/ipxe/src/interface/efi/efi_debug.c
index d23960140..473803951 100644
--- a/qemu/roms/ipxe/src/interface/efi/efi_debug.c
+++ b/qemu/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/qemu/roms/ipxe/src/interface/efi/efi_file.c b/qemu/roms/ipxe/src/interface/efi/efi_file.c
index 2ef3c5734..3715b70bf 100644
--- a/qemu/roms/ipxe/src/interface/efi/efi_file.c
+++ b/qemu/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/qemu/roms/ipxe/src/interface/efi/efi_guid.c b/qemu/roms/ipxe/src/interface/efi/efi_guid.c
index 52ba58ae4..ab1c91e9f 100644
--- a/qemu/roms/ipxe/src/interface/efi/efi_guid.c
+++ b/qemu/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/qemu/roms/ipxe/src/interface/efi/efi_hii.c b/qemu/roms/ipxe/src/interface/efi/efi_hii.c
index 834060b54..0ea970e67 100644
--- a/qemu/roms/ipxe/src/interface/efi/efi_hii.c
+++ b/qemu/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/qemu/roms/ipxe/src/interface/efi/efi_pci.c b/qemu/roms/ipxe/src/interface/efi/efi_pci.c
index 86c781d82..97ea72bb9 100644
--- a/qemu/roms/ipxe/src/interface/efi/efi_pci.c
+++ b/qemu/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/qemu/roms/ipxe/src/interface/efi/efi_reboot.c b/qemu/roms/ipxe/src/interface/efi/efi_reboot.c
index 96638c48e..35919221e 100644
--- a/qemu/roms/ipxe/src/interface/efi/efi_reboot.c
+++ b/qemu/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/qemu/roms/ipxe/src/interface/efi/efi_snp.c b/qemu/roms/ipxe/src/interface/efi/efi_snp.c
index 67fba342e..3dfcc5e16 100644
--- a/qemu/roms/ipxe/src/interface/efi/efi_snp.c
+++ b/qemu/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/qemu/roms/ipxe/src/interface/efi/efi_snp_hii.c b/qemu/roms/ipxe/src/interface/efi/efi_snp_hii.c
index c49c76a32..720402bdb 100644
--- a/qemu/roms/ipxe/src/interface/efi/efi_snp_hii.c
+++ b/qemu/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/qemu/roms/ipxe/src/interface/efi/efi_strings.c b/qemu/roms/ipxe/src/interface/efi/efi_strings.c
index 751589b46..aa3afc64f 100644
--- a/qemu/roms/ipxe/src/interface/efi/efi_strings.c
+++ b/qemu/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/qemu/roms/ipxe/src/interface/efi/efi_time.c b/qemu/roms/ipxe/src/interface/efi/efi_time.c
new file mode 100644
index 000000000..983a0ef5c
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/interface/efi/efi_timer.c b/qemu/roms/ipxe/src/interface/efi/efi_timer.c
index 7a1ff7869..81620c92c 100644
--- a/qemu/roms/ipxe/src/interface/efi/efi_timer.c
+++ b/qemu/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/qemu/roms/ipxe/src/interface/efi/efi_uaccess.c b/qemu/roms/ipxe/src/interface/efi/efi_uaccess.c
index 8b429b9ee..e058be66b 100644
--- a/qemu/roms/ipxe/src/interface/efi/efi_uaccess.c
+++ b/qemu/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/qemu/roms/ipxe/src/interface/efi/efi_umalloc.c b/qemu/roms/ipxe/src/interface/efi/efi_umalloc.c
index 356efaa6f..e3f1dacc2 100644
--- a/qemu/roms/ipxe/src/interface/efi/efi_umalloc.c
+++ b/qemu/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/qemu/roms/ipxe/src/interface/efi/efi_watchdog.c b/qemu/roms/ipxe/src/interface/efi/efi_watchdog.c
new file mode 100644
index 000000000..7061f81d8
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/interface/efi/efi_wrap.c b/qemu/roms/ipxe/src/interface/efi/efi_wrap.c
index ff46b76ed..2ea184e97 100644
--- a/qemu/roms/ipxe/src/interface/efi/efi_wrap.c
+++ b/qemu/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/qemu/roms/ipxe/src/interface/hyperv/vmbus.c b/qemu/roms/ipxe/src/interface/hyperv/vmbus.c
new file mode 100644
index 000000000..795929eae
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/interface/linux/linux_entropy.c b/qemu/roms/ipxe/src/interface/linux/linux_entropy.c
index 4671a48da..0f8e45d36 100644
--- a/qemu/roms/ipxe/src/interface/linux/linux_entropy.c
+++ b/qemu/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/qemu/roms/ipxe/src/interface/linux/linux_pci.c b/qemu/roms/ipxe/src/interface/linux/linux_pci.c
index cbd825c18..0c140cb89 100644
--- a/qemu/roms/ipxe/src/interface/linux/linux_pci.c
+++ b/qemu/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/qemu/roms/ipxe/src/interface/linux/linux_time.c b/qemu/roms/ipxe/src/interface/linux/linux_time.c
index e3cbafec6..9e99fe9cd 100644
--- a/qemu/roms/ipxe/src/interface/linux/linux_time.c
+++ b/qemu/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/qemu/roms/ipxe/src/interface/linux/linux_uaccess.c b/qemu/roms/ipxe/src/interface/linux/linux_uaccess.c
index 5ab0b6b65..ea2d8057c 100644
--- a/qemu/roms/ipxe/src/interface/linux/linux_uaccess.c
+++ b/qemu/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/qemu/roms/ipxe/src/interface/smbios/smbios.c b/qemu/roms/ipxe/src/interface/smbios/smbios.c
index 856943428..1dcf819c2 100644
--- a/qemu/roms/ipxe/src/interface/smbios/smbios.c
+++ b/qemu/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/qemu/roms/ipxe/src/interface/smbios/smbios_settings.c b/qemu/roms/ipxe/src/interface/smbios/smbios_settings.c
index 83e4320e9..5eadfa081 100644
--- a/qemu/roms/ipxe/src/interface/smbios/smbios_settings.c
+++ b/qemu/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/qemu/roms/ipxe/src/interface/xen/xenbus.c b/qemu/roms/ipxe/src/interface/xen/xenbus.c
index ffc8aba3e..c328af443 100644
--- a/qemu/roms/ipxe/src/interface/xen/xenbus.c
+++ b/qemu/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/qemu/roms/ipxe/src/interface/xen/xengrant.c b/qemu/roms/ipxe/src/interface/xen/xengrant.c
index be12b23dc..269cd5836 100644
--- a/qemu/roms/ipxe/src/interface/xen/xengrant.c
+++ b/qemu/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/qemu/roms/ipxe/src/interface/xen/xenstore.c b/qemu/roms/ipxe/src/interface/xen/xenstore.c
index b96982927..23424a926 100644
--- a/qemu/roms/ipxe/src/interface/xen/xenstore.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/80211/net80211.c b/qemu/roms/ipxe/src/net/80211/net80211.c
index 434944523..d4970ad5c 100644
--- a/qemu/roms/ipxe/src/net/80211/net80211.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/80211/wpa.c b/qemu/roms/ipxe/src/net/80211/wpa.c
index e2c4945f9..77f66d825 100644
--- a/qemu/roms/ipxe/src/net/80211/wpa.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/80211/wpa_ccmp.c b/qemu/roms/ipxe/src/net/80211/wpa_ccmp.c
index f98ebea26..a073c6a3c 100644
--- a/qemu/roms/ipxe/src/net/80211/wpa_ccmp.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/80211/wpa_tkip.c b/qemu/roms/ipxe/src/net/80211/wpa_tkip.c
index fa3e0763b..3b1934b59 100644
--- a/qemu/roms/ipxe/src/net/80211/wpa_tkip.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/aoe.c b/qemu/roms/ipxe/src/net/aoe.c
index a6d7b3e7b..2da8655b4 100644
--- a/qemu/roms/ipxe/src/net/aoe.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/arp.c b/qemu/roms/ipxe/src/net/arp.c
index 261e681e1..1e27c44e7 100644
--- a/qemu/roms/ipxe/src/net/arp.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/dhcpopts.c b/qemu/roms/ipxe/src/net/dhcpopts.c
index 8cd19cf80..cdb632b46 100644
--- a/qemu/roms/ipxe/src/net/dhcpopts.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/dhcppkt.c b/qemu/roms/ipxe/src/net/dhcppkt.c
index a9a6d3a94..4e64f85e4 100644
--- a/qemu/roms/ipxe/src/net/dhcppkt.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/eth_slow.c b/qemu/roms/ipxe/src/net/eth_slow.c
index db54b55a4..049c26cb3 100644
--- a/qemu/roms/ipxe/src/net/eth_slow.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/ethernet.c b/qemu/roms/ipxe/src/net/ethernet.c
index 03978c2a8..6ddf05344 100644
--- a/qemu/roms/ipxe/src/net/ethernet.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/fakedhcp.c b/qemu/roms/ipxe/src/net/fakedhcp.c
index 3dec88b11..b6c456a59 100644
--- a/qemu/roms/ipxe/src/net/fakedhcp.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/fc.c b/qemu/roms/ipxe/src/net/fc.c
index 58008995c..2e8070272 100644
--- a/qemu/roms/ipxe/src/net/fc.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/fcels.c b/qemu/roms/ipxe/src/net/fcels.c
index 1cfe90727..5fc27cef4 100644
--- a/qemu/roms/ipxe/src/net/fcels.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/fcns.c b/qemu/roms/ipxe/src/net/fcns.c
index 3ca4ad557..be4dfea24 100644
--- a/qemu/roms/ipxe/src/net/fcns.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/fcoe.c b/qemu/roms/ipxe/src/net/fcoe.c
index e9e404ec3..c3258f15e 100644
--- a/qemu/roms/ipxe/src/net/fcoe.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/fcp.c b/qemu/roms/ipxe/src/net/fcp.c
index 9c36a4c72..930bf7dd4 100644
--- a/qemu/roms/ipxe/src/net/fcp.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/fragment.c b/qemu/roms/ipxe/src/net/fragment.c
index 410915b3b..781b9bc60 100644
--- a/qemu/roms/ipxe/src/net/fragment.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/icmp.c b/qemu/roms/ipxe/src/net/icmp.c
index 1bbf8bd30..5371277e4 100644
--- a/qemu/roms/ipxe/src/net/icmp.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/icmpv4.c b/qemu/roms/ipxe/src/net/icmpv4.c
index 996ba1490..0858ff37f 100644
--- a/qemu/roms/ipxe/src/net/icmpv4.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/icmpv6.c b/qemu/roms/ipxe/src/net/icmpv6.c
index 479800e7d..8555aaf0b 100644
--- a/qemu/roms/ipxe/src/net/icmpv6.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/infiniband.c b/qemu/roms/ipxe/src/net/infiniband.c
index 12d1d83ce..2e3d76d54 100644
--- a/qemu/roms/ipxe/src/net/infiniband.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/infiniband/ib_cm.c b/qemu/roms/ipxe/src/net/infiniband/ib_cm.c
index 797639bc8..85982f09d 100644
--- a/qemu/roms/ipxe/src/net/infiniband/ib_cm.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/infiniband/ib_mcast.c b/qemu/roms/ipxe/src/net/infiniband/ib_mcast.c
index 0a5e72a37..fc4ff7f0a 100644
--- a/qemu/roms/ipxe/src/net/infiniband/ib_mcast.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/infiniband/ib_mi.c b/qemu/roms/ipxe/src/net/infiniband/ib_mi.c
index ef6d539f1..b43212974 100644
--- a/qemu/roms/ipxe/src/net/infiniband/ib_mi.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/infiniband/ib_packet.c b/qemu/roms/ipxe/src/net/infiniband/ib_packet.c
index 6c850e39b..d3a22d309 100644
--- a/qemu/roms/ipxe/src/net/infiniband/ib_packet.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/infiniband/ib_pathrec.c b/qemu/roms/ipxe/src/net/infiniband/ib_pathrec.c
index 1b95cbfa8..f9cbab87f 100644
--- a/qemu/roms/ipxe/src/net/infiniband/ib_pathrec.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/infiniband/ib_sma.c b/qemu/roms/ipxe/src/net/infiniband/ib_sma.c
index 86553732a..a05d7c924 100644
--- a/qemu/roms/ipxe/src/net/infiniband/ib_sma.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/infiniband/ib_smc.c b/qemu/roms/ipxe/src/net/infiniband/ib_smc.c
index 4d947d568..c1741b26c 100644
--- a/qemu/roms/ipxe/src/net/infiniband/ib_smc.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/infiniband/ib_srp.c b/qemu/roms/ipxe/src/net/infiniband/ib_srp.c
index 7b2b2b4ea..3700184c0 100644
--- a/qemu/roms/ipxe/src/net/infiniband/ib_srp.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/iobpad.c b/qemu/roms/ipxe/src/net/iobpad.c
index 9cc8328e9..936b4bde4 100644
--- a/qemu/roms/ipxe/src/net/iobpad.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/ipv4.c b/qemu/roms/ipxe/src/net/ipv4.c
index 9c5cf2eb4..a54784049 100644
--- a/qemu/roms/ipxe/src/net/ipv4.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/ipv6.c b/qemu/roms/ipxe/src/net/ipv6.c
index 3c374168c..a75e72ddb 100644
--- a/qemu/roms/ipxe/src/net/ipv6.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/neighbour.c b/qemu/roms/ipxe/src/net/neighbour.c
index e3026ce46..7f66d9992 100644
--- a/qemu/roms/ipxe/src/net/neighbour.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/netdev_settings.c b/qemu/roms/ipxe/src/net/netdev_settings.c
index b3b2e68d8..edd4c4b9f 100644
--- a/qemu/roms/ipxe/src/net/netdev_settings.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/netdevice.c b/qemu/roms/ipxe/src/net/netdevice.c
index a55e6b7d7..7c40a2ac8 100644
--- a/qemu/roms/ipxe/src/net/netdevice.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/nullnet.c b/qemu/roms/ipxe/src/net/nullnet.c
index 4ac50f64b..2948b38c0 100644
--- a/qemu/roms/ipxe/src/net/nullnet.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/pccrc.c b/qemu/roms/ipxe/src/net/pccrc.c
new file mode 100644
index 000000000..4cd82cd1c
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/net/pccrd.c b/qemu/roms/ipxe/src/net/pccrd.c
new file mode 100644
index 000000000..04b5dd86c
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/net/peerblk.c b/qemu/roms/ipxe/src/net/peerblk.c
new file mode 100644
index 000000000..fd7ea0893
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/net/peerdisc.c b/qemu/roms/ipxe/src/net/peerdisc.c
new file mode 100644
index 000000000..5b0e98911
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/net/peerdist.c b/qemu/roms/ipxe/src/net/peerdist.c
new file mode 100644
index 000000000..48933f951
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/net/peermux.c b/qemu/roms/ipxe/src/net/peermux.c
new file mode 100644
index 000000000..634c69992
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/net/ping.c b/qemu/roms/ipxe/src/net/ping.c
index d9da87ade..3f4fa5c11 100644
--- a/qemu/roms/ipxe/src/net/ping.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/rarp.c b/qemu/roms/ipxe/src/net/rarp.c
index 371145015..c194a404f 100644
--- a/qemu/roms/ipxe/src/net/rarp.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/retry.c b/qemu/roms/ipxe/src/net/retry.c
index 8f210bdcc..734567be5 100644
--- a/qemu/roms/ipxe/src/net/retry.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/rndis.c b/qemu/roms/ipxe/src/net/rndis.c
new file mode 100644
index 000000000..8c4fe8b30
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/net/socket.c b/qemu/roms/ipxe/src/net/socket.c
index 24f6a0892..2009ab237 100644
--- a/qemu/roms/ipxe/src/net/socket.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/stp.c b/qemu/roms/ipxe/src/net/stp.c
new file mode 100644
index 000000000..d4e65a1a2
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/net/tcp.c b/qemu/roms/ipxe/src/net/tcp.c
index 987cb63e1..c69c83b85 100644
--- a/qemu/roms/ipxe/src/net/tcp.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/tcp/http.c b/qemu/roms/ipxe/src/net/tcp/http.c
index 90bae9d7a..b000ed80f 100644
--- a/qemu/roms/ipxe/src/net/tcp/http.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/tcp/httpauth.c b/qemu/roms/ipxe/src/net/tcp/httpauth.c
new file mode 100644
index 000000000..fb6dcd035
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/net/tcp/httpbasic.c b/qemu/roms/ipxe/src/net/tcp/httpbasic.c
new file mode 100644
index 000000000..7ed7de9e7
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/net/tcp/httpblock.c b/qemu/roms/ipxe/src/net/tcp/httpblock.c
new file mode 100644
index 000000000..e124ad2d6
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/net/tcp/httpconn.c b/qemu/roms/ipxe/src/net/tcp/httpconn.c
new file mode 100644
index 000000000..7e4877b7b
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/net/tcp/httpcore.c b/qemu/roms/ipxe/src/net/tcp/httpcore.c
index 1d1953e61..af3ca9780 100644
--- a/qemu/roms/ipxe/src/net/tcp/httpcore.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/tcp/httpdigest.c b/qemu/roms/ipxe/src/net/tcp/httpdigest.c
new file mode 100644
index 000000000..626dd7e9d
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/net/tcp/https.c b/qemu/roms/ipxe/src/net/tcp/https.c
index 6112acdae..e91000322 100644
--- a/qemu/roms/ipxe/src/net/tcp/https.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/tcp/iscsi.c b/qemu/roms/ipxe/src/net/tcp/iscsi.c
index 03c6d0f23..019a4c14e 100644
--- a/qemu/roms/ipxe/src/net/tcp/iscsi.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/tcp/syslogs.c b/qemu/roms/ipxe/src/net/tcp/syslogs.c
index 095afc543..0c07f86d5 100644
--- a/qemu/roms/ipxe/src/net/tcp/syslogs.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/tcpip.c b/qemu/roms/ipxe/src/net/tcpip.c
index 4bcbe64bb..5ad982fd1 100644
--- a/qemu/roms/ipxe/src/net/tcpip.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/tls.c b/qemu/roms/ipxe/src/net/tls.c
index 30ccc932e..db01fb291 100644
--- a/qemu/roms/ipxe/src/net/tls.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/udp.c b/qemu/roms/ipxe/src/net/udp.c
index 76da67ecf..0f7dfb24a 100644
--- a/qemu/roms/ipxe/src/net/udp.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/udp/dhcp.c b/qemu/roms/ipxe/src/net/udp/dhcp.c
index 04fad04c2..aed5ee360 100644
--- a/qemu/roms/ipxe/src/net/udp/dhcp.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/udp/dhcpv6.c b/qemu/roms/ipxe/src/net/udp/dhcpv6.c
index f7736d08e..a63543775 100644
--- a/qemu/roms/ipxe/src/net/udp/dhcpv6.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/udp/dns.c b/qemu/roms/ipxe/src/net/udp/dns.c
index fffe6e697..2d77477f6 100644
--- a/qemu/roms/ipxe/src/net/udp/dns.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/udp/slam.c b/qemu/roms/ipxe/src/net/udp/slam.c
index 3cb492d73..8b26bfb3c 100644
--- a/qemu/roms/ipxe/src/net/udp/slam.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/udp/syslog.c b/qemu/roms/ipxe/src/net/udp/syslog.c
index d65d19ab8..b6eee6036 100644
--- a/qemu/roms/ipxe/src/net/udp/syslog.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/udp/tftp.c b/qemu/roms/ipxe/src/net/udp/tftp.c
index ee827ae3d..953bcb46a 100644
--- a/qemu/roms/ipxe/src/net/udp/tftp.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/validator.c b/qemu/roms/ipxe/src/net/validator.c
index 74d70e312..db968398a 100644
--- a/qemu/roms/ipxe/src/net/validator.c
+++ b/qemu/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/qemu/roms/ipxe/src/net/vlan.c b/qemu/roms/ipxe/src/net/vlan.c
index b4ddde42d..f515c2dc9 100644
--- a/qemu/roms/ipxe/src/net/vlan.c
+++ b/qemu/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/qemu/roms/ipxe/src/tests/aes_cbc_test.c b/qemu/roms/ipxe/src/tests/aes_cbc_test.c
deleted file mode 100644
index 4ae3a92e5..000000000
--- a/qemu/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/qemu/roms/ipxe/src/tests/aes_test.c b/qemu/roms/ipxe/src/tests/aes_test.c
new file mode 100644
index 000000000..ad66c734c
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/tests/base16_test.c b/qemu/roms/ipxe/src/tests/base16_test.c
index 9b047b74c..46884aef7 100644
--- a/qemu/roms/ipxe/src/tests/base16_test.c
+++ b/qemu/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/qemu/roms/ipxe/src/tests/base64_test.c b/qemu/roms/ipxe/src/tests/base64_test.c
index c088298ca..0fc595d90 100644
--- a/qemu/roms/ipxe/src/tests/base64_test.c
+++ b/qemu/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/qemu/roms/ipxe/src/tests/bigint_test.c b/qemu/roms/ipxe/src/tests/bigint_test.c
index 75a80622f..8d40c3188 100644
--- a/qemu/roms/ipxe/src/tests/bigint_test.c
+++ b/qemu/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/qemu/roms/ipxe/src/tests/bofm_test.c b/qemu/roms/ipxe/src/tests/bofm_test.c
index e430d12d4..829924887 100644
--- a/qemu/roms/ipxe/src/tests/bofm_test.c
+++ b/qemu/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/qemu/roms/ipxe/src/tests/byteswap_test.c b/qemu/roms/ipxe/src/tests/byteswap_test.c
index a500218be..92bdb1d59 100644
--- a/qemu/roms/ipxe/src/tests/byteswap_test.c
+++ b/qemu/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/qemu/roms/ipxe/src/tests/cbc_test.h b/qemu/roms/ipxe/src/tests/cbc_test.h
deleted file mode 100644
index ad9e6f341..000000000
--- a/qemu/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/qemu/roms/ipxe/src/tests/cbc_test.c b/qemu/roms/ipxe/src/tests/cipher_test.c
index cb0f7bdea..800d6c138 100644
--- a/qemu/roms/ipxe/src/tests/cbc_test.c
+++ b/qemu/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/qemu/roms/ipxe/src/tests/cipher_test.h b/qemu/roms/ipxe/src/tests/cipher_test.h
new file mode 100644
index 000000000..d7c5aef8f
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/tests/cms_test.c b/qemu/roms/ipxe/src/tests/cms_test.c
index 8767504c0..b805a9974 100644
--- a/qemu/roms/ipxe/src/tests/cms_test.c
+++ b/qemu/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/qemu/roms/ipxe/src/tests/crc32_test.c b/qemu/roms/ipxe/src/tests/crc32_test.c
index 873f633a5..46cde0f7b 100644
--- a/qemu/roms/ipxe/src/tests/crc32_test.c
+++ b/qemu/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/qemu/roms/ipxe/src/tests/deflate_test.c b/qemu/roms/ipxe/src/tests/deflate_test.c
index 68c1aad96..20ff5b9a2 100644
--- a/qemu/roms/ipxe/src/tests/deflate_test.c
+++ b/qemu/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/qemu/roms/ipxe/src/tests/digest_test.c b/qemu/roms/ipxe/src/tests/digest_test.c
index 4df26c099..c3a128853 100644
--- a/qemu/roms/ipxe/src/tests/digest_test.c
+++ b/qemu/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/qemu/roms/ipxe/src/tests/digest_test.h b/qemu/roms/ipxe/src/tests/digest_test.h
index 49e06d1cb..abf1b834f 100644
--- a/qemu/roms/ipxe/src/tests/digest_test.h
+++ b/qemu/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/qemu/roms/ipxe/src/tests/dns_test.c b/qemu/roms/ipxe/src/tests/dns_test.c
index 52f5f19f2..f08e7810f 100644
--- a/qemu/roms/ipxe/src/tests/dns_test.c
+++ b/qemu/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/qemu/roms/ipxe/src/tests/entropy_sample.c b/qemu/roms/ipxe/src/tests/entropy_sample.c
index 95a662e3e..b45648c11 100644
--- a/qemu/roms/ipxe/src/tests/entropy_sample.c
+++ b/qemu/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/qemu/roms/ipxe/src/tests/hash_df_test.c b/qemu/roms/ipxe/src/tests/hash_df_test.c
index 74c8d0f4d..0b7d56ad7 100644
--- a/qemu/roms/ipxe/src/tests/hash_df_test.c
+++ b/qemu/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/qemu/roms/ipxe/src/tests/hmac_drbg_test.c b/qemu/roms/ipxe/src/tests/hmac_drbg_test.c
index 8cbf1cc8b..ddf9db2c5 100644
--- a/qemu/roms/ipxe/src/tests/hmac_drbg_test.c
+++ b/qemu/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/qemu/roms/ipxe/src/tests/ipv4_test.c b/qemu/roms/ipxe/src/tests/ipv4_test.c
new file mode 100644
index 000000000..f84a8b81f
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/tests/ipv6_test.c b/qemu/roms/ipxe/src/tests/ipv6_test.c
index e16fc7c3d..772eb1b82 100644
--- a/qemu/roms/ipxe/src/tests/ipv6_test.c
+++ b/qemu/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/qemu/roms/ipxe/src/tests/linebuf_test.c b/qemu/roms/ipxe/src/tests/linebuf_test.c
index e06ac7d86..0dd486e9d 100644
--- a/qemu/roms/ipxe/src/tests/linebuf_test.c
+++ b/qemu/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/qemu/roms/ipxe/src/tests/list_test.c b/qemu/roms/ipxe/src/tests/list_test.c
index 35cbd5e5f..352c87da0 100644
--- a/qemu/roms/ipxe/src/tests/list_test.c
+++ b/qemu/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/qemu/roms/ipxe/src/tests/math_test.c b/qemu/roms/ipxe/src/tests/math_test.c
index e12b7939d..1a244f1eb 100644
--- a/qemu/roms/ipxe/src/tests/math_test.c
+++ b/qemu/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/qemu/roms/ipxe/src/tests/md5_test.c b/qemu/roms/ipxe/src/tests/md5_test.c
index ba5f24c3e..e9ed2716a 100644
--- a/qemu/roms/ipxe/src/tests/md5_test.c
+++ b/qemu/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/qemu/roms/ipxe/src/tests/memcpy_test.c b/qemu/roms/ipxe/src/tests/memcpy_test.c
index f1e5503a6..0247c71d4 100644
--- a/qemu/roms/ipxe/src/tests/memcpy_test.c
+++ b/qemu/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/qemu/roms/ipxe/src/tests/memset_test.c b/qemu/roms/ipxe/src/tests/memset_test.c
new file mode 100644
index 000000000..d96f83fa6
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/tests/ocsp_test.c b/qemu/roms/ipxe/src/tests/ocsp_test.c
index a318c185a..c6d458596 100644
--- a/qemu/roms/ipxe/src/tests/ocsp_test.c
+++ b/qemu/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/qemu/roms/ipxe/src/tests/pccrc_test.c b/qemu/roms/ipxe/src/tests/pccrc_test.c
new file mode 100644
index 000000000..f4ab573ac
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/tests/pixbuf_test.c b/qemu/roms/ipxe/src/tests/pixbuf_test.c
index 15cd33dfd..aaa516bb2 100644
--- a/qemu/roms/ipxe/src/tests/pixbuf_test.c
+++ b/qemu/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/qemu/roms/ipxe/src/tests/pixbuf_test.h b/qemu/roms/ipxe/src/tests/pixbuf_test.h
index 394f7f5fa..d12829d89 100644
--- a/qemu/roms/ipxe/src/tests/pixbuf_test.h
+++ b/qemu/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/qemu/roms/ipxe/src/tests/png_test.c b/qemu/roms/ipxe/src/tests/png_test.c
index cf32f2034..e921aa2a6 100644
--- a/qemu/roms/ipxe/src/tests/png_test.c
+++ b/qemu/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/qemu/roms/ipxe/src/tests/pnm_test.c b/qemu/roms/ipxe/src/tests/pnm_test.c
index 26b0c0726..d57fdaaef 100644
--- a/qemu/roms/ipxe/src/tests/pnm_test.c
+++ b/qemu/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/qemu/roms/ipxe/src/tests/profile_test.c b/qemu/roms/ipxe/src/tests/profile_test.c
index 9d682bf2b..d2f8df211 100644
--- a/qemu/roms/ipxe/src/tests/profile_test.c
+++ b/qemu/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/qemu/roms/ipxe/src/tests/pubkey_test.h b/qemu/roms/ipxe/src/tests/pubkey_test.h
index 7678453a9..cd65b8703 100644
--- a/qemu/roms/ipxe/src/tests/pubkey_test.h
+++ b/qemu/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/qemu/roms/ipxe/src/tests/rsa_test.c b/qemu/roms/ipxe/src/tests/rsa_test.c
index 3b32c74bc..c0d05d263 100644
--- a/qemu/roms/ipxe/src/tests/rsa_test.c
+++ b/qemu/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/qemu/roms/ipxe/src/tests/setjmp_test.c b/qemu/roms/ipxe/src/tests/setjmp_test.c
new file mode 100644
index 000000000..50ad13f3c
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/tests/settings_test.c b/qemu/roms/ipxe/src/tests/settings_test.c
index 4ee6a10fa..f7fb35d0d 100644
--- a/qemu/roms/ipxe/src/tests/settings_test.c
+++ b/qemu/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/qemu/roms/ipxe/src/tests/sha1_test.c b/qemu/roms/ipxe/src/tests/sha1_test.c
index bcf761bdd..9f1d75686 100644
--- a/qemu/roms/ipxe/src/tests/sha1_test.c
+++ b/qemu/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/qemu/roms/ipxe/src/tests/sha256_test.c b/qemu/roms/ipxe/src/tests/sha256_test.c
index 06a8cae25..3b4c423fd 100644
--- a/qemu/roms/ipxe/src/tests/sha256_test.c
+++ b/qemu/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/qemu/roms/ipxe/src/tests/sha512_test.c b/qemu/roms/ipxe/src/tests/sha512_test.c
new file mode 100644
index 000000000..be530ebad
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/tests/string_test.c b/qemu/roms/ipxe/src/tests/string_test.c
index 3b48d9f3d..4693b5f65 100644
--- a/qemu/roms/ipxe/src/tests/string_test.c
+++ b/qemu/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/qemu/roms/ipxe/src/tests/tcpip_test.c b/qemu/roms/ipxe/src/tests/tcpip_test.c
index 00c88ae32..759f886bc 100644
--- a/qemu/roms/ipxe/src/tests/tcpip_test.c
+++ b/qemu/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/qemu/roms/ipxe/src/tests/test.c b/qemu/roms/ipxe/src/tests/test.c
index c05e72a76..67bd4cf89 100644
--- a/qemu/roms/ipxe/src/tests/test.c
+++ b/qemu/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/qemu/roms/ipxe/src/tests/tests.c b/qemu/roms/ipxe/src/tests/tests.c
index 2b4b78c7c..54ce86677 100644
--- a/qemu/roms/ipxe/src/tests/tests.c
+++ b/qemu/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/qemu/roms/ipxe/src/tests/time_test.c b/qemu/roms/ipxe/src/tests/time_test.c
index 28acebee6..3bf01dd1d 100644
--- a/qemu/roms/ipxe/src/tests/time_test.c
+++ b/qemu/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/qemu/roms/ipxe/src/tests/uri_test.c b/qemu/roms/ipxe/src/tests/uri_test.c
index 14f1b4ad0..da7fb8abe 100644
--- a/qemu/roms/ipxe/src/tests/uri_test.c
+++ b/qemu/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/qemu/roms/ipxe/src/tests/vsprintf_test.c b/qemu/roms/ipxe/src/tests/vsprintf_test.c
index 11512ec8e..0ad4f1c56 100644
--- a/qemu/roms/ipxe/src/tests/vsprintf_test.c
+++ b/qemu/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/qemu/roms/ipxe/src/tests/x509_test.c b/qemu/roms/ipxe/src/tests/x509_test.c
index fd39e12d2..658d5247c 100644
--- a/qemu/roms/ipxe/src/tests/x509_test.c
+++ b/qemu/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/qemu/roms/ipxe/src/usr/autoboot.c b/qemu/roms/ipxe/src/usr/autoboot.c
index 47476ae40..912543828 100644
--- a/qemu/roms/ipxe/src/usr/autoboot.c
+++ b/qemu/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/qemu/roms/ipxe/src/usr/dhcpmgmt.c b/qemu/roms/ipxe/src/usr/dhcpmgmt.c
index 23982b19c..dcb360b23 100644
--- a/qemu/roms/ipxe/src/usr/dhcpmgmt.c
+++ b/qemu/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/qemu/roms/ipxe/src/usr/fcmgmt.c b/qemu/roms/ipxe/src/usr/fcmgmt.c
index a30f37a71..6f626143f 100644
--- a/qemu/roms/ipxe/src/usr/fcmgmt.c
+++ b/qemu/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/qemu/roms/ipxe/src/usr/ifmgmt.c b/qemu/roms/ipxe/src/usr/ifmgmt.c
index 3d05895c2..aefdaa45d 100644
--- a/qemu/roms/ipxe/src/usr/ifmgmt.c
+++ b/qemu/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/qemu/roms/ipxe/src/usr/imgmgmt.c b/qemu/roms/ipxe/src/usr/imgmgmt.c
index c9c571640..352dd0242 100644
--- a/qemu/roms/ipxe/src/usr/imgmgmt.c
+++ b/qemu/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/qemu/roms/ipxe/src/usr/imgtrust.c b/qemu/roms/ipxe/src/usr/imgtrust.c
index da7ff2ef0..a269833a6 100644
--- a/qemu/roms/ipxe/src/usr/imgtrust.c
+++ b/qemu/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/qemu/roms/ipxe/src/usr/ipstat.c b/qemu/roms/ipxe/src/usr/ipstat.c
index 95ad799dc..0f09cc2ff 100644
--- a/qemu/roms/ipxe/src/usr/ipstat.c
+++ b/qemu/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/qemu/roms/ipxe/src/usr/lotest.c b/qemu/roms/ipxe/src/usr/lotest.c
index ad7a2fad7..6b328713c 100644
--- a/qemu/roms/ipxe/src/usr/lotest.c
+++ b/qemu/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/qemu/roms/ipxe/src/usr/neighmgmt.c b/qemu/roms/ipxe/src/usr/neighmgmt.c
index e4d21a208..9fd88f82b 100644
--- a/qemu/roms/ipxe/src/usr/neighmgmt.c
+++ b/qemu/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/qemu/roms/ipxe/src/usr/pingmgmt.c b/qemu/roms/ipxe/src/usr/pingmgmt.c
index 16b3ec994..bb33c5d47 100644
--- a/qemu/roms/ipxe/src/usr/pingmgmt.c
+++ b/qemu/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/qemu/roms/ipxe/src/usr/profstat.c b/qemu/roms/ipxe/src/usr/profstat.c
index 991427473..d80fa26b2 100644
--- a/qemu/roms/ipxe/src/usr/profstat.c
+++ b/qemu/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/qemu/roms/ipxe/src/usr/prompt.c b/qemu/roms/ipxe/src/usr/prompt.c
index 957b4ab3d..fca0a157c 100644
--- a/qemu/roms/ipxe/src/usr/prompt.c
+++ b/qemu/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/qemu/roms/ipxe/src/usr/pxemenu.c b/qemu/roms/ipxe/src/usr/pxemenu.c
index b69905df1..2d05d3f51 100644
--- a/qemu/roms/ipxe/src/usr/pxemenu.c
+++ b/qemu/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/qemu/roms/ipxe/src/usr/route.c b/qemu/roms/ipxe/src/usr/route.c
index ba4cc3221..690ba3b6b 100644
--- a/qemu/roms/ipxe/src/usr/route.c
+++ b/qemu/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/qemu/roms/ipxe/src/usr/route_ipv4.c b/qemu/roms/ipxe/src/usr/route_ipv4.c
index b4d1b7bf3..6260335ac 100644
--- a/qemu/roms/ipxe/src/usr/route_ipv4.c
+++ b/qemu/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/qemu/roms/ipxe/src/usr/route_ipv6.c b/qemu/roms/ipxe/src/usr/route_ipv6.c
index 6045f85bb..9e94b4a15 100644
--- a/qemu/roms/ipxe/src/usr/route_ipv6.c
+++ b/qemu/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/qemu/roms/ipxe/src/usr/sync.c b/qemu/roms/ipxe/src/usr/sync.c
index f7a04c44c..f599588ae 100644
--- a/qemu/roms/ipxe/src/usr/sync.c
+++ b/qemu/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/qemu/roms/ipxe/src/util/Option/ROM.pm b/qemu/roms/ipxe/src/util/Option/ROM.pm
index 6c396730e..232cf16b8 100644
--- a/qemu/roms/ipxe/src/util/Option/ROM.pm
+++ b/qemu/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/qemu/roms/ipxe/src/util/disrom.pl b/qemu/roms/ipxe/src/util/disrom.pl
index 574957acd..920a86b24 100755
--- a/qemu/roms/ipxe/src/util/disrom.pl
+++ b/qemu/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/qemu/roms/ipxe/src/util/elf2efi.c b/qemu/roms/ipxe/src/util/elf2efi.c
index 45d539574..e68fa5d14 100644
--- a/qemu/roms/ipxe/src/util/elf2efi.c
+++ b/qemu/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/qemu/roms/ipxe/src/util/licence.pl b/qemu/roms/ipxe/src/util/licence.pl
index 0e43c7b4c..79e70fd65 100755
--- a/qemu/roms/ipxe/src/util/licence.pl
+++ b/qemu/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/qemu/roms/ipxe/src/util/parserom.pl b/qemu/roms/ipxe/src/util/parserom.pl
index e278e6336..28df60652 100755
--- a/qemu/roms/ipxe/src/util/parserom.pl
+++ b/qemu/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/qemu/roms/ipxe/src/util/relicense.pl b/qemu/roms/ipxe/src/util/relicense.pl
new file mode 100755
index 000000000..41954c1b3
--- /dev/null
+++ b/qemu/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/qemu/roms/ipxe/src/util/zbin.c b/qemu/roms/ipxe/src/util/zbin.c
index 3b7cf95b3..1862a3827 100644
--- a/qemu/roms/ipxe/src/util/zbin.c
+++ b/qemu/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/qemu/roms/openbios/Makefile.target b/qemu/roms/openbios/Makefile.target
index a7363e667..4c54105a7 100644
--- a/qemu/roms/openbios/Makefile.target
+++ b/qemu/roms/openbios/Makefile.target
@@ -15,7 +15,7 @@ HOSTCFLAGS+= -Wstrict-aliasing -Wwrite-strings -Wmissing-prototypes -Wnested-ext
HOSTCFLAGS+= -W
# Flags for dependency generation
HOSTCFLAGS+= -MMD -MP -MT $@ -MF '$(*D)/$(*F).d'
-HOSTINCLUDES := -I$(SRCDIR)/include -I$(SRCDIR)/kernel -I$(SRCDIR)/kernel/include -I$(ODIR)/target/include
+HOSTINCLUDES := -I$(SRCDIR)/include -I$(SRCDIR)/kernel -I$(SRCDIR)/kernel/include -iquote $(ODIR)/target/include
CC := $(TARGET)gcc
AS := $(TARGET)as
diff --git a/qemu/roms/openbios/arch/ppc/qemu/init.c b/qemu/roms/openbios/arch/ppc/qemu/init.c
index 4fe8b7220..b76c5706f 100644
--- a/qemu/roms/openbios/arch/ppc/qemu/init.c
+++ b/qemu/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
@@ -596,6 +601,11 @@ go(void)
{
ucell addr;
+ /* Insert copyright property for MacOS 9 and below */
+ if (find_dev("/rom/macos")) {
+ fword("insert-copyright-property");
+ }
+
feval("saved-program-state >sps.entry @");
addr = POP();
@@ -680,6 +690,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 +1009,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/qemu/roms/openbios/arch/ppc/qemu/methods.c b/qemu/roms/openbios/arch/ppc/qemu/methods.c
index fd993daa9..930b47c4e 100644
--- a/qemu/roms/openbios/arch/ppc/qemu/methods.c
+++ b/qemu/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/qemu/roms/openbios/arch/ppc/qemu/qemu.fs b/qemu/roms/openbios/arch/ppc/qemu/qemu.fs
index 458af1bc7..3d99a34a1 100644
--- a/qemu/roms/openbios/arch/ppc/qemu/qemu.fs
+++ b/qemu/roms/openbios/arch/ppc/qemu/qemu.fs
@@ -93,3 +93,48 @@ variable keyboard-phandle 0 keyboard-phandle !
:noname
set-defaults
; PREPOST-initializer
+
+\ -------------------------------------------------------------------------
+\ copyright property handling
+\ -------------------------------------------------------------------------
+
+: insert-copyright-property
+ \ As required for MacOS 9 and below
+ " Pbclevtug 1983-2001 Nccyr Pbzchgre, Vap. GUVF ZRFFNTR SBE PBZCNGVOVYVGL BAYL"
+ rot13-str encode-string " copyright"
+ " /" find-package if
+ " set-property" $find if
+ execute
+ else
+ 3drop drop
+ then
+ then
+;
+
+: delete-copyright-property
+ \ Remove copyright property created above
+ active-package
+ " /" find-package if
+ active-package!
+ " copyright" delete-property
+ then
+ active-package!
+;
+
+: (exit)
+ \ Clean up before returning to the interpreter
+ delete-copyright-property
+;
+
+\ -------------------------------------------------------------------------
+\ Adler-32 wrapper
+\ -------------------------------------------------------------------------
+
+: adler32 ( adler buf len -- checksum )
+ " (adler32)" $find if
+ execute
+ else
+ ." Can't find " ( adler32-name ) type cr
+ 3drop 0
+ then
+;
diff --git a/qemu/roms/openbios/arch/ppc/qemu/tree.fs b/qemu/roms/openbios/arch/ppc/qemu/tree.fs
index 1ed838397..5b6bbc6f7 100644
--- a/qemu/roms/openbios/arch/ppc/qemu/tree.fs
+++ b/qemu/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/qemu/roms/openbios/arch/sparc64/call-client.S b/qemu/roms/openbios/arch/sparc64/call-client.S
index f365e3cb1..a8c0348e4 100644
--- a/qemu/roms/openbios/arch/sparc64/call-client.S
+++ b/qemu/roms/openbios/arch/sparc64/call-client.S
@@ -1,3 +1,5 @@
+#include "cpustate.h"
+
.globl sparc64_of_client_interface, client_tba
@@ -9,151 +11,9 @@
* behaviour of OBP.
*/
-#define SAVE_WINDOW_STATE(type) \
- setx client_window, %g6, %g1; \
- rdpr %cwp, %g7; \
- stx %g7, [%g1]; \
- rdpr %cansave, %g7; \
- stx %g7, [%g1 + 0x8]; \
- rdpr %canrestore, %g7; \
- stx %g7, [%g1 + 0x10]; \
- rdpr %otherwin, %g7; \
- stx %g7, [%g1 + 0x18]; \
- rdpr %wstate, %g7; \
- stx %g7, [%g1 + 0x20]; \
- rdpr %cleanwin, %g7; \
- stx %g7, [%g1 + 0x28]; \
- \
- stx %o0, [%g1 + 0x30]; \
- stx %o1, [%g1 + 0x38]; \
- stx %o2, [%g1 + 0x40]; \
- stx %o3, [%g1 + 0x48]; \
- stx %o4, [%g1 + 0x50]; \
- stx %o5, [%g1 + 0x58]; \
- stx %o6, [%g1 + 0x60]; \
- stx %o7, [%g1 + 0x68]; \
- \
- rdpr %pstate, %g7; \
- stx %g7, [%g1 + 0x70]; \
- rd %y, %g7; \
- stx %g7, [%g1 + 0x78]; \
- rd %fprs, %g7; \
- stx %g7, [%g1 + 0x80]; \
- \
- /* Now iterate through all of the windows saving all l and i registers */ \
- add %g1, 0x90, %g5; \
- \
- /* Get the number of windows in %g6 */ \
- rdpr %ver, %g6; \
- and %g6, 0xf, %g6; \
- inc %g6; \
- \
-save_cpu_window_##type: \
- deccc %g6; \
- wrpr %g6, %cwp; \
- stx %l0, [%g5]; \
- stx %l1, [%g5 + 0x8]; \
- stx %l2, [%g5 + 0x10]; \
- stx %l3, [%g5 + 0x18]; \
- stx %l4, [%g5 + 0x20]; \
- stx %l5, [%g5 + 0x28]; \
- stx %l6, [%g5 + 0x30]; \
- stx %l7, [%g5 + 0x38]; \
- stx %i0, [%g5 + 0x40]; \
- stx %i1, [%g5 + 0x48]; \
- stx %i2, [%g5 + 0x50]; \
- stx %i3, [%g5 + 0x58]; \
- stx %i4, [%g5 + 0x60]; \
- stx %i5, [%g5 + 0x68]; \
- stx %i6, [%g5 + 0x70]; \
- stx %i7, [%g5 + 0x78]; \
- bne save_cpu_window_##type; \
- add %g5, 0x80, %g5; \
- \
- /* For 8 windows with 16 registers to save in the window, memory required \
- is 16*8*8 = 0x400 bytes */ \
- \
- /* Now we should be in window 0 so update the other window registers */ \
- rdpr %ver, %g6; \
- and %g6, 0xf, %g6; \
- dec %g6; \
- wrpr %g6, %cansave; \
- \
- wrpr %g0, %cleanwin; \
- wrpr %g0, %canrestore; \
- wrpr %g0, %otherwin;
-
-
-#define RESTORE_WINDOW_STATE(type) \
- setx client_window, %g6, %g1; \
- \
- /* Get the number of windows in %g6 */ \
- rdpr %ver, %g6; \
- and %g6, 0xf, %g6; \
- inc %g6; \
- \
- /* Now iterate through all of the windows restoring all l and i registers */ \
- add %g1, 0x90, %g5; \
- \
-restore_cpu_window_##type: \
- deccc %g6; \
- wrpr %g6, %cwp; \
- ldx [%g5], %l0; \
- ldx [%g5 + 0x8], %l1; \
- ldx [%g5 + 0x10], %l2; \
- ldx [%g5 + 0x18], %l3; \
- ldx [%g5 + 0x20], %l4; \
- ldx [%g5 + 0x28], %l5; \
- ldx [%g5 + 0x30], %l6; \
- ldx [%g5 + 0x38], %l7; \
- ldx [%g5 + 0x40], %i0; \
- ldx [%g5 + 0x48], %i1; \
- ldx [%g5 + 0x50], %i2; \
- ldx [%g5 + 0x58], %i3; \
- ldx [%g5 + 0x60], %i4; \
- ldx [%g5 + 0x68], %i5; \
- ldx [%g5 + 0x70], %i6; \
- ldx [%g5 + 0x78], %i7; \
- bne restore_cpu_window_##type; \
- add %g5, 0x80, %g5; \
- \
- /* Restore the window registers to their original value */ \
- ldx [%g1], %g7; \
- wrpr %g7, %cwp; \
- ldx [%g1 + 0x8], %g7; \
- wrpr %g7, %cansave; \
- ldx [%g1 + 0x10], %g7; \
- wrpr %g7, %canrestore; \
- ldx [%g1 + 0x18], %g7; \
- wrpr %g7, %otherwin; \
- ldx [%g1 + 0x20], %g7; \
- wrpr %g7, %wstate; \
- ldx [%g1 + 0x28], %g7; \
- wrpr %g7, %cleanwin; \
- \
- ldx [%g1 + 0x30], %o0; \
- ldx [%g1 + 0x38], %o1; \
- ldx [%g1 + 0x40], %o2; \
- ldx [%g1 + 0x48], %o3; \
- ldx [%g1 + 0x50], %o4; \
- ldx [%g1 + 0x58], %o5; \
- ldx [%g1 + 0x60], %o6; \
- ldx [%g1 + 0x68], %o7; \
- \
- ldx [%g1 + 0x70], %g7; \
- wrpr %g7, %pstate; \
- ldx [%g1 + 0x78], %g7; \
- wr %g7, 0, %y; \
- ldx [%g1 + 0x80], %g7; \
- wr %g7, 0, %fprs
-
-
.data
.align 8
- .skip 16384
-openbios_stack:
-
client_stack:
.xword 0
client_tba:
@@ -176,15 +36,15 @@ client_window:
sparc64_of_client_interface:
/* Save globals on callers stack */
- add %sp, -56, %sp
+ add %sp, -248, %sp
- stx %g1, [%sp + 2047 + 0]
- stx %g2, [%sp + 2047 + 8]
- stx %g3, [%sp + 2047 + 16]
- stx %g4, [%sp + 2047 + 24]
- stx %g5, [%sp + 2047 + 32]
- stx %g6, [%sp + 2047 + 40]
- stx %g7, [%sp + 2047 + 48]
+ stx %g1, [%sp + 2047 + 192]
+ stx %g2, [%sp + 2047 + 200]
+ stx %g3, [%sp + 2047 + 208]
+ stx %g4, [%sp + 2047 + 216]
+ stx %g5, [%sp + 2047 + 224]
+ stx %g6, [%sp + 2047 + 232]
+ stx %g7, [%sp + 2047 + 240]
/* Save client trap table */
setx client_tba, %g6, %g7
@@ -196,22 +56,44 @@ sparc64_of_client_interface:
stx %sp, [%g7]
/* Save windows */
- SAVE_WINDOW_STATE(cif)
-
- /* Move to OpenBIOS stack */
- setx openbios_stack - 2047 - 192, %g6, %g7
+ setx _fcstack_ptr, %g6, %g7
+ ldx [%g7], %g1
+ add %g1, -CONTEXT_STATE_SIZE, %g1
+ stx %g1, [%g7]
+
+ SAVE_CPU_WINDOW_STATE(cif)
+
+ /* Move to OpenBIOS context stack */
+ setx _fcstack_ptr, %g6, %g7
+ ldx [%g7], %g6
+ setx CONTEXT_STACK_SIZE, %g4, %g5
+ sub %g6, %g5, %g6
+ stx %g6, [%g7]
+
+ setx - 2047 - 192, %g6, %g7
+ add %g1, %g7, %g7
mov %g7, %sp
/* Call client inteface */
call of_client_interface
ldx [%g1 + 0x30], %o0
- setx client_window, %g6, %g1
- stx %o0, [%g1 + 0x30]
-
/* Restore windows */
- RESTORE_WINDOW_STATE(cif)
-
+ setx _fcstack_ptr, %g6, %g7
+ ldx [%g7], %g1
+ setx CONTEXT_STACK_SIZE, %g4, %g5
+ add %g1, %g5, %g1
+ stx %g1, [%g7]
+
+ /* Return value */
+ stx %o0, [%g1 + 0x30]
+
+ RESTORE_CPU_WINDOW_STATE(cif)
+
+ add %g1, CONTEXT_STATE_SIZE, %g1
+ setx _fcstack_ptr, %g6, %g7
+ stx %g1, [%g7]
+
/* Restore stack */
setx client_stack, %g6, %g7
ldx [%g7], %sp
@@ -222,15 +104,15 @@ sparc64_of_client_interface:
wrpr %g6, %tba
/* Restore globals */
- ldx [%sp + 2047 + 0], %g1
- ldx [%sp + 2047 + 8], %g2
- ldx [%sp + 2047 + 16], %g3
- ldx [%sp + 2047 + 24], %g4
- ldx [%sp + 2047 + 32], %g5
- ldx [%sp + 2047 + 40], %g6
- ldx [%sp + 2047 + 48], %g7
-
- add %sp, 56, %sp
+ ldx [%sp + 2047 + 192], %g1
+ ldx [%sp + 2047 + 200], %g2
+ ldx [%sp + 2047 + 208], %g3
+ ldx [%sp + 2047 + 216], %g4
+ ldx [%sp + 2047 + 224], %g5
+ ldx [%sp + 2047 + 232], %g6
+ ldx [%sp + 2047 + 240], %g7
+
+ add %sp, 248, %sp
jmp %o7+8
nop
diff --git a/qemu/roms/openbios/arch/sparc64/context.c b/qemu/roms/openbios/arch/sparc64/context.c
index 2e7668958..98932ee9c 100644
--- a/qemu/roms/openbios/arch/sparc64/context.c
+++ b/qemu/roms/openbios/arch/sparc64/context.c
@@ -40,6 +40,10 @@ static uint8_t image_stack[IMAGE_STACK_SIZE];
/* Pointer to startup context (physical address) */
unsigned long __boot_ctx;
+/* Pointer to Forth context stack */
+void *_fcstack_ptr = &_efcstack;
+
+
/*
* Main starter
* This is the C function that runs first.
diff --git a/qemu/roms/openbios/arch/sparc64/cpustate.h b/qemu/roms/openbios/arch/sparc64/cpustate.h
new file mode 100644
index 000000000..0c276bfd1
--- /dev/null
+++ b/qemu/roms/openbios/arch/sparc64/cpustate.h
@@ -0,0 +1,244 @@
+/*
+ * Save/restore CPU state macros
+ *
+ * Copyright (C) 2015 Mark Cave-Ayland (mark.cave-ayland@ilande.co.uk>)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2
+ *
+ */
+
+/* State size for context (see below) */
+#define CONTEXT_STATE_SIZE 0x510
+
+/* Stack size for context (allocated inline of the context stack) */
+#define CONTEXT_STACK_SIZE 0x2000
+
+/*
+ * SAVE_CPU_STATE and RESTORE_CPU_STATE are macros used to enable a context switch
+ * to C to occur within the MMU I/D TLB miss handlers.
+ *
+ * Because these handlers are called on a TLB miss, we cannot use flushw to store
+ * processor window state on the stack, as the memory areas used by each window's
+ * stack pointer may not be in the TLB, causing recursive TLB miss traps.
+ *
+ * For this reason, we save window state by manually rotating the window registers
+ * and saving their contents (along with other vital registers) into a special
+ * tlb_handler_stack defined above which is guaranteed to be locked in the TLB, and
+ * so won't cause issues with trap recursion.
+ *
+ * Once this process is complete, we remain in a TL=0, CWP=0 state (with IE=1 to allow
+ * window fill/spill traps if required), switch to our safe tlb_handler_stack and
+ * invoke the miss handler.
+ */
+
+#define SAVE_CPU_WINDOW_STATE(type) \
+ /* Save window state into context at %g1 */ \
+ rdpr %cwp, %g7; \
+ stx %g7, [%g1]; \
+ rdpr %cansave, %g7; \
+ stx %g7, [%g1 + 0x8]; \
+ rdpr %canrestore, %g7; \
+ stx %g7, [%g1 + 0x10]; \
+ rdpr %otherwin, %g7; \
+ stx %g7, [%g1 + 0x18]; \
+ rdpr %wstate, %g7; \
+ stx %g7, [%g1 + 0x20]; \
+ rdpr %cleanwin, %g7; \
+ stx %g7, [%g1 + 0x28]; \
+ \
+ stx %o0, [%g1 + 0x30]; \
+ stx %o1, [%g1 + 0x38]; \
+ stx %o2, [%g1 + 0x40]; \
+ stx %o3, [%g1 + 0x48]; \
+ stx %o4, [%g1 + 0x50]; \
+ stx %o5, [%g1 + 0x58]; \
+ stx %o6, [%g1 + 0x60]; \
+ stx %o7, [%g1 + 0x68]; \
+ \
+ rdpr %pstate, %g7; \
+ stx %g7, [%g1 + 0x70]; \
+ rd %y, %g7; \
+ stx %g7, [%g1 + 0x78]; \
+ rd %fprs, %g7; \
+ stx %g7, [%g1 + 0x80]; \
+ rdpr %tl, %g7; \
+ stx %g7, [%g1 + 0x88]; \
+ \
+ /* Now iterate through all of the windows saving all l and i registers */ \
+ add %g1, 0x90, %g5; \
+ \
+ /* Get the number of windows in %g6 */ \
+ rdpr %ver, %g6; \
+ and %g6, 0xf, %g6; \
+ \
+ mov %g6, %g4; \
+ inc %g4; \
+ \
+ /* Starting cwp in g7 */ \
+ rdpr %cwp, %g7; \
+ \
+save_cpu_window_##type: \
+ wrpr %g7, %cwp; \
+ stx %l0, [%g5]; \
+ stx %l1, [%g5 + 0x8]; \
+ stx %l2, [%g5 + 0x10]; \
+ stx %l3, [%g5 + 0x18]; \
+ stx %l4, [%g5 + 0x20]; \
+ stx %l5, [%g5 + 0x28]; \
+ stx %l6, [%g5 + 0x30]; \
+ stx %l7, [%g5 + 0x38]; \
+ stx %i0, [%g5 + 0x40]; \
+ stx %i1, [%g5 + 0x48]; \
+ stx %i2, [%g5 + 0x50]; \
+ stx %i3, [%g5 + 0x58]; \
+ stx %i4, [%g5 + 0x60]; \
+ stx %i5, [%g5 + 0x68]; \
+ stx %i6, [%g5 + 0x70]; \
+ stx %i7, [%g5 + 0x78]; \
+ dec %g7; \
+ and %g7, %g6, %g7; \
+ subcc %g4, 1, %g4; \
+ bne save_cpu_window_##type; \
+ add %g5, 0x80, %g5; \
+ \
+ /* For 8 windows with 16 registers to save in the window, memory required \
+ is 16*8*8 = 0x400 bytes */ \
+ \
+ /* Now we should be in window 0 so update the other window registers */ \
+ rdpr %ver, %g6; \
+ and %g6, 0xf, %g6; \
+ dec %g6; \
+ wrpr %g6, %cansave; \
+ \
+ wrpr %g0, %cleanwin; \
+ wrpr %g0, %canrestore; \
+ wrpr %g0, %otherwin; \
+
+
+#define SAVE_CPU_TRAP_STATE(type) \
+ /* Save trap state into context at %g1 */ \
+ add %g1, 0x490, %g5; \
+ mov 4, %g6; \
+ \
+save_trap_state_##type: \
+ deccc %g6; \
+ wrpr %g6, %tl; \
+ rdpr %tpc, %g7; \
+ stx %g7, [%g5]; \
+ rdpr %tnpc, %g7; \
+ stx %g7, [%g5 + 0x8]; \
+ rdpr %tstate, %g7; \
+ stx %g7, [%g5 + 0x10]; \
+ rdpr %tt, %g7; \
+ stx %g7, [%g5 + 0x18]; \
+ bne save_trap_state_##type; \
+ add %g5, 0x20, %g5; \
+ \
+ /* For 4 trap levels with 4 registers, memory required is \
+ 4*8*4 = 0x80 bytes */
+
+/* Save all state into context at %g1 */
+#define SAVE_CPU_STATE(type) \
+ SAVE_CPU_WINDOW_STATE(type); \
+ SAVE_CPU_TRAP_STATE(type);
+
+
+#define RESTORE_CPU_WINDOW_STATE(type) \
+ /* Restore window state from context at %g1 */ \
+ \
+ /* Get the number of windows in %g6 */ \
+ rdpr %ver, %g6; \
+ and %g6, 0xf, %g6; \
+ \
+ mov %g6, %g4; \
+ inc %g4; \
+ \
+ /* Set starting window */ \
+ ldx [%g1], %g7; \
+ \
+ /* Now iterate through all of the windows restoring all l and i registers */ \
+ add %g1, 0x90, %g5; \
+ \
+restore_cpu_window_##type: \
+ wrpr %g7, %cwp; \
+ ldx [%g5], %l0; \
+ ldx [%g5 + 0x8], %l1; \
+ ldx [%g5 + 0x10], %l2; \
+ ldx [%g5 + 0x18], %l3; \
+ ldx [%g5 + 0x20], %l4; \
+ ldx [%g5 + 0x28], %l5; \
+ ldx [%g5 + 0x30], %l6; \
+ ldx [%g5 + 0x38], %l7; \
+ ldx [%g5 + 0x40], %i0; \
+ ldx [%g5 + 0x48], %i1; \
+ ldx [%g5 + 0x50], %i2; \
+ ldx [%g5 + 0x58], %i3; \
+ ldx [%g5 + 0x60], %i4; \
+ ldx [%g5 + 0x68], %i5; \
+ ldx [%g5 + 0x70], %i6; \
+ ldx [%g5 + 0x78], %i7; \
+ dec %g7; \
+ and %g7, %g6, %g7; \
+ subcc %g4, 1, %g4; \
+ bne restore_cpu_window_##type; \
+ add %g5, 0x80, %g5; \
+ \
+ /* Restore the window registers to their original value */ \
+ ldx [%g1], %g7; \
+ wrpr %g7, %cwp; \
+ ldx [%g1 + 0x8], %g7; \
+ wrpr %g7, %cansave; \
+ ldx [%g1 + 0x10], %g7; \
+ wrpr %g7, %canrestore; \
+ ldx [%g1 + 0x18], %g7; \
+ wrpr %g7, %otherwin; \
+ ldx [%g1 + 0x20], %g7; \
+ wrpr %g7, %wstate; \
+ ldx [%g1 + 0x28], %g7; \
+ wrpr %g7, %cleanwin; \
+ \
+ ldx [%g1 + 0x30], %o0; \
+ ldx [%g1 + 0x38], %o1; \
+ ldx [%g1 + 0x40], %o2; \
+ ldx [%g1 + 0x48], %o3; \
+ ldx [%g1 + 0x50], %o4; \
+ ldx [%g1 + 0x58], %o5; \
+ ldx [%g1 + 0x60], %o6; \
+ ldx [%g1 + 0x68], %o7; \
+ \
+ ldx [%g1 + 0x70], %g7; \
+ wrpr %g7, %pstate; \
+ ldx [%g1 + 0x78], %g7; \
+ wr %g7, 0, %y; \
+ ldx [%g1 + 0x80], %g7; \
+ wr %g7, 0, %fprs; \
+
+
+#define RESTORE_CPU_TRAP_STATE(type) \
+ /* Restore trap state from context at %g1 */ \
+ add %g1, 0x490, %g5; \
+ mov 4, %g6; \
+ \
+restore_trap_state_##type: \
+ deccc %g6; \
+ wrpr %g6, %tl; \
+ ldx [%g5], %g7; \
+ wrpr %g7, %tpc; \
+ ldx [%g5 + 0x8], %g7; \
+ wrpr %g7, %tnpc; \
+ ldx [%g5 + 0x10], %g7; \
+ wrpr %g7, %tstate; \
+ ldx [%g5 + 0x18], %g7; \
+ wrpr %g7, %tt; \
+ bne restore_trap_state_##type; \
+ add %g5, 0x20, %g5; \
+ \
+ ldx [%g1 + 0x88], %g7; \
+ wrpr %g7, %tl
+
+/* Restore all state from context at %g1 */
+#define RESTORE_CPU_STATE(type) \
+ RESTORE_CPU_WINDOW_STATE(type); \
+ RESTORE_CPU_TRAP_STATE(type);
diff --git a/qemu/roms/openbios/arch/sparc64/ldscript b/qemu/roms/openbios/arch/sparc64/ldscript
index 54288e825..c5cc6a5ce 100644
--- a/qemu/roms/openbios/arch/sparc64/ldscript
+++ b/qemu/roms/openbios/arch/sparc64/ldscript
@@ -50,6 +50,11 @@ SECTIONS
*(.bss.*)
*(COMMON)
+ _fcstack = .;
+ . += 32768;
+ . = ALIGN(16);
+ _efcstack = .;
+
_stack = .;
. += STACK_SIZE;
. = ALIGN(16);
diff --git a/qemu/roms/openbios/arch/sparc64/lib.c b/qemu/roms/openbios/arch/sparc64/lib.c
index e9101af52..4709ca8fe 100644
--- a/qemu/roms/openbios/arch/sparc64/lib.c
+++ b/qemu/roms/openbios/arch/sparc64/lib.c
@@ -458,10 +458,10 @@ NODE_METHODS(mmu) = {
void ob_mmu_init(const char *cpuname, uint64_t ram_size)
{
/* memory node */
- REGISTER_NODE_METHODS(memory, "/memory");
+ REGISTER_NODE(memory);
/* MMU node */
- REGISTER_NODE_METHODS(mmu, "/virtual-memory");
+ REGISTER_NODE(mmu);
ofmem_register(find_dev("/memory"), find_dev("/virtual-memory"));
diff --git a/qemu/roms/openbios/arch/sparc64/vectors.S b/qemu/roms/openbios/arch/sparc64/vectors.S
index 927c1cdc7..9d86b6bd8 100644
--- a/qemu/roms/openbios/arch/sparc64/vectors.S
+++ b/qemu/roms/openbios/arch/sparc64/vectors.S
@@ -24,6 +24,7 @@
*/
#define __ASSEMBLY__
+#include "cpustate.h"
#include "pstate.h"
#include <asm/asi.h>
#define ASI_BP ASI_PHYS_BYPASS_EC_E
@@ -276,17 +277,8 @@ tl1_resv1f0: BTRAPS(0x1f0) BTRAPS(0x1f8)
.section ".data"
.align 8
- .globl tlb_handler_stack_top, tlb_handler_stack_pointer, obp_ticks_pointer
+ .globl obp_ticks_pointer
- ! Stack for the tlb MMU trap handlers
-tlb_handler_stack_bottom:
- .skip 8192
-tlb_handler_stack_top:
- .skip 8
-
- ! MMU trap handler stack pointer
-tlb_handler_stack_pointer:
- .xword tlb_handler_stack_top
! Pointer to current tick value
obp_ticks_pointer:
@@ -336,234 +328,30 @@ fill_32bit:
restored
retry
-/*
- * SAVE_CPU_STATE and RESTORE_CPU_STATE are macros used to enable a context switch
- * to C to occur within the MMU I/D TLB miss handlers.
- *
- * Because these handlers are called on a TLB miss, we cannot use flushw to store
- * processor window state on the stack, as the memory areas used by each window's
- * stack pointer may not be in the TLB, causing recursive TLB miss traps.
- *
- * For this reason, we save window state by manually rotating the window registers
- * and saving their contents (along with other vital registers) into a special
- * tlb_handler_stack defined above which is guaranteed to be locked in the TLB, and
- * so won't cause issues with trap recursion.
- *
- * Once this process is complete, we remain in a TL=0, CWP=0 state (with IE=1 to allow
- * window fill/spill traps if required), switch to our safe tlb_handler_stack and
- * invoke the miss handler.
- */
-
-#define SAVE_CPU_STATE(type) \
- /* Set up our exception stack pointer in %g1 */ \
- setx tlb_handler_stack_pointer, %g7, %g6; \
- ldx [%g6], %g1; \
- add %g1, -0x510, %g1; \
- \
- /* First save the various state registers */ \
- rdpr %cwp, %g7; \
- stx %g7, [%g1]; \
- rdpr %cansave, %g7; \
- stx %g7, [%g1 + 0x8]; \
- rdpr %canrestore, %g7; \
- stx %g7, [%g1 + 0x10]; \
- rdpr %otherwin, %g7; \
- stx %g7, [%g1 + 0x18]; \
- rdpr %wstate, %g7; \
- stx %g7, [%g1 + 0x20]; \
- rdpr %cleanwin, %g7; \
- stx %g7, [%g1 + 0x28]; \
- rdpr %pstate, %g7; \
- stx %g7, [%g1 + 0x30]; \
- \
- rd %y, %g7; \
- stx %g7, [%g1 + 0x38]; \
- rd %fprs, %g7; \
- stx %g7, [%g1 + 0x40]; \
- \
- rdpr %tl, %g7; \
- stx %g7, [%g1 + 0x48]; \
- \
- /* Trap state */ \
- add %g1, 0x50, %g5; \
- mov 4, %g6; \
- \
-save_trap_state_##type: \
- deccc %g6; \
- wrpr %g6, %tl; \
- rdpr %tpc, %g7; \
- stx %g7, [%g5]; \
- rdpr %tnpc, %g7; \
- stx %g7, [%g5 + 0x8]; \
- rdpr %tstate, %g7; \
- stx %g7, [%g5 + 0x10]; \
- rdpr %tt, %g7; \
- stx %g7, [%g5 + 0x18]; \
- bne save_trap_state_##type; \
- add %g5, 0x20, %g5; \
- \
- /* For 4 trap levels with 4 registers, memory required is
- 4*8*4 = 0x80 bytes */ \
- \
- /* Save the o registers */ \
- stx %o0, [%g1 + 0xd0]; \
- stx %o1, [%g1 + 0xd8]; \
- stx %o2, [%g1 + 0xe0]; \
- stx %o3, [%g1 + 0xe8]; \
- stx %o4, [%g1 + 0xf0]; \
- stx %o5, [%g1 + 0xf8]; \
- stx %o6, [%g1 + 0x100]; \
- stx %o7, [%g1 + 0x108]; \
- \
- /* Now iterate through all of the windows saving all l and i registers */ \
- add %g1, 0x110, %g5; \
- \
- /* Get the number of windows in %g6 */ \
- rdpr %ver, %g6; \
- and %g6, 0xf, %g6; \
- inc %g6; \
- \
-save_cpu_window_##type: \
- deccc %g6; \
- wrpr %g6, %cwp; \
- stx %l0, [%g5]; \
- stx %l1, [%g5 + 0x8]; \
- stx %l2, [%g5 + 0x10]; \
- stx %l3, [%g5 + 0x18]; \
- stx %l4, [%g5 + 0x20]; \
- stx %l5, [%g5 + 0x28]; \
- stx %l6, [%g5 + 0x30]; \
- stx %l7, [%g5 + 0x38]; \
- stx %i0, [%g5 + 0x40]; \
- stx %i1, [%g5 + 0x48]; \
- stx %i2, [%g5 + 0x50]; \
- stx %i3, [%g5 + 0x58]; \
- stx %i4, [%g5 + 0x60]; \
- stx %i5, [%g5 + 0x68]; \
- stx %i6, [%g5 + 0x70]; \
- stx %i7, [%g5 + 0x78]; \
- bne save_cpu_window_##type; \
- add %g5, 0x80, %g5; \
- \
- /* For 8 windows with 16 registers to save in the window, memory required
- is 16*8*8 = 0x400 bytes */ \
- \
- /* Now we should be in window 0 so update the other window registers */ \
- rdpr %ver, %g6; \
- and %g6, 0xf, %g6; \
- dec %g6; \
- wrpr %g6, %cansave; \
- \
- wrpr %g0, %cleanwin; \
- wrpr %g0, %canrestore; \
- wrpr %g0, %otherwin; \
- \
- /* Update our exception stack pointer */ \
- setx tlb_handler_stack_pointer, %g7, %g6; \
- stx %g1, [%g6];
-
-
-#define RESTORE_CPU_STATE(type) \
- /* Set up our exception stack pointer in %g1 */ \
- setx tlb_handler_stack_pointer, %g7, %g6; \
- ldx [%g6], %g1; \
- \
- /* Get the number of windows in %g6 */ \
- rdpr %ver, %g6; \
- and %g6, 0xf, %g6; \
- inc %g6; \
- \
- /* Now iterate through all of the windows restoring all l and i registers */ \
- add %g1, 0x110, %g5; \
- \
-restore_cpu_window_##type: \
- deccc %g6; \
- wrpr %g6, %cwp; \
- ldx [%g5], %l0; \
- ldx [%g5 + 0x8], %l1; \
- ldx [%g5 + 0x10], %l2; \
- ldx [%g5 + 0x18], %l3; \
- ldx [%g5 + 0x20], %l4; \
- ldx [%g5 + 0x28], %l5; \
- ldx [%g5 + 0x30], %l6; \
- ldx [%g5 + 0x38], %l7; \
- ldx [%g5 + 0x40], %i0; \
- ldx [%g5 + 0x48], %i1; \
- ldx [%g5 + 0x50], %i2; \
- ldx [%g5 + 0x58], %i3; \
- ldx [%g5 + 0x60], %i4; \
- ldx [%g5 + 0x68], %i5; \
- ldx [%g5 + 0x70], %i6; \
- ldx [%g5 + 0x78], %i7; \
- bne restore_cpu_window_##type; \
- add %g5, 0x80, %g5; \
- \
- /* Restore the window registers to their original value */ \
- ldx [%g1], %g7; \
- wrpr %g7, %cwp; \
- ldx [%g1 + 0x8], %g7; \
- wrpr %g7, %cansave; \
- ldx [%g1 + 0x10], %g7; \
- wrpr %g7, %canrestore; \
- ldx [%g1 + 0x18], %g7; \
- wrpr %g7, %otherwin; \
- ldx [%g1 + 0x20], %g7; \
- wrpr %g7, %wstate; \
- ldx [%g1 + 0x28], %g7; \
- wrpr %g7, %cleanwin; \
- ldx [%g1 + 0x30], %g7; \
- wrpr %g7, %pstate; \
- \
- /* Restore the o registers */ \
- ldx [%g1 + 0xd0], %o0; \
- ldx [%g1 + 0xd8], %o1; \
- ldx [%g1 + 0xe0], %o2; \
- ldx [%g1 + 0xe8], %o3; \
- ldx [%g1 + 0xf0], %o4; \
- ldx [%g1 + 0xf8], %o5; \
- ldx [%g1 + 0x100], %o6; \
- ldx [%g1 + 0x108], %o7; \
- \
- /* Restore the trap state */ \
- add %g1, 0x50, %g5; \
- mov 4, %g6; \
- \
-restore_trap_state_##type: \
- deccc %g6; \
- wrpr %g6, %tl; \
- ldx [%g5], %g7; \
- wrpr %g7, %tpc; \
- ldx [%g5 + 0x8], %g7; \
- wrpr %g7, %tnpc; \
- ldx [%g5 + 0x10], %g7; \
- wrpr %g7, %tstate; \
- ldx [%g5 + 0x18], %g7; \
- wrpr %g7, %tt; \
- bne restore_trap_state_##type; \
- add %g5, 0x20, %g5; \
- \
- ldx [%g1 + 0x38], %g7; \
- wr %g7, 0, %y; \
- ldx [%g1 + 0x40], %g7; \
- wr %g7, 0, %fprs; \
- ldx [%g1 + 0x48], %g7; \
- wrpr %g7, %tl; \
- \
- /* Restore exception stack pointer to previous value */ \
- setx tlb_handler_stack_pointer, %g7, %g6; \
- add %g1, 0x510, %g1; \
- stx %g1, [%g6];
-
.globl reload_DMMU_tlb, reload_IMMU_tlb, bug
reload_DMMU_tlb:
-
+
+ /* Save CPU state to stack */
+ setx _fcstack_ptr, %g6, %g7
+ ldx [%g7], %g1
+ add %g1, -CONTEXT_STATE_SIZE, %g1
+ stx %g1, [%g7]
+
SAVE_CPU_STATE(dtlb)
- /* Switch to TLB locked stack space (note we add an additional 192 bytes required for
+ /* Switch to 8K TLB locked OpenBIOS stack (note we add an additional 192 bytes required for
gcc to save its arguments when building with -O0) */
- add %g1, -STACK_BIAS - 192, %sp
+ setx _fcstack_ptr, %g6, %g7
+ ldx [%g7], %g6
+ setx CONTEXT_STACK_SIZE, %g4, %g5
+ sub %g6, %g5, %g6
+ stx %g6, [%g7]
+
+ setx - 2047 - 192, %g6, %g7
+ add %g1, %g7, %g7
+ mov %g7, %sp
/* Enable interrupts for window spill/fill traps */
rdpr %pstate, %g7
@@ -577,18 +365,44 @@ reload_DMMU_tlb:
rdpr %pstate, %g7
andn %g7, PSTATE_IE, %g7
wrpr %g7, %pstate
-
+
+ /* Restore CPU state from stack */
+ setx _fcstack_ptr, %g6, %g7
+ ldx [%g7], %g1
+ setx CONTEXT_STACK_SIZE, %g4, %g5
+ add %g1, %g5, %g1
+ stx %g1, [%g7]
+
RESTORE_CPU_STATE(dtlb)
-
+
+ setx _fcstack_ptr, %g6, %g7
+ ldx [%g7], %g1
+ add %g1, CONTEXT_STATE_SIZE, %g1
+ stx %g1, [%g7]
+
retry
reload_IMMU_tlb:
-
+
+ /* Save CPU state to stack */
+ setx _fcstack_ptr, %g6, %g7
+ ldx [%g7], %g1
+ add %g1, -CONTEXT_STATE_SIZE, %g1
+ stx %g1, [%g7]
+
SAVE_CPU_STATE(itlb)
- /* Switch to TLB locked stack space (note we add an additional 192 bytes required for
+ /* Switch to 8K TLB locked OpenBIOS stack (note we add an additional 192 bytes required for
gcc to save its arguments when building with -O0) */
- add %g1, -STACK_BIAS - 192, %sp
+ setx _fcstack_ptr, %g6, %g7
+ ldx [%g7], %g6
+ setx CONTEXT_STACK_SIZE, %g4, %g5
+ sub %g6, %g5, %g6
+ stx %g6, [%g7]
+
+ setx - 2047 - 192, %g6, %g7
+ add %g1, %g7, %g7
+ mov %g7, %sp
/* Enable interrupts for window spill/fill traps */
rdpr %pstate, %g7
@@ -602,8 +416,20 @@ reload_IMMU_tlb:
rdpr %pstate, %g7
andn %g7, PSTATE_IE, %g7
wrpr %g7, %pstate
-
+
+ /* Restore CPU state from stack */
+ setx _fcstack_ptr, %g6, %g7
+ ldx [%g7], %g1
+ setx CONTEXT_STACK_SIZE, %g4, %g5
+ add %g1, %g5, %g1
+ stx %g1, [%g7]
+
RESTORE_CPU_STATE(itlb)
+
+ setx _fcstack_ptr, %g6, %g7
+ ldx [%g7], %g1
+ add %g1, CONTEXT_STATE_SIZE, %g1
+ stx %g1, [%g7]
retry
diff --git a/qemu/roms/openbios/config/scripts/switch-arch b/qemu/roms/openbios/config/scripts/switch-arch
index d5e2f7710..ab3b4ce69 100755
--- a/qemu/roms/openbios/config/scripts/switch-arch
+++ b/qemu/roms/openbios/config/scripts/switch-arch
@@ -17,48 +17,57 @@ if [ x"$1" = x -o "$1" = "-help" ]; then
exit 0
fi
-crosscflags()
+is_bigendian()
{
- host=$1
- target=$2
-
- if test "$host" = "powerpc" -o "$host" = "ppc" \
- -o "$host" = "mips" -o "$host" = "s390" \
- -o "$host" = "sparc32" -o "$host" = "sparc64" \
- -o "$host" = "m68k" -o "$host" = "armv4b"; then
- hostbigendian="yes"
+ cpu=$1
+
+ if test "$cpu" = "powerpc" -o "$cpu" = "ppc" \
+ -o "$cpu" = "powerpc64" -o "$cpu" = "ppc64" \
+ -o "$cpu" = "mips" -o "$cpu" = "s390" \
+ -o "$cpu" = "sparc32" -o "$cpu" = "sparc64" \
+ -o "$cpu" = "m68k" -o "$cpu" = "armv4b"; then
+ echo yes
else
- hostbigendian="no"
+ echo no
fi
+}
-# host long bits test
- if test "$host" = "sparc64" -o "$host" = "ia64" \
- -o "$host" = "amd64" -o "$host" = "x86_64" \
- -o "$host" = "alpha"; then
- hostlongbits="64"
+longbits()
+{
+ cpu=$1
+ if test "$cpu" = "sparc64" -o "$cpu" = "ia64" \
+ -o "$cpu" = "amd64" -o "$cpu" = "x86_64" \
+ -o "$cpu" = "powerpc64" -o "$cpu" = "ppc64" \
+ -o "$cpu" = "alpha"; then
+ echo 64
else
- hostlongbits="32"
+ echo 32
fi
+}
- if test "$target" = "powerpc" -o "$target" = "ppc" \
- -o "$target" = "powerpc64" -o "$target" = "ppc64" \
- -o "$target" = "mips" -o "$target" = "s390" \
- -o "$target" = "sparc32" -o "$target" = "sparc64" \
- -o "$target" = "m68k" -o "$target" = "armv4b"; then
- targetbigendian="yes"
- else
- targetbigendian="no"
- fi
+basearch()
+{
+ arch=$1
+ case $arch in
+ powerpc|ppc64|powerpc64)
+ echo ppc
+ ;;
+ *)
+ echo $arch
+ ;;
+ esac
+}
-# target long bits test
- if test "$target" = "sparc64" -o "$target" = "ia64" \
- -o "$target" = "amd64" -o "$target" = "x86_64" \
- -o "$target" = "powerpc64" -o "$target" = "ppc64" \
- -o "$target" = "alpha"; then
- targetlongbits="64"
- else
- targetlongbits="32"
- fi
+crosscflags()
+{
+ host=$1
+ target=$2
+
+ hostbigendian=$(is_bigendian $host)
+ hostlongbits=$(longbits $host)
+
+ targetbigendian=$(is_bigendian $target)
+ targetlongbits=$(longbits $target)
if test "$targetbigendian" = "$hostbigendian"; then
cflags="-USWAP_ENDIANNESS"
@@ -99,23 +108,27 @@ archname()
select_prefix()
{
- TARGETS="${1}-unknown-linux-gnu- ${1}-linux-gnu- ${1}-linux- ${1}-elf- ${1}-eabi-"
+ BASEARCH=$(basearch $ARCH)
+ 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 [ "$BASEARCH" = "$(basearch $HOSTARCH)" ]; then
+ TARGET=""
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
}
@@ -242,7 +255,6 @@ for ARCH in $arch_list; do
esac
done
- BASEARCH=$ARCH
case $ARCH in
amd64)
select_prefix x86_64
@@ -251,9 +263,10 @@ 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"
+ # 604 cpu includes support for PReP as well as Mac
+ CFLAGS="-m32 -mcpu=604 -msoft-float -fno-builtin-bcopy -fno-builtin-log2"
AS_FLAGS="-m32"
else
CFLAGS="-fno-builtin"
@@ -263,13 +276,14 @@ for ARCH in $arch_list; do
ppc64)
select_prefix powerpc64
- CFLAGS="-Wa,-a64 -m64 -msoft-float -fno-builtin"
+
+ # 970 cpu is used in all 64-bit Macs but disable altivec
+ CFLAGS="-mcpu=970 -mno-altivec -Wa,-a64 -m64 -msoft-float -fno-builtin"
AS_FLAGS="-Wa,-a64"
- BASEARCH=ppc
;;
sparc32)
- select_prefix sparc
+ select_prefix sparc sparc64
CFLAGS="-Wa,-xarch=v8 -Wa,-32 -m32 -mcpu=supersparc -fno-builtin"
AS_FLAGS="-Wa,-xarch=v8 -Wa,-32"
;;
diff --git a/qemu/roms/openbios/drivers/cuda.c b/qemu/roms/openbios/drivers/cuda.c
index 9555dea49..ff5d22de2 100644
--- a/qemu/roms/openbios/drivers/cuda.c
+++ b/qemu/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/qemu/roms/openbios/drivers/escc.c b/qemu/roms/openbios/drivers/escc.c
index 240043be3..1990e798d 100644
--- a/qemu/roms/openbios/drivers/escc.c
+++ b/qemu/roms/openbios/drivers/escc.c
@@ -380,12 +380,44 @@ 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];
+ ucell offset;
+ int index;
+ int legacy;
+
+ int dbdma_offsets[2][2] = {
+ /* ch-b */
+ { 0x6, 0x7 },
+ /* ch-a */
+ { 0x4, 0x5 }
+ };
+
+ int reg_offsets[2][2][3] = {
+ {
+ /* ch-b */
+ { 0x00, 0x10, 0x40 },
+ /* ch-a */
+ { 0x20, 0x30, 0x50 }
+ },{
+ /* legacy ch-b */
+ { 0x0, 0x2, 0x8 },
+ /* legacy ch-a */
+ { 0x4, 0x6, 0xa }
+ }
+ };
+
+ switch (esnum) {
+ case 2: index = 1; legacy = 0; break;
+ case 3: index = 0; legacy = 0; break;
+ case 4: index = 1; legacy = 1; break;
+ case 5: index = 0; legacy = 1; break;
+ default: return;
+ }
/* add device */
@@ -411,31 +443,49 @@ 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);
+ snprintf(buf, sizeof(buf), "chrp,es%d", esnum);
+ set_property(dnode, "compatible", buf, 9);
- props[0] = IO_ESCC_OFFSET + offset * 0x20;
- props[1] = 0x00000020;
- set_property(dnode, "reg", (char *)&props, 2 * sizeof(cell));
+ if (legacy) {
+ offset = IO_ESCC_LEGACY_OFFSET;
+ } else {
+ offset = IO_ESCC_OFFSET;
+ }
- props[0] = addr + IO_ESCC_OFFSET + offset * 0x20;
+ props[0] = offset + reg_offsets[legacy][index][0];
+ props[1] = 0x1;
+ props[2] = offset + reg_offsets[legacy][index][1];
+ props[3] = 0x1;
+ props[4] = offset + reg_offsets[legacy][index][2];
+ props[5] = 0x1;
+ props[6] = 0x8000 + dbdma_offsets[index][0] * 0x100;
+ props[7] = 0x100;
+ props[8] = 0x8000 + dbdma_offsets[index][1] * 0x100;
+ props[9] = 0x100;
+ set_property(dnode, "reg", (char *)&props, 10 * sizeof(cell));
+
+ props[0] = addr + offset + reg_offsets[legacy][index][0];
OLDWORLD(set_property(dnode, "AAPL,address",
(char *)&props, 1 * sizeof(cell)));
- props[0] = 0x00000010 - offset;
+ props[0] = 0x10 - index;
OLDWORLD(set_property(dnode, "AAPL,interrupts",
(char *)&props, 1 * sizeof(cell)));
- props[0] = (0x24) + offset;
- props[1] = 0;
+ props[0] = (0x24) + index;
+ props[1] = 0x1;
+ props[2] = dbdma_offsets[index][0];
+ props[3] = 0x0;
+ props[4] = dbdma_offsets[index][1];
+ props[5] = 0x0;
NEWWORLD(set_property(dnode, "interrupts",
- (char *)&props, 2 * sizeof(cell)));
+ (char *)&props, 6 * sizeof(cell)));
+
+ set_int_property(dnode, "slot-names", 0);
device_end();
- uart_init_line((unsigned char*)addr + IO_ESCC_OFFSET + offset * 0x20,
+ uart_init_line((unsigned char*)addr + offset + reg_offsets[legacy][index][0],
CONFIG_SERIAL_SPEED);
}
@@ -464,13 +514,39 @@ escc_init(const char *path, phys_addr_t addr)
set_property(dnode, "device_type", "escc",
strlen("escc") + 1);
set_property(dnode, "compatible", "escc\0CHRP,es0", 14);
+ set_property(dnode, "ranges", "", 0);
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);
+ set_property(dnode, "ranges", "", 0);
+
+ fword("finish-device");
+
+ escc_add_channel(buf, "a", addr, 4);
+ escc_add_channel(buf, "b", addr, 5);
}
#endif
diff --git a/qemu/roms/openbios/drivers/escc.h b/qemu/roms/openbios/drivers/escc.h
index caaf00d40..e73f267b2 100644
--- a/qemu/roms/openbios/drivers/escc.h
+++ b/qemu/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/qemu/roms/openbios/drivers/ide.c b/qemu/roms/openbios/drivers/ide.c
index 327c64a40..1da60c895 100644
--- a/qemu/roms/openbios/drivers/ide.c
+++ b/qemu/roms/openbios/drivers/ide.c
@@ -73,13 +73,13 @@ static inline void ide_add_channel(struct ide_channel *chan)
channels = chan;
}
-static struct ide_channel *ide_seek_channel(const char *name)
+static struct ide_channel *ide_seek_channel(phandle_t ph)
{
struct ide_channel *current;
current = channels;
while (current) {
- if (!strcmp(current->name, name))
+ if (current->ph == ph)
return current;
current = current->next;
}
@@ -1247,11 +1247,10 @@ ob_ide_initialize(int *idx)
static void
ob_ide_open(int *idx)
{
- int ret=1, len;
+ int ret=1;
phandle_t ph;
struct ide_drive *drive;
struct ide_channel *chan;
- char *idename;
int unit;
fword("my-unit");
@@ -1260,9 +1259,8 @@ ob_ide_open(int *idx)
fword("my-parent");
fword("ihandle>phandle");
ph=(phandle_t)POP();
- idename=get_property(ph, "name", &len);
- chan = ide_seek_channel(idename);
+ chan = ide_seek_channel(ph);
drive = &chan->drives[unit];
*(struct ide_drive **)idx = drive;
@@ -1380,9 +1378,6 @@ int ob_ide_init(const char *path, uint32_t io_port0, uint32_t ctl_port0,
chan = malloc(sizeof(struct ide_channel));
- snprintf(chan->name, sizeof(chan->name),
- DEV_NAME, current_channel);
-
chan->mmio = 0;
for (j = 0; j < 8; j++)
@@ -1424,9 +1419,9 @@ int ob_ide_init(const char *path, uint32_t io_port0, uint32_t ctl_port0,
snprintf(nodebuff, sizeof(nodebuff), "%s/" DEV_NAME, path,
current_channel);
- REGISTER_NAMED_NODE(ob_ide_ctrl, nodebuff);
+ REGISTER_NAMED_NODE_PHANDLE(ob_ide_ctrl, nodebuff, dnode);
- dnode = find_dev(nodebuff);
+ chan->ph = dnode;
#if !defined(CONFIG_PPC) && !defined(CONFIG_SPARC64)
props[0]=14; props[1]=0;
@@ -1468,11 +1463,9 @@ int ob_ide_init(const char *path, uint32_t io_port0, uint32_t ctl_port0,
break;
}
IDE_DPRINTF("%s]: %s\n", media, drive->model);
- snprintf(nodebuff, sizeof(nodebuff),
- "%s/" DEV_NAME "/%s", path, current_channel,
- media);
- REGISTER_NAMED_NODE(ob_ide, nodebuff);
- dnode=find_dev(nodebuff);
+ snprintf(nodebuff, sizeof(nodebuff), "%s/%s",
+ get_path_from_ph(dnode), media);
+ REGISTER_NAMED_NODE_PHANDLE(ob_ide, nodebuff, dnode);
set_int_property(dnode, "reg", j);
/* create aliases */
@@ -1488,6 +1481,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)
@@ -1527,16 +1542,13 @@ int macio_ide_init(const char *path, uint32_t addr, int nb_channels)
struct ide_channel *chan;
/* IDE ports on Macs are numbered from 3.
- * Also see comments in macio.c:openpic_init() */
+ * Also see comments in pci.c:ob_pci_host_set_interrupt_map() */
current_channel = 3;
- for (i = 0; i < nb_channels; i++, current_channel++) {
+ for (i = 0; i < nb_channels; i++) {
chan = malloc(sizeof(struct ide_channel));
- snprintf(chan->name, sizeof(chan->name),
- DEV_NAME, current_channel);
-
chan->mmio = addr + MACIO_IDE_OFFSET + i * MACIO_IDE_SIZE;
chan->obide_inb = macio_ide_inb;
@@ -1574,13 +1586,19 @@ int macio_ide_init(const char *path, uint32_t addr, int nb_channels)
snprintf(nodebuff, sizeof(nodebuff), "%s/" DEV_NAME, path,
current_channel);
- REGISTER_NAMED_NODE(ob_ide_ctrl, nodebuff);
+ REGISTER_NAMED_NODE_PHANDLE(ob_ide_ctrl, nodebuff, dnode);
- dnode = find_dev(nodebuff);
+ chan->ph = dnode;
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 +1607,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 */
@@ -1633,9 +1651,9 @@ int macio_ide_init(const char *path, uint32_t addr, int nb_channels)
OLDWORLD(set_property(dnode, "AAPL,address",
(char *)&props, 2*sizeof(props[0])));
- props[0] = 0;
- OLDWORLD(set_property(dnode, "AAPL,bus-id", (char*)props,
- 1 * sizeof(props[0])));
+ props[0] = i;
+ 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);
@@ -1663,11 +1681,9 @@ int macio_ide_init(const char *path, uint32_t addr, int nb_channels)
break;
}
IDE_DPRINTF("%s]: %s\n", media, drive->model);
- snprintf(nodebuff, sizeof(nodebuff),
- "%s/" DEV_NAME "/%s", path, current_channel,
- media);
- REGISTER_NAMED_NODE(ob_ide, nodebuff);
- dnode = find_dev(nodebuff);
+ snprintf(nodebuff, sizeof(nodebuff), "%s/%s",
+ get_path_from_ph(dnode), media);
+ REGISTER_NAMED_NODE_PHANDLE(ob_ide, nodebuff, dnode);
set_int_property(dnode, "reg", j);
/* create aliases */
diff --git a/qemu/roms/openbios/drivers/ide.h b/qemu/roms/openbios/drivers/ide.h
index d6c4b9f5d..8983c8ecf 100644
--- a/qemu/roms/openbios/drivers/ide.h
+++ b/qemu/roms/openbios/drivers/ide.h
@@ -167,7 +167,7 @@ struct ide_drive {
struct ide_channel {
- char name[32];
+ phandle_t ph;
struct ide_channel *next;
/*
diff --git a/qemu/roms/openbios/drivers/obio.c b/qemu/roms/openbios/drivers/obio.c
index 7c135a362..4ac063188 100644
--- a/qemu/roms/openbios/drivers/obio.c
+++ b/qemu/roms/openbios/drivers/obio.c
@@ -26,8 +26,6 @@
#define PROMDEV_SCREEN 0 /* output to screen */
#define PROMDEV_TTYA 1 /* in/out to ttya */
-/* DECLARE data structures for the nodes. */
-DECLARE_UNNAMED_NODE( ob_obio, INSTALL_OPEN, sizeof(int) );
void
ob_new_obio_device(const char *name, const char *type)
@@ -397,45 +395,6 @@ ob_smp_init(unsigned long mem_size)
}
static void
-ob_obio_open(__attribute__((unused))int *idx)
-{
- int ret=1;
- RET ( -ret );
-}
-
-static void
-ob_obio_close(__attribute__((unused))int *idx)
-{
- selfword("close-deblocker");
-}
-
-static void
-ob_obio_initialize(__attribute__((unused))int *idx)
-{
- push_str("/");
- fword("find-device");
- fword("new-device");
-
- push_str("obio");
- fword("device-name");
-
- push_str("hierarchical");
- fword("device-type");
-
- PUSH(2);
- fword("encode-int");
- push_str("#address-cells");
- fword("property");
-
- PUSH(1);
- fword("encode-int");
- push_str("#size-cells");
- fword("property");
-
- fword("finish-device");
-}
-
-static void
ob_set_obio_ranges(uint64_t base)
{
push_str("/obio");
@@ -458,27 +417,6 @@ ob_set_obio_ranges(uint64_t base)
fword("property");
}
-static void
-ob_obio_decodeunit(__attribute__((unused)) int *idx)
-{
- fword("decode-unit-sbus");
-}
-
-
-static void
-ob_obio_encodeunit(__attribute__((unused)) int *idx)
-{
- fword("encode-unit-sbus");
-}
-
-NODE_METHODS(ob_obio) = {
- { NULL, ob_obio_initialize },
- { "open", ob_obio_open },
- { "close", ob_obio_close },
- { "encode-unit", ob_obio_encodeunit },
- { "decode-unit", ob_obio_decodeunit },
-};
-
int
ob_obio_init(uint64_t slavio_base, unsigned long fd_offset,
@@ -491,10 +429,6 @@ ob_obio_init(uint64_t slavio_base, unsigned long fd_offset,
// http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
//printk("Initializing OBIO devices...\n");
-#if 0 // XXX
- REGISTER_NAMED_NODE(ob_obio, "/obio");
- device_end();
-#endif
ob_set_obio_ranges(slavio_base);
// Zilog Z8530 serial ports, see http://www.zilog.com
diff --git a/qemu/roms/openbios/drivers/pci.c b/qemu/roms/openbios/drivers/pci.c
index 366f4a17f..5062f302f 100644
--- a/qemu/roms/openbios/drivers/pci.c
+++ b/qemu/roms/openbios/drivers/pci.c
@@ -144,9 +144,16 @@ static void dump_reg_property(const char* description, int nreg, u32 *reg)
}
#endif
-static unsigned long pci_bus_addr_to_host_addr(uint32_t ba)
+static unsigned long pci_bus_addr_to_host_addr(int space, uint32_t ba)
{
- return arch->host_pci_base + (unsigned long)ba;
+ if (space == IO_SPACE) {
+ return arch->io_base + (unsigned long)ba;
+ } else if (space == MEMORY_SPACE_32) {
+ return arch->host_pci_base + (unsigned long)ba;
+ } else {
+ /* Return unaltered to aid debugging property values */
+ return (unsigned long)ba;
+ }
}
static void
@@ -340,22 +347,27 @@ ob_pci_encode_unit(int *idx)
ss, dev, fn, buf);
}
-/* ( pci-addr.lo pci-addr.hi size -- virt ) */
+/* ( pci-addr.lo pci-addr.mid pci-addr.hi size -- virt ) */
static void
ob_pci_map_in(int *idx)
{
phys_addr_t phys;
uint32_t ba;
- ucell size, virt;
+ ucell size, virt, tmp;
+ int space;
PCI_DPRINTF("ob_pci_bar_map_in idx=%p\n", idx);
size = POP();
+ tmp = POP();
POP();
ba = POP();
- phys = pci_bus_addr_to_host_addr(ba);
+ /* Get the space from the pci-addr.hi */
+ space = ((tmp & PCI_RANGE_TYPE_MASK) >> 24);
+
+ phys = pci_bus_addr_to_host_addr(space, ba);
#if defined(CONFIG_OFMEM)
ofmem_claim_phys(phys, size, 0);
@@ -448,13 +460,18 @@ static void pci_host_set_ranges(const pci_config_t *config)
int ncells;
ncells = 0;
- /* first encode PCI configuration space */
- {
- ncells += pci_encode_phys_addr(props + ncells, 0, CONFIGURATION_SPACE,
+
+#ifdef CONFIG_SPARC64
+ /* While configuration space isn't mentioned in the IEEE-1275 PCI
+ bindings, it appears in the PCI host bridge ranges property in
+ real device trees. Hence we disable this range for all host
+ bridges except for SPARC, particularly as it causes Darwin/OS X
+ to incorrectly calculated PCI memory space ranges on PPC. */
+ ncells += pci_encode_phys_addr(props + ncells, 0, CONFIGURATION_SPACE,
config->dev, 0, 0);
ncells += host_encode_phys_addr(props + ncells, arch->cfg_addr);
ncells += pci_encode_size(props + ncells, arch->cfg_len);
- }
+#endif
if (arch->io_base) {
ncells += pci_encode_phys_addr(props + ncells, 0, IO_SPACE,
@@ -585,13 +602,18 @@ static void pci_set_AAPL_address(const pci_config_t *config)
{
phandle_t dev = get_cur_dev();
cell props[7];
- int ncells, i;
+ uint32_t mask;
+ int ncells, i, flags, space_code;
ncells = 0;
for (i = 0; i < 6; i++) {
if (!config->assigned[i] || !config->sizes[i])
continue;
- props[ncells++] = config->assigned[i] & ~0x0000000F;
+ pci_decode_pci_addr(config->assigned[i],
+ &flags, &space_code, &mask);
+
+ props[ncells++] = pci_bus_addr_to_host_addr(space_code,
+ config->assigned[i] & ~mask);
}
if (ncells)
set_property(dev, "AAPL,address", (char *)props,
@@ -752,13 +774,19 @@ int macio_keylargo_config_cb (const pci_config_t *config)
int vga_config_cb (const pci_config_t *config)
{
unsigned long rom;
- uint32_t rom_size, size;
+ uint32_t rom_size, size, mask;
+ int flags, space_code;
phandle_t ph;
if (config->assigned[0] != 0x00000000) {
setup_video();
- rom = pci_bus_addr_to_host_addr(config->assigned[1] & ~0x0000000F);
+ pci_decode_pci_addr(config->assigned[1],
+ &flags, &space_code, &mask);
+
+ rom = pci_bus_addr_to_host_addr(space_code,
+ config->assigned[1] & ~0x0000000F);
+
rom_size = config->sizes[1];
ph = get_cur_dev();
@@ -824,7 +852,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];
}
@@ -997,7 +1025,10 @@ static void ob_pci_add_properties(phandle_t phandle,
}
pci_set_assigned_addresses(phandle, config, num_bars);
- OLDWORLD(pci_set_AAPL_address(config));
+
+ if (is_apple()) {
+ pci_set_AAPL_address(config);
+ }
PCI_DPRINTF("\n");
}
@@ -1397,9 +1428,11 @@ static void ob_pci_set_available(phandle_t host, unsigned long mem_base, unsigne
static void ob_pci_host_set_interrupt_map(phandle_t host)
{
- phandle_t dnode = 0;
- u32 props[128];
- int i;
+ phandle_t dnode = 0, pci_childnode = 0;
+ u32 props[128], intno;
+ int i, ncells, len;
+ u32 *val, addr;
+ char *reg;
#if defined(CONFIG_PPC)
phandle_t target_node;
@@ -1420,16 +1453,22 @@ 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
* On g3beige they all called just ide.
- * We take ata-3 and ata-4 which seems to work for both
- * at least for clients we care about */
- target_node = find_dev("/pci/mac-io/ata-3");
+ * We take 2 x ata-3 buses which seems to work for
+ * at least the clients we care about */
+ target_node = find_dev("/pci/mac-io/ata-3@20000");
set_int_property(target_node, "interrupt-parent", dnode);
- target_node = find_dev("/pci/mac-io/ata-4");
+ target_node = find_dev("/pci/mac-io/ata-3@21000");
set_int_property(target_node, "interrupt-parent", dnode);
target_node = find_dev("/pci/mac-io/via-cuda");
@@ -1437,69 +1476,61 @@ static void ob_pci_host_set_interrupt_map(phandle_t host)
target_node = find_dev("/pci");
set_int_property(target_node, "interrupt-parent", dnode);
-
- /* openpic interrupt mapping */
- for (i = 0; i < (7*8); i += 7) {
- props[i + PCI_INT_MAP_PCI0] = 0;
- props[i + PCI_INT_MAP_PCI1] = 0;
- props[i + PCI_INT_MAP_PCI2] = 0;
- props[i + PCI_INT_MAP_PCI_INT] = (i / 7) + 1; // starts at PINA=1
- props[i + PCI_INT_MAP_PIC_HANDLE] = dnode;
- props[i + PCI_INT_MAP_PIC_INT] = arch->irqs[i / 7];
- props[i + PCI_INT_MAP_PIC_POL] = 3;
- }
- set_property(host, "interrupt-map", (char *)props, 7 * 8 * sizeof(props[0]));
-
- props[PCI_INT_MAP_PCI0] = 0;
- props[PCI_INT_MAP_PCI1] = 0;
- props[PCI_INT_MAP_PCI2] = 0;
- props[PCI_INT_MAP_PCI_INT] = 0x7;
-
- set_property(host, "interrupt-map-mask", (char *)props, 4 * sizeof(props[0]));
}
-#elif defined(CONFIG_SPARC64)
- int ncells, len;
- u32 *val, addr;
- char *reg;
+#else
+ /* PCI host bridge is the default interrupt controller */
+ dnode = host;
+#endif
/* Set interrupt-map for PCI devices with an interrupt pin present */
ncells = 0;
PUSH(host);
fword("child");
- dnode = POP();
- while (dnode) {
- if (get_int_property(dnode, "interrupts", &len)) {
- reg = get_property(dnode, "reg", &len);
- if (reg) {
+ pci_childnode = POP();
+ while (pci_childnode) {
+ intno = get_int_property(pci_childnode, "interrupts", &len);
+ if (len && intno) {
+ reg = get_property(pci_childnode, "reg", &len);
+ if (len && reg) {
val = (u32 *)reg;
for (i = 0; i < (len / sizeof(u32)); i += 5) {
addr = val[i];
/* Device address is in 1st 32-bit word of encoded PCI address for config space */
- if (!(addr & 0x03000000)) {
+ if ((addr & PCI_RANGE_TYPE_MASK) == PCI_RANGE_CONFIG) {
+#if defined(CONFIG_SPARC64)
ncells += pci_encode_phys_addr(props + ncells, 0, 0, addr, 0, 0);
- props[ncells++] = 1; /* always interrupt pin 1 for QEMU */
- props[ncells++] = host;
- props[ncells++] = SUN4U_INTERRUPT(addr, 1);
+ props[ncells++] = intno;
+ props[ncells++] = dnode;
+ props[ncells++] = SUN4U_INTERRUPT(addr, intno);
+#elif defined(CONFIG_PPC)
+ ncells += pci_encode_phys_addr(props + ncells, 0, 0, addr, 0, 0);
+ props[ncells++] = intno;
+ props[ncells++] = dnode;
+ props[ncells++] = arch->irqs[intno - 1];
+ props[ncells++] = 3;
+#else
+ /* Keep compiler quiet */
+ dnode = dnode;
+#endif
}
}
}
}
- PUSH(dnode);
+ PUSH(pci_childnode);
fword("peer");
- dnode = POP();
+ pci_childnode = POP();
}
set_property(host, "interrupt-map", (char *)props, ncells * sizeof(props[0]));
props[0] = 0x0000f800;
props[1] = 0x0;
props[2] = 0x0;
- props[3] = 7;
+ props[3] = 0x7;
set_property(host, "interrupt-map-mask", (char *)props, 4 * sizeof(props[0]));
-#endif
}
int ob_pci_init(void)
diff --git a/qemu/roms/openbios/drivers/pci.fs b/qemu/roms/openbios/drivers/pci.fs
index 563b652a4..a7b56e1f8 100644
--- a/qemu/roms/openbios/drivers/pci.fs
+++ b/qemu/roms/openbios/drivers/pci.fs
@@ -12,59 +12,19 @@
rot encode-int encode+
;
-\ Get region offset for BAR reg
-: pci-bar-offset@ ( bar-reg -- off.lo off.hi -1 | 0 )
- " reg" active-package get-package-property 0= if
- begin
- decode-phys \ ( reg prop prop-len phys.lo phys.mid phys.hi )
- ff and 5 pick = if
- >r >r 3drop r> r>
- -1 exit
- else
- 2drop
- then
- \ Drop the size as we don't need it
- decode-int drop decode-int drop
- dup 0=
- until
- 3drop
- 0 exit
- else
- 0
- then
- ;
-
-\ Get region size for BAR reg
-: pci-bar-size@ ( bar-reg -- size )
- " reg" active-package get-package-property 0= if
- begin
- decode-phys \ ( reg prop prop-len phys.lo phys.mid phys.hi )
- ff and 5 pick = if
- 2drop decode-int drop
- decode-int
- >r 3drop r>
- exit
- else
- 2drop decode-int drop
- decode-int drop
- then
- dup 0=
- until
- 3drop
- 0 \ default size of 0 if BAR not found
- then
- ;
-
-\ Get base address for configured BAR reg
-: pci-bar-base@ ( bar-reg -- addr.lo addr.hi -1 | 0 )
+\ Get PCI physical address and size for configured BAR reg
+: pci-bar>pci-addr ( bar-reg -- addr.lo addr.mid addr.hi size -1 | 0 )
" assigned-addresses" active-package get-package-property 0= if
begin
decode-phys \ ( reg prop prop-len phys.lo phys.mid phys.hi )
- ff and 5 pick = if
- >r >r 3drop r> r>
+ dup ff and 6 pick = if
+ >r >r >r rot drop
+ decode-int drop decode-int
+ -rot 2drop
+ r> swap r> r> rot
-1 exit
else
- 2drop
+ 3drop
then
\ Drop the size as we don't need it
decode-int drop decode-int drop
@@ -77,16 +37,4 @@
then
;
-\ Get PCI bus address and size for configured BAR reg
-: pci-bar>pci-region ( bar-reg -- addr.lo addr.hi size )
- dup
- >r pci-bar-offset@ if
- swap r@ pci-bar-base@ if
- swap d+
- then
- swap r@ pci-bar-size@
- then
- r> drop
- ;
-
[THEN]
diff --git a/qemu/roms/openbios/drivers/pci.h b/qemu/roms/openbios/drivers/pci.h
index 84a2b2cf6..d5aa5f84a 100644
--- a/qemu/roms/openbios/drivers/pci.h
+++ b/qemu/roms/openbios/drivers/pci.h
@@ -59,6 +59,15 @@
#define PCI_MIN_GNT 0x3e /* 8 bits */
#define PCI_MAX_LAT 0x3f /* 8 bits */
+#define PCI_RANGE_RELOCATABLE 0x80000000
+#define PCI_RANGE_PREFETCHABLE 0x40000000
+#define PCI_RANGE_ALIASED 0x20000000
+#define PCI_RANGE_TYPE_MASK 0x03000000
+#define PCI_RANGE_MMIO_64BIT 0x03000000
+#define PCI_RANGE_MMIO 0x02000000
+#define PCI_RANGE_IOPORT 0x01000000
+#define PCI_RANGE_CONFIG 0x00000000
+
typedef struct {
u16 signature;
u8 reserved[0x16];
diff --git a/qemu/roms/openbios/drivers/sbus.c b/qemu/roms/openbios/drivers/sbus.c
index a9b26c0a0..4caa59aaf 100644
--- a/qemu/roms/openbios/drivers/sbus.c
+++ b/qemu/roms/openbios/drivers/sbus.c
@@ -369,31 +369,6 @@ sbus_probe_slot_ss600mp(unsigned int slot, uint64_t base)
}
}
-static void
-ob_sbus_open(void)
-{
- int ret=1;
- RET ( -ret );
-}
-
-static void
-ob_sbus_close(void)
-{
- selfword("close-deblocker");
-}
-
-static void
-ob_sbus_initialize(void)
-{
-}
-
-
-NODE_METHODS(ob_sbus_node) = {
- { NULL, ob_sbus_initialize },
- { "open", ob_sbus_open },
- { "close", ob_sbus_close },
-};
-
struct sbus_offset {
int slot, type;
uint64_t base;
diff --git a/qemu/roms/openbios/drivers/usbohci_private.h b/qemu/roms/openbios/drivers/usbohci_private.h
index b3a723e21..99c964100 100644
--- a/qemu/roms/openbios/drivers/usbohci_private.h
+++ b/qemu/roms/openbios/drivers/usbohci_private.h
@@ -43,7 +43,7 @@
// FIXME: fake
typedef enum { CMD} reg;
- enum {
+ extern enum {
NumberDownstreamPorts = 1<<0,
PowerSwitchingMode = 1<<8,
NoPowerSwitching = 1<<9,
@@ -53,17 +53,17 @@
PowerOnToPowerGoodTime = 1<<24
} HcRhDescriptorAReg;
- enum {
+ extern enum {
NumberDownstreamPortsMask = MASK(0, 8),
PowerOnToPowerGoodTimeMask = MASK(24, 8)
} HcRhDescriptorAMask;
- enum {
+ extern enum {
DeviceRemovable = 1<<0,
PortPowerControlMask = 1<<16
} HcRhDescriptorBReg;
- enum {
+ extern enum {
CurrentConnectStatus = 1<<0,
PortEnableStatus = 1<<1,
PortSuspendStatus = 1<<2,
@@ -77,7 +77,7 @@
PortOverCurrentIndicatorChange = 1<<19,
PortResetStatusChange = 1<<20
} HcRhPortStatusRead;
- enum {
+ extern enum {
ClearPortEnable = 1<<0,
SetPortEnable = 1<<1,
SetPortSuspend = 1<<2,
@@ -87,7 +87,7 @@
ClearPortPower = 1<<9,
} HcRhPortStatusSet;
- enum {
+ extern enum {
LocalPowerStatus = 1<<0,
OverCurrentIndicator = 1<<1,
DeviceRemoteWakeupEnable = 1<<15,
@@ -96,18 +96,18 @@
ClearRemoteWakeupEnable = 1<<31
} HcRhStatusReg;
- enum {
+ extern enum {
FrameInterval = 1<<0,
FSLargestDataPacket = 1<<16,
FrameIntervalToggle = 1<<31
} HcFmIntervalOffset;
- enum {
+ extern enum {
FrameIntervalMask = MASK(0, 14),
FSLargestDataPacketMask = MASK(16, 15),
FrameIntervalToggleMask = MASK(31, 1)
} HcFmIntervalMask;
- enum {
+ extern enum {
ControlBulkServiceRatio = 1<<0,
PeriodicListEnable = 1<<2,
IsochronousEnable = 1<<3,
@@ -119,7 +119,7 @@
RemoteWakeupEnable = 1<<10
} HcControlReg;
- enum {
+ extern enum {
ControlBulkServiceRatioMask = MASK(0, 2),
HostControllerFunctionalStateMask = MASK(6, 2)
} HcControlMask;
@@ -131,7 +131,7 @@
USBSuspend = 3*HostControllerFunctionalState
};
- enum {
+ extern enum {
HostControllerReset = 1<<0,
ControlListFilled = 1<<1,
BulkListFilled = 1<<2,
@@ -139,16 +139,16 @@
SchedulingOverrunCount = 1<<16
} HcCommandStatusReg;
- enum {
+ extern enum {
SchedulingOverrunCountMask = MASK(16, 2)
} HcCommandStatusMask;
- enum {
+ extern enum {
FrameRemaining = 1<<0,
FrameRemainingToggle = 1<<31
} HcFmRemainingReg;
- enum {
+ extern enum {
SchedulingOverrung = 1<<0,
WritebackDoneHead = 1<<1,
StartofFrame = 1<<2,
diff --git a/qemu/roms/openbios/drivers/vga.fs b/qemu/roms/openbios/drivers/vga.fs
index ec4c6c5f1..29a043a7a 100644
--- a/qemu/roms/openbios/drivers/vga.fs
+++ b/qemu/roms/openbios/drivers/vga.fs
@@ -109,16 +109,17 @@ h# 1 constant VBE_DISPI_ENABLED
\ PCI
\
-" pci-bar>pci-region" (find-xt) value pci-bar>pci-region-xt
-: pci-bar>pci-region pci-bar>pci-region-xt execute ;
+" pci-bar>pci-addr" (find-xt) value pci-bar>pci-addr-xt
+: pci-bar>pci-addr pci-bar>pci-addr-xt execute ;
h# 10 constant cfg-bar0 \ Framebuffer BAR
-1 value fb-addr
: map-fb ( -- )
- cfg-bar0 pci-bar>pci-region \ ( pci-addr.lo pci-addr.hi size )
- " pci-map-in" $call-parent
- to fb-addr
+ cfg-bar0 pci-bar>pci-addr if \ ( pci-addr.lo pci-addr.mid pci-addr.hi size )
+ " pci-map-in" $call-parent
+ to fb-addr
+ then
;
\
diff --git a/qemu/roms/openbios/forth/lib/string.fs b/qemu/roms/openbios/forth/lib/string.fs
index eb6474917..f97db232f 100644
--- a/qemu/roms/openbios/forth/lib/string.fs
+++ b/qemu/roms/openbios/forth/lib/string.fs
@@ -125,3 +125,17 @@
: parse-hex ( str len -- value )
base @ hex -rot $number if 0 then swap base !
;
+
+
+\ -----------------------------------------------------
+\ miscellaneous functions
+\ -----------------------------------------------------
+
+: rot13 ( c - c )
+ dup upc [char] A [char] M between if d# 13 + exit then
+ dup upc [char] N [char] Z between if d# 13 - then
+;
+
+: rot13-str ( str len -- newstr len )
+ strdup 2dup bounds ?do i c@ rot13 i c! loop
+;
diff --git a/qemu/roms/openbios/forth/system/ciface.fs b/qemu/roms/openbios/forth/system/ciface.fs
index fd6c54efd..85a607627 100644
--- a/qemu/roms/openbios/forth/system/ciface.fs
+++ b/qemu/roms/openbios/forth/system/ciface.fs
@@ -326,6 +326,14 @@ external
: exit ( -- )
." EXIT"
+
+ \ Execute (exit) hook if one exists
+ s" (exit)" $find if
+ execute
+ else
+ 2drop
+ then
+
outer-interpreter
;
diff --git a/qemu/roms/openbios/include/arch/ppc/types.h b/qemu/roms/openbios/include/arch/ppc/types.h
index 69b3db405..b2246d060 100644
--- a/qemu/roms/openbios/include/arch/ppc/types.h
+++ b/qemu/roms/openbios/include/arch/ppc/types.h
@@ -84,21 +84,13 @@ typedef uint32_t prom_uarg_t;
/* size named types */
typedef unsigned char u8;
-typedef unsigned char __u8;
typedef unsigned short u16;
-typedef unsigned short __u16;
typedef unsigned int u32;
-typedef unsigned int __u32;
typedef unsigned long long u64;
-typedef unsigned long long __u64;
typedef signed char s8;
-typedef signed char __s8;
typedef short s16;
-typedef short __s16;
typedef int s32;
-typedef int __s32;
typedef long long s64;
-typedef long long __s64;
#endif
diff --git a/qemu/roms/openbios/include/arch/sparc64/io.h b/qemu/roms/openbios/include/arch/sparc64/io.h
index 2e4dfa37f..0f1a73284 100644
--- a/qemu/roms/openbios/include/arch/sparc64/io.h
+++ b/qemu/roms/openbios/include/arch/sparc64/io.h
@@ -9,7 +9,7 @@
extern unsigned long va_shift; // Set in entry.S
// Defined in ldscript
-extern char _start, _data, _stack, _estack, _end, _iomem;
+extern char _start, _data, _stack, _estack, _fcstack, _efcstack, _end, _iomem;
// XXX check use and merge
#define phys_to_virt(phys) ((void *) ((unsigned long) (phys)))
diff --git a/qemu/roms/openbios/include/drivers/drivers.h b/qemu/roms/openbios/include/drivers/drivers.h
index 3b83b12d1..48f81a870 100644
--- a/qemu/roms/openbios/include/drivers/drivers.h
+++ b/qemu/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/qemu/roms/openbios/include/libopenbios/bindings.h b/qemu/roms/openbios/include/libopenbios/bindings.h
index de9c77520..4ec978912 100644
--- a/qemu/roms/openbios/include/libopenbios/bindings.h
+++ b/qemu/roms/openbios/include/libopenbios/bindings.h
@@ -56,6 +56,7 @@ extern ihandle_t open_package( const char *argstr, phandle_t ph );
extern ihandle_t open_dev( const char *spec );
extern void close_package( ihandle_t ih );
extern void close_dev( ihandle_t ih );
+extern char *get_path_from_ph( phandle_t ph );
/* property access */
extern void set_property( phandle_t ph, const char *name,
diff --git a/qemu/roms/openbios/libopenbios/bindings.c b/qemu/roms/openbios/libopenbios/bindings.c
index 5323421f5..4f7a99379 100644
--- a/qemu/roms/openbios/libopenbios/bindings.c
+++ b/qemu/roms/openbios/libopenbios/bindings.c
@@ -366,6 +366,14 @@ find_dev( const char *path )
return ret;
}
+char *
+get_path_from_ph( phandle_t ph )
+{
+ PUSH(ph);
+ fword("get-package-path");
+ return pop_fstr_copy();
+}
+
phandle_t
dt_iter_begin( void )
{
diff --git a/qemu/roms/openbios/libopenbios/bootinfo_load.c b/qemu/roms/openbios/libopenbios/bootinfo_load.c
index fa9e36bd4..f33678185 100644
--- a/qemu/roms/openbios/libopenbios/bootinfo_load.c
+++ b/qemu/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);
diff --git a/qemu/roms/seabios/.version b/qemu/roms/seabios/.version
index a96337339..89c0c6acb 100644
--- a/qemu/roms/seabios/.version
+++ b/qemu/roms/seabios/.version
@@ -1 +1 @@
-rel-1.8.2-0-g33fbe13
+rel-1.9.1-0-gb3ef39f
diff --git a/qemu/roms/seabios/Makefile b/qemu/roms/seabios/Makefile
index 83cdff377..4e4092d07 100644
--- a/qemu/roms/seabios/Makefile
+++ b/qemu/roms/seabios/Makefile
@@ -34,15 +34,16 @@ SRCBOTH=misc.c stacks.c output.c string.c block.c cdrom.c disk.c mouse.c kbd.c \
hw/usb.c hw/usb-uhci.c hw/usb-ohci.c hw/usb-ehci.c \
hw/usb-hid.c hw/usb-msc.c hw/usb-uas.c \
hw/blockcmd.c hw/floppy.c hw/ata.c hw/ramdisk.c \
- hw/virtio-ring.c hw/virtio-pci.c hw/virtio-blk.c hw/virtio-scsi.c \
hw/lsi-scsi.c hw/esp-scsi.c hw/megasas.c
SRC16=$(SRCBOTH)
-SRC32FLAT=$(SRCBOTH) post.c memmap.c malloc.c romfile.c x86.c optionroms.c \
- pmm.c font.c boot.c bootsplash.c jpeg.c bmp.c \
+SRC32FLAT=$(SRCBOTH) post.c e820map.c malloc.c romfile.c x86.c optionroms.c \
+ pmm.c font.c boot.c bootsplash.c jpeg.c bmp.c tcgbios.c sha1.c \
hw/ahci.c hw/pvscsi.c hw/usb-xhci.c hw/usb-hub.c hw/sdcard.c \
- fw/coreboot.c fw/lzmadecode.c fw/csm.c fw/biostables.c \
+ fw/coreboot.c fw/lzmadecode.c fw/multiboot.c fw/csm.c fw/biostables.c \
fw/paravirt.c fw/shadow.c fw/pciinit.c fw/smm.c fw/smp.c fw/mtrr.c fw/xen.c \
- fw/acpi.c fw/mptable.c fw/pirtable.c fw/smbios.c fw/romfile_loader.c
+ fw/acpi.c fw/mptable.c fw/pirtable.c fw/smbios.c fw/romfile_loader.c \
+ hw/virtio-ring.c hw/virtio-pci.c hw/virtio-blk.c hw/virtio-scsi.c \
+ hw/tpm_drivers.c
SRC32SEG=string.c output.c pcibios.c apm.c stacks.c hw/pci.c hw/serialio.c
DIRS=src src/hw src/fw vgasrc
@@ -50,6 +51,8 @@ DIRS=src src/hw src/fw vgasrc
cc-option=$(shell if test -z "`$(1) $(2) -S -o /dev/null -xc /dev/null 2>&1`" \
; then echo "$(2)"; else echo "$(3)"; fi ;)
+EXTRAVERSION=
+
CPPFLAGS = -P -MD -MT $@
COMMONCFLAGS := -I$(OUT) -Isrc -Os -MD -g \
@@ -62,6 +65,7 @@ COMMONCFLAGS := -I$(OUT) -Isrc -Os -MD -g \
COMMONCFLAGS += $(call cc-option,$(CC),-nopie,)
COMMONCFLAGS += $(call cc-option,$(CC),-fno-stack-protector,)
COMMONCFLAGS += $(call cc-option,$(CC),-fno-stack-protector-all,)
+COMMONCFLAGS += $(call cc-option,$(CC),-fstack-check=no,)
COMMA := ,
CFLAGS32FLAT := $(COMMONCFLAGS) -DMODE16=0 -DMODESEGMENT=0
@@ -152,10 +156,10 @@ $(OUT)romlayout.o: src/romlayout.S $(OUT)autoconf.h $(OUT)asm-offsets.h
@echo " Compiling (16bit) $@"
$(Q)$(CC) $(CFLAGS16) -c -D__ASSEMBLY__ $< -o $@
-$(OUT)romlayout16.lds: $(OUT)ccode32flat.o $(OUT)code32seg.o $(OUT)ccode16.o $(OUT)romlayout.o scripts/layoutrom.py scripts/buildversion.sh
+$(OUT)romlayout16.lds: $(OUT)ccode32flat.o $(OUT)code32seg.o $(OUT)ccode16.o $(OUT)romlayout.o src/version.c scripts/layoutrom.py scripts/buildversion.py
@echo " Building ld scripts"
- $(Q)BUILD_VERSION="$(VERSION)" ./scripts/buildversion.sh $(OUT)version.c
- $(Q)$(CC) $(CFLAGS32FLAT) -c $(OUT)version.c -o $(OUT)version.o
+ $(Q)$(PYTHON) ./scripts/buildversion.py -e "$(EXTRAVERSION)" -t "$(CC);$(AS);$(LD);$(OBJCOPY);$(OBJDUMP);$(STRIP)" $(OUT)autoversion.h
+ $(Q)$(CC) $(CFLAGS32FLAT) -c src/version.c -o $(OUT)version.o
$(Q)$(LD) $(LD32BIT_FLAG) -r $(OUT)ccode32flat.o $(OUT)version.o -o $(OUT)code32flat.o
$(Q)$(LD) $(LD32BIT_FLAG) -r $(OUT)ccode16.o $(OUT)romlayout.o -o $(OUT)code16.o
$(Q)$(OBJDUMP) -thr $(OUT)code32flat.o > $(OUT)code32flat.o.objdump
@@ -177,7 +181,7 @@ $(OUT)rom32seg.o: $(OUT)code32seg.o $(OUT)romlayout32seg.lds
$(OUT)rom.o: $(OUT)rom16.strip.o $(OUT)rom32seg.strip.o $(OUT)code32flat.o $(OUT)romlayout32flat.lds
@echo " Linking $@"
- $(Q)$(LD) -T $(OUT)romlayout32flat.lds $(OUT)rom16.strip.o $(OUT)rom32seg.strip.o $(OUT)code32flat.o -o $@
+ $(Q)$(LD) -N -T $(OUT)romlayout32flat.lds $(OUT)rom16.strip.o $(OUT)rom32seg.strip.o $(OUT)code32flat.o -o $@
$(OUT)bios.bin.prep: $(OUT)rom.o scripts/checkrom.py
@echo " Prepping $@"
@@ -224,10 +228,10 @@ $(OUT)vgaentry.o: vgasrc/vgaentry.S $(OUT)autoconf.h $(OUT)asm-offsets.h
@echo " Compiling (16bit) $@"
$(Q)$(CC) $(CFLAGS16) -c -D__ASSEMBLY__ $< -o $@
-$(OUT)vgarom.o: $(OUT)vgaccode16.o $(OUT)vgaentry.o $(OUT)vgasrc/vgalayout.lds scripts/buildversion.sh
+$(OUT)vgarom.o: $(OUT)vgaccode16.o $(OUT)vgaentry.o $(OUT)vgasrc/vgalayout.lds vgasrc/vgaversion.c scripts/buildversion.py
@echo " Linking $@"
- $(Q)BUILD_VERSION="$(VERSION)" ./scripts/buildversion.sh $(OUT)vgaversion.c VAR16
- $(Q)$(CC) $(CFLAGS16) -c $(OUT)vgaversion.c -o $(OUT)vgaversion.o
+ $(Q)$(PYTHON) ./scripts/buildversion.py -e "$(EXTRAVERSION)" -t "$(CC);$(AS);$(LD);$(OBJCOPY);$(OBJDUMP);$(STRIP)" $(OUT)autovgaversion.h
+ $(Q)$(CC) $(CFLAGS16) -c vgasrc/vgaversion.c -o $(OUT)vgaversion.o
$(Q)$(LD) --gc-sections -T $(OUT)vgasrc/vgalayout.lds $(OUT)vgaccode16.o $(OUT)vgaentry.o $(OUT)vgaversion.o -o $@
$(OUT)vgabios.bin.raw: $(OUT)vgarom.o
diff --git a/qemu/roms/seabios/docs/Build_overview.md b/qemu/roms/seabios/docs/Build_overview.md
index 26db22691..8c6b2f458 100644
--- a/qemu/roms/seabios/docs/Build_overview.md
+++ b/qemu/roms/seabios/docs/Build_overview.md
@@ -52,6 +52,34 @@ CSM_ENABLE'. The SeaBIOS binary will be included as a discrete file
within the 'Flash Volume' which is created, and there are tools which
will extract it and allow it to be replaced.
+Distribution builds
+===================
+
+If one is building a binary version of SeaBIOS as part of a package
+(such as an rpm) or for wide distribution, please provide the
+EXTRAVERSION field during the build. For example:
+
+`make EXTRAVERSION="-${RPM_PACKAGE_RELEASE}"`
+
+The EXTRAVERSION field should provide the package version (if
+applicable) and the name of the distribution (if that's not already
+obvious from the package version). This string will be appended to the
+main SeaBIOS version. The above information helps SeaBIOS developers
+correlate defect reports to the source code and build environment.
+
+If one is building a binary in a build environment that does not have
+access to the git tool or does not have the full SeaBIOS git repo
+available, then please use an official SeaBIOS release tar file as
+source. If building from a snapshot (where there is no official
+SeaBIOS tar) then one should generate a snapshot tar file on a machine
+that does support git using the scripts/tarball.sh tool. For example:
+
+`scripts/tarball.sh`
+
+The tarball.sh script encodes version information in the resulting tar
+file which the build can extract and include in the final binary. The
+above EXTRAVERSION field should still be set when building from a tar.
+
Overview of files in the repository
===================================
@@ -61,11 +89,7 @@ drivers. The **src/fw/** directory contains source code for platform
firmware initialization. The **src/std/** directory contains header
files describing standard bios, firmware, and hardware interfaces.
-The **vgasrc/** directory contains code for VGA BIOS implementations.
-This code is separate from the main BIOS code in the src/ directory.
-When the build is configured to produce a VGA BIOS the resulting
-binary is found in out/vgabios.bin. The VGA BIOS code is always
-compiled in 16bit mode.
+The **vgasrc/** directory contains code for [SeaVGABIOS](SeaVGABIOS).
The **scripts/** directory contains helper utilities for manipulating
and building the final roms.
diff --git a/qemu/roms/seabios/docs/Contributing.md b/qemu/roms/seabios/docs/Contributing.md
new file mode 100644
index 000000000..d0f2b5b5e
--- /dev/null
+++ b/qemu/roms/seabios/docs/Contributing.md
@@ -0,0 +1,20 @@
+SeaBIOS welcomes contributions of code (either fixing bugs or adding
+new functionality). At a high level, the process to contribute a
+change is:
+
+1. [Obtain](Download) the current code and documentation
+2. Enhance and test the code locally
+3. Submit changes to the SeaBIOS [mailing list](Mailinglist) as a
+ patch
+4. Receive feedback, answer questions, and possibly provide updated
+ patches
+5. When accepted, a maintainer (Kevin O'Connor or Gerd Hoffman) will
+ commit the change to the master SeaBIOS repository
+
+The SeaBIOS patch submission process is similar to the
+[QEMU process](http://wiki.qemu.org/Contribute/SubmitAPatch). Please
+review the QEMU process for more details and tips on the best way to
+submit patches. The SeaBIOS C code does follow a slightly different
+coding style from QEMU (eg, mixed code and C99 style variable
+declarations are encouraged, braces are not required around single
+statement blocks), however patches in the QEMU style are acceptable.
diff --git a/qemu/roms/seabios/docs/Debugging.md b/qemu/roms/seabios/docs/Debugging.md
index 03567de4d..7ab5d02d8 100644
--- a/qemu/roms/seabios/docs/Debugging.md
+++ b/qemu/roms/seabios/docs/Debugging.md
@@ -55,8 +55,10 @@ rate.
The tool can also timestamp the messages from the QEMU debug port. To
use with QEMU run the following:
-`mkfifo qemudebugpipe`\
-`qemu -chardev pipe,path=qemudebugpipe,id=seabios -device isa-debugcon,iobase=0x402,chardev=seabios ...`
+```
+mkfifo qemudebugpipe
+qemu -chardev pipe,path=qemudebugpipe,id=seabios -device isa-debugcon,iobase=0x402,chardev=seabios ...
+```
and then in another session:
@@ -84,20 +86,23 @@ bios 16bit code) or out/rom.o (to debug bios 32bit code). For example:
`gdb out/rom16.o`
-Once in gdb, use the command "target remote localhost:1234" to have
+Once in gdb, use the command `target remote localhost:1234` to have
gdb connect to QEMU. See the QEMU documentation for more information
on using gdb and QEMU in this mode.
-When debugging 16bit code, also run the following commands in gdb:
+When debugging 16bit code it is necessary to load the 16bit symbols
+twice in order for gdb to properly handle break points. To do this,
+run the following command `objcopy --adjust-vma 0xf0000 out/rom16.o
+rom16offset.o` and then run the following in gdb:
-`set architecture i8086`\
-`add-symbol-file out/rom16.o 0xf0000`
+```
+set architecture i8086
+add-symbol-file rom16offset.o 0
+```
-The second command loads the 16bit symbols a second time at an offset
-of 0xf0000, which helps gdb set and catch breakpoints correctly.
-
-To debug a VGA BIOS image, run "gdb out/vgarom.o" add use the gdb
-command "add-symbol-file out/vgarom.o 0xc0000" to load the 16bit VGA
+To debug a VGA BIOS image, run `gdb out/vgarom.o`, create a
+vgaromoffset.o file with offset 0xc0000, add use the gdb
+command `add-symbol-file out/vgaromoffset.o 0` to load the 16bit VGA
BIOS symbols twice.
If debugging the 32bit SeaBIOS initialization code with gdb, note that
diff --git a/qemu/roms/seabios/docs/Developer_Documentation.md b/qemu/roms/seabios/docs/Developer_Documentation.md
index d50455d36..24bf48a3e 100644
--- a/qemu/roms/seabios/docs/Developer_Documentation.md
+++ b/qemu/roms/seabios/docs/Developer_Documentation.md
@@ -10,15 +10,16 @@ page.
See details on [building SeaBIOS](Build overview).
There is also information on the SeaBIOS [Memory Model](Memory Model).
-
Along with information on SeaBIOS [Execution and code flow](Execution
-and code flow).
+and code flow). A description of the process of linking the final
+SeaBIOS binary is available at [Linking overview](Linking overview).
-A description of the process of linking the final SeaBIOS binary is
-available at [Linking overview](Linking overview).
+The list of available runtime configuration items is at
+[runtime config](Runtime_config).
To debug SeaBIOS and report problems see SeaBIOS
-[debugging](Debugging).
+[debugging](Debugging). To contribute changes to SeaBIOS see
+[contributing](Contributing).
Useful links to specifications is available at [Developer
links](Developer links).
diff --git a/qemu/roms/seabios/docs/Download.md b/qemu/roms/seabios/docs/Download.md
index a49c6fb74..9b1492ac5 100644
--- a/qemu/roms/seabios/docs/Download.md
+++ b/qemu/roms/seabios/docs/Download.md
@@ -9,8 +9,10 @@ The SeaBIOS project uses the [git](http://git-scm.com/) revision
control system. To download the latest source from revision control,
run:
-`$ git clone git://git.seabios.org/seabios.git seabios`\
-`$ cd seabios`
+```
+$ git clone git://git.seabios.org/seabios.git seabios
+$ cd seabios
+```
There's also a [website](http://git.seabios.org/) to browse the latest
source code online.
diff --git a/qemu/roms/seabios/docs/Execution_and_code_flow.md b/qemu/roms/seabios/docs/Execution_and_code_flow.md
index 9396ecaa4..a54776eef 100644
--- a/qemu/roms/seabios/docs/Execution_and_code_flow.md
+++ b/qemu/roms/seabios/docs/Execution_and_code_flow.md
@@ -36,7 +36,7 @@ process.
The POST phase itself has several sub-phases.
-* The "preinit" sub-phase: code run prior to code relocation.
+* The "preinit" sub-phase: code run prior to [code relocation](Linking overview#Code relocation).
* The "init" sub-phase: code to initialize internal variables and
interfaces.
* The "setup" sub-phase: code to setup hardware and drivers.
diff --git a/qemu/roms/seabios/docs/Linking_overview.md b/qemu/roms/seabios/docs/Linking_overview.md
index fb938b632..bcb8298c3 100644
--- a/qemu/roms/seabios/docs/Linking_overview.md
+++ b/qemu/roms/seabios/docs/Linking_overview.md
@@ -92,15 +92,9 @@ those situations where an address of a C function in another mode is
required the build supports symbols with a special "\_cfuncX_"
prefix. The layoutrom.py script detects these references and will emit
a corresponding symbol definitions in the linker script that points to
-the C code of the specified mode. This is typically seen with code
-like:
-
-`extern void _cfunc32flat_process_op(void);`\
-`return call32(_cfunc32flat_process_op, 0, 0);`
-
-In the above example, when the build finds the symbol
-"\_cfunc32flat_process_op" it will emit that symbol with the physical
-address of the 32bit "flat" version of the process_op() C function.
+the C code of the specified mode. The call32() and stack_hop_back()
+macros automatically add the required prefix for C code, but the
+prefixes need to be explicitly added in assembler code.
Build garbage collection
------------------------
diff --git a/qemu/roms/seabios/docs/Releases.md b/qemu/roms/seabios/docs/Releases.md
index 6a1ecd564..c24d3c0b7 100644
--- a/qemu/roms/seabios/docs/Releases.md
+++ b/qemu/roms/seabios/docs/Releases.md
@@ -1,6 +1,25 @@
History of SeaBIOS releases. Please see [download](Download) for
information on obtaining these releases.
+SeaBIOS 1.9.0
+=============
+
+Available on 20151117. Major changes in this release:
+
+* The default boot menu key is now the ESC key (instead of F12)
+* Initial support for Trusted Platform Module (TPM) hardware and BIOS calls
+* Initial support for chain loading SeaBIOS from Grub (via multiboot
+ support)
+* Initial support for booting from SD cards on real hardware
+* virtio 1.0 device support
+* The build will no longer include the build hostname or build time on
+ "clean" builds. This makes the build binaries more "reproducible".
+* Basic support for running SeaBIOS on Baytrail Chromebooks
+* SeaVGABIOS improvements:
+ * Improved support for old versions of x86emu (the "leal"
+ instruction is now emulated)
+* Several bug fixes and code cleanups
+
SeaBIOS 1.8.0
=============
@@ -23,6 +42,16 @@ two release numbers (eg, 1.8) and stable releases will use three
numbers (eg, 1.8.1). The prior behavior of using a forth number
(eg, 1.7.5.1) for stable releases will no longer be used.
+SeaBIOS 1.8.1
+-------------
+
+Available on 20150316. Stable release containing only bug fixes.
+
+SeaBIOS 1.8.2
+-------------
+
+Available on 20150617. Stable release containing only bug fixes.
+
SeaBIOS 1.7.5
=============
diff --git a/qemu/roms/seabios/docs/Runtime_config.md b/qemu/roms/seabios/docs/Runtime_config.md
new file mode 100644
index 000000000..d6fea2827
--- /dev/null
+++ b/qemu/roms/seabios/docs/Runtime_config.md
@@ -0,0 +1,191 @@
+SeaBIOS can read several configuration items at runtime. On coreboot
+the configuration comes from files located in CBFS. When SeaBIOS runs
+natively on QEMU the files are passed from QEMU via the fw_cfg
+interface.
+
+This page documents the user visible configuration and control
+features that SeaBIOS supports.
+
+LZMA compression
+================
+
+On coreboot, when scanning files in CBFS, any filename that ends with
+a ".lzma" suffix will be treated as a raw file that is compressed with
+the lzma compression algorithm. This works for option ROMs,
+configuration files, floppy images, etc. . (This feature should not be
+used with embedded payloads - to compress payloads, use the standard
+section based compression algorithm that is built into the payload
+specification.)
+
+For example, the file **pci1106,3344.rom.lzma** would be treated the
+same as **pci1106,3344.rom**, but will be automatically uncompressed
+when accessed.
+
+A file is typically compressed with the lzma compression command line
+tool. For example:
+
+`lzma -zc /path/to/somefile.bin > somefile.bin.lzma`
+
+However, some recent versions of lzma no longer supply an uncompressed
+file size in the lzma header. (They instead populate the field with
+zero.) Unfortunately, SeaBIOS requires the uncompressed file size, so
+it may be necessary to use a different version of the lzma tool.
+
+File aliases
+============
+
+It is possible to create the equivalent of "symbolic links" so that
+one file's content appears under another name. To do this, create a
+**links** file with one line per link and each line having the format
+of "linkname" and "destname" separated by a space character. For
+example, the **links** file may look like:
+
+```
+pci1234,1000.rom somerom.rom
+pci1234,1001.rom somerom.rom
+pci1234,1002.rom somerom.rom
+```
+
+The above example would cause SeaBIOS to treat "pci1234,1000.rom" or
+"pci1234,1001.rom" as files with the same content as the file
+"somerom.rom".
+
+Option ROMs
+===========
+
+SeaBIOS will scan all of the PCI devices in the target machine for
+option ROMs on PCI devices. It recognizes option ROMs in files that
+have the form **pciVVVV,DDDD.rom**. The VVVV,DDDD should correspond to
+the PCI vendor and device id of a device in the machine. If a given
+file is found then SeaBIOS will deploy the file instead of attempting
+to extract an option ROM from the device. In addition to supplying
+option ROMs for on-board devices that do not store their own ROMs,
+this mechanism may be used to prevent a ROM on a specific device from
+running.
+
+SeaBIOS always deploys the VGA rom associated with the active VGA
+device before any other ROMs.
+
+In addition, SeaBIOS will also run any file in the directory
+**vgaroms/** as a VGA option ROM not specific to a device and files in
+**genroms/** as a generic option ROM not specific to a device. The
+ROMS in **vgaroms/** are run immediately after running the option ROM
+associated with the primary VGA device (if any were found), and the
+**genroms/** ROMs are run after all other PCI ROMs are run.
+
+Bootsplash images
+=================
+
+SeaBIOS can show a custom [JPEG](http://en.wikipedia.org/wiki/JPEG)
+image or [BMP](http://en.wikipedia.org/wiki/BMP_file_format) image
+during bootup. To enable this, add the JPEG file to flash with the
+name **bootsplash.jpg** or BMP file as **bootsplash.bmp**.
+
+The size of the image determines the video mode to use for showing the
+image. Make sure the dimensions of the image exactly correspond to an
+available video mode (eg, 640x480, or 1024x768), otherwise it will not
+be displayed.
+
+SeaBIOS will show the image during the wait for the boot menu (if the
+boot menu has been disabled, users will not see the image). The image
+should probably have "Press ESC for boot menu" embedded in it so users
+know they can enter the normal SeaBIOS boot menu. By default, the boot
+menu prompt (and thus graphical image) is shown for 2.5 seconds. This
+can be customized via a [configuration
+parameter](#Other_Configuration_items).
+
+The JPEG viewer in SeaBIOS uses a simplified decoding algorithm. It
+supports most common JPEGs, but does not support all possible formats.
+Please see the [trouble reporting section](Debugging) if a valid image
+isn't displayed properly.
+
+Payloads
+========
+
+On coreboot, SeaBIOS will treat all files found in the **img/**
+directory as a coreboot payload. Each payload file will be available
+for boot, and one can select from the available payloads in the
+bootmenu. SeaBIOS supports both uncompressed and lzma compressed
+payloads.
+
+Floppy images
+=============
+
+It is possible to embed an image of a floppy into a file. SeaBIOS can
+then boot from and redirect floppy BIOS calls to the image. This is
+mainly useful for legacy software (such as DOS utilities). To use this
+feature, place a floppy image into the directory **floppyimg/**.
+
+Using LZMA file compression with the [.lzma file
+suffix](#LZMA_compression) is a useful way to reduce the file
+size. Several floppy formats are available: 360K, 1.2MB, 720K, 1.44MB,
+2.88MB, 160K, 180K, 320K.
+
+The floppy image will appear as writable to the system, however all
+writes are discarded on reboot.
+
+When using this system, SeaBIOS reserves high-memory to store the
+floppy. The reserved memory is then no longer available for OS use, so
+this feature should only be used when needed.
+
+Configuring boot order
+======================
+
+The **bootorder** file may be used to configure the boot up order. The
+file should be ASCII text and contain one line per boot method. The
+description of each boot method follows an [Open
+Firmware](https://secure.wikimedia.org/wikipedia/en/wiki/Open_firmware)
+device path format. SeaBIOS will attempt to boot from each item in the
+file - first line of the file first.
+
+The easiest way to find the available boot methods is to look for
+"Searching bootorder for" in the SeaBIOS debug output. For example,
+one may see lines similar to:
+
+```
+Searching bootorder for: /pci@i0cf8/*@f/drive@1/disk@0
+Searching bootorder for: /pci@i0cf8/*@f,1/drive@2/disk@1
+Searching bootorder for: /pci@i0cf8/usb@10,4/*@2
+```
+
+The above represents the patterns SeaBIOS will search for in the
+bootorder file. However, it's safe to just copy and paste the pattern
+into bootorder. For example, the file:
+
+```
+/pci@i0cf8/usb@10,4/*@2
+/pci@i0cf8/*@f/drive@1/disk@0
+```
+
+will instruct SeaBIOS to attempt to boot from the given USB drive
+first and then attempt the given ATA harddrive second.
+
+SeaBIOS also supports a special "HALT" directive. If a line that
+contains "HALT" is found in the bootorder file then SeaBIOS will (by
+default) only attempt to boot from devices explicitly listed above
+HALT in the file.
+
+Other Configuration items
+=========================
+
+There are several additional configuration options available in the
+**etc/** directory.
+
+| Filename | Description
+|---------------------|---------------------------------------------------
+| show-boot-menu | Controls the display of the boot menu. Set to 0 to disable the boot menu.
+| boot-menu-message | Customize the text boot menu message. Normally, when in text mode SeaBIOS will report the string "\\nPress ESC for boot menu.\\n\\n". This field allows the string to be changed. (This is a string field, and is added as a file containing the raw string.)
+| boot-menu-key | Controls which key activates the boot menu. The value stored is the DOS scan code (eg, 0x86 for F12, 0x01 for Esc). If this field is set, be sure to also customize the **boot-menu-message** field above.
+| boot-menu-wait | Amount of time (in milliseconds) to wait at the boot menu prompt before selecting the default boot.
+| boot-fail-wait | If no boot devices are found SeaBIOS will reboot after 60 seconds. Set this to the amount of time (in milliseconds) to customize the reboot delay or set to -1 to disable rebooting when no boot devices are found
+| extra-pci-roots | If the target machine has multiple independent root buses set this to a positive value. The SeaBIOS PCI probe will then search for the given number of extra root buses.
+| ps2-keyboard-spinup | Some laptops that emulate PS2 keyboards don't respond to keyboard commands immediately after powering on. One may specify the amount of time (in milliseconds) here to allow as additional time for the keyboard to become responsive. When this field is set, SeaBIOS will repeatedly attempt to detect the keyboard until the keyboard is found or the specified timeout is reached.
+| optionroms-checksum | Option ROMs are required to have correct checksums. However, some option ROMs in the wild don't correctly follow the specifications and have bad checksums. Set this to a zero value to allow SeaBIOS to execute them anyways.
+| pci-optionrom-exec | Controls option ROM execution for roms found on PCI devices (as opposed to roms found in CBFS/fw_cfg). Valid values are 0: Execute no ROMs, 1: Execute only VGA ROMs, 2: Execute all ROMs. The default is 2 (execute all ROMs).
+| s3-resume-vga-init | Set this to a non-zero value to instruct SeaBIOS to run the vga rom on an S3 resume.
+| screen-and-debug | Set this to a zero value to instruct SeaBIOS to not write characters it sends to the screen to the debug ports. This can be useful when using sgabios.
+| advertise-serial-debug-port | If using a serial debug port, one can set this file to a zero value to prevent SeaBIOS from listing that serial port as available for operating system use. This can be useful when running old DOS programs that are known to reset the baud rate of all advertised serial ports.
+| floppy0 | Set this to the type of the first floppy drive in the system (only type 4 for 3.5 inch drives is supported).
+| floppy1 | The type of the second floppy drive in the system. See the description of **floppy0** for more info.
+| threads | By default, SeaBIOS will parallelize hardware initialization during bootup to reduce boot time. Multiple hardware devices can be initialized in parallel between vga initialization and option rom initialization. One can set this file to a value of zero to force hardware initialization to run serially. Alternatively, one can set this file to 2 to enable early hardware initialization that runs in parallel with vga, option rom initialization, and the boot menu.
+| sdcard* | One may create one or more files with an "sdcard" prefix (eg, "etc/sdcard0") with the physical memory address of an SDHCI controller (one memory address per file). This may be useful for SDHCI controllers that do not appear as PCI devices, but are mapped to a consistent memory address.
diff --git a/qemu/roms/seabios/docs/SeaBIOS.md b/qemu/roms/seabios/docs/SeaBIOS.md
index 831bfced9..e24913a64 100644
--- a/qemu/roms/seabios/docs/SeaBIOS.md
+++ b/qemu/roms/seabios/docs/SeaBIOS.md
@@ -10,6 +10,8 @@ information on using SeaBIOS in coreboot. Please see the
[releases](Releases) page for information on recent releases. See the
[download](Download) page to obtain SeaBIOS.
+[SeaVGABIOS](SeaVGABIOS) is a sub-project of SeaBIOS.
+
Please join the [mailing list](Mailinglist) to contribute to
SeaBIOS. Information on the internals of SeaBIOS is available on the
[Developer Documentation](Developer Documentation) page.
diff --git a/qemu/roms/seabios/docs/SeaVGABIOS.md b/qemu/roms/seabios/docs/SeaVGABIOS.md
new file mode 100644
index 000000000..7ec27804d
--- /dev/null
+++ b/qemu/roms/seabios/docs/SeaVGABIOS.md
@@ -0,0 +1,39 @@
+SeaVGABIOS is a sub-project of the SeaBIOS project - it is an open
+source implementation of a 16bit X86
+[VGA BIOS](http://en.wikipedia.org/wiki/Video_BIOS). SeaVGABIOS is the
+default VGA BIOS on [QEMU](http://www.qemu.org/). SeaVGABIOS can also
+run natively on some X86 VGA hardware with
+[coreboot](http://www.coreboot.org/).
+
+Building SeaVGABIOS
+===================
+
+To build SeaVGABIOS, obtain the [code](Download), run `make
+menuconfig` and select the type of VGA BIOS to build in the "VGA ROM"
+menu. Once selected, run `make` and the final VGA BIOS binary will be
+located in "out/vgabios.bin".
+
+The choice of available VGA BIOSes within "make menuconfig" is
+dependent on whether CONFIG_QEMU, CONFIG_COREBOOT, or CONFIG_CSM is
+selected. Also, the debug options under the "Debugging" menu apply to
+SeaVGABIOS. All other options found in "make menuconfig" apply only to
+SeaBIOS and will not impact the SeaVGABIOS build.
+
+If SeaVGABIOS is needed for multiple different devices (eg, QEMU's
+cirrus emulation and QEMU's "dispi" emulation), then one must compile
+SeaVGABIOS multiple times with the appropriate config for each build.
+
+SeaVGABIOS code
+===============
+
+The source code for SeaVGABIOS is located in the SeaBIOS
+[git repository](Download). The main VGA BIOS code is located in the
+"vgasrc/" directory. The VGA BIOS code is always compiled in 16bit
+mode.
+
+The SeaVGABIOS builds to a separate binary from the main SeaBIOS
+binary, and much of the VGA BIOS code is separate from the main BIOS
+code. However, much of the SeaBIOS
+[developer documentation](Developer_Documentation) applies to
+SeaVGABIOS. To contribute, please join the
+[SeaBIOS mailing list](Mailinglist).
diff --git a/qemu/roms/seabios/scripts/buildversion.py b/qemu/roms/seabios/scripts/buildversion.py
new file mode 100755
index 000000000..46928984e
--- /dev/null
+++ b/qemu/roms/seabios/scripts/buildversion.py
@@ -0,0 +1,134 @@
+#!/usr/bin/env python
+# Generate version information for a program
+#
+# Copyright (C) 2015 Kevin O'Connor <kevin@koconnor.net>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+import sys, os, subprocess, shlex, time, socket, optparse, logging, traceback
+
+VERSION_FORMAT = """
+/* DO NOT EDIT! This is an autogenerated file. See scripts/buildversion.py. */
+#define BUILD_VERSION "%s"
+#define BUILD_TOOLS "%s"
+"""
+
+# Run program and return the specified output
+def check_output(prog):
+ logging.debug("Running %s" % (repr(prog),))
+ try:
+ process = subprocess.Popen(shlex.split(prog), stdout=subprocess.PIPE)
+ output = process.communicate()[0]
+ retcode = process.poll()
+ except OSError:
+ logging.debug("Exception on run: %s" % (traceback.format_exc(),))
+ return ""
+ logging.debug("Got (code=%s): %s" % (retcode, repr(output)))
+ if retcode:
+ return ""
+ try:
+ return output.decode()
+ except UnicodeError:
+ logging.debug("Exception on decode: %s" % (traceback.format_exc(),))
+ return ""
+
+# Obtain version info from "git" program
+def git_version():
+ if not os.path.exists('.git'):
+ logging.debug("No '.git' file/directory found")
+ return ""
+ ver = check_output("git describe --tags --long --dirty").strip()
+ logging.debug("Got git version: %s" % (repr(ver),))
+ return ver
+
+# Look for version in a ".version" file. Official release tarballs
+# have this file (see scripts/tarball.sh).
+def file_version():
+ if not os.path.isfile('.version'):
+ logging.debug("No '.version' file found")
+ return ""
+ try:
+ f = open('.version', 'r')
+ ver = f.readline().strip()
+ f.close()
+ except OSError:
+ logging.debug("Exception on read: %s" % (traceback.format_exc(),))
+ return ""
+ logging.debug("Got .version: %s" % (repr(ver),))
+ return ver
+
+# Generate an output file with the version information
+def write_version(outfile, version, toolstr):
+ logging.debug("Write file %s and %s" % (repr(version), repr(toolstr)))
+ sys.stdout.write("Version: %s\n" % (version,))
+ f = open(outfile, 'w')
+ f.write(VERSION_FORMAT % (version, toolstr))
+ f.close()
+
+# Run "tool --version" for each specified tool and extract versions
+def tool_versions(tools):
+ tools = [t.strip() for t in tools.split(';')]
+ versions = ['', '']
+ success = 0
+ for tool in tools:
+ # Extract first line from "tool --version" output
+ verstr = check_output("%s --version" % (tool,)).split('\n')[0]
+ # Check if this tool looks like a binutils program
+ isbinutils = 0
+ if verstr.startswith('GNU '):
+ isbinutils = 1
+ verstr = verstr[4:]
+ # Extract version information and exclude program name
+ if ' ' not in verstr:
+ continue
+ prog, ver = verstr.split(' ', 1)
+ if not prog or not ver:
+ continue
+ # Check for any version conflicts
+ if versions[isbinutils] and versions[isbinutils] != ver:
+ logging.debug("Mixed version %s vs %s" % (
+ repr(versions[isbinutils]), repr(ver)))
+ versions[isbinutils] = "mixed"
+ continue
+ versions[isbinutils] = ver
+ success += 1
+ cleanbuild = versions[0] and versions[1] and success == len(tools)
+ return cleanbuild, "gcc: %s binutils: %s" % (versions[0], versions[1])
+
+def main():
+ usage = "%prog [options] <outputheader.h>"
+ opts = optparse.OptionParser(usage)
+ opts.add_option("-e", "--extra", dest="extra", default="",
+ help="extra version string to append to version")
+ opts.add_option("-t", "--tools", dest="tools", default="",
+ help="list of build programs to extract version from")
+ opts.add_option("-v", action="store_true", dest="verbose",
+ help="enable debug messages")
+
+ options, args = opts.parse_args()
+ if len(args) != 1:
+ opts.error("Incorrect arguments")
+ outfile = args[0]
+ if options.verbose:
+ logging.basicConfig(level=logging.DEBUG)
+
+ cleanbuild, toolstr = tool_versions(options.tools)
+
+ ver = git_version()
+ cleanbuild = cleanbuild and 'dirty' not in ver
+ if not ver:
+ ver = file_version()
+ # We expect the "extra version" to contain information on the
+ # distributor and distribution package version (if
+ # applicable). It is a "clean" build if this is a build from
+ # an official release tarball and the above info is present.
+ cleanbuild = cleanbuild and ver and options.extra != ""
+ if not ver:
+ ver = "?"
+ if not cleanbuild:
+ btime = time.strftime("%Y%m%d_%H%M%S")
+ hostname = socket.gethostname()
+ ver = "%s-%s-%s" % (ver, btime, hostname)
+ write_version(outfile, ver + options.extra, toolstr)
+
+if __name__ == '__main__':
+ main()
diff --git a/qemu/roms/seabios/scripts/buildversion.sh b/qemu/roms/seabios/scripts/buildversion.sh
deleted file mode 100755
index 516aff5b2..000000000
--- a/qemu/roms/seabios/scripts/buildversion.sh
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/sh
-# Script to generate a C file with version information.
-OUTFILE="$1"
-VAR16MODE="$2"
-
-# Extract version info
-if [ -z "$BUILD_VERSION" ]; then
- if [ -d .git -o -f .git ]; then
- VERSION="`git describe --tags --long --dirty`"
- elif [ -f .version ]; then
- VERSION="`cat .version`"
- else
- VERSION="?"
- fi
- VERSION="${VERSION}-`date +"%Y%m%d_%H%M%S"`-`hostname`"
-else
- VERSION="$BUILD_VERSION"
-fi
-echo "Version: ${VERSION}"
-
-# Build header file
-if [ "$VAR16MODE" = "VAR16" ]; then
- cat > ${OUTFILE} <<EOF
-#include "types.h"
-char VERSION[] VAR16 = "${VERSION}";
-EOF
-else
- cat > ${OUTFILE} <<EOF
-char VERSION[] = "${VERSION}";
-EOF
-fi
diff --git a/qemu/roms/seabios/scripts/checkrom.py b/qemu/roms/seabios/scripts/checkrom.py
index 377277db5..aced5e2cf 100755
--- a/qemu/roms/seabios/scripts/checkrom.py
+++ b/qemu/roms/seabios/scripts/checkrom.py
@@ -39,7 +39,7 @@ def main():
finalsize = 256*1024
if datasize > finalsize:
print("Error! ROM doesn't fit (%d > %d)" % (datasize, finalsize))
- print(" You have to either increate the size (CONFIG_ROM_SIZE)")
+ print(" You have to either increase the size (CONFIG_ROM_SIZE)")
print(" or turn off some features (such as hardware support not")
print(" needed) to make it fit. Trying a more recent gcc version")
print(" might work too.")
diff --git a/qemu/roms/seabios/scripts/checkstack.py b/qemu/roms/seabios/scripts/checkstack.py
index b49b6c8cc..5d9b0bfaf 100755
--- a/qemu/roms/seabios/scripts/checkstack.py
+++ b/qemu/roms/seabios/scripts/checkstack.py
@@ -2,7 +2,7 @@
# Script that tries to find how much stack space each function in an
# object is using.
#
-# Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+# Copyright (C) 2008-2015 Kevin O'Connor <kevin@koconnor.net>
#
# This file may be distributed under the terms of the GNU GPLv3 license.
@@ -26,85 +26,84 @@ OUTPUTDESC = """
# insn_addr:called_function [u+c,t,usage_to_yield_point]
"""
+class function:
+ def __init__(self, funcaddr, funcname):
+ self.funcaddr = funcaddr
+ self.funcname = funcname
+ self.basic_stack_usage = 0
+ self.max_stack_usage = None
+ self.yield_usage = -1
+ self.max_yield_usage = None
+ self.total_calls = 0
+ # called_funcs = [(insnaddr, calladdr, stackusage), ...]
+ self.called_funcs = []
+ self.subfuncs = {}
+ # Update function info with a found "yield" point.
+ def noteYield(self, stackusage):
+ if self.yield_usage < stackusage:
+ self.yield_usage = stackusage
+ # Update function info with a found "call" point.
+ def noteCall(self, insnaddr, calladdr, stackusage):
+ if (calladdr, stackusage) in self.subfuncs:
+ # Already noted a nearly identical call - ignore this one.
+ return
+ self.called_funcs.append((insnaddr, calladdr, stackusage))
+ self.subfuncs[(calladdr, stackusage)] = 1
+
# Find out maximum stack usage for a function
-def calcmaxstack(funcs, funcaddr):
- info = funcs[funcaddr]
- # Find max of all nested calls.
- maxusage = info[1]
- maxyieldusage = doesyield = 0
- if info[3] is not None:
- maxyieldusage = info[3]
- doesyield = 1
- info[2] = maxusage
- info[4] = info[3]
+def calcmaxstack(info, funcs):
+ if info.max_stack_usage is not None:
+ return
+ info.max_stack_usage = max_stack_usage = info.basic_stack_usage
+ info.max_yield_usage = max_yield_usage = info.yield_usage
+ total_calls = 0
seenbefore = {}
- totcalls = 0
- for insnaddr, calladdr, usage in info[6]:
+ # Find max of all nested calls.
+ for insnaddr, calladdr, usage in info.called_funcs:
callinfo = funcs.get(calladdr)
if callinfo is None:
continue
- if callinfo[2] is None:
- calcmaxstack(funcs, calladdr)
- if callinfo[0] not in seenbefore:
- seenbefore[callinfo[0]] = 1
- totcalls += 1 + callinfo[5]
- funcnameroot = callinfo[0].split('.')[0]
+ calcmaxstack(callinfo, funcs)
+ if callinfo.funcname not in seenbefore:
+ seenbefore[callinfo.funcname] = 1
+ total_calls += callinfo.total_calls + 1
+ funcnameroot = callinfo.funcname.split('.')[0]
if funcnameroot in IGNORE:
# This called function is ignored - don't contribute it to
# the max stack.
continue
+ totusage = usage + callinfo.max_stack_usage
+ totyieldusage = usage + callinfo.max_yield_usage
if funcnameroot in STACKHOP:
- if usage > maxusage:
- maxusage = usage
- if callinfo[4] is not None:
- doesyield = 1
- if usage > maxyieldusage:
- maxyieldusage = usage
- continue
- totusage = usage + callinfo[2]
- if totusage > maxusage:
- maxusage = totusage
- if callinfo[4] is not None:
- doesyield = 1
- totyieldusage = usage + callinfo[4]
- if totyieldusage > maxyieldusage:
- maxyieldusage = totyieldusage
- info[2] = maxusage
- if doesyield:
- info[4] = maxyieldusage
- info[5] = totcalls
+ # Don't count children of this function
+ totusage = totyieldusage = usage
+ if totusage > max_stack_usage:
+ max_stack_usage = totusage
+ if callinfo.max_yield_usage >= 0 and totyieldusage > max_yield_usage:
+ max_yield_usage = totyieldusage
+ info.max_stack_usage = max_stack_usage
+ info.max_yield_usage = max_yield_usage
+ info.total_calls = total_calls
# Try to arrange output so that functions that call each other are
# near each other.
def orderfuncs(funcaddrs, availfuncs):
- l = [(availfuncs[funcaddr][5], availfuncs[funcaddr][0], funcaddr)
+ l = [(availfuncs[funcaddr].total_calls
+ , availfuncs[funcaddr].funcname, funcaddr)
for funcaddr in funcaddrs if funcaddr in availfuncs]
l.sort()
l.reverse()
out = []
while l:
count, name, funcaddr = l.pop(0)
- if funcaddr not in availfuncs:
+ info = availfuncs.get(funcaddr)
+ if info is None:
continue
- calladdrs = [calls[1] for calls in availfuncs[funcaddr][6]]
+ calladdrs = [calls[1] for calls in info.called_funcs]
del availfuncs[funcaddr]
- out = out + orderfuncs(calladdrs, availfuncs) + [funcaddr]
+ out = out + orderfuncs(calladdrs, availfuncs) + [info]
return out
-# Update function info with a found "yield" point.
-def noteYield(info, stackusage):
- prevyield = info[3]
- if prevyield is None or prevyield < stackusage:
- info[3] = stackusage
-
-# Update function info with a found "call" point.
-def noteCall(info, subfuncs, insnaddr, calladdr, stackusage):
- if (calladdr, stackusage) in subfuncs:
- # Already noted a nearly identical call - ignore this one.
- return
- info[6].append((insnaddr, calladdr, stackusage))
- subfuncs[(calladdr, stackusage)] = 1
-
hex_s = r'[0-9a-f]+'
re_func = re.compile(r'^(?P<funcaddr>' + hex_s + r') <(?P<func>.*)>:$')
re_asm = re.compile(
@@ -114,11 +113,12 @@ re_asm = re.compile(
re_usestack = re.compile(
r'^(push[f]?[lw])|(sub.* [$](?P<num>0x' + hex_s + r'),%esp)$')
-def calc():
- # funcs[funcaddr] = [funcname, basicstackusage, maxstackusage
- # , yieldusage, maxyieldusage, totalcalls
- # , [(insnaddr, calladdr, stackusage), ...]]
- funcs = {-1: ['<indirect>', 0, 0, None, None, 0, []]}
+def main():
+ unknownfunc = function(None, "<unknown>")
+ indirectfunc = function(-1, '<indirect>')
+ unknownfunc.max_stack_usage = indirectfunc.max_stack_usage = 0
+ unknownfunc.max_yield_usage = indirectfunc.max_yield_usage = -1
+ funcs = {-1: indirectfunc}
cur = None
atstart = 0
stackusage = 0
@@ -129,99 +129,93 @@ def calc():
if m is not None:
# Found function
funcaddr = int(m.group('funcaddr'), 16)
- funcs[funcaddr] = cur = [m.group('func'), 0, None, None, None, 0, []]
+ funcs[funcaddr] = cur = function(funcaddr, m.group('func'))
stackusage = 0
atstart = 1
- subfuncs = {}
continue
m = re_asm.match(line)
- if m is not None:
- insn = m.group('insn')
-
- im = re_usestack.match(insn)
- if im is not None:
- if insn.startswith('pushl') or insn.startswith('pushfl'):
- stackusage += 4
- continue
- elif insn.startswith('pushw') or insn.startswith('pushfw'):
- stackusage += 2
- continue
- stackusage += int(im.group('num'), 16)
-
- if atstart:
- if '%esp' in insn or insn.startswith('leal'):
- # Still part of initial header
- continue
- cur[1] = stackusage
- atstart = 0
-
- insnaddr = m.group('insnaddr')
- calladdr = m.group('calladdr')
- if calladdr is None:
- if insn.startswith('lcallw'):
- noteCall(cur, subfuncs, insnaddr, -1, stackusage + 4)
- noteYield(cur, stackusage + 4)
- elif insn.startswith('int'):
- noteCall(cur, subfuncs, insnaddr, -1, stackusage + 6)
- noteYield(cur, stackusage + 6)
- elif insn.startswith('sti'):
- noteYield(cur, stackusage)
- else:
- # misc instruction
- continue
+ if m is None:
+ #print("other", repr(line))
+ continue
+ insn = m.group('insn')
+
+ im = re_usestack.match(insn)
+ if im is not None:
+ if insn.startswith('pushl') or insn.startswith('pushfl'):
+ stackusage += 4
+ continue
+ elif insn.startswith('pushw') or insn.startswith('pushfw'):
+ stackusage += 2
+ continue
+ stackusage += int(im.group('num'), 16)
+
+ if atstart:
+ if '%esp' in insn or insn.startswith('leal'):
+ # Still part of initial header
+ continue
+ cur.basic_stack_usage = stackusage
+ atstart = 0
+
+ insnaddr = m.group('insnaddr')
+ calladdr = m.group('calladdr')
+ if calladdr is None:
+ if insn.startswith('lcallw'):
+ cur.noteCall(insnaddr, -1, stackusage + 4)
+ cur.noteYield(stackusage + 4)
+ elif insn.startswith('int'):
+ cur.noteCall(insnaddr, -1, stackusage + 6)
+ cur.noteYield(stackusage + 6)
+ elif insn.startswith('sti'):
+ cur.noteYield(stackusage)
+ else:
+ # misc instruction
+ continue
+ else:
+ # Jump or call insn
+ calladdr = int(calladdr, 16)
+ ref = m.group('ref')
+ if '+' in ref:
+ # Inter-function jump.
+ pass
+ elif insn.startswith('j'):
+ # Tail call
+ cur.noteCall(insnaddr, calladdr, 0)
+ elif insn.startswith('calll'):
+ cur.noteCall(insnaddr, calladdr, stackusage + 4)
+ elif insn.startswith('callw'):
+ cur.noteCall(insnaddr, calladdr, stackusage + 2)
else:
- # Jump or call insn
- calladdr = int(calladdr, 16)
- ref = m.group('ref')
- if '+' in ref:
- # Inter-function jump.
- pass
- elif insn.startswith('j'):
- # Tail call
- noteCall(cur, subfuncs, insnaddr, calladdr, 0)
- elif insn.startswith('calll'):
- noteCall(cur, subfuncs, insnaddr, calladdr, stackusage + 4)
- elif insn.startswith('callw'):
- noteCall(cur, subfuncs, insnaddr, calladdr, stackusage + 2)
- else:
- print("unknown call", ref)
- noteCall(cur, subfuncs, insnaddr, calladdr, stackusage)
- # Reset stack usage to preamble usage
- stackusage = cur[1]
-
- #print("other", repr(line))
+ print("unknown call", ref)
+ cur.noteCall(insnaddr, calladdr, stackusage)
+ # Reset stack usage to preamble usage
+ stackusage = cur.basic_stack_usage
# Calculate maxstackusage
- for funcaddr, info in funcs.items():
- if info[2] is not None:
- continue
- calcmaxstack(funcs, funcaddr)
+ for info in funcs.values():
+ calcmaxstack(info, funcs)
# Sort functions for output
- funcaddrs = orderfuncs(funcs.keys(), funcs.copy())
+ funcinfos = orderfuncs(funcs.keys(), funcs.copy())
# Show all functions
print(OUTPUTDESC)
- for funcaddr in funcaddrs:
- name, basicusage, maxusage, yieldusage, maxyieldusage, count, calls = \
- funcs[funcaddr]
- if maxusage == 0 and maxyieldusage is None:
+ for info in funcinfos:
+ if info.max_stack_usage == 0 and info.max_yield_usage < 0:
continue
yieldstr = ""
- if maxyieldusage is not None:
- yieldstr = ",%d" % maxyieldusage
- print("\n%s[%d,%d%s]:" % (name, basicusage, maxusage, yieldstr))
- for insnaddr, calladdr, stackusage in calls:
- callinfo = funcs.get(calladdr, ("<unknown>", 0, 0, 0, None))
+ if info.max_yield_usage >= 0:
+ yieldstr = ",%d" % info.max_yield_usage
+ print("\n%s[%d,%d%s]:" % (info.funcname, info.basic_stack_usage
+ , info.max_stack_usage, yieldstr))
+ for insnaddr, calladdr, stackusage in info.called_funcs:
+ callinfo = funcs.get(calladdr, unknownfunc)
yieldstr = ""
- if callinfo[4] is not None:
- yieldstr = ",%d" % (stackusage + callinfo[4])
+ if callinfo.max_yield_usage >= 0:
+ yieldstr = ",%d" % (stackusage + callinfo.max_yield_usage)
print(" %04s:%-40s [%d+%d,%d%s]" % (
- insnaddr, callinfo[0], stackusage, callinfo[1]
- , stackusage+callinfo[2], yieldstr))
-
-def main():
- calc()
+ insnaddr, callinfo.funcname, stackusage
+ , callinfo.basic_stack_usage
+ , stackusage+callinfo.max_stack_usage, yieldstr))
if __name__ == '__main__':
main()
diff --git a/qemu/roms/seabios/scripts/kconfig/lxdialog/util.c b/qemu/roms/seabios/scripts/kconfig/lxdialog/util.c
index f7abdeb92..2a0d182e8 100644
--- a/qemu/roms/seabios/scripts/kconfig/lxdialog/util.c
+++ b/qemu/roms/seabios/scripts/kconfig/lxdialog/util.c
@@ -376,7 +376,7 @@ void print_title(WINDOW *dialog, const char *title, int width)
/*
* Print a string of text in a window, automatically wrap around to the
* next line if the string is too long to fit on one line. Newline
- * characters '\n' are propperly processed. We start on a new line
+ * characters '\n' are properly processed. We start on a new line
* if there is no room for at least 4 nonblanks following a double-space.
*/
void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
diff --git a/qemu/roms/seabios/scripts/layoutrom.py b/qemu/roms/seabios/scripts/layoutrom.py
index dd770fe49..b976fb056 100755
--- a/qemu/roms/seabios/scripts/layoutrom.py
+++ b/qemu/roms/seabios/scripts/layoutrom.py
@@ -161,6 +161,7 @@ def getSectionsPrefix(sections, prefix):
# The sections (and associated information) to be placed in output rom
class LayoutInfo:
sections = None
+ config = None
genreloc = None
sec32init_start = sec32init_end = sec32init_align = None
sec32low_start = sec32low_end = None
@@ -172,6 +173,7 @@ class LayoutInfo:
# Determine final memory addresses for sections
def doLayout(sections, config, genreloc):
li = LayoutInfo()
+ li.config = config
li.sections = sections
li.genreloc = genreloc
# Determine 16bit positions
@@ -399,6 +401,10 @@ def writeLinkerScripts(li, out16, out32seg, out32flat):
filesections32flat = getSectionsFileid(li.sections, '32flat')
out = outXRefs([], exportsyms=li.varlowsyms
, forcedelta=li.final_sec32low_start-li.sec32low_start)
+ multiboot_header = ""
+ if li.config.get('CONFIG_MULTIBOOT'):
+ multiboot_header = "LONG(0x1BADB002) LONG(0) LONG(-0x1BADB002)"
+ sec32all_start -= 3 * 4
out += outXRefs(filesections32flat, exportsyms=[li.entrysym]) + """
_reloc_min_align = 0x%x ;
zonefseg_start = 0x%x ;
@@ -415,6 +421,7 @@ def writeLinkerScripts(li, out16, out32seg, out32flat):
.text code32flat_start : {
%s
%s
+%s
code32flat_end = ABSOLUTE(.) ;
} :text
""" % (li.sec32init_align,
@@ -428,6 +435,7 @@ def writeLinkerScripts(li, out16, out32seg, out32flat):
li.sec32init_start,
li.sec32init_end,
sec32all_start,
+ multiboot_header,
relocstr,
outRelSections(li.sections, 'code32flat_start'))
out = COMMONHEADER + out + COMMONTRAILER + """
diff --git a/qemu/roms/seabios/src/Kconfig b/qemu/roms/seabios/src/Kconfig
index 45ca59cf3..95bf087b8 100644
--- a/qemu/roms/seabios/src/Kconfig
+++ b/qemu/roms/seabios/src/Kconfig
@@ -20,7 +20,7 @@ choice
Configure for an emulated machine (QEMU, Xen, KVM, or Bochs).
config CSM
- bool "Build as Compatibilty Support Module for EFI BIOS"
+ bool "Build as Compatibility Support Module for EFI BIOS"
help
Configure to be used by EFI firmware as Compatibility Support
module (CSM) to provide legacy BIOS services.
@@ -96,12 +96,13 @@ endchoice
the CBFS filesystem is at a non-standard location (eg,
0xffe00000 if CBFS ends 2Meg below the end of flash).
- config FLASH_FLOPPY
- depends on COREBOOT_FLASH
- bool "Floppy images in CBFS"
+ config MULTIBOOT
+ depends on COREBOOT
+ bool "multiboot support"
default y
help
- Support floppy images in coreboot flash.
+ Add multiboot header in bios.bin.raw and accept files supplied
+ as multiboot modules.
config ENTRY_EXTRASTACK
bool "Use internal stack for 16bit interrupt entry points"
default y
@@ -160,7 +161,7 @@ menu "Hardware support"
help
Support for AHCI disk code.
config SDCARD
- depends on DRIVES && QEMU_HARDWARE
+ depends on DRIVES
bool "SD controllers"
default y
help
@@ -208,11 +209,18 @@ menu "Hardware support"
help
Support boot from LSI MegaRAID SAS scsi storage.
config FLOPPY
- depends on DRIVES
+ depends on DRIVES && HARDWARE_IRQ
bool "Floppy controller"
default y
help
Support floppy drive access.
+ config FLASH_FLOPPY
+ depends on DRIVES
+ bool "Floppy images from CBFS or fw_cfg"
+ default y
+ help
+ Support floppy images stored in coreboot flash or from
+ QEMU fw_cfg.
config PS2PORT
depends on KEYBOARD || MOUSE
@@ -291,6 +299,26 @@ menu "Hardware support"
default y
help
Support parallel ports. This also enables int 17 parallel port calls.
+ config RTC_TIMER
+ bool "Real Time Clock (RTC) scheduling"
+ depends on HARDWARE_IRQ
+ default y
+ help
+ Support MC146818 Real Time Clock chip timer
+ interrupts. This also enables int 1583 and int 1586 calls.
+
+ Disabling this support does not disable access to the RTC
+ cmos registers.
+
+ config HARDWARE_IRQ
+ bool "Hardware interrupts"
+ default y
+ help
+ Program and support hardware interrupts using the i8259
+ programmable interrupt controller (PIC). This option must
+ be enabled in order to support most boot loaders. Only
+ disable this option if running on peculiar hardware known
+ not to support irq routing.
config USE_SMM
depends on QEMU
@@ -309,10 +337,16 @@ menu "Hardware support"
help
Initialize the Memory Type Range Registers (on emulators).
config PMTIMER
- bool "Use ACPI timer"
+ bool "Support ACPI timer"
default y
help
- Use the ACPI timer instead of the TSC for timekeeping (on qemu).
+ Detect and use the ACPI timer for timekeeping.
+ config TSC_TIMER
+ bool "Support CPU timestamp counter as timer"
+ default y
+ help
+ Support for using the CPU timestamp counter as an internal
+ timing source.
endmenu
menu "BIOS interfaces"
@@ -421,6 +455,13 @@ menu "BIOS interfaces"
modified by programs. However, some old DOS high memory
managers may require the UMB region to be read-only.
+ config TCGBIOS
+ depends on S3_RESUME
+ bool "TPM support and TCG BIOS extensions"
+ default y
+ help
+ Provide TPM support along with TCG BIOS extensions
+
endmenu
menu "BIOS Tables"
diff --git a/qemu/roms/seabios/src/biosvar.h b/qemu/roms/seabios/src/biosvar.h
index 58bcbcedb..f61fb6a50 100644
--- a/qemu/roms/seabios/src/biosvar.h
+++ b/qemu/roms/seabios/src/biosvar.h
@@ -8,11 +8,12 @@
#include "config.h" // SEG_BDA
#include "farptr.h" // GET_FARVAR
+#include "memmap.h" // SYMBOL
#include "std/bda.h" // struct bios_data_area_s
/****************************************************************
- * Interupt vector table
+ * Interrupt vector table
****************************************************************/
#define GET_IVT(vector) \
@@ -112,13 +113,12 @@ static inline u16 get_global_seg(void) {
* "Low" memory variables
****************************************************************/
-extern u8 _zonelow_seg, zonelow_base[];
-#define SEG_LOW ((u32)&_zonelow_seg)
+#define SEG_LOW SYMBOL(_zonelow_seg)
#if MODESEGMENT
#define GET_LOW(var) GET_FARVAR(SEG_LOW, (var))
#define SET_LOW(var, val) SET_FARVAR(SEG_LOW, (var), (val))
-#define LOWFLAT2LOW(var) ((typeof(var))((void*)(var) - (u32)zonelow_base))
+#define LOWFLAT2LOW(var) ((typeof(var))((void*)(var) - SYMBOL(zonelow_base)))
#else
#define GET_LOW(var) (var)
#define SET_LOW(var, val) do { (var) = (val); } while (0)
diff --git a/qemu/roms/seabios/src/block.c b/qemu/roms/seabios/src/block.c
index 3f7ecb1d7..1762e2a33 100644
--- a/qemu/roms/seabios/src/block.c
+++ b/qemu/roms/seabios/src/block.c
@@ -10,9 +10,16 @@
#include "hw/ata.h" // process_ata_op
#include "hw/ahci.h" // process_ahci_op
#include "hw/blockcmd.h" // cdb_*
+#include "hw/esp-scsi.h" // esp_scsi_process_op
+#include "hw/lsi-scsi.h" // lsi_scsi_process_op
+#include "hw/megasas.h" // megasas_process_op
#include "hw/pci.h" // pci_bdf_to_bus
+#include "hw/pvscsi.h" // pvscsi_process_op
#include "hw/rtc.h" // rtc_read
+#include "hw/usb-msc.h" // usb_process_op
+#include "hw/usb-uas.h" // uas_process_op
#include "hw/virtio-blk.h" // process_virtio_blk_op
+#include "hw/virtio-scsi.h" // virtio_scsi_process_op
#include "malloc.h" // malloc_low
#include "output.h" // dprintf
#include "stacks.h" // stack_hop
@@ -67,10 +74,8 @@ get_translation(struct drive_s *drive)
u8 type = drive->type;
if (CONFIG_QEMU && type == DTYPE_ATA) {
// Emulators pass in the translation info via nvram.
- u8 ataid = drive->cntl_id;
- u8 channel = ataid / 2;
- u8 translation = rtc_read(CMOS_BIOS_DISKTRANSFLAG + channel/2);
- translation >>= 2 * (ataid % 4);
+ u8 translation = rtc_read(CMOS_BIOS_DISKTRANSFLAG + drive->cntl_id/4);
+ translation >>= 2 * (drive->cntl_id % 4);
translation &= 0x03;
return translation;
}
@@ -282,11 +287,21 @@ map_floppy_drive(struct drive_s *drive)
* Extended Disk Drive (EDD) get drive parameters
****************************************************************/
+// flags for bus_iface field in fill_generic_edd()
+#define EDD_ISA 0x01
+#define EDD_PCI 0x02
+#define EDD_BUS_MASK 0x0f
+#define EDD_ATA 0x10
+#define EDD_SCSI 0x20
+#define EDD_IFACE_MASK 0xf0
+
+// Fill in EDD info
static int
-fill_generic_edd(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf
- , u32 dpte_so, char *iface_type
- , int bdf, u8 channel, u16 iobase, u64 device_path)
+fill_generic_edd(struct segoff_s edd, struct drive_s *drive_gf
+ , u32 dpte_so, u8 bus_iface, u32 iface_path, u32 device_path)
{
+ u16 seg = edd.seg;
+ struct int13dpt_s *param_far = (void*)(edd.offset+0);
u16 size = GET_FARVAR(seg, param_far->size);
u16 t13 = size == 74;
@@ -335,7 +350,7 @@ fill_generic_edd(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf
SET_FARVAR(seg, param_far->size, 30);
SET_FARVAR(seg, param_far->dpte.segoff, dpte_so);
- if (size < 66 || !iface_type)
+ if (size < 66 || !bus_iface)
return DISK_RET_SUCCESS;
// EDD 3.x
@@ -344,32 +359,22 @@ fill_generic_edd(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf
SET_FARVAR(seg, param_far->reserved1, 0);
SET_FARVAR(seg, param_far->reserved2, 0);
- int i;
- for (i=0; i<sizeof(param_far->iface_type); i++)
- SET_FARVAR(seg, param_far->iface_type[i], GET_GLOBAL(iface_type[i]));
-
- if (bdf != -1) {
- SET_FARVAR(seg, param_far->host_bus[0], 'P');
- SET_FARVAR(seg, param_far->host_bus[1], 'C');
- SET_FARVAR(seg, param_far->host_bus[2], 'I');
- SET_FARVAR(seg, param_far->host_bus[3], ' ');
-
- u32 path = (pci_bdf_to_bus(bdf) | (pci_bdf_to_dev(bdf) << 8)
- | (pci_bdf_to_fn(bdf) << 16));
- if (t13)
- path |= channel << 24;
-
- SET_FARVAR(seg, param_far->iface_path, path);
- } else {
- // ISA
- SET_FARVAR(seg, param_far->host_bus[0], 'I');
- SET_FARVAR(seg, param_far->host_bus[1], 'S');
- SET_FARVAR(seg, param_far->host_bus[2], 'A');
- SET_FARVAR(seg, param_far->host_bus[3], ' ');
-
- SET_FARVAR(seg, param_far->iface_path, iobase);
+ const char *host_bus = "ISA ";
+ if ((bus_iface & EDD_BUS_MASK) == EDD_PCI) {
+ host_bus = "PCI ";
+ if (!t13)
+ // Phoenix v3 spec (pre t13) did not define the PCI channel field
+ iface_path &= 0x00ffffff;
}
-
+ memcpy_far(seg, param_far->host_bus, SEG_BIOS, host_bus
+ , sizeof(param_far->host_bus));
+ SET_FARVAR(seg, param_far->iface_path, iface_path);
+
+ const char *iface_type = "ATA ";
+ if ((bus_iface & EDD_IFACE_MASK) == EDD_SCSI)
+ iface_type = "SCSI ";
+ memcpy_far(seg, param_far->iface_type, SEG_BIOS, iface_type
+ , sizeof(param_far->iface_type));
if (t13) {
SET_FARVAR(seg, param_far->t13.device_path[0], device_path);
SET_FARVAR(seg, param_far->t13.device_path[1], 0);
@@ -386,10 +391,19 @@ fill_generic_edd(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf
return DISK_RET_SUCCESS;
}
+// Build an EDD "iface_path" field for a PCI device
+static u32
+edd_pci_path(u16 bdf, u8 channel)
+{
+ return (pci_bdf_to_bus(bdf) | (pci_bdf_to_dev(bdf) << 8)
+ | (pci_bdf_to_fn(bdf) << 16) | ((u32)channel << 24));
+}
+
struct dpte_s DefaultDPTE VARLOW;
+// EDD info for ATA and ATAPI drives
static int
-fill_ata_edd(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf)
+fill_ata_edd(struct segoff_s edd, struct drive_s *drive_gf)
{
if (!CONFIG_ATA)
return DISK_RET_EPARAM;
@@ -440,109 +454,141 @@ fill_ata_edd(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf)
u8 sum = checksum_far(SEG_LOW, &DefaultDPTE, 15);
SET_LOW(DefaultDPTE.checksum, -sum);
+ u32 bustype = EDD_ISA, ifpath = iobase1;
+ if (bdf >= 0) {
+ bustype = EDD_PCI;
+ ifpath = edd_pci_path(bdf, channel);
+ }
return fill_generic_edd(
- seg, param_far, drive_gf, SEGOFF(SEG_LOW, (u32)&DefaultDPTE).segoff
- , "ATA ", bdf, channel, iobase1, slave);
+ edd, drive_gf, SEGOFF(SEG_LOW, (u32)&DefaultDPTE).segoff
+ , bustype | EDD_ATA, ifpath, slave);
}
+// Fill Extended Disk Drive (EDD) "Get drive parameters" info for a drive
int noinline
-fill_edd(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf)
+fill_edd(struct segoff_s edd, struct drive_s *drive_gf)
{
switch (GET_GLOBALFLAT(drive_gf->type)) {
case DTYPE_ATA:
case DTYPE_ATA_ATAPI:
- return fill_ata_edd(seg, param_far, drive_gf);
+ return fill_ata_edd(edd, drive_gf);
case DTYPE_VIRTIO_BLK:
case DTYPE_VIRTIO_SCSI:
return fill_generic_edd(
- seg, param_far, drive_gf, 0xffffffff
- , "SCSI ", GET_GLOBALFLAT(drive_gf->cntl_id), 0, 0, 0);
+ edd, drive_gf, 0xffffffff, EDD_PCI | EDD_SCSI
+ , edd_pci_path(GET_GLOBALFLAT(drive_gf->cntl_id), 0), 0);
default:
- return fill_generic_edd(seg, param_far, drive_gf, 0, NULL, 0, 0, 0, 0);
+ return fill_generic_edd(edd, drive_gf, 0, 0, 0, 0);
}
}
/****************************************************************
- * 16bit calling interface
+ * Disk driver dispatch
****************************************************************/
-int VISIBLE32FLAT
-process_atapi_op(struct disk_op_s *op)
+// Fallback handler for command requests not implemented by drivers
+int
+default_process_op(struct disk_op_s *op)
{
switch (op->command) {
- case CMD_WRITE:
case CMD_FORMAT:
- return DISK_RET_EWRITEPROTECT;
+ case CMD_RESET:
+ case CMD_ISREADY:
+ case CMD_VERIFY:
+ case CMD_SEEK:
+ // Return success if the driver doesn't implement these commands
+ return DISK_RET_SUCCESS;
default:
- return scsi_process_op(op);
+ return DISK_RET_EPARAM;
}
}
-// Execute a disk_op request.
-int
-process_op(struct disk_op_s *op)
+// Command dispatch for disk drivers that run in both 16bit and 32bit mode
+static int
+process_op_both(struct disk_op_s *op)
{
- ASSERT16();
- int ret, origcount = op->count;
- if (origcount * GET_GLOBALFLAT(op->drive_gf->blksize) > 64*1024) {
- op->count = 0;
- return DISK_RET_EBOUNDARY;
- }
- u8 type = GET_GLOBALFLAT(op->drive_gf->type);
- switch (type) {
- case DTYPE_FLOPPY:
- ret = process_floppy_op(op);
- break;
- case DTYPE_ATA:
- ret = process_ata_op(op);
- break;
- case DTYPE_RAMDISK:
- ret = process_ramdisk_op(op);
- break;
- case DTYPE_CDEMU:
- ret = process_cdemu_op(op);
- break;
- case DTYPE_VIRTIO_BLK:
- ret = process_virtio_blk_op(op);
- break;
- case DTYPE_AHCI: ;
- extern void _cfunc32flat_process_ahci_op(void);
- ret = call32(_cfunc32flat_process_ahci_op
- , (u32)MAKE_FLATPTR(GET_SEG(SS), op), DISK_RET_EPARAM);
- break;
+ switch (GET_GLOBALFLAT(op->drive_gf->type)) {
case DTYPE_ATA_ATAPI:
- ret = process_atapi_op(op);
- break;
- case DTYPE_AHCI_ATAPI: ;
- extern void _cfunc32flat_process_atapi_op(void);
- ret = call32(_cfunc32flat_process_atapi_op
- , (u32)MAKE_FLATPTR(GET_SEG(SS), op), DISK_RET_EPARAM);
- break;
- case DTYPE_SDCARD: ;
- extern void _cfunc32flat_process_sdcard_op(void);
- ret = call32(_cfunc32flat_process_sdcard_op
- , (u32)MAKE_FLATPTR(GET_SEG(SS), op), DISK_RET_EPARAM);
- break;
+ return ata_atapi_process_op(op);
case DTYPE_USB:
+ return usb_process_op(op);
case DTYPE_UAS:
- case DTYPE_VIRTIO_SCSI:
+ return uas_process_op(op);
case DTYPE_LSI_SCSI:
+ return lsi_scsi_process_op(op);
case DTYPE_ESP_SCSI:
+ return esp_scsi_process_op(op);
case DTYPE_MEGASAS:
- ret = scsi_process_op(op);
- break;
+ return megasas_process_op(op);
+ default:
+ if (!MODESEGMENT)
+ return DISK_RET_EPARAM;
+ // In 16bit mode and driver not found - try in 32bit mode
+ return call32(process_op_32, MAKE_FLATPTR(GET_SEG(SS), op)
+ , DISK_RET_EPARAM);
+ }
+}
+
+// Command dispatch for disk drivers that only run in 32bit mode
+int VISIBLE32FLAT
+process_op_32(struct disk_op_s *op)
+{
+ ASSERT32FLAT();
+ switch (op->drive_gf->type) {
+ case DTYPE_VIRTIO_BLK:
+ return virtio_blk_process_op(op);
+ case DTYPE_AHCI:
+ return ahci_process_op(op);
+ case DTYPE_AHCI_ATAPI:
+ return ahci_atapi_process_op(op);
+ case DTYPE_SDCARD:
+ return sdcard_process_op(op);
case DTYPE_USB_32:
+ return usb_process_op(op);
case DTYPE_UAS_32:
- case DTYPE_PVSCSI: ;
- extern void _cfunc32flat_scsi_process_op(void);
- ret = call32(_cfunc32flat_scsi_process_op
- , (u32)MAKE_FLATPTR(GET_SEG(SS), op), DISK_RET_EPARAM);
- break;
+ return uas_process_op(op);
+ case DTYPE_VIRTIO_SCSI:
+ return virtio_scsi_process_op(op);
+ case DTYPE_PVSCSI:
+ return pvscsi_process_op(op);
default:
- ret = DISK_RET_EPARAM;
- break;
+ return process_op_both(op);
}
+}
+
+// Command dispatch for disk drivers that only run in 16bit mode
+static int
+process_op_16(struct disk_op_s *op)
+{
+ ASSERT16();
+ switch (GET_GLOBALFLAT(op->drive_gf->type)) {
+ case DTYPE_FLOPPY:
+ return floppy_process_op(op);
+ case DTYPE_ATA:
+ return ata_process_op(op);
+ case DTYPE_RAMDISK:
+ return ramdisk_process_op(op);
+ case DTYPE_CDEMU:
+ return cdemu_process_op(op);
+ default:
+ return process_op_both(op);
+ }
+}
+
+// Execute a disk_op_s request.
+int
+process_op(struct disk_op_s *op)
+{
+ int ret, origcount = op->count;
+ if (origcount * GET_GLOBALFLAT(op->drive_gf->blksize) > 64*1024) {
+ op->count = 0;
+ return DISK_RET_EBOUNDARY;
+ }
+ if (MODESEGMENT)
+ ret = process_op_16(op);
+ else
+ ret = process_op_32(op);
if (ret && op->count == origcount)
// If the count hasn't changed on error, assume no data transferred.
op->count = 0;
@@ -578,5 +624,5 @@ send_disk_op(struct disk_op_s *op)
if (! CONFIG_DRIVES)
return -1;
- return stack_hop((u32)op, GET_SEG(SS), __send_disk_op);
+ return stack_hop(__send_disk_op, op, GET_SEG(SS));
}
diff --git a/qemu/roms/seabios/src/block.h b/qemu/roms/seabios/src/block.h
index 8182288d4..2ff359fb2 100644
--- a/qemu/roms/seabios/src/block.h
+++ b/qemu/roms/seabios/src/block.h
@@ -9,11 +9,19 @@
****************************************************************/
struct disk_op_s {
- u64 lba;
void *buf_fl;
struct drive_s *drive_gf;
- u16 count;
u8 command;
+ u16 count;
+ union {
+ // Commands: READ, WRITE, VERIFY, SEEK, FORMAT
+ u64 lba;
+ // Commands: SCSI
+ struct {
+ u16 blocksize;
+ void *cdbcmd;
+ };
+ };
};
#define CMD_RESET 0x00
@@ -23,6 +31,7 @@ struct disk_op_s {
#define CMD_FORMAT 0x05
#define CMD_SEEK 0x07
#define CMD_ISREADY 0x10
+#define CMD_SCSI 0x20
/****************************************************************
@@ -101,7 +110,8 @@ void map_floppy_drive(struct drive_s *drive);
void map_hd_drive(struct drive_s *drive);
void map_cd_drive(struct drive_s *drive);
struct int13dpt_s;
-int fill_edd(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf);
+int fill_edd(struct segoff_s edd, struct drive_s *drive_gf);
+int default_process_op(struct disk_op_s *op);
int process_op(struct disk_op_s *op);
int send_disk_op(struct disk_op_s *op);
int create_bounce_buf(void);
diff --git a/qemu/roms/seabios/src/bmp.c b/qemu/roms/seabios/src/bmp.c
index d8e76b789..96a2b3f22 100644
--- a/qemu/roms/seabios/src/bmp.c
+++ b/qemu/roms/seabios/src/bmp.c
@@ -1,6 +1,6 @@
/*
* Basic BMP data process and Raw picture data handle functions.
-* Could be used to adjust pixel data format, get infomation, etc.
+* Could be used to adjust pixel data format, get information, etc.
*
* Copyright (C) 2011 Wayne Xia <xiawenc@cn.ibm.com>
*
diff --git a/qemu/roms/seabios/src/boot.c b/qemu/roms/seabios/src/boot.c
index f23e9e154..e0f73a385 100644
--- a/qemu/roms/seabios/src/boot.c
+++ b/qemu/roms/seabios/src/boot.c
@@ -19,6 +19,7 @@
#include "std/disk.h" // struct mbr_s
#include "string.h" // memset
#include "util.h" // irqtimer_calc
+#include "tcgbios.h" // tpm_*
/****************************************************************
@@ -111,9 +112,9 @@ build_pci_path(char *buf, int max, const char *devname, struct pci_device *pci)
if (pci->parent) {
p = build_pci_path(p, max, "pci-bridge", pci->parent);
} else {
- if (pci->rootbus)
- p += snprintf(p, max, "/pci-root@%x", pci->rootbus);
p += snprintf(p, buf+max-p, "%s", FW_PCI_DOMAIN);
+ if (pci->rootbus)
+ p += snprintf(p, buf+max-p, ",%x", pci->rootbus);
}
int dev = pci_bdf_to_dev(pci->bdf), fn = pci_bdf_to_fn(pci->bdf);
@@ -459,8 +460,8 @@ interactive_bootmenu(void)
;
char *bootmsg = romfile_loadfile("etc/boot-menu-message", NULL);
- int menukey = romfile_loadint("etc/boot-menu-key", 0x86);
- printf("%s", bootmsg ?: "\nPress F12 for boot menu.\n\n");
+ int menukey = romfile_loadint("etc/boot-menu-key", 1);
+ printf("%s", bootmsg ?: "\nPress ESC for boot menu.\n\n");
free(bootmsg);
u32 menutime = romfile_loadint("etc/boot-menu-wait", DEFAULT_BOOTMENU_WAIT);
@@ -486,9 +487,15 @@ interactive_bootmenu(void)
, strtcpy(desc, pos->description, ARRAY_SIZE(desc)));
}
- // Get key press
+ // Get key press. If the menu key is ESC, do not restart boot unless
+ // 1.5 seconds have passed. Otherwise users (trained by years of
+ // repeatedly hitting keys to enter the BIOS) will end up hitting ESC
+ // multiple times and immediately booting the primary boot device.
+ int esc_accepted_time = irqtimer_calc(menukey == 1 ? 1500 : 0);
for (;;) {
scan_code = get_keystroke(1000);
+ if (scan_code == 1 && !irqtimer_check(esc_accepted_time))
+ continue;
if (scan_code >= 1 && scan_code <= maxmenu+1)
break;
}
@@ -622,6 +629,8 @@ boot_disk(u8 bootdrv, int checksig)
}
}
+ tpm_add_bcv(bootdrv, MAKE_FLATPTR(bootseg, 0), 512);
+
/* Canonicalize bootseg:bootip */
u16 bootip = (bootseg & 0x0fff) << 4;
bootseg &= 0xf000;
@@ -645,6 +654,9 @@ boot_cdrom(struct drive_s *drive_g)
u8 bootdrv = CDEmu.emulated_drive;
u16 bootseg = CDEmu.load_segment;
+
+ tpm_add_cdrom(bootdrv, MAKE_FLATPTR(bootseg, 0), 512);
+
/* Canonicalize bootseg:bootip */
u16 bootip = (bootseg & 0x0fff) << 4;
bootseg &= 0xf000;
diff --git a/qemu/roms/seabios/src/cdrom.c b/qemu/roms/seabios/src/cdrom.c
index 92f34f42b..a4f31adde 100644
--- a/qemu/roms/seabios/src/cdrom.c
+++ b/qemu/roms/seabios/src/cdrom.c
@@ -15,9 +15,7 @@
#include "std/disk.h" // DISK_RET_SUCCESS
#include "string.h" // memset
#include "util.h" // cdrom_prepboot
-
-// Locks for removable devices
-u8 CDRom_locks[BUILD_MAX_EXTDRIVE] VARLOW;
+#include "tcgbios.h" // tpm_*
/****************************************************************
@@ -88,7 +86,7 @@ cdemu_read(struct disk_op_s *op)
}
int
-process_cdemu_op(struct disk_op_s *op)
+cdemu_process_op(struct disk_op_s *op)
{
if (!CONFIG_CDROM_EMU)
return 0;
@@ -99,13 +97,8 @@ process_cdemu_op(struct disk_op_s *op)
case CMD_WRITE:
case CMD_FORMAT:
return DISK_RET_EWRITEPROTECT;
- case CMD_VERIFY:
- case CMD_RESET:
- case CMD_SEEK:
- case CMD_ISREADY:
- return DISK_RET_SUCCESS;
default:
- return DISK_RET_EPARAM;
+ return default_process_op(op);
}
}
@@ -122,7 +115,6 @@ cdrom_prepboot(void)
struct drive_s *drive = malloc_fseg(sizeof(*drive));
if (!drive) {
warn_noalloc();
- free(drive);
return;
}
cdemu_drive_gf = drive;
@@ -158,7 +150,7 @@ cdrom_boot(struct drive_s *drive)
dop.lba = 0x11;
dop.count = 1;
dop.buf_fl = buffer;
- ret = scsi_process_op(&dop);
+ ret = process_op(&dop);
if (ret)
return 3;
@@ -174,7 +166,7 @@ cdrom_boot(struct drive_s *drive)
// And we read the Boot Catalog
dop.lba = lba;
dop.count = 1;
- ret = scsi_process_op(&dop);
+ ret = process_op(&dop);
if (ret)
return 7;
@@ -192,6 +184,9 @@ cdrom_boot(struct drive_s *drive)
if (buffer[0x20] != 0x88)
return 11; // Bootable
+ /* measure 2048 bytes (one sector) */
+ tpm_add_cdrom_catalog(MAKE_FLATPTR(GET_SEG(SS), buffer), sizeof(buffer));
+
// Fill in el-torito cdrom emulation fields.
emulated_drive_gf = drive;
u8 media = buffer[0x21];
@@ -220,7 +215,7 @@ cdrom_boot(struct drive_s *drive)
if (count > 64*1024/CDROM_SECTOR_SIZE)
count = 64*1024/CDROM_SECTOR_SIZE;
dop.count = count;
- ret = scsi_process_op(&dop);
+ ret = process_op(&dop);
if (ret)
return 12;
nbsectors -= count;
diff --git a/qemu/roms/seabios/src/clock.c b/qemu/roms/seabios/src/clock.c
index 9ab0ac026..e83e0f338 100644
--- a/qemu/roms/seabios/src/clock.c
+++ b/qemu/roms/seabios/src/clock.c
@@ -8,6 +8,7 @@
#include "biosvar.h" // SET_BDA
#include "bregs.h" // struct bregs
#include "hw/pic.h" // pic_eoi1
+#include "hw/ps2port.h" // ps2_check_event
#include "hw/rtc.h" // rtc_read
#include "hw/usb-hid.h" // usb_check_event
#include "output.h" // debug_enter
@@ -55,7 +56,8 @@ clock_setup(void)
}
enable_hwirq(0, FUNC16(entry_08));
- enable_hwirq(8, FUNC16(entry_70));
+ if (CONFIG_RTC_TIMER)
+ enable_hwirq(8, FUNC16(entry_70));
}
@@ -239,6 +241,16 @@ handle_1a07(struct bregs *regs)
set_success(regs);
}
+static void
+handle_1abb(struct bregs *regs)
+{
+ if (!CONFIG_TCGBIOS)
+ return;
+
+ dprintf(DEBUG_tcg, "16: Calling tpm_interrupt_handler\n");
+ call32(tpm_interrupt_handler32, MAKE_FLATPTR(GET_SEG(SS), regs), 0);
+}
+
// Unsupported
static void
handle_1aXX(struct bregs *regs)
@@ -260,17 +272,15 @@ handle_1a(struct bregs *regs)
case 0x05: handle_1a05(regs); break;
case 0x06: handle_1a06(regs); break;
case 0x07: handle_1a07(regs); break;
+ case 0xbb: handle_1abb(regs); break;
default: handle_1aXX(regs); break;
}
}
-// INT 08h System Timer ISR Entry Point
-void VISIBLE16
-handle_08(void)
+// Update main tick counter
+static void
+clock_update(void)
{
- debug_isr(DEBUG_ISR_08);
-
- // Update counter
u32 counter = GET_BDA(timer_counter);
counter++;
// compare to one days worth of timer ticks at 18.2 hz
@@ -284,6 +294,15 @@ handle_08(void)
// Check for internal events.
floppy_tick();
usb_check_event();
+ ps2_check_event();
+}
+
+// INT 08h System Timer ISR Entry Point
+void VISIBLE16
+handle_08(void)
+{
+ debug_isr(DEBUG_ISR_08);
+ clock_update();
// chain to user timer tick INT #0x1c
struct bregs br;
@@ -294,6 +313,20 @@ handle_08(void)
pic_eoi1();
}
+u32 last_timer_check VARLOW;
+
+// Simulate timer irq on machines without hardware irqs
+void
+clock_poll_irq(void)
+{
+ if (CONFIG_HARDWARE_IRQ)
+ return;
+ if (!timer_check(GET_LOW(last_timer_check)))
+ return;
+ SET_LOW(last_timer_check, timer_calc(ticks_to_ms(1)));
+ clock_update();
+}
+
/****************************************************************
* IRQ based timer
@@ -359,6 +392,10 @@ clear_usertimer(void)
void
handle_1586(struct bregs *regs)
{
+ if (!CONFIG_RTC_TIMER) {
+ set_code_unimplemented(regs, RET_EUNSUPPORTED);
+ return;
+ }
// Use the rtc to wait for the specified time.
u8 statusflag = 0;
u32 count = (regs->cx << 16) | regs->dx;
@@ -402,6 +439,10 @@ handle_1583XX(struct bregs *regs)
void
handle_1583(struct bregs *regs)
{
+ if (!CONFIG_RTC_TIMER) {
+ handle_1583XX(regs);
+ return;
+ }
switch (regs->al) {
case 0x00: handle_158300(regs); break;
case 0x01: handle_158301(regs); break;
@@ -415,6 +456,8 @@ handle_1583(struct bregs *regs)
void VISIBLE16
handle_70(void)
{
+ if (!CONFIG_RTC_TIMER)
+ return;
debug_isr(DEBUG_ISR_70);
// Check which modes are enabled and have occurred.
diff --git a/qemu/roms/seabios/src/config.h b/qemu/roms/seabios/src/config.h
index 6da067d0b..6c47f161c 100644
--- a/qemu/roms/seabios/src/config.h
+++ b/qemu/roms/seabios/src/config.h
@@ -22,6 +22,8 @@
#define BUILD_MAX_EXTDRIVE 16
// Number of bytes the smbios may be and still live in the f-segment
#define BUILD_MAX_SMBIOS_FSEG 600
+// Maximum number of bytes the mptable may be and still be copied to f-segment
+#define BUILD_MAX_MPTABLE_FSEG 600
#define BUILD_MODEL_ID 0xFC
#define BUILD_SUBMODEL_ID 0x00
@@ -104,5 +106,6 @@
#define DEBUG_unimplemented 2
#define DEBUG_invalid 3
#define DEBUG_thread 2
+#define DEBUG_tcg 20
#endif // config.h
diff --git a/qemu/roms/seabios/src/disk.c b/qemu/roms/seabios/src/disk.c
index 0e0af24b3..3854d0024 100644
--- a/qemu/roms/seabios/src/disk.c
+++ b/qemu/roms/seabios/src/disk.c
@@ -407,6 +407,9 @@ disk_1344(struct bregs *regs, struct drive_s *drive_gf)
extended_access(regs, drive_gf, CMD_VERIFY);
}
+// Locks for removable devices
+u8 CDRom_locks[BUILD_MAX_EXTDRIVE] VARLOW;
+
// lock
static void
disk_134500(struct bregs *regs, struct drive_s *drive_gf)
@@ -519,7 +522,7 @@ disk_1347(struct bregs *regs, struct drive_s *drive_gf)
static void
disk_1348(struct bregs *regs, struct drive_s *drive_gf)
{
- int ret = fill_edd(regs->ds, (void*)(regs->si+0), drive_gf);
+ int ret = fill_edd(SEGOFF(regs->ds, regs->si), drive_gf);
disk_ret(regs, ret);
}
diff --git a/qemu/roms/seabios/src/memmap.c b/qemu/roms/seabios/src/e820map.c
index e03f8d0bf..39445cf63 100644
--- a/qemu/roms/seabios/src/memmap.c
+++ b/qemu/roms/seabios/src/e820map.c
@@ -5,7 +5,7 @@
// This file may be distributed under the terms of the GNU LGPLv3 license.
#include "config.h" // BUILD_MAX_E820
-#include "memmap.h" // struct e820entry
+#include "e820map.h" // struct e820entry
#include "output.h" // dprintf
#include "string.h" // memmove
@@ -54,7 +54,6 @@ e820_type_name(u32 type)
case E820_ACPI: return "ACPI";
case E820_NVS: return "NVS";
case E820_UNUSABLE: return "UNUSABLE";
- case E820_HOLE: return "HOLE";
default: return "UNKNOWN";
}
}
@@ -73,12 +72,14 @@ dump_map(void)
}
}
+#define E820_HOLE ((u32)-1) // Used internally to remove entries
+
// Add a new entry to the list. This scans for overlaps and keeps the
// list sorted.
void
-add_e820(u64 start, u64 size, u32 type)
+e820_add(u64 start, u64 size, u32 type)
{
- dprintf(8, "Add to e820 map: %08x %08x %d\n", (u32)start, (u32)size, type);
+ dprintf(8, "Add to e820 map: %08llx %08llx %d\n", start, size, type);
if (! size)
// Huh? Nothing to do.
@@ -136,9 +137,16 @@ add_e820(u64 start, u64 size, u32 type)
//dump_map();
}
+// Remove any definitions in a memory range (make a memory hole).
+void
+e820_remove(u64 start, u64 size)
+{
+ e820_add(start, size, E820_HOLE);
+}
+
// Report on final memory locations.
void
-memmap_prepboot(void)
+e820_prepboot(void)
{
dump_map();
}
diff --git a/qemu/roms/seabios/src/e820map.h b/qemu/roms/seabios/src/e820map.h
new file mode 100644
index 000000000..de8b52300
--- /dev/null
+++ b/qemu/roms/seabios/src/e820map.h
@@ -0,0 +1,26 @@
+#ifndef __E820MAP_H
+#define __E820MAP_H
+
+#include "types.h" // u64
+
+#define E820_RAM 1
+#define E820_RESERVED 2
+#define E820_ACPI 3
+#define E820_NVS 4
+#define E820_UNUSABLE 5
+
+struct e820entry {
+ u64 start;
+ u64 size;
+ u32 type;
+};
+
+void e820_add(u64 start, u64 size, u32 type);
+void e820_remove(u64 start, u64 size);
+void e820_prepboot(void);
+
+// e820 map storage
+extern struct e820entry e820_list[];
+extern int e820_count;
+
+#endif // e820map.h
diff --git a/qemu/roms/seabios/src/fw/biostables.c b/qemu/roms/seabios/src/fw/biostables.c
index 50a891be8..9fb9ff9df 100644
--- a/qemu/roms/seabios/src/fw/biostables.c
+++ b/qemu/roms/seabios/src/fw/biostables.c
@@ -6,14 +6,15 @@
#include "byteorder.h" // le32_to_cpu
#include "config.h" // CONFIG_*
+#include "hw/pci.h" // pci_config_writeb
#include "malloc.h" // malloc_fseg
+#include "memmap.h" // SYMBOL
#include "output.h" // dprintf
-#include "hw/pci.h" // pci_config_writeb
+#include "romfile.h" // romfile_find
#include "std/acpi.h" // struct rsdp_descriptor
#include "std/mptable.h" // MPTABLE_SIGNATURE
#include "std/pirtable.h" // struct pir_header
#include "std/smbios.h" // struct smbios_entry_point
-#include "romfile.h"
#include "string.h" // memcpy
#include "util.h" // copy_table
#include "x86.h" // outb
@@ -54,6 +55,11 @@ copy_mptable(void *pos)
return;
u32 length = p->length * 16;
u16 mpclength = ((struct mptable_config_s *)p->physaddr)->length;
+ if (length + mpclength > BUILD_MAX_MPTABLE_FSEG) {
+ dprintf(1, "Skipping MPTABLE copy due to large size (%d bytes)\n"
+ , length + mpclength);
+ return;
+ }
// Allocate final memory location. (In theory the config
// structure can go in high memory, but Linux kernels before
// v2.6.30 crash with that.)
@@ -117,9 +123,8 @@ copy_acpi_rsdp(void *pos)
void *find_acpi_rsdp(void)
{
- extern u8 zonefseg_start[], zonefseg_end[];
- unsigned long start = (unsigned long)zonefseg_start;
- unsigned long end = (unsigned long)zonefseg_end;
+ unsigned long start = SYMBOL(zonefseg_start);
+ unsigned long end = SYMBOL(zonefseg_end);
unsigned long pos;
for (pos = ALIGN(start, 0x10); pos <= ALIGN_DOWN(end, 0x10); pos += 0x10)
@@ -271,7 +276,7 @@ copy_smbios(void *pos)
if (SMBiosAddr)
return;
struct smbios_entry_point *p = pos;
- if (memcmp(p->anchor_string, "_SM_", 4))
+ if (p->signature != SMBIOS_SIGNATURE)
return;
if (checksum(pos, 0x10) != 0)
return;
@@ -301,17 +306,42 @@ display_uuid(void)
if (memcmp(uuid, empty_uuid, sizeof(empty_uuid)) == 0)
return;
- printf("Machine UUID"
- " %02x%02x%02x%02x"
- "-%02x%02x"
- "-%02x%02x"
- "-%02x%02x"
- "-%02x%02x%02x%02x%02x%02x\n"
- , uuid[ 0], uuid[ 1], uuid[ 2], uuid[ 3]
- , uuid[ 4], uuid[ 5]
- , uuid[ 6], uuid[ 7]
- , uuid[ 8], uuid[ 9]
- , uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
+ /*
+ * According to SMBIOS v2.6 the first three fields are encoded in
+ * little-endian format. Versions prior to v2.6 did not specify
+ * the encoding, but we follow dmidecode and assume big-endian
+ * encoding.
+ */
+ if (SMBiosAddr->smbios_major_version > 2 ||
+ (SMBiosAddr->smbios_major_version == 2 &&
+ SMBiosAddr->smbios_minor_version >= 6)) {
+ printf("Machine UUID"
+ " %02x%02x%02x%02x"
+ "-%02x%02x"
+ "-%02x%02x"
+ "-%02x%02x"
+ "-%02x%02x%02x%02x%02x%02x\n"
+ , uuid[ 3], uuid[ 2], uuid[ 1], uuid[ 0]
+ , uuid[ 5], uuid[ 4]
+ , uuid[ 7], uuid[ 6]
+ , uuid[ 8], uuid[ 9]
+ , uuid[10], uuid[11], uuid[12]
+ , uuid[13], uuid[14], uuid[15]);
+ } else {
+ printf("Machine UUID"
+ " %02x%02x%02x%02x"
+ "-%02x%02x"
+ "-%02x%02x"
+ "-%02x%02x"
+ "-%02x%02x%02x%02x%02x%02x\n"
+ , uuid[ 0], uuid[ 1], uuid[ 2], uuid[ 3]
+ , uuid[ 4], uuid[ 5]
+ , uuid[ 6], uuid[ 7]
+ , uuid[ 8], uuid[ 9]
+ , uuid[10], uuid[11], uuid[12]
+ , uuid[13], uuid[14], uuid[15]);
+ }
+
return;
}
}
@@ -447,7 +477,7 @@ void
smbios_setup(void)
{
if (smbios_romfile_setup())
- return;
+ return;
smbios_legacy_setup();
}
diff --git a/qemu/roms/seabios/src/fw/coreboot.c b/qemu/roms/seabios/src/fw/coreboot.c
index 8fd84493b..4fe12928c 100644
--- a/qemu/roms/seabios/src/fw/coreboot.c
+++ b/qemu/roms/seabios/src/fw/coreboot.c
@@ -7,10 +7,10 @@
#include "block.h" // MAXDESCSIZE
#include "byteorder.h" // be32_to_cpu
#include "config.h" // CONFIG_*
+#include "e820map.h" // e820_add
#include "hw/pci.h" // pci_probe_devices
#include "lzmadecode.h" // LzmaDecode
#include "malloc.h" // free
-#include "memmap.h" // add_e820
#include "output.h" // dprintf
#include "paravirt.h" // PlatformRunningOn
#include "romfile.h" // romfile_findprefix
@@ -184,12 +184,12 @@ coreboot_preinit(void)
u32 type = m->type;
if (type == CB_MEM_TABLE)
type = E820_RESERVED;
- add_e820(m->start, m->size, type);
+ e820_add(m->start, m->size, type);
}
// Ughh - coreboot likes to set a map at 0x0000-0x1000, but this
// confuses grub. So, override it.
- add_e820(0, 16*1024, E820_RAM);
+ e820_add(0, 16*1024, E820_RAM);
struct cb_cbmem_ref *cbref = find_cb_subtable(cbh, CB_TAG_CBMEM_CONSOLE);
if (cbref) {
@@ -210,7 +210,7 @@ coreboot_preinit(void)
fail:
// No table found.. Use 16Megs as a dummy value.
dprintf(1, "Unable to find coreboot table!\n");
- add_e820(0, 16*1024*1024, E820_RAM);
+ e820_add(0, 16*1024*1024, E820_RAM);
return;
}
@@ -421,6 +421,13 @@ coreboot_cbfs_init(void)
return;
struct cbfs_header *hdr = *(void **)(CONFIG_CBFS_LOCATION - 4);
+ if ((u32)hdr & 0x03) {
+ dprintf(1, "Invalid CBFS pointer %p\n", hdr);
+ return;
+ }
+ if (CONFIG_CBFS_LOCATION && (u32)hdr > CONFIG_CBFS_LOCATION)
+ // Looks like the pointer is relative to CONFIG_CBFS_LOCATION
+ hdr = (void*)hdr + CONFIG_CBFS_LOCATION;
if (hdr->magic != cpu_to_be32(CBFS_HEADER_MAGIC)) {
dprintf(1, "Unable to find CBFS (ptr=%p; got %x not %x)\n"
, hdr, hdr->magic, cpu_to_be32(CBFS_HEADER_MAGIC));
@@ -503,7 +510,7 @@ cbfs_run_payload(struct cbfs_file *fhdr)
break;
case PAYLOAD_SEGMENT_ENTRY: {
dprintf(1, "Calling addr %p\n", dest);
- void (*func)() = dest;
+ void (*func)(void) = dest;
func();
return;
}
diff --git a/qemu/roms/seabios/src/fw/csm.c b/qemu/roms/seabios/src/fw/csm.c
index 7cdb398f2..7cadd12e5 100644
--- a/qemu/roms/seabios/src/fw/csm.c
+++ b/qemu/roms/seabios/src/fw/csm.c
@@ -4,20 +4,21 @@
//
// This file may be distributed under the terms of the GNU LGPLv3 license.
-#include "bregs.h"
+#include "bregs.h" // struct bregs
#include "config.h" // CONFIG_*
+#include "e820map.h" // e820_add
#include "farptr.h" // MAKE_FLATPTR
-#include "hw/pci.h"
-#include "hw/pic.h"
-#include "malloc.h" // csm_malloc_preinit
-#include "memmap.h"
+#include "hw/pci.h" // pci_probe_devices
+#include "hw/pic.h" // pic_irqmask_read
+#include "malloc.h" // malloc_csm_preinit
+#include "memmap.h" // SYMBOL
#include "output.h" // dprintf
+#include "paravirt.h" // qemu_preinit
#include "stacks.h" // wait_threads
#include "std/acpi.h" // RSDP_SIGNATURE
#include "std/bda.h" // struct bios_data_area_s
#include "std/optionrom.h" // struct rom_header
#include "util.h" // copy_smbios
-#include "paravirt.h" // qemu_preinit
#define UINT8 u8
#define UINT16 u16
@@ -47,12 +48,11 @@ static void
csm_return(struct bregs *regs)
{
u32 rommax = rom_get_max();
- extern u8 final_readonly_start[];
dprintf(3, "handle_csm returning AX=%04x\n", regs->ax);
csm_compat_table.UmaAddress = rommax;
- csm_compat_table.UmaSize = (u32)final_readonly_start - rommax;
+ csm_compat_table.UmaSize = SYMBOL(final_readonly_start) - rommax;
PICMask = pic_irqmask_read();
__csm_return(regs);
@@ -95,7 +95,7 @@ handle_csm_0000(struct bregs *regs)
dprintf(3, "LoPmmMemory %08x\n", csm_init_table->LowPmmMemory);
dprintf(3, "LoPmmMemorySize %08x\n", csm_init_table->LowPmmMemorySizeInBytes);
- csm_malloc_preinit(csm_init_table->LowPmmMemory,
+ malloc_csm_preinit(csm_init_table->LowPmmMemory,
csm_init_table->LowPmmMemorySizeInBytes,
csm_init_table->HiPmmMemory,
csm_init_table->HiPmmMemorySizeInBytes);
@@ -147,11 +147,11 @@ handle_csm_0002(struct bregs *regs)
struct e820entry *p = (void *)csm_compat_table.E820Pointer;
int i;
for (i=0; i < csm_compat_table.E820Length / sizeof(struct e820entry); i++)
- add_e820(p[i].start, p[i].size, p[i].type);
+ e820_add(p[i].start, p[i].size, p[i].type);
if (csm_init_table->HiPmmMemorySizeInBytes > BUILD_MAX_HIGHTABLE) {
u32 hi_pmm_end = csm_init_table->HiPmmMemory + csm_init_table->HiPmmMemorySizeInBytes;
- add_e820(hi_pmm_end - BUILD_MAX_HIGHTABLE, BUILD_MAX_HIGHTABLE, E820_RESERVED);
+ e820_add(hi_pmm_end - BUILD_MAX_HIGHTABLE, BUILD_MAX_HIGHTABLE, E820_RESERVED);
}
// For PCIBIOS 1ab10e
@@ -183,6 +183,7 @@ handle_csm_0002(struct bregs *regs)
struct bios_data_area_s *bda = MAKE_FLATPTR(SEG_BDA, 0);
bda->hdcount = 0;
+ thread_setup();
mathcp_setup();
timer_setup();
clock_setup();
diff --git a/qemu/roms/seabios/src/fw/dev-q35.h b/qemu/roms/seabios/src/fw/dev-q35.h
index c6f8bd9e7..201825deb 100644
--- a/qemu/roms/seabios/src/fw/dev-q35.h
+++ b/qemu/roms/seabios/src/fw/dev-q35.h
@@ -27,6 +27,9 @@
#define ICH9_LPC_GEN_PMCON_1_SMI_LOCK (1 << 4)
#define ICH9_LPC_PORT_ELCR1 0x4d0
#define ICH9_LPC_PORT_ELCR2 0x4d1
+#define ICH9_LPC_RCBA 0xf0
+#define ICH9_LPC_RCBA_ADDR 0xfed1c000
+#define ICH9_LPC_RCBA_EN 0x1
#define PCI_DEVICE_ID_INTEL_ICH9_SMBUS 0x2930
#define ICH9_SMB_SMB_BASE 0x20
#define ICH9_SMB_HOSTC 0x40
diff --git a/qemu/roms/seabios/src/fw/multiboot.c b/qemu/roms/seabios/src/fw/multiboot.c
new file mode 100644
index 000000000..d9df06764
--- /dev/null
+++ b/qemu/roms/seabios/src/fw/multiboot.c
@@ -0,0 +1,111 @@
+// Multiboot interface support.
+//
+// Copyright (C) 2015 Vladimir Serbinenko <phcoder@gmail.com>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "config.h" // CONFIG_*
+#include "malloc.h" // free
+#include "output.h" // dprintf
+#include "romfile.h" // romfile_add
+#include "std/multiboot.h" // MULTIBOOT_*
+#include "string.h" // memset
+#include "util.h" // multiboot_init
+
+struct mbfs_romfile_s {
+ struct romfile_s file;
+ void *data;
+};
+
+static int
+extract_filename(char *dest, char *src, size_t lim)
+{
+ char *ptr;
+ for (ptr = src; *ptr; ptr++) {
+ if (!(ptr == src || ptr[-1] == ' ' || ptr[-1] == '\t'))
+ continue;
+ /* memcmp stops early if it encounters \0 as it doesn't match name=. */
+ if (memcmp(ptr, "name=", 5) == 0) {
+ int i;
+ char *optr = dest;
+ for (i = 0, ptr += 5; *ptr && *ptr != ' ' && i < lim; i++) {
+ *optr++ = *ptr++;
+ }
+ *optr++ = '\0';
+ return 1;
+ }
+ }
+ return 0;
+}
+
+// Copy a file to memory
+static int
+mbfs_copyfile(struct romfile_s *file, void *dst, u32 maxlen)
+{
+ struct mbfs_romfile_s *cfile;
+ cfile = container_of(file, struct mbfs_romfile_s, file);
+ u32 size = cfile->file.size;
+ void *src = cfile->data;
+
+ // Not compressed.
+ dprintf(3, "Copying data %d@%p to %d@%p\n", size, src, maxlen, dst);
+ if (size > maxlen) {
+ warn_noalloc();
+ return -1;
+ }
+ iomemcpy(dst, src, size);
+ return size;
+}
+
+u32 __VISIBLE entry_elf_eax, entry_elf_ebx;
+
+void
+multiboot_init(void)
+{
+ struct multiboot_info *mbi;
+ if (!CONFIG_MULTIBOOT)
+ return;
+ dprintf(1, "multiboot: eax=%x, ebx=%x\n", entry_elf_eax, entry_elf_ebx);
+ if (entry_elf_eax != MULTIBOOT_BOOTLOADER_MAGIC)
+ return;
+ mbi = (void *)entry_elf_ebx;
+ dprintf(1, "mbptr=%p\n", mbi);
+ dprintf(1, "flags=0x%x, mods=0x%x, mods_c=%d\n", mbi->flags, mbi->mods_addr,
+ mbi->mods_count);
+ if (!(mbi->flags & MULTIBOOT_INFO_MODS))
+ return;
+ int i;
+ struct multiboot_mod_list *mod = (void *)mbi->mods_addr;
+ for (i = 0; i < mbi->mods_count; i++) {
+ struct mbfs_romfile_s *cfile;
+ u8 *copy;
+ u32 len;
+ if (!mod[i].cmdline)
+ continue;
+ len = mod[i].mod_end - mod[i].mod_start;
+ cfile = malloc_tmp(sizeof(*cfile));
+ if (!cfile) {
+ warn_noalloc();
+ return;
+ }
+ memset(cfile, 0, sizeof(*cfile));
+ dprintf(1, "module %s, size 0x%x\n", (char *)mod[i].cmdline, len);
+ if (!extract_filename(cfile->file.name, (char *)mod[i].cmdline,
+ sizeof(cfile->file.name))) {
+ free(cfile);
+ continue;
+ }
+ dprintf(1, "assigned file name <%s>\n", cfile->file.name);
+ cfile->file.size = len;
+ copy = malloc_tmp(len);
+ if (!copy) {
+ warn_noalloc();
+ free(cfile);
+ return;
+ }
+ memcpy(copy, (void *)mod[i].mod_start, len);
+ cfile->file.copy = mbfs_copyfile;
+ cfile->data = copy;
+ romfile_add(&cfile->file);
+ }
+}
diff --git a/qemu/roms/seabios/src/fw/paravirt.c b/qemu/roms/seabios/src/fw/paravirt.c
index db22ae8fc..3fae13a83 100644
--- a/qemu/roms/seabios/src/fw/paravirt.c
+++ b/qemu/roms/seabios/src/fw/paravirt.c
@@ -10,11 +10,11 @@
#include "byteorder.h" // be32_to_cpu
#include "config.h" // CONFIG_QEMU
+#include "e820map.h" // e820_add
#include "hw/pci.h" // create_pirtable
#include "hw/pci_regs.h" // PCI_DEVICE_ID
#include "hw/rtc.h" // CMOS_*
#include "malloc.h" // malloc_tmp
-#include "memmap.h" // add_e820
#include "output.h" // dprintf
#include "paravirt.h" // qemu_cfg_preinit
#include "romfile.h" // romfile_loadint
@@ -23,6 +23,7 @@
#include "util.h" // pci_setup
#include "x86.h" // cpuid
#include "xen.h" // xen_biostable_setup
+#include "stacks.h" // yield
// Amount of continuous ram under 4Gig
u32 RamSize;
@@ -30,6 +31,13 @@ u32 RamSize;
u64 RamSizeOver4G;
// Type of emulator platform.
int PlatformRunningOn VARFSEG;
+// cfg_dma enabled
+int cfg_dma_enabled = 0;
+
+inline int qemu_cfg_dma_enabled(void)
+{
+ return cfg_dma_enabled;
+}
/* This CPUID returns the signature 'KVMKVMKVM' in ebx, ecx, and edx. It
* should be used to determine that a VM is running under KVM.
@@ -114,10 +122,10 @@ qemu_preinit(void)
| (rtc_read(CMOS_MEM_EXTMEM_HIGH) << 18))
+ 1 * 1024 * 1024);
RamSize = rs;
- add_e820(0, rs, E820_RAM);
+ e820_add(0, rs, E820_RAM);
/* reserve 256KB BIOS area at the end of 4 GB */
- add_e820(0xfffc0000, 256*1024, E820_RESERVED);
+ e820_add(0xfffc0000, 256*1024, E820_RESERVED);
dprintf(1, "RamSize: 0x%08x [cmos]\n", RamSize);
}
@@ -199,23 +207,63 @@ qemu_cfg_select(u16 f)
}
static void
+qemu_cfg_dma_transfer(void *address, u32 length, u32 control)
+{
+ QemuCfgDmaAccess access;
+
+ access.address = cpu_to_be64((u64)(u32)address);
+ access.length = cpu_to_be32(length);
+ access.control = cpu_to_be32(control);
+
+ barrier();
+
+ outl(cpu_to_be32((u32)&access), PORT_QEMU_CFG_DMA_ADDR_LOW);
+
+ while(be32_to_cpu(access.control) & ~QEMU_CFG_DMA_CTL_ERROR) {
+ yield();
+ }
+}
+
+static void
qemu_cfg_read(void *buf, int len)
{
- insb(PORT_QEMU_CFG_DATA, buf, len);
+ if (len == 0) {
+ return;
+ }
+
+ if (qemu_cfg_dma_enabled()) {
+ qemu_cfg_dma_transfer(buf, len, QEMU_CFG_DMA_CTL_READ);
+ } else {
+ insb(PORT_QEMU_CFG_DATA, buf, len);
+ }
}
static void
qemu_cfg_skip(int len)
{
- while (len--)
- inb(PORT_QEMU_CFG_DATA);
+ if (len == 0) {
+ return;
+ }
+
+ if (qemu_cfg_dma_enabled()) {
+ qemu_cfg_dma_transfer(0, len, QEMU_CFG_DMA_CTL_SKIP);
+ } else {
+ while (len--)
+ inb(PORT_QEMU_CFG_DATA);
+ }
}
static void
qemu_cfg_read_entry(void *buf, int e, int len)
{
- qemu_cfg_select(e);
- qemu_cfg_read(buf, len);
+ if (qemu_cfg_dma_enabled()) {
+ u32 control = (e << 16) | QEMU_CFG_DMA_CTL_SELECT
+ | QEMU_CFG_DMA_CTL_READ;
+ qemu_cfg_dma_transfer(buf, len, control);
+ } else {
+ qemu_cfg_select(e);
+ qemu_cfg_read(buf, len);
+ }
}
struct qemu_romfile_s {
@@ -230,9 +278,14 @@ qemu_cfg_read_file(struct romfile_s *file, void *dst, u32 maxlen)
return -1;
struct qemu_romfile_s *qfile;
qfile = container_of(file, struct qemu_romfile_s, file);
- qemu_cfg_select(qfile->select);
- qemu_cfg_skip(qfile->skip);
- qemu_cfg_read(dst, file->size);
+ if (qfile->skip == 0) {
+ /* Do it in one transfer */
+ qemu_cfg_read_entry(dst, qfile->select, file->size);
+ } else {
+ qemu_cfg_select(qfile->select);
+ qemu_cfg_skip(qfile->skip);
+ qemu_cfg_read(dst, file->size);
+ }
return file->size;
}
@@ -302,7 +355,7 @@ qemu_cfg_e820(void)
}
/* fall through */
case E820_RESERVED:
- add_e820(table[i].address, table[i].length, table[i].type);
+ e820_add(table[i].address, table[i].length, table[i].type);
break;
default:
/*
@@ -324,13 +377,13 @@ qemu_cfg_e820(void)
int i;
for (i = 0; i < count32; i++) {
qemu_cfg_read(&entry, sizeof(entry));
- add_e820(entry.address, entry.length, entry.type);
+ e820_add(entry.address, entry.length, entry.type);
}
} else if (runningOnKVM()) {
// Backwards compatibility - provide hard coded range.
// 4 pages before the bios, 3 pages for vmx tss pages, the
// other page for EPT real mode pagetable
- add_e820(0xfffbc000, 4*4096, E820_RESERVED);
+ e820_add(0xfffbc000, 4*4096, E820_RESERVED);
}
// Check for memory over 4Gig in cmos
@@ -338,7 +391,7 @@ qemu_cfg_e820(void)
| ((u32)rtc_read(CMOS_MEM_HIGHMEM_MID) << 24)
| ((u64)rtc_read(CMOS_MEM_HIGHMEM_HIGH) << 32));
RamSizeOver4G = high;
- add_e820(0x100000000ull, high, E820_RAM);
+ e820_add(0x100000000ull, high, E820_RAM);
dprintf(1, "RamSizeOver4G: 0x%016llx [cmos]\n", RamSizeOver4G);
}
@@ -422,8 +475,18 @@ void qemu_cfg_init(void)
for (i = 0; i < 4; i++)
if (inb(PORT_QEMU_CFG_DATA) != sig[i])
return;
+
dprintf(1, "Found QEMU fw_cfg\n");
+ // Detect DMA interface.
+ u32 id;
+ qemu_cfg_read_entry(&id, QEMU_CFG_ID, sizeof(id));
+
+ if (id & QEMU_CFG_VERSION_DMA) {
+ dprintf(1, "QEMU fw_cfg DMA interface supported\n");
+ cfg_dma_enabled = 1;
+ }
+
// Populate romfiles for legacy fw_cfg entries
qemu_cfg_legacy();
diff --git a/qemu/roms/seabios/src/fw/paravirt.h b/qemu/roms/seabios/src/fw/paravirt.h
index 95ffb92ad..ed8e5f1f8 100644
--- a/qemu/roms/seabios/src/fw/paravirt.h
+++ b/qemu/roms/seabios/src/fw/paravirt.h
@@ -9,6 +9,12 @@
#define PF_XEN (1<<1)
#define PF_KVM (1<<2)
+typedef struct QemuCfgDmaAccess {
+ u32 control;
+ u32 length;
+ u64 address;
+} PACKED QemuCfgDmaAccess;
+
extern u32 RamSize;
extern u64 RamSizeOver4G;
extern int PlatformRunningOn;
@@ -25,11 +31,23 @@ static inline int runningOnKVM(void) {
}
// Common paravirt ports.
-#define PORT_SMI_CMD 0x00b2
-#define PORT_SMI_STATUS 0x00b3
-#define PORT_QEMU_CFG_CTL 0x0510
-#define PORT_QEMU_CFG_DATA 0x0511
+#define PORT_SMI_CMD 0x00b2
+#define PORT_SMI_STATUS 0x00b3
+#define PORT_QEMU_CFG_CTL 0x0510
+#define PORT_QEMU_CFG_DATA 0x0511
+#define PORT_QEMU_CFG_DMA_ADDR_HIGH 0x0514
+#define PORT_QEMU_CFG_DMA_ADDR_LOW 0x0518
+
+// QEMU_CFG_DMA_CONTROL bits
+#define QEMU_CFG_DMA_CTL_ERROR 0x01
+#define QEMU_CFG_DMA_CTL_READ 0x02
+#define QEMU_CFG_DMA_CTL_SKIP 0x04
+#define QEMU_CFG_DMA_CTL_SELECT 0x08
+
+// QEMU_CFG_DMA ID bit
+#define QEMU_CFG_VERSION_DMA 2
+int qemu_cfg_dma_enabled(void);
void qemu_preinit(void);
void qemu_platform_setup(void);
void qemu_cfg_init(void);
diff --git a/qemu/roms/seabios/src/fw/pciinit.c b/qemu/roms/seabios/src/fw/pciinit.c
index 46ae7090e..c31c2fa0c 100644
--- a/qemu/roms/seabios/src/fw/pciinit.c
+++ b/qemu/roms/seabios/src/fw/pciinit.c
@@ -9,13 +9,13 @@
#include "config.h" // CONFIG_*
#include "dev-q35.h" // Q35_HOST_BRIDGE_PCIEXBAR_ADDR
#include "dev-piix.h" // PIIX_*
+#include "e820map.h" // e820_add
#include "hw/ata.h" // PORT_ATA1_CMD_BASE
#include "hw/pci.h" // pci_config_readl
#include "hw/pci_ids.h" // PCI_VENDOR_ID_INTEL
#include "hw/pci_regs.h" // PCI_COMMAND
#include "list.h" // struct hlist_node
#include "malloc.h" // free
-#include "memmap.h" // add_e820
#include "output.h" // dprintf
#include "paravirt.h" // RamSize
#include "romfile.h" // romfile_loadint
@@ -183,6 +183,11 @@ static void mch_isa_bridge_setup(struct pci_device *dev, void *arg)
/* acpi enable, SCI: IRQ9 000b = irq9*/
pci_config_writeb(bdf, ICH9_LPC_ACPI_CTRL, ICH9_LPC_ACPI_CTRL_ACPI_EN);
+ /* set root complex register block BAR */
+ pci_config_writel(bdf, ICH9_LPC_RCBA,
+ ICH9_LPC_RCBA_ADDR | ICH9_LPC_RCBA_EN);
+ e820_add(ICH9_LPC_RCBA_ADDR, 16*1024, E820_RESERVED);
+
acpi_pm1a_cnt = acpi_pm_base + 0x04;
pmtimer_setup(acpi_pm_base + 0x08);
}
@@ -316,6 +321,10 @@ static void pci_bios_init_device(struct pci_device *pci)
/* enable memory mappings */
pci_config_maskw(bdf, PCI_COMMAND, 0,
PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_SERR);
+ /* enable SERR# for forwarding */
+ if (pci->header_type & PCI_HEADER_TYPE_BRIDGE)
+ pci_config_maskw(bdf, PCI_BRIDGE_CONTROL, 0,
+ PCI_BRIDGE_CTL_SERR);
}
static void pci_bios_init_devices(void)
@@ -391,7 +400,7 @@ static void mch_mem_addr_setup(struct pci_device *dev, void *arg)
pci_config_writel(bdf, Q35_HOST_BRIDGE_PCIEXBAR, 0);
pci_config_writel(bdf, Q35_HOST_BRIDGE_PCIEXBAR + 4, upper);
pci_config_writel(bdf, Q35_HOST_BRIDGE_PCIEXBAR, lower);
- add_e820(addr, size, E820_RESERVED);
+ e820_add(addr, size, E820_RESERVED);
/* setup pci i/o window (above mmconfig) */
pcimem_start = addr + size;
@@ -636,9 +645,8 @@ pci_region_create_entry(struct pci_bus *bus, struct pci_device *dev,
return entry;
}
-static int pci_bus_hotplug_support(struct pci_bus *bus)
+static int pci_bus_hotplug_support(struct pci_bus *bus, u8 pcie_cap)
{
- u8 pcie_cap = pci_find_capability(bus->bus_dev, PCI_CAP_ID_EXP);
u8 shpc_cap;
if (pcie_cap) {
@@ -662,7 +670,7 @@ static int pci_bus_hotplug_support(struct pci_bus *bus)
return downstream_port && slot_implemented;
}
- shpc_cap = pci_find_capability(bus->bus_dev, PCI_CAP_ID_SHPC);
+ shpc_cap = pci_find_capability(bus->bus_dev, PCI_CAP_ID_SHPC, 0);
return !!shpc_cap;
}
@@ -718,7 +726,8 @@ static int pci_bios_check_devices(struct pci_bus *busses)
*/
parent = &busses[0];
int type;
- int hotplug_support = pci_bus_hotplug_support(s);
+ u8 pcie_cap = pci_find_capability(s->bus_dev, PCI_CAP_ID_EXP, 0);
+ int hotplug_support = pci_bus_hotplug_support(s, pcie_cap);
for (type = 0; type < PCI_REGION_TYPE_COUNT; type++) {
u64 align = (type == PCI_REGION_TYPE_IO) ?
PCI_BRIDGE_IO_MIN : PCI_BRIDGE_MEM_MIN;
@@ -727,7 +736,8 @@ static int pci_bios_check_devices(struct pci_bus *busses)
if (pci_region_align(&s->r[type]) > align)
align = pci_region_align(&s->r[type]);
u64 sum = pci_region_sum(&s->r[type]);
- if (!sum && hotplug_support)
+ int resource_optional = pcie_cap && (type == PCI_REGION_TYPE_IO);
+ if (!sum && hotplug_support && !resource_optional)
sum = align; /* reserve min size for hot-plug */
u64 size = ALIGN(sum, align);
int is64 = pci_bios_bridge_region_is64(&s->r[type],
diff --git a/qemu/roms/seabios/src/fw/shadow.c b/qemu/roms/seabios/src/fw/shadow.c
index 4f00006bf..ee87d36e0 100644
--- a/qemu/roms/seabios/src/fw/shadow.c
+++ b/qemu/roms/seabios/src/fw/shadow.c
@@ -53,9 +53,8 @@ __make_bios_writable_intel(u16 bdf, u32 pam0)
return;
// Copy bios.
- extern u8 code32flat_start[], code32flat_end[];
- memcpy(code32flat_start, code32flat_start + BIOS_SRC_OFFSET
- , code32flat_end - code32flat_start);
+ memcpy(VSYMBOL(code32flat_start), VSYMBOL(code32flat_start) + BIOS_SRC_OFFSET
+ , SYMBOL(code32flat_end) - SYMBOL(code32flat_start));
}
static void
@@ -65,7 +64,7 @@ make_bios_writable_intel(u16 bdf, u32 pam0)
if (!(reg & 0x10)) {
// QEMU doesn't fully implement the piix shadow capabilities -
// if ram isn't backing the bios segment when shadowing is
- // disabled, the code itself wont be in memory. So, run the
+ // disabled, the code itself won't be in memory. So, run the
// code from the high-memory flash location.
u32 pos = (u32)__make_bios_writable_intel + BIOS_SRC_OFFSET;
void (*func)(u16 bdf, u32 pam0) = (void*)pos;
@@ -165,7 +164,6 @@ qemu_prep_reset(void)
// QEMU doesn't map 0xc0000-0xfffff back to the original rom on a
// reset, so do that manually before invoking a hard reset.
make_bios_writable();
- extern u8 code32flat_start[], code32flat_end[];
- memcpy(code32flat_start, code32flat_start + BIOS_SRC_OFFSET
- , code32flat_end - code32flat_start);
+ memcpy(VSYMBOL(code32flat_start), VSYMBOL(code32flat_start) + BIOS_SRC_OFFSET
+ , SYMBOL(code32flat_end) - SYMBOL(code32flat_start));
}
diff --git a/qemu/roms/seabios/src/fw/smbios.c b/qemu/roms/seabios/src/fw/smbios.c
index dba054133..f3b5ad9dd 100644
--- a/qemu/roms/seabios/src/fw/smbios.c
+++ b/qemu/roms/seabios/src/fw/smbios.c
@@ -37,7 +37,7 @@ smbios_entry_point_setup(u16 max_structure_size,
struct smbios_entry_point ep;
memset(&ep, 0, sizeof(ep));
- memcpy(ep.anchor_string, "_SM_", 4);
+ ep.signature = SMBIOS_SIGNATURE;
ep.length = 0x1f;
ep.smbios_major_version = 2;
ep.smbios_minor_version = 4;
diff --git a/qemu/roms/seabios/src/fw/smm.c b/qemu/roms/seabios/src/fw/smm.c
index 6cb484e7e..8f042ee4d 100644
--- a/qemu/roms/seabios/src/fw/smm.c
+++ b/qemu/roms/seabios/src/fw/smm.c
@@ -64,11 +64,11 @@ handle_smi(u16 cs)
return;
u8 cmd = inb(PORT_SMI_CMD);
struct smm_layout *smm = MAKE_FLATPTR(cs, 0);
+ u32 rev = smm->cpu.i32.smm_rev & SMM_REV_MASK;
dprintf(DEBUG_HDL_smi, "handle_smi cmd=%x smbase=%p\n", cmd, smm);
if (smm == (void*)BUILD_SMM_INIT_ADDR) {
// relocate SMBASE to 0xa0000
- u32 rev = smm->cpu.i32.smm_rev & SMM_REV_MASK;
if (rev == SMM_REV_I32) {
smm->cpu.i32.smm_base = BUILD_SMM_ADDR;
} else if (rev == SMM_REV_I64) {
@@ -92,7 +92,7 @@ handle_smi(u16 cs)
}
if (CONFIG_CALL32_SMM && cmd == CALL32SMM_CMDID) {
- if (smm->cpu.i32.smm_rev == SMM_REV_I32) {
+ if (rev == SMM_REV_I32) {
u32 regs[8];
memcpy(regs, &smm->cpu.i32.eax, sizeof(regs));
if (smm->cpu.i32.ecx == CALL32SMM_ENTERID) {
@@ -107,7 +107,7 @@ handle_smi(u16 cs)
memcpy(&smm->cpu.i32.eax, regs, sizeof(regs));
smm->cpu.i32.eip = regs[3];
}
- } else if (smm->cpu.i64.smm_rev == SMM_REV_I64) {
+ } else if (rev == SMM_REV_I64) {
u64 regs[8];
memcpy(regs, &smm->cpu.i64.rdi, sizeof(regs));
if ((u32)smm->cpu.i64.rcx == CALL32SMM_ENTERID) {
@@ -184,7 +184,7 @@ static void piix4_apmc_smm_setup(int isabdf, int i440_bdf)
/* enable SMI generation */
value = inl(acpi_pm_base + PIIX_PMIO_GLBCTL);
- outl(acpi_pm_base + PIIX_PMIO_GLBCTL, value | PIIX_PMIO_GLBCTL_SMI_EN);
+ outl(value | PIIX_PMIO_GLBCTL_SMI_EN, acpi_pm_base + PIIX_PMIO_GLBCTL);
smm_relocate_and_restore();
diff --git a/qemu/roms/seabios/src/fw/smp.c b/qemu/roms/seabios/src/fw/smp.c
index a466ea6e9..579acdbd0 100644
--- a/qemu/roms/seabios/src/fw/smp.c
+++ b/qemu/roms/seabios/src/fw/smp.c
@@ -52,9 +52,6 @@ handle_smp(void)
if (!CONFIG_QEMU)
return;
- // Enable CPU caching
- setcr0(getcr0() & ~(CR0_CD|CR0_NW));
-
// Detect apic_id
u32 eax, ebx, ecx, cpuid_features;
cpuid(1, &eax, &ebx, &ecx, &cpuid_features);
diff --git a/qemu/roms/seabios/src/fw/xen.c b/qemu/roms/seabios/src/fw/xen.c
index dd8e8afd4..3f19ef2dc 100644
--- a/qemu/roms/seabios/src/fw/xen.c
+++ b/qemu/roms/seabios/src/fw/xen.c
@@ -4,16 +4,17 @@
//
// This file may be distributed under the terms of the GNU LGPLv3 license.
-#include "config.h"
+#include "config.h" // CONFIG_XEN
+#include "e820map.h" // e820_add
#include "hw/serialio.h" // DebugOutputPort
#include "malloc.h" // memalign_high
-#include "memmap.h" // add_e820
+#include "memmap.h" // PAGE_SIZE
#include "output.h" // dprintf
#include "paravirt.h" // PlatformRunningOn
#include "string.h" // memcpy
#include "util.h" // copy_acpi_rsdp
#include "x86.h" // cpuid
-#include "xen.h"
+#include "xen.h" // xen_extraversion_t
#define INFO_PHYSICAL_ADDRESS 0x00001000
@@ -142,6 +143,6 @@ void xen_ramsize_preinit(void)
for (i = 0; i < info->e820_nr; i++) {
struct e820entry *e = &e820[i];
- add_e820(e->start, e->size, e->type);
+ e820_add(e->start, e->size, e->type);
}
}
diff --git a/qemu/roms/seabios/src/hw/ahci.c b/qemu/roms/seabios/src/hw/ahci.c
index 3193d81a6..83b747cb2 100644
--- a/qemu/roms/seabios/src/hw/ahci.c
+++ b/qemu/roms/seabios/src/hw/ahci.c
@@ -213,7 +213,7 @@ static int ahci_command(struct ahci_port_s *port_gf, int iswrite, int isatapi,
#define CDROM_CDB_SIZE 12
-int ahci_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
+int ahci_atapi_process_op(struct disk_op_s *op)
{
if (! CONFIG_AHCI)
return 0;
@@ -221,15 +221,14 @@ int ahci_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
struct ahci_port_s *port_gf = container_of(
op->drive_gf, struct ahci_port_s, drive);
struct ahci_cmd_s *cmd = port_gf->cmd;
- u8 *atapi = cdbcmd;
- int i, rc;
+ if (op->command == CMD_WRITE || op->command == CMD_FORMAT)
+ return DISK_RET_EWRITEPROTECT;
+ int blocksize = scsi_fill_cmd(op, cmd->atapi, CDROM_CDB_SIZE);
+ if (blocksize < 0)
+ return default_process_op(op);
sata_prep_atapi(&cmd->fis, blocksize);
- for (i = 0; i < CDROM_CDB_SIZE; i++) {
- cmd->atapi[i] = atapi[i];
- }
- rc = ahci_command(port_gf, 0, 1, op->buf_fl,
- op->count * blocksize);
+ int rc = ahci_command(port_gf, 0, 1, op->buf_fl, op->count * blocksize);
if (rc < 0)
return DISK_RET_EBADTRACK;
return DISK_RET_SUCCESS;
@@ -296,8 +295,8 @@ ahci_disk_readwrite(struct disk_op_s *op, int iswrite)
}
// command demuxer
-int VISIBLE32FLAT
-process_ahci_op(struct disk_op_s *op)
+int
+ahci_process_op(struct disk_op_s *op)
{
if (!CONFIG_AHCI)
return 0;
@@ -306,15 +305,8 @@ process_ahci_op(struct disk_op_s *op)
return ahci_disk_readwrite(op, 0);
case CMD_WRITE:
return ahci_disk_readwrite(op, 1);
- case CMD_FORMAT:
- case CMD_RESET:
- case CMD_ISREADY:
- case CMD_VERIFY:
- case CMD_SEEK:
- return DISK_RET_SUCCESS;
default:
- dprintf(1, "AHCI: unknown disk command %d\n", op->command);
- return DISK_RET_EPARAM;
+ return default_process_op(op);
}
}
@@ -405,6 +397,14 @@ static struct ahci_port_s* ahci_port_realloc(struct ahci_port_s *port)
port->list = memalign_high(1024, 1024);
port->fis = memalign_high(256, 256);
port->cmd = memalign_high(256, 256);
+ if (!port->list || !port->fis || !port->cmd) {
+ warn_noalloc();
+ free(port->list);
+ free(port->fis);
+ free(port->cmd);
+ free(port);
+ return NULL;
+ }
ahci_port_writel(port->ctrl, port->pnr, PORT_LST_ADDR, (u32)port->list);
ahci_port_writel(port->ctrl, port->pnr, PORT_FIS_ADDR, (u32)port->fis);
diff --git a/qemu/roms/seabios/src/hw/ahci.h b/qemu/roms/seabios/src/hw/ahci.h
index c8c755a3f..fa11d6619 100644
--- a/qemu/roms/seabios/src/hw/ahci.h
+++ b/qemu/roms/seabios/src/hw/ahci.h
@@ -83,8 +83,8 @@ struct ahci_port_s {
};
void ahci_setup(void);
-int process_ahci_op(struct disk_op_s *op);
-int ahci_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize);
+int ahci_process_op(struct disk_op_s *op);
+int ahci_atapi_process_op(struct disk_op_s *op);
#define AHCI_IRQ_ON_SG (1 << 31)
#define AHCI_CMD_ATAPI (1 << 5)
diff --git a/qemu/roms/seabios/src/hw/ata.c b/qemu/roms/seabios/src/hw/ata.c
index d805706dd..fbbbbc1bb 100644
--- a/qemu/roms/seabios/src/hw/ata.c
+++ b/qemu/roms/seabios/src/hw/ata.c
@@ -552,7 +552,7 @@ ata_readwrite(struct disk_op_s *op, int iswrite)
// 16bit command demuxer for ATA harddrives.
int
-process_ata_op(struct disk_op_s *op)
+ata_process_op(struct disk_op_s *op)
{
if (!CONFIG_ATA)
return 0;
@@ -569,12 +569,8 @@ process_ata_op(struct disk_op_s *op)
return DISK_RET_SUCCESS;
case CMD_ISREADY:
return isready(adrive_gf);
- case CMD_FORMAT:
- case CMD_VERIFY:
- case CMD_SEEK:
- return DISK_RET_SUCCESS;
default:
- return DISK_RET_EPARAM;
+ return default_process_op(op);
}
}
@@ -587,11 +583,18 @@ process_ata_op(struct disk_op_s *op)
// Low-level atapi command transmit function.
int
-atapi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
+ata_atapi_process_op(struct disk_op_s *op)
{
if (! CONFIG_ATA)
return 0;
+ if (op->command == CMD_WRITE || op->command == CMD_FORMAT)
+ return DISK_RET_EWRITEPROTECT;
+ u8 cdbcmd[CDROM_CDB_SIZE];
+ int blocksize = scsi_fill_cmd(op, cdbcmd, sizeof(cdbcmd));
+ if (blocksize < 0)
+ return default_process_op(op);
+
struct atadrive_s *adrive_gf = container_of(
op->drive_gf, struct atadrive_s, drive);
struct ata_channel_s *chan_gf = GET_GLOBALFLAT(adrive_gf->chan_gf);
@@ -715,7 +718,7 @@ init_atadrive(struct atadrive_s *dummy, u16 *buffer)
memset(adrive, 0, sizeof(*adrive));
adrive->chan_gf = dummy->chan_gf;
adrive->slave = dummy->slave;
- adrive->drive.cntl_id = adrive->chan_gf->chanid * 2 + dummy->slave;
+ adrive->drive.cntl_id = adrive->chan_gf->ataid * 2 + dummy->slave;
adrive->drive.removable = (buffer[0] & 0x80) ? 1 : 0;
return adrive;
}
@@ -740,7 +743,7 @@ init_drive_atapi(struct atadrive_s *dummy, u16 *buffer)
char model[MAXMODEL+1];
char *desc = znprintf(MAXDESCSIZE
, "DVD/CD [ata%d-%d: %s ATAPI-%d %s]"
- , adrive->chan_gf->chanid, adrive->slave
+ , adrive->chan_gf->ataid, adrive->slave
, ata_extract_model(model, MAXMODEL, buffer)
, ata_extract_version(buffer)
, (iscd ? "DVD/CD" : "Device"));
@@ -792,7 +795,7 @@ init_drive_ata(struct atadrive_s *dummy, u16 *buffer)
char model[MAXMODEL+1];
char *desc = znprintf(MAXDESCSIZE
, "ata%d-%d: %s ATA-%d Hard-Disk (%u %ciBytes)"
- , adrive->chan_gf->chanid, adrive->slave
+ , adrive->chan_gf->ataid, adrive->slave
, ata_extract_model(model, MAXMODEL, buffer)
, ata_extract_version(buffer)
, (u32)adjsize, adjprefix);
@@ -866,7 +869,7 @@ ata_detect(void *data)
u8 sc = inb(iobase1+ATA_CB_SC);
u8 sn = inb(iobase1+ATA_CB_SN);
dprintf(6, "ata_detect ata%d-%d: sc=%x sn=%x dh=%x\n"
- , chan_gf->chanid, slave, sc, sn, dh);
+ , chan_gf->ataid, slave, sc, sn, dh);
if (sc != 0x55 || sn != 0xaa || dh != newdh)
continue;
@@ -913,16 +916,17 @@ ata_detect(void *data)
// Initialize an ata controller and detect its drives.
static void
-init_controller(struct pci_device *pci, int irq
+init_controller(struct pci_device *pci, int chanid, int irq
, u32 port1, u32 port2, u32 master)
{
- static int chanid = 0;
+ static int ataid = 0;
struct ata_channel_s *chan_gf = malloc_fseg(sizeof(*chan_gf));
if (!chan_gf) {
warn_noalloc();
return;
}
- chan_gf->chanid = chanid++;
+ chan_gf->ataid = ataid++;
+ chan_gf->chanid = chanid;
chan_gf->irq = irq;
chan_gf->pci_bdf = pci ? pci->bdf : -1;
chan_gf->pci_tmp = pci;
@@ -930,7 +934,7 @@ init_controller(struct pci_device *pci, int irq
chan_gf->iobase2 = port2;
chan_gf->iomaster = master;
dprintf(1, "ATA controller %d at %x/%x/%x (irq %d dev %x)\n"
- , chanid, port1, port2, master, irq, chan_gf->pci_bdf);
+ , ataid, port1, port2, master, irq, chan_gf->pci_bdf);
run_thread(ata_detect, chan_gf);
}
@@ -966,7 +970,7 @@ init_pciata(struct pci_device *pci, u8 prog_if)
port2 = PORT_ATA1_CTRL_BASE;
irq = IRQ_ATA1;
}
- init_controller(pci, irq, port1, port2, master);
+ init_controller(pci, 0, irq, port1, port2, master);
if (prog_if & 4) {
port1 = (pci_config_readl(bdf, PCI_BASE_ADDRESS_2)
@@ -979,7 +983,7 @@ init_pciata(struct pci_device *pci, u8 prog_if)
port2 = PORT_ATA2_CTRL_BASE;
irq = IRQ_ATA2;
}
- init_controller(pci, irq, port1, port2, master ? master + 8 : 0);
+ init_controller(pci, 1, irq, port1, port2, master ? master + 8 : 0);
}
static void
@@ -1011,9 +1015,9 @@ ata_scan(void)
if (CONFIG_QEMU && hlist_empty(&PCIDevices)) {
// No PCI devices found - probably a QEMU "-M isapc" machine.
// Try using ISA ports for ATA controllers.
- init_controller(NULL, IRQ_ATA1
+ init_controller(NULL, 0, IRQ_ATA1
, PORT_ATA1_CMD_BASE, PORT_ATA1_CTRL_BASE, 0);
- init_controller(NULL, IRQ_ATA2
+ init_controller(NULL, 1, IRQ_ATA2
, PORT_ATA2_CMD_BASE, PORT_ATA2_CTRL_BASE, 0);
return;
}
diff --git a/qemu/roms/seabios/src/hw/ata.h b/qemu/roms/seabios/src/hw/ata.h
index c73892bbe..cd14e59e9 100644
--- a/qemu/roms/seabios/src/hw/ata.h
+++ b/qemu/roms/seabios/src/hw/ata.h
@@ -11,6 +11,7 @@ struct ata_channel_s {
u16 iomaster;
u8 irq;
u8 chanid;
+ u8 ataid;
int pci_bdf;
struct pci_device *pci_tmp;
};
@@ -24,10 +25,9 @@ struct atadrive_s {
// ata.c
char *ata_extract_model(char *model, u32 size, u16 *buffer);
int ata_extract_version(u16 *buffer);
-int cdrom_read(struct disk_op_s *op);
-int atapi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize);
+int ata_process_op(struct disk_op_s *op);
+int ata_atapi_process_op(struct disk_op_s *op);
void ata_setup(void);
-int process_ata_op(struct disk_op_s *op);
#define PORT_ATA2_CMD_BASE 0x0170
#define PORT_ATA1_CMD_BASE 0x01f0
diff --git a/qemu/roms/seabios/src/hw/blockcmd.c b/qemu/roms/seabios/src/hw/blockcmd.c
index 78c0e65f4..0725b46db 100644
--- a/qemu/roms/seabios/src/hw/blockcmd.c
+++ b/qemu/roms/seabios/src/hw/blockcmd.c
@@ -5,67 +5,14 @@
//
// This file may be distributed under the terms of the GNU LGPLv3 license.
-#include "ahci.h" // atapi_cmd_data
-#include "ata.h" // atapi_cmd_data
#include "biosvar.h" // GET_GLOBALFLAT
#include "block.h" // struct disk_op_s
#include "blockcmd.h" // struct cdb_request_sense
#include "byteorder.h" // be32_to_cpu
-#include "esp-scsi.h" // esp_scsi_cmd_data
-#include "lsi-scsi.h" // lsi_scsi_cmd_data
-#include "megasas.h" // megasas_cmd_data
-#include "pvscsi.h" // pvscsi_cmd_data
#include "output.h" // dprintf
#include "std/disk.h" // DISK_RET_EPARAM
#include "string.h" // memset
-#include "usb-msc.h" // usb_cmd_data
-#include "usb-uas.h" // usb_cmd_data
#include "util.h" // timer_calc
-#include "virtio-scsi.h" // virtio_scsi_cmd_data
-
-// Route command to low-level handler.
-static int
-cdb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
-{
- u8 type = GET_GLOBALFLAT(op->drive_gf->type);
- switch (type) {
- case DTYPE_ATA_ATAPI:
- return atapi_cmd_data(op, cdbcmd, blocksize);
- case DTYPE_USB:
- return usb_cmd_data(op, cdbcmd, blocksize);
- case DTYPE_UAS:
- return uas_cmd_data(op, cdbcmd, blocksize);
- case DTYPE_VIRTIO_SCSI:
- return virtio_scsi_cmd_data(op, cdbcmd, blocksize);
- case DTYPE_LSI_SCSI:
- return lsi_scsi_cmd_data(op, cdbcmd, blocksize);
- case DTYPE_ESP_SCSI:
- return esp_scsi_cmd_data(op, cdbcmd, blocksize);
- case DTYPE_MEGASAS:
- return megasas_cmd_data(op, cdbcmd, blocksize);
- case DTYPE_USB_32:
- if (!MODESEGMENT)
- return usb_cmd_data(op, cdbcmd, blocksize);
- case DTYPE_UAS_32:
- if (!MODESEGMENT)
- return uas_cmd_data(op, cdbcmd, blocksize);
- case DTYPE_PVSCSI:
- if (!MODESEGMENT)
- return pvscsi_cmd_data(op, cdbcmd, blocksize);
- case DTYPE_AHCI_ATAPI:
- if (!MODESEGMENT)
- return ahci_cmd_data(op, cdbcmd, blocksize);
- default:
- return DISK_RET_EPARAM;
- }
-}
-
-// Determine if the command is a request to pull data from the device
-int
-cdb_is_read(u8 *cdbcmd, u16 blocksize)
-{
- return blocksize && cdbcmd[0] != CDB_CMD_WRITE_10;
-}
/****************************************************************
@@ -79,9 +26,12 @@ cdb_get_inquiry(struct disk_op_s *op, struct cdbres_inquiry *data)
memset(&cmd, 0, sizeof(cmd));
cmd.command = CDB_CMD_INQUIRY;
cmd.length = sizeof(*data);
+ op->command = CMD_SCSI;
op->count = 1;
op->buf_fl = data;
- return cdb_cmd_data(op, &cmd, sizeof(*data));
+ op->cdbcmd = &cmd;
+ op->blocksize = sizeof(*data);
+ return process_op(op);
}
// Request SENSE
@@ -92,9 +42,12 @@ cdb_get_sense(struct disk_op_s *op, struct cdbres_request_sense *data)
memset(&cmd, 0, sizeof(cmd));
cmd.command = CDB_CMD_REQUEST_SENSE;
cmd.length = sizeof(*data);
+ op->command = CMD_SCSI;
op->count = 1;
op->buf_fl = data;
- return cdb_cmd_data(op, &cmd, sizeof(*data));
+ op->cdbcmd = &cmd;
+ op->blocksize = sizeof(*data);
+ return process_op(op);
}
// Test unit ready
@@ -104,9 +57,12 @@ cdb_test_unit_ready(struct disk_op_s *op)
struct cdb_request_sense cmd;
memset(&cmd, 0, sizeof(cmd));
cmd.command = CDB_CMD_TEST_UNIT_READY;
+ op->command = CMD_SCSI;
op->count = 0;
op->buf_fl = NULL;
- return cdb_cmd_data(op, &cmd, 0);
+ op->cdbcmd = &cmd;
+ op->blocksize = 0;
+ return process_op(op);
}
// Request capacity
@@ -116,9 +72,12 @@ cdb_read_capacity(struct disk_op_s *op, struct cdbres_read_capacity *data)
struct cdb_read_capacity cmd;
memset(&cmd, 0, sizeof(cmd));
cmd.command = CDB_CMD_READ_CAPACITY;
+ op->command = CMD_SCSI;
op->count = 1;
op->buf_fl = data;
- return cdb_cmd_data(op, &cmd, sizeof(*data));
+ op->cdbcmd = &cmd;
+ op->blocksize = sizeof(*data);
+ return process_op(op);
}
// Mode sense, geometry page.
@@ -131,33 +90,12 @@ cdb_mode_sense_geom(struct disk_op_s *op, struct cdbres_mode_sense_geom *data)
cmd.flags = 8; /* DBD */
cmd.page = MODE_PAGE_HD_GEOMETRY;
cmd.count = cpu_to_be16(sizeof(*data));
+ op->command = CMD_SCSI;
op->count = 1;
op->buf_fl = data;
- return cdb_cmd_data(op, &cmd, sizeof(*data));
-}
-
-// Read sectors.
-static int
-cdb_read(struct disk_op_s *op)
-{
- struct cdb_rwdata_10 cmd;
- memset(&cmd, 0, sizeof(cmd));
- cmd.command = CDB_CMD_READ_10;
- cmd.lba = cpu_to_be32(op->lba);
- cmd.count = cpu_to_be16(op->count);
- return cdb_cmd_data(op, &cmd, GET_GLOBALFLAT(op->drive_gf->blksize));
-}
-
-// Write sectors.
-static int
-cdb_write(struct disk_op_s *op)
-{
- struct cdb_rwdata_10 cmd;
- memset(&cmd, 0, sizeof(cmd));
- cmd.command = CDB_CMD_WRITE_10;
- cmd.lba = cpu_to_be32(op->lba);
- cmd.count = cpu_to_be16(op->count);
- return cdb_cmd_data(op, &cmd, GET_GLOBALFLAT(op->drive_gf->blksize));
+ op->cdbcmd = &cmd;
+ op->blocksize = sizeof(*data);
+ return process_op(op);
}
@@ -165,25 +103,36 @@ cdb_write(struct disk_op_s *op)
* Main SCSI commands
****************************************************************/
-int VISIBLE32FLAT
-scsi_process_op(struct disk_op_s *op)
+// Create a scsi command request from a disk_op_s request
+int
+scsi_fill_cmd(struct disk_op_s *op, void *cdbcmd, int maxcdb)
{
switch (op->command) {
case CMD_READ:
- return cdb_read(op);
- case CMD_WRITE:
- return cdb_write(op);
- case CMD_FORMAT:
- case CMD_RESET:
- case CMD_ISREADY:
- case CMD_VERIFY:
- case CMD_SEEK:
- return DISK_RET_SUCCESS;
+ case CMD_WRITE: ;
+ struct cdb_rwdata_10 *cmd = cdbcmd;
+ memset(cmd, 0, maxcdb);
+ cmd->command = (op->command == CMD_READ ? CDB_CMD_READ_10
+ : CDB_CMD_WRITE_10);
+ cmd->lba = cpu_to_be32(op->lba);
+ cmd->count = cpu_to_be16(op->count);
+ return GET_GLOBALFLAT(op->drive_gf->blksize);
+ case CMD_SCSI:
+ memcpy(cdbcmd, op->cdbcmd, maxcdb);
+ return op->blocksize;
default:
- return DISK_RET_EPARAM;
+ return -1;
}
}
+// Determine if the command is a request to pull data from the device
+int
+scsi_is_read(struct disk_op_s *op)
+{
+ return op->command == CMD_READ || (op->command == CMD_SCSI && op->blocksize);
+}
+
+// Check if a SCSI device is ready to receive commands
int
scsi_is_ready(struct disk_op_s *op)
{
@@ -219,7 +168,7 @@ scsi_is_ready(struct disk_op_s *op)
if (sense.asc == 0x04 && sense.ascq == 0x01 && !in_progress) {
/* IN PROGRESS OF BECOMING READY */
- printf("Waiting for device to detect medium... ");
+ dprintf(1, "Waiting for device to detect medium... ");
/* Allow 30 seconds more */
end = timer_calc(30000);
in_progress = 1;
diff --git a/qemu/roms/seabios/src/hw/blockcmd.h b/qemu/roms/seabios/src/hw/blockcmd.h
index df12a6d42..b543f85eb 100644
--- a/qemu/roms/seabios/src/hw/blockcmd.h
+++ b/qemu/roms/seabios/src/hw/blockcmd.h
@@ -100,9 +100,9 @@ struct cdbres_mode_sense_geom {
} PACKED;
// blockcmd.c
-int cdb_is_read(u8 *cdbcmd, u16 blocksize);
struct disk_op_s;
-int scsi_process_op(struct disk_op_s *op);
+int scsi_fill_cmd(struct disk_op_s *op, void *cdbcmd, int maxcdb);
+int scsi_is_read(struct disk_op_s *op);
int scsi_is_ready(struct disk_op_s *op);
struct drive_s;
int scsi_drive_setup(struct drive_s *drive, const char *s, int prio);
diff --git a/qemu/roms/seabios/src/hw/esp-scsi.c b/qemu/roms/seabios/src/hw/esp-scsi.c
index 33cc44986..d4e47e3c5 100644
--- a/qemu/roms/seabios/src/hw/esp-scsi.c
+++ b/qemu/roms/seabios/src/hw/esp-scsi.c
@@ -76,10 +76,19 @@ esp_scsi_dma(u32 iobase, u32 buf, u32 len, int read)
outb(read ? 0x83 : 0x03, iobase + ESP_DMA_CMD);
}
-static int
-esp_scsi_cmd(struct esp_lun_s *llun_gf, struct disk_op_s *op,
- u8 *cdbcmd, u16 target, u16 lun, u16 blocksize)
+int
+esp_scsi_process_op(struct disk_op_s *op)
{
+ if (!CONFIG_ESP_SCSI)
+ return DISK_RET_EBADTRACK;
+ struct esp_lun_s *llun_gf =
+ container_of(op->drive_gf, struct esp_lun_s, drive);
+ u16 target = GET_GLOBALFLAT(llun_gf->target);
+ u16 lun = GET_GLOBALFLAT(llun_gf->lun);
+ u8 cdbcmd[16];
+ int blocksize = scsi_fill_cmd(op, cdbcmd, sizeof(cdbcmd));
+ if (blocksize < 0)
+ return default_process_op(op);
u32 iobase = GET_GLOBALFLAT(llun_gf->iobase);
int i, state;
u8 status;
@@ -113,8 +122,7 @@ esp_scsi_cmd(struct esp_lun_s *llun_gf, struct disk_op_s *op,
if (op->count && blocksize) {
/* Data phase. */
u32 count = (u32)op->count * blocksize;
- esp_scsi_dma(iobase, (u32)op->buf_fl, count,
- cdb_is_read(cdbcmd, blocksize));
+ esp_scsi_dma(iobase, (u32)op->buf_fl, count, scsi_is_read(op));
outb(ESP_CMD_TI | ESP_CMD_DMA, iobase + ESP_CMD);
continue;
}
@@ -144,21 +152,6 @@ esp_scsi_cmd(struct esp_lun_s *llun_gf, struct disk_op_s *op,
return DISK_RET_EBADTRACK;
}
-int
-esp_scsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
-{
- if (!CONFIG_ESP_SCSI)
- return DISK_RET_EBADTRACK;
-
- struct esp_lun_s *llun_gf =
- container_of(op->drive_gf, struct esp_lun_s, drive);
-
- return esp_scsi_cmd(llun_gf, op, cdbcmd,
- GET_GLOBALFLAT(llun_gf->target),
- GET_GLOBALFLAT(llun_gf->lun),
- blocksize);
-}
-
static int
esp_scsi_add_lun(struct pci_device *pci, u32 iobase, u8 target, u8 lun)
{
diff --git a/qemu/roms/seabios/src/hw/esp-scsi.h b/qemu/roms/seabios/src/hw/esp-scsi.h
index dc555f395..0616d14b1 100644
--- a/qemu/roms/seabios/src/hw/esp-scsi.h
+++ b/qemu/roms/seabios/src/hw/esp-scsi.h
@@ -2,7 +2,7 @@
#define __ESP_SCSI_H
struct disk_op_s;
-int esp_scsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize);
+int esp_scsi_process_op(struct disk_op_s *op);
void esp_scsi_setup(void);
#endif /* __ESP_SCSI_H */
diff --git a/qemu/roms/seabios/src/hw/floppy.c b/qemu/roms/seabios/src/hw/floppy.c
index d60362a34..a14f7e093 100644
--- a/qemu/roms/seabios/src/hw/floppy.c
+++ b/qemu/roms/seabios/src/hw/floppy.c
@@ -613,7 +613,7 @@ floppy_format(struct disk_op_s *op)
}
int
-process_floppy_op(struct disk_op_s *op)
+floppy_process_op(struct disk_op_s *op)
{
if (!CONFIG_FLOPPY)
return 0;
diff --git a/qemu/roms/seabios/src/hw/lsi-scsi.c b/qemu/roms/seabios/src/hw/lsi-scsi.c
index b1d6bbf4b..ad3352886 100644
--- a/qemu/roms/seabios/src/hw/lsi-scsi.c
+++ b/qemu/roms/seabios/src/hw/lsi-scsi.c
@@ -50,12 +50,21 @@ struct lsi_lun_s {
u8 lun;
};
-static int
-lsi_scsi_cmd(struct lsi_lun_s *llun_gf, struct disk_op_s *op,
- void *cdbcmd, u16 target, u16 lun, u16 blocksize)
+int
+lsi_scsi_process_op(struct disk_op_s *op)
{
+ if (!CONFIG_LSI_SCSI)
+ return DISK_RET_EBADTRACK;
+ struct lsi_lun_s *llun_gf =
+ container_of(op->drive_gf, struct lsi_lun_s, drive);
+ u16 target = GET_GLOBALFLAT(llun_gf->target);
+ u16 lun = GET_GLOBALFLAT(llun_gf->lun);
+ u8 cdbcmd[16];
+ int blocksize = scsi_fill_cmd(op, cdbcmd, sizeof(cdbcmd));
+ if (blocksize < 0)
+ return default_process_op(op);
u32 iobase = GET_GLOBALFLAT(llun_gf->iobase);
- u32 dma = ((cdb_is_read(cdbcmd, blocksize) ? 0x01000000 : 0x00000000) |
+ u32 dma = ((scsi_is_read(op) ? 0x01000000 : 0x00000000) |
(op->count * blocksize));
u8 msgout[] = {
0x80 | lun, // select lun
@@ -122,21 +131,6 @@ fail:
return DISK_RET_EBADTRACK;
}
-int
-lsi_scsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
-{
- if (!CONFIG_LSI_SCSI)
- return DISK_RET_EBADTRACK;
-
- struct lsi_lun_s *llun_gf =
- container_of(op->drive_gf, struct lsi_lun_s, drive);
-
- return lsi_scsi_cmd(llun_gf, op, cdbcmd,
- GET_GLOBALFLAT(llun_gf->target),
- GET_GLOBALFLAT(llun_gf->lun),
- blocksize);
-}
-
static int
lsi_scsi_add_lun(struct pci_device *pci, u32 iobase, u8 target, u8 lun)
{
diff --git a/qemu/roms/seabios/src/hw/lsi-scsi.h b/qemu/roms/seabios/src/hw/lsi-scsi.h
index 9c5a9b212..6baf4a162 100644
--- a/qemu/roms/seabios/src/hw/lsi-scsi.h
+++ b/qemu/roms/seabios/src/hw/lsi-scsi.h
@@ -2,7 +2,7 @@
#define __LSI_SCSI_H
struct disk_op_s;
-int lsi_scsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize);
+int lsi_scsi_process_op(struct disk_op_s *op);
void lsi_scsi_setup(void);
#endif /* __LSI_SCSI_H */
diff --git a/qemu/roms/seabios/src/hw/megasas.c b/qemu/roms/seabios/src/hw/megasas.c
index b2a65e48b..cb1a2a653 100644
--- a/qemu/roms/seabios/src/hw/megasas.c
+++ b/qemu/roms/seabios/src/hw/megasas.c
@@ -157,18 +157,20 @@ static int megasas_fire_cmd(u16 pci_id, u32 ioaddr,
}
int
-megasas_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
+megasas_process_op(struct disk_op_s *op)
{
+ if (!CONFIG_MEGASAS)
+ return DISK_RET_EBADTRACK;
+ u8 cdb[16];
+ int blocksize = scsi_fill_cmd(op, cdb, sizeof(cdb));
+ if (blocksize < 0)
+ return default_process_op(op);
struct megasas_lun_s *mlun_gf =
container_of(op->drive_gf, struct megasas_lun_s, drive);
- u8 *cdb = cdbcmd;
struct megasas_cmd_frame *frame = GET_GLOBALFLAT(mlun_gf->frame);
u16 pci_id = GET_GLOBALFLAT(mlun_gf->pci_id);
int i;
- if (!CONFIG_MEGASAS)
- return DISK_RET_EBADTRACK;
-
memset_fl(frame, 0, sizeof(*frame));
SET_LOWFLAT(frame->cmd, MFI_CMD_LD_SCSI_IO);
SET_LOWFLAT(frame->cmd_status, 0xFF);
@@ -241,7 +243,10 @@ static void megasas_scan_target(struct pci_device *pci, u32 iobase)
{
struct mfi_ld_list_s ld_list;
struct megasas_cmd_frame *frame = memalign_tmp(256, sizeof(*frame));
- int i;
+ if (!frame) {
+ warn_noalloc();
+ return;
+ }
memset(&ld_list, 0, sizeof(ld_list));
memset_fl(frame, 0, sizeof(*frame));
@@ -258,6 +263,7 @@ static void megasas_scan_target(struct pci_device *pci, u32 iobase)
if (megasas_fire_cmd(pci->device, iobase, frame) == 0) {
dprintf(2, "%d LD found\n", ld_list.count);
+ int i;
for (i = 0; i < ld_list.count; i++) {
dprintf(2, "LD %d:%d state 0x%x\n",
ld_list.lds[i].target, ld_list.lds[i].lun,
@@ -295,9 +301,9 @@ static int megasas_transition_to_ready(struct pci_device *pci, u32 ioaddr)
pci->device == PCI_DEVICE_ID_LSI_SAS2008 ||
pci->device == PCI_DEVICE_ID_LSI_SAS2208 ||
pci->device == PCI_DEVICE_ID_LSI_SAS3108) {
- outl(ioaddr + MFI_DB, mfi_flags);
+ outl(mfi_flags, ioaddr + MFI_DB);
} else {
- outl(ioaddr + MFI_IDB, mfi_flags);
+ outl(mfi_flags, ioaddr + MFI_IDB);
}
break;
case MFI_STATE_OPERATIONAL:
@@ -306,7 +312,7 @@ static int megasas_transition_to_ready(struct pci_device *pci, u32 ioaddr)
pci->device == PCI_DEVICE_ID_LSI_SAS2008 ||
pci->device == PCI_DEVICE_ID_LSI_SAS2208 ||
pci->device == PCI_DEVICE_ID_LSI_SAS3108) {
- outl(ioaddr + MFI_DB, mfi_flags);
+ outl(mfi_flags, ioaddr + MFI_DB);
if (pci->device == PCI_DEVICE_ID_LSI_SAS2208 ||
pci->device == PCI_DEVICE_ID_LSI_SAS3108) {
int j = 0;
@@ -321,7 +327,7 @@ static int megasas_transition_to_ready(struct pci_device *pci, u32 ioaddr)
}
}
} else {
- outw(ioaddr + MFI_IDB, mfi_flags);
+ outl(mfi_flags, ioaddr + MFI_IDB);
}
break;
case MFI_STATE_READY:
diff --git a/qemu/roms/seabios/src/hw/megasas.h b/qemu/roms/seabios/src/hw/megasas.h
index 124042e1c..ed0e4f096 100644
--- a/qemu/roms/seabios/src/hw/megasas.h
+++ b/qemu/roms/seabios/src/hw/megasas.h
@@ -2,7 +2,7 @@
#define __MEGASAS_H
struct disk_op_s;
-int megasas_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize);
+int megasas_process_op(struct disk_op_s *op);
void megasas_setup(void);
#endif /* __MEGASAS_H */
diff --git a/qemu/roms/seabios/src/hw/pci.c b/qemu/roms/seabios/src/hw/pci.c
index 0379b558e..a241d0675 100644
--- a/qemu/roms/seabios/src/hw/pci.c
+++ b/qemu/roms/seabios/src/hw/pci.c
@@ -221,16 +221,21 @@ pci_find_init_device(const struct pci_device_id *ids, void *arg)
return NULL;
}
-u8 pci_find_capability(struct pci_device *pci, u8 cap_id)
+u8 pci_find_capability(struct pci_device *pci, u8 cap_id, u8 cap)
{
int i;
- u8 cap;
u16 status = pci_config_readw(pci->bdf, PCI_STATUS);
if (!(status & PCI_STATUS_CAP_LIST))
return 0;
- cap = pci_config_readb(pci->bdf, PCI_CAPABILITY_LIST);
+ if (cap == 0) {
+ /* find first */
+ cap = pci_config_readb(pci->bdf, PCI_CAPABILITY_LIST);
+ } else {
+ /* find next */
+ cap = pci_config_readb(pci->bdf, cap + PCI_CAP_LIST_NEXT);
+ }
for (i = 0; cap && i <= 0xff; i++) {
if (pci_config_readb(pci->bdf, cap + PCI_CAP_LIST_ID) == cap_id)
return cap;
diff --git a/qemu/roms/seabios/src/hw/pci.h b/qemu/roms/seabios/src/hw/pci.h
index 0aaa84c1a..fc5e7b9bf 100644
--- a/qemu/roms/seabios/src/hw/pci.h
+++ b/qemu/roms/seabios/src/hw/pci.h
@@ -123,7 +123,7 @@ int pci_init_device(const struct pci_device_id *ids
, struct pci_device *pci, void *arg);
struct pci_device *pci_find_init_device(const struct pci_device_id *ids
, void *arg);
-u8 pci_find_capability(struct pci_device *pci, u8 cap_id);
+u8 pci_find_capability(struct pci_device *pci, u8 cap_id, u8 cap);
int pci_bridge_has_region(struct pci_device *pci,
enum pci_region_type region_type);
void pci_reboot(void);
diff --git a/qemu/roms/seabios/src/hw/pci_ids.h b/qemu/roms/seabios/src/hw/pci_ids.h
index 1cd4f7269..cdf9b3cbc 100644
--- a/qemu/roms/seabios/src/hw/pci_ids.h
+++ b/qemu/roms/seabios/src/hw/pci_ids.h
@@ -2616,8 +2616,12 @@
#define PCI_DEVICE_ID_RME_DIGI32_8 0x9898
#define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4
-#define PCI_DEVICE_ID_VIRTIO_BLK 0x1001
-#define PCI_DEVICE_ID_VIRTIO_SCSI 0x1004
+/* virtio 0.9.5 ids (legacy/transitional devices) */
+#define PCI_DEVICE_ID_VIRTIO_BLK_09 0x1001
+#define PCI_DEVICE_ID_VIRTIO_SCSI_09 0x1004
+/* virtio 1.0 ids (modern devices) */
+#define PCI_DEVICE_ID_VIRTIO_BLK_10 0x1042
+#define PCI_DEVICE_ID_VIRTIO_SCSI_10 0x1048
#define PCI_VENDOR_ID_VMWARE 0x15ad
#define PCI_DEVICE_ID_VMWARE_PVSCSI 0x07C0
diff --git a/qemu/roms/seabios/src/hw/pic.c b/qemu/roms/seabios/src/hw/pic.c
index 6ff696765..d8b9764c7 100644
--- a/qemu/roms/seabios/src/hw/pic.c
+++ b/qemu/roms/seabios/src/hw/pic.c
@@ -13,12 +13,16 @@
u16
pic_irqmask_read(void)
{
+ if (!CONFIG_HARDWARE_IRQ)
+ return 0;
return inb(PORT_PIC1_DATA) | (inb(PORT_PIC2_DATA) << 8);
}
void
pic_irqmask_write(u16 mask)
{
+ if (!CONFIG_HARDWARE_IRQ)
+ return;
outb(mask, PORT_PIC1_DATA);
outb(mask >> 8, PORT_PIC2_DATA);
}
@@ -26,6 +30,8 @@ pic_irqmask_write(u16 mask)
void
pic_irqmask_mask(u16 off, u16 on)
{
+ if (!CONFIG_HARDWARE_IRQ)
+ return;
u8 pic1off = off, pic1on = on, pic2off = off>>8, pic2on = on>>8;
outb((inb(PORT_PIC1_DATA) & ~pic1off) | pic1on, PORT_PIC1_DATA);
outb((inb(PORT_PIC2_DATA) & ~pic2off) | pic2on, PORT_PIC2_DATA);
@@ -34,6 +40,8 @@ pic_irqmask_mask(u16 off, u16 on)
void
pic_reset(u8 irq0, u8 irq8)
{
+ if (!CONFIG_HARDWARE_IRQ)
+ return;
// Send ICW1 (select OCW1 + will send ICW4)
outb(0x11, PORT_PIC1_CMD);
outb(0x11, PORT_PIC2_CMD);
@@ -60,6 +68,8 @@ pic_setup(void)
void
enable_hwirq(int hwirq, struct segoff_s func)
{
+ if (!CONFIG_HARDWARE_IRQ)
+ return;
pic_irqmask_mask(1 << hwirq, 0);
int vector;
if (hwirq < 8)
@@ -72,6 +82,8 @@ enable_hwirq(int hwirq, struct segoff_s func)
static u8
pic_isr1_read(void)
{
+ if (!CONFIG_HARDWARE_IRQ)
+ return 0;
// 0x0b == select OCW1 + read ISR
outb(0x0b, PORT_PIC1_CMD);
return inb(PORT_PIC1_CMD);
@@ -80,6 +92,8 @@ pic_isr1_read(void)
static u8
pic_isr2_read(void)
{
+ if (!CONFIG_HARDWARE_IRQ)
+ return 0;
// 0x0b == select OCW1 + read ISR
outb(0x0b, PORT_PIC2_CMD);
return inb(PORT_PIC2_CMD);
diff --git a/qemu/roms/seabios/src/hw/pic.h b/qemu/roms/seabios/src/hw/pic.h
index 6947b6e81..f2d9f6130 100644
--- a/qemu/roms/seabios/src/hw/pic.h
+++ b/qemu/roms/seabios/src/hw/pic.h
@@ -34,6 +34,8 @@
static inline void
pic_eoi1(void)
{
+ if (!CONFIG_HARDWARE_IRQ)
+ return;
// Send eoi (select OCW2 + eoi)
outb(0x20, PORT_PIC1_CMD);
}
@@ -41,6 +43,8 @@ pic_eoi1(void)
static inline void
pic_eoi2(void)
{
+ if (!CONFIG_HARDWARE_IRQ)
+ return;
// Send eoi (select OCW2 + eoi)
outb(0x20, PORT_PIC2_CMD);
pic_eoi1();
diff --git a/qemu/roms/seabios/src/hw/ps2port.c b/qemu/roms/seabios/src/hw/ps2port.c
index 04995c881..d5504f71e 100644
--- a/qemu/roms/seabios/src/hw/ps2port.c
+++ b/qemu/roms/seabios/src/hw/ps2port.c
@@ -210,7 +210,7 @@ ps2_sendbyte(int aux, u8 command, int timeout)
return 0;
}
-u8 Ps2ctr VARLOW;
+u8 Ps2ctr VARLOW = I8042_CTR_KBDDIS | I8042_CTR_AUXDIS;
static int
__ps2_command(int aux, int command, u8 *param)
@@ -232,6 +232,7 @@ __ps2_command(int aux, int command, u8 *param)
yield();
// Enable port command is being sent to.
+ SET_LOW(Ps2ctr, newctr);
if (aux)
newctr &= ~I8042_CTR_AUXDIS;
else
@@ -240,8 +241,8 @@ __ps2_command(int aux, int command, u8 *param)
if (ret)
goto fail;
- if (command == ATKBD_CMD_RESET_BAT) {
- // Reset is special wrt timeouts and bytes received.
+ if ((u8)command == (u8)ATKBD_CMD_RESET_BAT) {
+ // Reset is special wrt timeouts.
// Send command.
ret = ps2_sendbyte(aux, command, 1000);
@@ -253,11 +254,12 @@ __ps2_command(int aux, int command, u8 *param)
if (ret < 0)
goto fail;
param[0] = ret;
- ret = ps2_recvbyte(aux, 0, 100);
- if (ret < 0)
- // Some devices only respond with one byte on reset.
- ret = 0;
- param[1] = ret;
+ if (receive > 1) {
+ ret = ps2_recvbyte(aux, 0, 500);
+ if (ret < 0)
+ goto fail;
+ param[1] = ret;
+ }
} else if (command == ATKBD_CMD_GETID) {
// Getid is special wrt bytes received.
@@ -308,6 +310,7 @@ __ps2_command(int aux, int command, u8 *param)
fail:
// Restore interrupts and keyboard/mouse.
+ SET_LOW(Ps2ctr, ps2ctr);
ret2 = i8042_command(I8042_CMD_CTL_WCTR, &ps2ctr);
if (ret2)
return ret2;
@@ -343,7 +346,8 @@ ps2_mouse_command(int command, u8 *param)
if (command == PSMOUSE_CMD_ENABLE || command == PSMOUSE_CMD_DISABLE) {
u8 ps2ctr = GET_LOW(Ps2ctr);
if (command == PSMOUSE_CMD_ENABLE)
- ps2ctr = (ps2ctr | I8042_CTR_AUXINT) & ~I8042_CTR_AUXDIS;
+ ps2ctr = ((ps2ctr | (CONFIG_HARDWARE_IRQ ? I8042_CTR_AUXINT : 0))
+ & ~I8042_CTR_AUXDIS);
else
ps2ctr = (ps2ctr | I8042_CTR_AUXDIS) & ~I8042_CTR_AUXINT;
SET_LOW(Ps2ctr, ps2ctr);
@@ -414,6 +418,31 @@ done:
pic_eoi1();
}
+// Check for ps2 activity on machines without hardware irqs
+void
+ps2_check_event(void)
+{
+ if (! CONFIG_PS2PORT || CONFIG_HARDWARE_IRQ)
+ return;
+ u8 ps2ctr = GET_LOW(Ps2ctr);
+ if ((ps2ctr & (I8042_CTR_KBDDIS|I8042_CTR_AUXDIS))
+ == (I8042_CTR_KBDDIS|I8042_CTR_AUXDIS))
+ return;
+ for (;;) {
+ u8 status = inb(PORT_PS2_STATUS);
+ if (!(status & I8042_STR_OBF))
+ break;
+ u8 data = inb(PORT_PS2_DATA);
+ if (status & I8042_STR_AUXDATA) {
+ if (!(ps2ctr & I8042_CTR_AUXDIS))
+ process_mouse(data);
+ } else {
+ if (!(ps2ctr & I8042_CTR_KBDDIS))
+ process_key(data);
+ }
+ }
+}
+
/****************************************************************
* Setup
@@ -446,9 +475,6 @@ ps2_keyboard_setup(void *data)
return;
}
- // Disable keyboard and mouse events.
- SET_LOW(Ps2ctr, I8042_CTR_KBDDIS | I8042_CTR_AUXDIS);
-
/* ------------------- keyboard side ------------------------*/
/* reset keyboard and self test (keyboard side) */
@@ -482,7 +508,8 @@ ps2_keyboard_setup(void *data)
return;
// Keyboard Mode: disable mouse, scan code convert, enable kbd IRQ
- SET_LOW(Ps2ctr, I8042_CTR_AUXDIS | I8042_CTR_XLATE | I8042_CTR_KBDINT);
+ Ps2ctr = (I8042_CTR_AUXDIS | I8042_CTR_XLATE
+ | (CONFIG_HARDWARE_IRQ ? I8042_CTR_KBDINT : 0));
/* Enable keyboard */
ret = ps2_kbd_command(ATKBD_CMD_ENABLE, NULL);
diff --git a/qemu/roms/seabios/src/hw/ps2port.h b/qemu/roms/seabios/src/hw/ps2port.h
index e5d9014b7..1338406ac 100644
--- a/qemu/roms/seabios/src/hw/ps2port.h
+++ b/qemu/roms/seabios/src/hw/ps2port.h
@@ -26,7 +26,7 @@
#define ATKBD_CMD_GETID 0x02f2
#define ATKBD_CMD_ENABLE 0x00f4
#define ATKBD_CMD_RESET_DIS 0x00f5
-#define ATKBD_CMD_RESET_BAT 0x02ff
+#define ATKBD_CMD_RESET_BAT 0x01ff
// Mouse commands
#define PSMOUSE_CMD_SETSCALE11 0x00e6
@@ -61,6 +61,7 @@
void i8042_reboot(void);
int ps2_kbd_command(int command, u8 *param);
int ps2_mouse_command(int command, u8 *param);
+void ps2_check_event(void);
void ps2port_setup(void);
#endif // ps2port.h
diff --git a/qemu/roms/seabios/src/hw/pvscsi.c b/qemu/roms/seabios/src/hw/pvscsi.c
index 601a551db..fa20efef7 100644
--- a/qemu/roms/seabios/src/hw/pvscsi.c
+++ b/qemu/roms/seabios/src/hw/pvscsi.c
@@ -11,6 +11,7 @@
#include "blockcmd.h" // scsi_drive_setup
#include "config.h" // CONFIG_*
#include "malloc.h" // free
+#include "memmap.h" // PAGE_SHIFT, virt_to_phys
#include "output.h" // dprintf
#include "pci.h" // foreachpci
#include "pci_ids.h" // PCI_DEVICE_ID_VMWARE_PVSCSI
@@ -19,7 +20,6 @@
#include "std/disk.h" // DISK_RET_SUCCESS
#include "string.h" // memset
#include "util.h" // usleep
-#include "virtio-ring.h" // PAGE_SHIFT, virt_to_phys
#include "x86.h" // writel
#define MASK(n) ((1 << (n)) - 1)
@@ -197,29 +197,6 @@ pvscsi_init_rings(void *iobase, struct pvscsi_ring_dsc_s **ring_dsc)
*ring_dsc = dsc;
}
-static void pvscsi_fill_req(struct PVSCSIRingsState *s,
- struct PVSCSIRingReqDesc *req,
- u16 target, u16 lun, void *cdbcmd, u16 blocksize,
- struct disk_op_s *op)
-{
- req->bus = 0;
- req->target = target;
- memset(req->lun, 0, sizeof(req->lun));
- req->lun[1] = lun;
- req->senseLen = 0;
- req->senseAddr = 0;
- req->cdbLen = 16;
- req->vcpuHint = 0;
- memcpy(req->cdb, cdbcmd, 16);
- req->tag = SIMPLE_QUEUE_TAG;
- req->flags = cdb_is_read(cdbcmd, blocksize) ?
- PVSCSI_FLAG_CMD_DIR_TOHOST : PVSCSI_FLAG_CMD_DIR_TODEVICE;
-
- req->dataLen = op->count * blocksize;
- req->dataAddr = (u32)op->buf_fl;
- s->reqProdIdx = s->reqProdIdx + 1;
-}
-
static u32
pvscsi_get_rsp(struct PVSCSIRingsState *s,
struct PVSCSIRingCmpDesc *rsp)
@@ -229,10 +206,13 @@ pvscsi_get_rsp(struct PVSCSIRingsState *s,
return status;
}
-static int
-pvscsi_cmd(struct pvscsi_lun_s *plun, struct disk_op_s *op,
- void *cdbcmd, u16 target, u16 lun, u16 blocksize)
+int
+pvscsi_process_op(struct disk_op_s *op)
{
+ if (!CONFIG_PVSCSI)
+ return DISK_RET_EBADTRACK;
+ struct pvscsi_lun_s *plun =
+ container_of(op->drive_gf, struct pvscsi_lun_s, drive);
struct pvscsi_ring_dsc_s *ring_dsc = plun->ring_dsc;
struct PVSCSIRingsState *s = ring_dsc->ring_state;
u32 req_entries = s->reqNumEntriesLog2;
@@ -248,7 +228,23 @@ pvscsi_cmd(struct pvscsi_lun_s *plun, struct disk_op_s *op,
}
req = ring_dsc->ring_reqs + (s->reqProdIdx & MASK(req_entries));
- pvscsi_fill_req(s, req, target, lun, cdbcmd, blocksize, op);
+ int blocksize = scsi_fill_cmd(op, req->cdb, 16);
+ if (blocksize < 0)
+ return default_process_op(op);
+ req->bus = 0;
+ req->target = plun->target;
+ memset(req->lun, 0, sizeof(req->lun));
+ req->lun[1] = plun->lun;
+ req->senseLen = 0;
+ req->senseAddr = 0;
+ req->cdbLen = 16;
+ req->vcpuHint = 0;
+ req->tag = SIMPLE_QUEUE_TAG;
+ req->flags = scsi_is_read(op) ?
+ PVSCSI_FLAG_CMD_DIR_TOHOST : PVSCSI_FLAG_CMD_DIR_TODEVICE;
+ req->dataLen = op->count * blocksize;
+ req->dataAddr = (u32)op->buf_fl;
+ s->reqProdIdx = s->reqProdIdx + 1;
pvscsi_kick_rw_io(plun->iobase);
pvscsi_wait_intr_cmpl(plun->iobase);
@@ -259,18 +255,6 @@ pvscsi_cmd(struct pvscsi_lun_s *plun, struct disk_op_s *op,
return status == 0 ? DISK_RET_SUCCESS : DISK_RET_EBADTRACK;
}
-int
-pvscsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
-{
- if (!CONFIG_PVSCSI)
- return DISK_RET_EBADTRACK;
-
- struct pvscsi_lun_s *plun =
- container_of(op->drive_gf, struct pvscsi_lun_s, drive);
-
- return pvscsi_cmd(plun, op, cdbcmd, plun->target, plun->lun, blocksize);
-}
-
static int
pvscsi_add_lun(struct pci_device *pci, void *iobase,
struct pvscsi_ring_dsc_s *ring_dsc, u8 target, u8 lun)
diff --git a/qemu/roms/seabios/src/hw/pvscsi.h b/qemu/roms/seabios/src/hw/pvscsi.h
index fde9f0b98..5af7dcb0e 100644
--- a/qemu/roms/seabios/src/hw/pvscsi.h
+++ b/qemu/roms/seabios/src/hw/pvscsi.h
@@ -2,7 +2,7 @@
#define _PVSCSI_H_
struct disk_op_s;
-int pvscsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize);
+int pvscsi_process_op(struct disk_op_s *op);
void pvscsi_setup(void);
#endif /* _PVSCSI_H_ */
diff --git a/qemu/roms/seabios/src/hw/ramdisk.c b/qemu/roms/seabios/src/hw/ramdisk.c
index 1177bc00a..adec1d1b3 100644
--- a/qemu/roms/seabios/src/hw/ramdisk.c
+++ b/qemu/roms/seabios/src/hw/ramdisk.c
@@ -7,8 +7,9 @@
#include "biosvar.h" // GET_GLOBALFLAT
#include "block.h" // struct drive_s
#include "bregs.h" // struct bregs
-#include "malloc.h" // malloc_fseg
-#include "memmap.h" // add_e820
+#include "e820map.h" // e820_add
+#include "malloc.h" // memalign_tmphigh
+#include "memmap.h" // PAGE_SIZE
#include "output.h" // dprintf
#include "romfile.h" // romfile_findprefix
#include "stacks.h" // call16_int
@@ -41,7 +42,7 @@ ramdisk_setup(void)
warn_noalloc();
return;
}
- add_e820((u32)pos, size, E820_RESERVED);
+ e820_add((u32)pos, size, E820_RESERVED);
// Copy image into ram.
int ret = file->copy(file, pos, size);
@@ -53,7 +54,7 @@ ramdisk_setup(void)
if (!drive)
return;
drive->type = DTYPE_RAMDISK;
- dprintf(1, "Mapping CBFS floppy %s to addr %p\n", filename, pos);
+ dprintf(1, "Mapping floppy %s to addr %p\n", filename, pos);
char *desc = znprintf(MAXDESCSIZE, "Ramdisk [%s]", &filename[10]);
boot_add_floppy(drive, desc, bootprio_find_named_rom(filename, 0));
}
@@ -91,7 +92,7 @@ ramdisk_copy(struct disk_op_s *op, int iswrite)
}
int
-process_ramdisk_op(struct disk_op_s *op)
+ramdisk_process_op(struct disk_op_s *op)
{
if (!CONFIG_FLASH_FLOPPY)
return 0;
@@ -101,11 +102,7 @@ process_ramdisk_op(struct disk_op_s *op)
return ramdisk_copy(op, 0);
case CMD_WRITE:
return ramdisk_copy(op, 1);
- case CMD_VERIFY:
- case CMD_FORMAT:
- case CMD_RESET:
- return DISK_RET_SUCCESS;
default:
- return DISK_RET_EPARAM;
+ return default_process_op(op);
}
}
diff --git a/qemu/roms/seabios/src/hw/rtc.c b/qemu/roms/seabios/src/hw/rtc.c
index 628d5429f..9649a5a79 100644
--- a/qemu/roms/seabios/src/hw/rtc.c
+++ b/qemu/roms/seabios/src/hw/rtc.c
@@ -30,6 +30,7 @@ rtc_write(u8 index, u8 val)
void
rtc_mask(u8 index, u8 off, u8 on)
{
+ index |= NMI_DISABLE_BIT;
outb(index, PORT_CMOS_INDEX);
u8 val = inb(PORT_CMOS_DATA);
outb((val & ~off) | on, PORT_CMOS_DATA);
@@ -62,6 +63,8 @@ rtc_updating(void)
void
rtc_setup(void)
{
+ if (!CONFIG_RTC_TIMER)
+ return;
rtc_write(CMOS_STATUS_A, 0x26); // 32,768Khz src, 976.5625us updates
rtc_mask(CMOS_STATUS_B, ~RTC_B_DSE, RTC_B_24HR);
rtc_read(CMOS_STATUS_C);
@@ -73,6 +76,8 @@ int RTCusers VARLOW;
void
rtc_use(void)
{
+ if (!CONFIG_RTC_TIMER)
+ return;
int count = GET_LOW(RTCusers);
SET_LOW(RTCusers, count+1);
if (count)
@@ -84,6 +89,8 @@ rtc_use(void)
void
rtc_release(void)
{
+ if (!CONFIG_RTC_TIMER)
+ return;
int count = GET_LOW(RTCusers);
SET_LOW(RTCusers, count-1);
if (count != 1)
diff --git a/qemu/roms/seabios/src/hw/sdcard.c b/qemu/roms/seabios/src/hw/sdcard.c
index 6ff93c856..e01e1bb02 100644
--- a/qemu/roms/seabios/src/hw/sdcard.c
+++ b/qemu/roms/seabios/src/hw/sdcard.c
@@ -5,12 +5,12 @@
// This file may be distributed under the terms of the GNU LGPLv3 license.
#include "block.h" // struct drive_s
-#include "fw/paravirt.h" // runningOnQEMU
#include "malloc.h" // malloc_fseg
#include "output.h" // znprintf
#include "pci.h" // pci_config_readl
#include "pci_ids.h" // PCI_CLASS_SYSTEM_SDHCI
#include "pci_regs.h" // PCI_BASE_ADDRESS_0
+#include "romfile.h" // romfile_findprefix
#include "stacks.h" // wait_preempt
#include "std/disk.h" // DISK_RET_SUCCESS
#include "string.h" // memset
@@ -42,8 +42,8 @@ struct sdhci_s {
u16 irq_signal;
u16 error_signal;
u16 auto_cmd12;
- u8 pad_3E[2];
- u64 cap;
+ u16 host_control2;
+ u32 cap_lo, cap_hi;
u64 max_current;
u16 force_auto_cmd12;
u16 force_error;
@@ -56,25 +56,38 @@ struct sdhci_s {
} PACKED;
// SDHCI commands
-#define SC_ALL_SEND_CID ((2<<8) | 0x21)
-#define SC_SEND_RELATIVE_ADDR ((3<<8) | 0x22)
-#define SC_SELECT_DESELECT_CARD ((7<<8) | 0x23)
-#define SC_READ_SINGLE ((17<<8) | 0x22)
-#define SC_READ_MULTIPLE ((18<<8) | 0x22)
-#define SC_WRITE_SINGLE ((24<<8) | 0x22)
-#define SC_WRITE_MULTIPLE ((25<<8) | 0x22)
-#define SC_APP_CMD ((55<<8) | 0x22)
-#define SC_APP_SEND_OP_COND ((41<<8) | 0x22)
+#define SCB_R0 0x00 // No response
+#define SCB_R48 0x1a // Response R1 (no data), R5, R6, R7
+#define SCB_R48d 0x3a // Response R1 (with data)
+#define SCB_R48b 0x1b // Response R1b, R5b
+#define SCB_R48o 0x02 // Response R3, R4
+#define SCB_R136 0x09 // Response R2
+#define SC_GO_IDLE_STATE ((0<<8) | SCB_R0)
+#define SC_SEND_OP_COND ((1<<8) | SCB_R48o)
+#define SC_ALL_SEND_CID ((2<<8) | SCB_R136)
+#define SC_SEND_RELATIVE_ADDR ((3<<8) | SCB_R48)
+#define SC_SELECT_DESELECT_CARD ((7<<8) | SCB_R48b)
+#define SC_SEND_IF_COND ((8<<8) | SCB_R48)
+#define SC_SEND_EXT_CSD ((8<<8) | SCB_R48d)
+#define SC_SEND_CSD ((9<<8) | SCB_R136)
+#define SC_READ_SINGLE ((17<<8) | SCB_R48d)
+#define SC_READ_MULTIPLE ((18<<8) | SCB_R48d)
+#define SC_WRITE_SINGLE ((24<<8) | SCB_R48d)
+#define SC_WRITE_MULTIPLE ((25<<8) | SCB_R48d)
+#define SC_APP_CMD ((55<<8) | SCB_R48)
+#define SC_APP_SEND_OP_COND ((41<<8) | SCB_R48o)
// SDHCI irqs
#define SI_CMD_COMPLETE (1<<0)
#define SI_TRANS_DONE (1<<1)
#define SI_WRITE_READY (1<<4)
#define SI_READ_READY (1<<5)
+#define SI_ERROR (1<<15)
// SDHCI present_state flags
-#define SP_CMD_INHIBIT (1<<0)
-#define SP_DAT_INHIBIT (1<<1)
+#define SP_CMD_INHIBIT (1<<0)
+#define SP_DAT_INHIBIT (1<<1)
+#define SP_CARD_INSERTED (1<<16)
// SDHCI transfer_mode flags
#define ST_BLOCKCOUNT (1<<1)
@@ -82,12 +95,43 @@ struct sdhci_s {
#define ST_READ (1<<4)
#define ST_MULTIPLE (1<<5)
+// SDHCI capabilities flags
+#define SD_CAPLO_V33 (1<<24)
+#define SD_CAPLO_V30 (1<<25)
+#define SD_CAPLO_V18 (1<<26)
+#define SD_CAPLO_BASECLOCK_SHIFT 8
+#define SD_CAPLO_BASECLOCK_MASK 0xff
+
+// SDHCI clock control flags
+#define SCC_INTERNAL_ENABLE (1<<0)
+#define SCC_STABLE (1<<1)
+#define SCC_CLOCK_ENABLE (1<<2)
+#define SCC_SDCLK_MASK 0xff
+#define SCC_SDCLK_SHIFT 8
+#define SCC_SDCLK_HI_MASK 0x300
+#define SCC_SDCLK_HI_RSHIFT 2
+
+// SDHCI power control flags
+#define SPC_POWER_ON (1<<0)
+#define SPC_V18 0x0a
+#define SPC_V30 0x0c
+#define SPC_V33 0x0e
+
+// SDHCI software reset flags
+#define SRF_ALL 0x01
+#define SRF_CMD 0x02
+#define SRF_DATA 0x04
+
// SDHCI result flags
-#define SR_OCR_CCS (1<<30)
+#define SR_OCR_CCS (1<<30)
+#define SR_OCR_NOTBUSY (1<<31)
// SDHCI timeouts
-#define SDHCI_PIO_TIMEOUT 1000 // XXX - these are just made up
-#define SDHCI_TRANSFER_TIMEOUT 10000
+#define SDHCI_POWER_OFF_TIME 1
+#define SDHCI_POWER_ON_TIME 1
+#define SDHCI_CLOCK_ON_TIME 1 // 74 clock cycles
+#define SDHCI_POWERUP_TIMEOUT 1000
+#define SDHCI_PIO_TIMEOUT 1000 // XXX - this is just made up
// Internal 'struct drive_s' storage for a detected card
struct sddrive_s {
@@ -97,18 +141,18 @@ struct sddrive_s {
};
// SD card types
-#define SF_MMC 0
-#define SF_SDSC 1
-#define SF_SDHC 2
+#define SF_MMC (1<<0)
+#define SF_HIGHCAPACITY (1<<1)
-// Repeatedly read a u16 register until the specific value is found
+// Repeatedly read a u16 register until any bit in a given mask is set
static int
-waitw(u16 *reg, u16 mask, u16 value, u32 end)
+sdcard_waitw(u16 *reg, u16 mask)
{
+ u32 end = timer_calc(SDHCI_PIO_TIMEOUT);
for (;;) {
u16 v = readw(reg);
- if ((v & mask) == value)
- return 0;
+ if (v & mask)
+ return v;
if (timer_check(end)) {
warn_timeout();
return -1;
@@ -117,24 +161,49 @@ waitw(u16 *reg, u16 mask, u16 value, u32 end)
}
}
+// Send an sdhci reset
+static int
+sdcard_reset(struct sdhci_s *regs, int flags)
+{
+ writeb(&regs->software_reset, flags);
+ u32 end = timer_calc(SDHCI_PIO_TIMEOUT);
+ while (readb(&regs->software_reset))
+ if (timer_check(end)) {
+ warn_timeout();
+ return -1;
+ }
+ return 0;
+}
+
// Send a command to the card.
static int
sdcard_pio(struct sdhci_s *regs, int cmd, u32 *param)
{
- u32 end = timer_calc(SDHCI_PIO_TIMEOUT);
- u16 busyf = SP_CMD_INHIBIT | ((cmd & 0x03) == 0x03 ? SP_DAT_INHIBIT : 0);
- int ret = waitw((u16*)&regs->present_state, busyf, 0, end);
- if (ret)
- return ret;
+ u32 state = readl(&regs->present_state);
+ dprintf(9, "sdcard_pio cmd %x %x %x\n", cmd, *param, state);
+ if ((state & SP_CMD_INHIBIT)
+ || ((cmd & 0x03) == 0x03 && state & SP_DAT_INHIBIT)) {
+ dprintf(1, "sdcard_pio not ready %x\n", state);
+ return -1;
+ }
// Send command
writel(&regs->arg, *param);
writew(&regs->cmd, cmd);
- ret = waitw(&regs->irq_status, SI_CMD_COMPLETE, SI_CMD_COMPLETE, end);
- if (ret)
+ int ret = sdcard_waitw(&regs->irq_status, SI_ERROR|SI_CMD_COMPLETE);
+ if (ret < 0)
return ret;
+ if (ret & SI_ERROR) {
+ u16 err = readw(&regs->error_irq_status);
+ dprintf(3, "sdcard_pio command stop (code=%x)\n", err);
+ sdcard_reset(regs, SRF_CMD|SRF_DATA);
+ writew(&regs->error_irq_status, err);
+ return -1;
+ }
writew(&regs->irq_status, SI_CMD_COMPLETE);
// Read response
memcpy(param, regs->response, sizeof(regs->response));
+ dprintf(9, "sdcard cmd %x response %x %x %x %x\n"
+ , cmd, param[0], param[1], param[2], param[3]);
return 0;
}
@@ -155,24 +224,23 @@ sdcard_pio_transfer(struct sddrive_s *drive, int cmd, u32 addr
, void *data, int count)
{
// Send command
- writel(&drive->regs->block_size, DISK_SECTOR_SIZE);
- writew(&drive->regs->block_count, count); // XXX - SC_SET_BLOCK_COUNT?
+ writew(&drive->regs->block_size, DISK_SECTOR_SIZE);
+ writew(&drive->regs->block_count, count);
int isread = cmd != SC_WRITE_SINGLE && cmd != SC_WRITE_MULTIPLE;
u16 tmode = ((count > 1 ? ST_MULTIPLE|ST_AUTO_CMD12|ST_BLOCKCOUNT : 0)
| (isread ? ST_READ : 0));
writew(&drive->regs->transfer_mode, tmode);
- if (drive->card_type < SF_SDHC)
+ if (!(drive->card_type & SF_HIGHCAPACITY))
addr *= DISK_SECTOR_SIZE;
u32 param[4] = { addr };
int ret = sdcard_pio(drive->regs, cmd, param);
if (ret)
return ret;
// Read/write data
- u32 end = timer_calc(SDHCI_TRANSFER_TIMEOUT);
u16 cbit = isread ? SI_READ_READY : SI_WRITE_READY;
while (count--) {
- ret = waitw(&drive->regs->irq_status, cbit, cbit, end);
- if (ret)
+ ret = sdcard_waitw(&drive->regs->irq_status, cbit);
+ if (ret < 0)
return ret;
writew(&drive->regs->irq_status, cbit);
int i;
@@ -185,9 +253,8 @@ sdcard_pio_transfer(struct sddrive_s *drive, int cmd, u32 addr
}
}
// Complete command
- // XXX - SC_STOP_TRANSMISSION?
- ret = waitw(&drive->regs->irq_status, SI_TRANS_DONE, SI_TRANS_DONE, end);
- if (ret)
+ ret = sdcard_waitw(&drive->regs->irq_status, SI_TRANS_DONE);
+ if (ret < 0)
return ret;
writew(&drive->regs->irq_status, SI_TRANS_DONE);
return 0;
@@ -208,8 +275,8 @@ sdcard_readwrite(struct disk_op_s *op, int iswrite)
return DISK_RET_SUCCESS;
}
-int VISIBLE32FLAT
-process_sdcard_op(struct disk_op_s *op)
+int
+sdcard_process_op(struct disk_op_s *op)
{
if (!CONFIG_SDCARD)
return 0;
@@ -218,14 +285,8 @@ process_sdcard_op(struct disk_op_s *op)
return sdcard_readwrite(op, 0);
case CMD_WRITE:
return sdcard_readwrite(op, 1);
- case CMD_FORMAT:
- case CMD_RESET:
- case CMD_ISREADY:
- case CMD_VERIFY:
- case CMD_SEEK:
- return DISK_RET_SUCCESS;
default:
- return DISK_RET_EPARAM;
+ return default_process_op(op);
}
}
@@ -234,75 +295,253 @@ process_sdcard_op(struct disk_op_s *op)
* Setup
****************************************************************/
+static int
+sdcard_set_power(struct sdhci_s *regs)
+{
+ u32 cap = readl(&regs->cap_lo);
+ u32 volt, vbits;
+ if (cap & SD_CAPLO_V33) {
+ volt = 1<<20;
+ vbits = SPC_V33;
+ } else if (cap & SD_CAPLO_V30) {
+ volt = 1<<18;
+ vbits = SPC_V30;
+ } else if (cap & SD_CAPLO_V18) {
+ volt = 1<<7;
+ vbits = SPC_V18;
+ } else {
+ dprintf(1, "SD controller unsupported volt range (%x)\n", cap);
+ return -1;
+ }
+ writeb(&regs->power_control, 0);
+ msleep(SDHCI_POWER_OFF_TIME);
+ writeb(&regs->power_control, vbits | SPC_POWER_ON);
+ msleep(SDHCI_POWER_ON_TIME);
+ return volt;
+}
+
+static int
+sdcard_set_frequency(struct sdhci_s *regs, u32 khz)
+{
+ u16 ver = readw(&regs->controller_version);
+ u32 cap = readl(&regs->cap_lo);
+ u32 base_freq = (cap >> SD_CAPLO_BASECLOCK_SHIFT) & SD_CAPLO_BASECLOCK_MASK;
+ if (!base_freq) {
+ dprintf(1, "Unknown base frequency for SD controller\n");
+ return -1;
+ }
+ // Set new frequency
+ u32 divisor = DIV_ROUND_UP(base_freq * 1000, khz);
+ u16 creg;
+ if ((ver & 0xff) <= 0x01) {
+ divisor = divisor > 1 ? 1 << __fls(divisor-1) : 0;
+ creg = (divisor & SCC_SDCLK_MASK) << SCC_SDCLK_SHIFT;
+ } else {
+ divisor = DIV_ROUND_UP(divisor, 2);
+ creg = (divisor & SCC_SDCLK_MASK) << SCC_SDCLK_SHIFT;
+ creg |= (divisor & SCC_SDCLK_HI_MASK) >> SCC_SDCLK_HI_RSHIFT;
+ }
+ dprintf(3, "sdcard_set_frequency %d %d %x\n", base_freq, khz, creg);
+ writew(&regs->clock_control, 0);
+ writew(&regs->clock_control, creg | SCC_INTERNAL_ENABLE);
+ // Wait for frequency to become active
+ int ret = sdcard_waitw(&regs->clock_control, SCC_STABLE);
+ if (ret < 0)
+ return ret;
+ // Enable SD clock
+ writew(&regs->clock_control, creg | SCC_INTERNAL_ENABLE | SCC_CLOCK_ENABLE);
+ return 0;
+}
+
+// Obtain the disk size of an SD card
+static int
+sdcard_get_capacity(struct sddrive_s *drive, u8 *csd)
+{
+ // Original MMC/SD card capacity formula
+ u16 C_SIZE = (csd[6] >> 6) | (csd[7] << 2) | ((csd[8] & 0x03) << 10);
+ u8 C_SIZE_MULT = (csd[4] >> 7) | ((csd[5] & 0x03) << 1);
+ u8 READ_BL_LEN = csd[9] & 0x0f;
+ u32 count = (C_SIZE+1) << (C_SIZE_MULT + 2 + READ_BL_LEN - 9);
+ // Check for newer encoding formats.
+ u8 CSD_STRUCTURE = csd[14] >> 6;
+ if ((drive->card_type & SF_MMC) && CSD_STRUCTURE >= 2) {
+ // Get capacity from EXT_CSD register
+ u8 ext_csd[512];
+ int ret = sdcard_pio_transfer(drive, SC_SEND_EXT_CSD, 0, ext_csd, 1);
+ if (ret)
+ return ret;
+ count = *(u32*)&ext_csd[212];
+ } else if (!(drive->card_type & SF_MMC) && CSD_STRUCTURE >= 1) {
+ // High capacity SD card
+ u32 C_SIZE2 = csd[5] | (csd[6] << 8) | ((csd[7] & 0x3f) << 16);
+ count = (C_SIZE2+1) << (19-9);
+ }
+ // Fill drive struct and return
+ drive->drive.blksize = DISK_SECTOR_SIZE;
+ drive->drive.sectors = count;
+ return 0;
+}
+
// Initialize an SD card
static int
-sdcard_card_setup(struct sdhci_s *regs)
+sdcard_card_setup(struct sddrive_s *drive, int volt, int prio)
{
- // XXX - works on QEMU; probably wont on real hardware!
- u32 param[4] = { 0x01 };
- int ret = sdcard_pio_app(regs, SC_APP_SEND_OP_COND, param);
+ struct sdhci_s *regs = drive->regs;
+ // Set controller to initialization clock rate
+ int ret = sdcard_set_frequency(regs, 400);
+ if (ret)
+ return ret;
+ msleep(SDHCI_CLOCK_ON_TIME);
+ // Reset card
+ u32 param[4] = { };
+ ret = sdcard_pio(regs, SC_GO_IDLE_STATE, param);
if (ret)
return ret;
- int card_type = (param[0] & SR_OCR_CCS) ? SF_SDHC : SF_SDSC;
+ // Let card know SDHC/SDXC is supported and confirm voltage
+ u32 hcs = 0, vrange = (volt >= (1<<15) ? 0x100 : 0x200) | 0xaa;
+ param[0] = vrange;
+ ret = sdcard_pio(regs, SC_SEND_IF_COND, param);
+ if (!ret && param[0] == vrange)
+ hcs = (1<<30);
+ // Verify SD card (instead of MMC or SDIO)
+ param[0] = 0x00;
+ ret = sdcard_pio_app(regs, SC_APP_SEND_OP_COND, param);
+ if (ret) {
+ // Check for MMC card
+ param[0] = 0x00;
+ ret = sdcard_pio(regs, SC_SEND_OP_COND, param);
+ if (ret)
+ return ret;
+ drive->card_type |= SF_MMC;
+ hcs = (1<<30);
+ }
+ // Init card
+ u32 end = timer_calc(SDHCI_POWERUP_TIMEOUT);
+ for (;;) {
+ param[0] = hcs | volt; // high-capacity support and voltage level
+ if (drive->card_type & SF_MMC)
+ ret = sdcard_pio(regs, SC_SEND_OP_COND, param);
+ else
+ ret = sdcard_pio_app(regs, SC_APP_SEND_OP_COND, param);
+ if (ret)
+ return ret;
+ if (param[0] & SR_OCR_NOTBUSY)
+ break;
+ if (timer_check(end)) {
+ warn_timeout();
+ return -1;
+ }
+ msleep(5); // Avoid flooding log when debugging
+ }
+ drive->card_type |= (param[0] & SR_OCR_CCS) ? SF_HIGHCAPACITY : 0;
+ // Select card (get cid, set rca, get csd, select card)
param[0] = 0x00;
ret = sdcard_pio(regs, SC_ALL_SEND_CID, param);
if (ret)
return ret;
- param[0] = 0x01 << 16;
+ u8 cid[16];
+ memcpy(cid, param, sizeof(cid));
+ param[0] = drive->card_type & SF_MMC ? 0x0001 << 16 : 0x00;
ret = sdcard_pio(regs, SC_SEND_RELATIVE_ADDR, param);
if (ret)
return ret;
- u16 rca = param[0] >> 16;
+ u16 rca = drive->card_type & SF_MMC ? 0x0001 : param[0] >> 16;
+ param[0] = rca << 16;
+ ret = sdcard_pio(regs, SC_SEND_CSD, param);
+ if (ret)
+ return ret;
+ u8 csd[16];
+ memcpy(csd, param, sizeof(csd));
param[0] = rca << 16;
ret = sdcard_pio(regs, SC_SELECT_DESELECT_CARD, param);
if (ret)
return ret;
- return card_type;
+ // Set controller to data transfer clock rate
+ ret = sdcard_set_frequency(regs, 25000);
+ if (ret)
+ return ret;
+ // Register drive
+ ret = sdcard_get_capacity(drive, csd);
+ if (ret)
+ return ret;
+ char pnm[7] = {};
+ int i;
+ for (i=0; i < (drive->card_type & SF_MMC ? 6 : 5); i++)
+ pnm[i] = cid[11-i];
+ char *desc = znprintf(MAXDESCSIZE, "%s %s %dMiB"
+ , drive->card_type & SF_MMC ? "MMC drive" : "SD card"
+ , pnm, (u32)(drive->drive.sectors >> 11));
+ dprintf(1, "Found sdcard at %p: %s\n", regs, desc);
+ boot_add_hd(&drive->drive, desc, prio);
+ return 0;
}
// Setup and configure an SD card controller
static void
-sdcard_controller_setup(void *data)
+sdcard_controller_setup(struct sdhci_s *regs, int prio)
{
- struct pci_device *pci = data;
- u16 bdf = pci->bdf;
- wait_preempt(); // Avoid pci_config_readl when preempting
- struct sdhci_s *regs = (void*)pci_config_readl(bdf, PCI_BASE_ADDRESS_0);
- pci_config_maskw(bdf, PCI_COMMAND, 0,
- PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
-
// Initialize controller
- if (!runningOnQEMU())
- // XXX - this init logic will probably only work on qemu!
+ u32 present_state = readl(&regs->present_state);
+ if (!(present_state & SP_CARD_INSERTED))
+ // No card present
return;
+ dprintf(3, "sdhci@%p ver=%x cap=%x %x\n", regs
+ , readw(&regs->controller_version)
+ , readl(&regs->cap_lo), readl(&regs->cap_hi));
+ sdcard_reset(regs, SRF_ALL);
writew(&regs->irq_signal, 0);
- writew(&regs->irq_enable, 0xffff);
+ writew(&regs->irq_enable, 0x01ff);
+ writew(&regs->irq_status, readw(&regs->irq_status));
writew(&regs->error_signal, 0);
- writeb(&regs->power_control, 0x0f);
- writew(&regs->clock_control, 0x0005);
-
- // Initialize card
- int card_type = sdcard_card_setup(regs);
- if (card_type < 0)
+ writew(&regs->error_irq_enable, 0x01ff);
+ writew(&regs->error_irq_status, readw(&regs->error_irq_status));
+ writeb(&regs->timeout_control, 0x0e); // Set to max timeout
+ int volt = sdcard_set_power(regs);
+ if (volt < 0)
return;
- // Register drive
+ // Initialize card
struct sddrive_s *drive = malloc_fseg(sizeof(*drive));
if (!drive) {
warn_noalloc();
- return;
+ goto fail;
}
memset(drive, 0, sizeof(*drive));
drive->drive.type = DTYPE_SDCARD;
- drive->drive.blksize = DISK_SECTOR_SIZE;
- drive->drive.sectors = (u64)-1; // XXX
drive->regs = regs;
- drive->card_type = card_type;
+ int ret = sdcard_card_setup(drive, volt, prio);
+ if (ret) {
+ free(drive);
+ goto fail;
+ }
+ return;
+fail:
+ writeb(&regs->power_control, 0);
+ writew(&regs->clock_control, 0);
+}
- dprintf(1, "Found SD Card at %02x:%02x.%x\n"
- , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf));
- char *desc = znprintf(MAXDESCSIZE, "SD Card"); // XXX
- boot_add_hd(&drive->drive, desc, bootprio_find_pci_device(pci));
+static void
+sdcard_pci_setup(void *data)
+{
+ struct pci_device *pci = data;
+ wait_preempt(); // Avoid pci_config_readl when preempting
+ // XXX - bars dependent on slot index register in pci config space
+ u32 regs = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0);
+ regs &= PCI_BASE_ADDRESS_MEM_MASK;
+ pci_config_maskw(pci->bdf, PCI_COMMAND, 0,
+ PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+ int prio = bootprio_find_pci_device(pci);
+ sdcard_controller_setup((void*)regs, prio);
+}
+
+static void
+sdcard_romfile_setup(void *data)
+{
+ struct romfile_s *file = data;
+ int prio = bootprio_find_named_rom(file->name, 0);
+ u32 addr = romfile_loadint(file->name, 0);
+ dprintf(1, "Starting sdcard controller check at addr %x\n", addr);
+ sdcard_controller_setup((void*)addr, prio);
}
void
@@ -311,11 +550,19 @@ sdcard_setup(void)
if (!CONFIG_SDCARD)
return;
+ struct romfile_s *file = NULL;
+ for (;;) {
+ file = romfile_findprefix("etc/sdcard", file);
+ if (!file)
+ break;
+ run_thread(sdcard_romfile_setup, file);
+ }
+
struct pci_device *pci;
foreachpci(pci) {
if (pci->class != PCI_CLASS_SYSTEM_SDHCI || pci->prog_if >= 2)
// Not an SDHCI controller following SDHCI spec
continue;
- run_thread(sdcard_controller_setup, pci);
+ run_thread(sdcard_pci_setup, pci);
}
}
diff --git a/qemu/roms/seabios/src/hw/timer.c b/qemu/roms/seabios/src/hw/timer.c
index 5edc9fdbb..03d22b2f5 100644
--- a/qemu/roms/seabios/src/hw/timer.c
+++ b/qemu/roms/seabios/src/hw/timer.c
@@ -49,8 +49,8 @@
#define PMTIMER_HZ 3579545 // Underlying Hz of the PM Timer
#define PMTIMER_TO_PIT 3 // Ratio of pmtimer rate to pit rate
-u32 TimerKHz VARFSEG;
-u16 TimerPort VARFSEG;
+u32 TimerKHz VARFSEG = DIV_ROUND_UP(PMTIMER_HZ, 1000 * PMTIMER_TO_PIT);
+u16 TimerPort VARFSEG = PORT_PIT_COUNTER0;
u8 ShiftTSC VARFSEG;
@@ -92,6 +92,7 @@ tsctimer_setup(void)
t = (t + 1) >> 1;
}
TimerKHz = DIV_ROUND_UP((u32)t, 1000 * PMTIMER_TO_PIT);
+ TimerPort = 0;
dprintf(1, "CPU Mhz=%u\n", (TimerKHz << ShiftTSC) / 1000);
}
@@ -100,24 +101,16 @@ tsctimer_setup(void)
void
timer_setup(void)
{
- if (CONFIG_PMTIMER && TimerPort) {
- dprintf(3, "pmtimer already configured; will not calibrate TSC\n");
+ if (!CONFIG_TSC_TIMER || (CONFIG_PMTIMER && TimerPort != PORT_PIT_COUNTER0))
return;
- }
+ // Check if CPU has a timestamp counter
u32 eax, ebx, ecx, edx, cpuid_features = 0;
cpuid(0, &eax, &ebx, &ecx, &edx);
if (eax > 0)
cpuid(1, &eax, &ebx, &ecx, &cpuid_features);
-
- if (!(cpuid_features & CPUID_TSC)) {
- TimerPort = PORT_PIT_COUNTER0;
- TimerKHz = DIV_ROUND_UP(PMTIMER_HZ, 1000 * PMTIMER_TO_PIT);
- dprintf(3, "386/486 class CPU. Using TSC emulation\n");
- return;
- }
-
- tsctimer_setup();
+ if (cpuid_features & CPUID_TSC)
+ tsctimer_setup();
}
void
@@ -154,7 +147,7 @@ static u32
timer_read(void)
{
u16 port = GET_GLOBAL(TimerPort);
- if (!port)
+ if (CONFIG_TSC_TIMER && !port)
// Read from CPU TSC
return rdtscll() >> GET_GLOBAL(ShiftTSC);
if (CONFIG_PMTIMER && port != PORT_PIT_COUNTER0)
@@ -249,6 +242,8 @@ ticks_from_ms(u32 ms)
void
pit_setup(void)
{
+ if (!CONFIG_HARDWARE_IRQ)
+ return;
// timer0: binary count, 16bit count, mode 2
outb(PM_SEL_TIMER0|PM_ACCESS_WORD|PM_MODE2|PM_CNT_BINARY, PORT_PIT_MODE);
// maximum count of 0000H = 18.2Hz
diff --git a/qemu/roms/seabios/src/hw/tpm_drivers.c b/qemu/roms/seabios/src/hw/tpm_drivers.c
new file mode 100644
index 000000000..444eac39b
--- /dev/null
+++ b/qemu/roms/seabios/src/hw/tpm_drivers.c
@@ -0,0 +1,291 @@
+// Implementation of a TPM driver for the TPM TIS interface
+//
+// Copyright (C) 2006-2011 IBM Corporation
+//
+// Authors:
+// Stefan Berger <stefanb@linux.vnet.ibm.com>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "config.h" // CONFIG_TPM_TIS_SHA1THRESHOLD
+#include "string.h" // memcpy
+#include "util.h" // msleep
+#include "x86.h" // readl
+#include "hw/tpm_drivers.h" // struct tpm_driver
+#include "tcgbios.h" // TCG_*
+
+static const u32 tis_default_timeouts[4] = {
+ TIS_DEFAULT_TIMEOUT_A,
+ TIS_DEFAULT_TIMEOUT_B,
+ TIS_DEFAULT_TIMEOUT_C,
+ TIS_DEFAULT_TIMEOUT_D,
+};
+
+static const u32 tpm_default_durations[3] = {
+ TPM_DEFAULT_DURATION_SHORT,
+ TPM_DEFAULT_DURATION_MEDIUM,
+ TPM_DEFAULT_DURATION_LONG,
+};
+
+/* determined values */
+static u32 tpm_default_dur[3];
+static u32 tpm_default_to[4];
+
+
+/* if device is not there, return '0', '1' otherwise */
+static u32 tis_probe(void)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ u32 rc = 0;
+ u32 didvid = readl(TIS_REG(0, TIS_REG_DID_VID));
+
+ if ((didvid != 0) && (didvid != 0xffffffff))
+ rc = 1;
+
+ return rc;
+}
+
+static u32 tis_init(void)
+{
+ if (!CONFIG_TCGBIOS)
+ return 1;
+
+ writeb(TIS_REG(0, TIS_REG_INT_ENABLE), 0);
+
+ if (tpm_drivers[TIS_DRIVER_IDX].durations == NULL) {
+ u32 *durations = tpm_default_dur;
+ memcpy(durations, tpm_default_durations,
+ sizeof(tpm_default_durations));
+ tpm_drivers[TIS_DRIVER_IDX].durations = durations;
+ }
+
+ if (tpm_drivers[TIS_DRIVER_IDX].timeouts == NULL) {
+ u32 *timeouts = tpm_default_to;
+ memcpy(timeouts, tis_default_timeouts,
+ sizeof(tis_default_timeouts));
+ tpm_drivers[TIS_DRIVER_IDX].timeouts = timeouts;
+ }
+
+ return 1;
+}
+
+
+static void set_timeouts(u32 timeouts[4], u32 durations[3])
+{
+ if (!CONFIG_TCGBIOS)
+ return;
+
+ u32 *tos = tpm_drivers[TIS_DRIVER_IDX].timeouts;
+ u32 *dus = tpm_drivers[TIS_DRIVER_IDX].durations;
+
+ if (tos && tos != tis_default_timeouts && timeouts)
+ memcpy(tos, timeouts, 4 * sizeof(u32));
+ if (dus && dus != tpm_default_durations && durations)
+ memcpy(dus, durations, 3 * sizeof(u32));
+}
+
+
+static u32 tis_wait_sts(u8 locty, u32 time, u8 mask, u8 expect)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ u32 rc = 1;
+
+ while (time > 0) {
+ u8 sts = readb(TIS_REG(locty, TIS_REG_STS));
+ if ((sts & mask) == expect) {
+ rc = 0;
+ break;
+ }
+ msleep(1);
+ time--;
+ }
+ return rc;
+}
+
+static u32 tis_activate(u8 locty)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ u32 rc = 0;
+ u8 acc;
+ int l;
+ u32 timeout_a = tpm_drivers[TIS_DRIVER_IDX].timeouts[TIS_TIMEOUT_TYPE_A];
+
+ if (!(readb(TIS_REG(locty, TIS_REG_ACCESS)) &
+ TIS_ACCESS_ACTIVE_LOCALITY)) {
+ /* release locality in use top-downwards */
+ for (l = 4; l >= 0; l--)
+ writeb(TIS_REG(l, TIS_REG_ACCESS),
+ TIS_ACCESS_ACTIVE_LOCALITY);
+ }
+
+ /* request access to locality */
+ writeb(TIS_REG(locty, TIS_REG_ACCESS), TIS_ACCESS_REQUEST_USE);
+
+ acc = readb(TIS_REG(locty, TIS_REG_ACCESS));
+ if ((acc & TIS_ACCESS_ACTIVE_LOCALITY)) {
+ writeb(TIS_REG(locty, TIS_REG_STS), TIS_STS_COMMAND_READY);
+ rc = tis_wait_sts(locty, timeout_a,
+ TIS_STS_COMMAND_READY, TIS_STS_COMMAND_READY);
+ }
+
+ return rc;
+}
+
+static u32 tis_find_active_locality(void)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ u8 locty;
+
+ for (locty = 0; locty <= 4; locty++) {
+ if ((readb(TIS_REG(locty, TIS_REG_ACCESS)) &
+ TIS_ACCESS_ACTIVE_LOCALITY))
+ return locty;
+ }
+
+ tis_activate(0);
+
+ return 0;
+}
+
+static u32 tis_ready(void)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ u32 rc = 0;
+ u8 locty = tis_find_active_locality();
+ u32 timeout_b = tpm_drivers[TIS_DRIVER_IDX].timeouts[TIS_TIMEOUT_TYPE_B];
+
+ writeb(TIS_REG(locty, TIS_REG_STS), TIS_STS_COMMAND_READY);
+ rc = tis_wait_sts(locty, timeout_b,
+ TIS_STS_COMMAND_READY, TIS_STS_COMMAND_READY);
+
+ return rc;
+}
+
+static u32 tis_senddata(const u8 *const data, u32 len)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ u32 rc = 0;
+ u32 offset = 0;
+ u32 end = 0;
+ u16 burst = 0;
+ u32 ctr = 0;
+ u8 locty = tis_find_active_locality();
+ u32 timeout_d = tpm_drivers[TIS_DRIVER_IDX].timeouts[TIS_TIMEOUT_TYPE_D];
+
+ do {
+ while (burst == 0 && ctr < timeout_d) {
+ burst = readl(TIS_REG(locty, TIS_REG_STS)) >> 8;
+ if (burst == 0) {
+ msleep(1);
+ ctr++;
+ }
+ }
+
+ if (burst == 0) {
+ rc = TCG_RESPONSE_TIMEOUT;
+ break;
+ }
+
+ while (1) {
+ writeb(TIS_REG(locty, TIS_REG_DATA_FIFO), data[offset++]);
+ burst--;
+
+ if (burst == 0 || offset == len)
+ break;
+ }
+
+ if (offset == len)
+ end = 1;
+ } while (end == 0);
+
+ return rc;
+}
+
+static u32 tis_readresp(u8 *buffer, u32 *len)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ u32 rc = 0;
+ u32 offset = 0;
+ u32 sts;
+ u8 locty = tis_find_active_locality();
+
+ while (offset < *len) {
+ buffer[offset] = readb(TIS_REG(locty, TIS_REG_DATA_FIFO));
+ offset++;
+ sts = readb(TIS_REG(locty, TIS_REG_STS));
+ /* data left ? */
+ if ((sts & TIS_STS_DATA_AVAILABLE) == 0)
+ break;
+ }
+
+ *len = offset;
+
+ return rc;
+}
+
+
+static u32 tis_waitdatavalid(void)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ u32 rc = 0;
+ u8 locty = tis_find_active_locality();
+ u32 timeout_c = tpm_drivers[TIS_DRIVER_IDX].timeouts[TIS_TIMEOUT_TYPE_C];
+
+ if (tis_wait_sts(locty, timeout_c, TIS_STS_VALID, TIS_STS_VALID) != 0)
+ rc = TCG_NO_RESPONSE;
+
+ return rc;
+}
+
+static u32 tis_waitrespready(enum tpmDurationType to_t)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ u32 rc = 0;
+ u8 locty = tis_find_active_locality();
+ u32 timeout = tpm_drivers[TIS_DRIVER_IDX].durations[to_t];
+
+ writeb(TIS_REG(locty ,TIS_REG_STS), TIS_STS_TPM_GO);
+
+ if (tis_wait_sts(locty, timeout,
+ TIS_STS_DATA_AVAILABLE, TIS_STS_DATA_AVAILABLE) != 0)
+ rc = TCG_NO_RESPONSE;
+
+ return rc;
+}
+
+
+struct tpm_driver tpm_drivers[TPM_NUM_DRIVERS] = {
+ [TIS_DRIVER_IDX] =
+ {
+ .timeouts = NULL,
+ .durations = NULL,
+ .set_timeouts = set_timeouts,
+ .probe = tis_probe,
+ .init = tis_init,
+ .activate = tis_activate,
+ .ready = tis_ready,
+ .senddata = tis_senddata,
+ .readresp = tis_readresp,
+ .waitdatavalid = tis_waitdatavalid,
+ .waitrespready = tis_waitrespready,
+ .sha1threshold = 100 * 1024,
+ },
+};
diff --git a/qemu/roms/seabios/src/hw/tpm_drivers.h b/qemu/roms/seabios/src/hw/tpm_drivers.h
new file mode 100644
index 000000000..34bb12d1c
--- /dev/null
+++ b/qemu/roms/seabios/src/hw/tpm_drivers.h
@@ -0,0 +1,90 @@
+#ifndef TPM_DRIVERS_H
+#define TPM_DRIVERS_H
+
+#include "types.h" // u32
+
+
+enum tpmDurationType {
+ TPM_DURATION_TYPE_SHORT = 0,
+ TPM_DURATION_TYPE_MEDIUM,
+ TPM_DURATION_TYPE_LONG,
+};
+
+/* low level driver implementation */
+struct tpm_driver {
+ u32 *timeouts;
+ u32 *durations;
+ void (*set_timeouts)(u32 timeouts[4], u32 durations[3]);
+ u32 (*probe)(void);
+ u32 (*init)(void);
+ u32 (*activate)(u8 locty);
+ u32 (*ready)(void);
+ u32 (*senddata)(const u8 *const data, u32 len);
+ u32 (*readresp)(u8 *buffer, u32 *len);
+ u32 (*waitdatavalid)(void);
+ u32 (*waitrespready)(enum tpmDurationType to_t);
+ /* the TPM will be used for buffers of sizes below the sha1threshold
+ for calculating the hash */
+ u32 sha1threshold;
+};
+
+extern struct tpm_driver tpm_drivers[];
+
+
+#define TIS_DRIVER_IDX 0
+#define TPM_NUM_DRIVERS 1
+
+#define TPM_INVALID_DRIVER -1
+
+/* TIS driver */
+/* address of locality 0 (TIS) */
+#define TPM_TIS_BASE_ADDRESS 0xfed40000
+
+#define TIS_REG(LOCTY, REG) \
+ (void *)(TPM_TIS_BASE_ADDRESS + (LOCTY << 12) + REG)
+
+/* hardware registers */
+#define TIS_REG_ACCESS 0x0
+#define TIS_REG_INT_ENABLE 0x8
+#define TIS_REG_INT_VECTOR 0xc
+#define TIS_REG_INT_STATUS 0x10
+#define TIS_REG_INTF_CAPABILITY 0x14
+#define TIS_REG_STS 0x18
+#define TIS_REG_DATA_FIFO 0x24
+#define TIS_REG_DID_VID 0xf00
+#define TIS_REG_RID 0xf04
+
+#define TIS_STS_VALID (1 << 7) /* 0x80 */
+#define TIS_STS_COMMAND_READY (1 << 6) /* 0x40 */
+#define TIS_STS_TPM_GO (1 << 5) /* 0x20 */
+#define TIS_STS_DATA_AVAILABLE (1 << 4) /* 0x10 */
+#define TIS_STS_EXPECT (1 << 3) /* 0x08 */
+#define TIS_STS_RESPONSE_RETRY (1 << 1) /* 0x02 */
+
+#define TIS_ACCESS_TPM_REG_VALID_STS (1 << 7) /* 0x80 */
+#define TIS_ACCESS_ACTIVE_LOCALITY (1 << 5) /* 0x20 */
+#define TIS_ACCESS_BEEN_SEIZED (1 << 4) /* 0x10 */
+#define TIS_ACCESS_SEIZE (1 << 3) /* 0x08 */
+#define TIS_ACCESS_PENDING_REQUEST (1 << 2) /* 0x04 */
+#define TIS_ACCESS_REQUEST_USE (1 << 1) /* 0x02 */
+#define TIS_ACCESS_TPM_ESTABLISHMENT (1 << 0) /* 0x01 */
+
+#define SCALER 10
+
+#define TIS_DEFAULT_TIMEOUT_A (750 * SCALER)
+#define TIS_DEFAULT_TIMEOUT_B (2000 * SCALER)
+#define TIS_DEFAULT_TIMEOUT_C (750 * SCALER)
+#define TIS_DEFAULT_TIMEOUT_D (750 * SCALER)
+
+enum tisTimeoutType {
+ TIS_TIMEOUT_TYPE_A = 0,
+ TIS_TIMEOUT_TYPE_B,
+ TIS_TIMEOUT_TYPE_C,
+ TIS_TIMEOUT_TYPE_D,
+};
+
+#define TPM_DEFAULT_DURATION_SHORT (2000 * SCALER)
+#define TPM_DEFAULT_DURATION_MEDIUM (20000 * SCALER)
+#define TPM_DEFAULT_DURATION_LONG (60000 * SCALER)
+
+#endif /* TPM_DRIVERS_H */
diff --git a/qemu/roms/seabios/src/hw/usb-hid.h b/qemu/roms/seabios/src/hw/usb-hid.h
index ef34e7963..fd7b8f8be 100644
--- a/qemu/roms/seabios/src/hw/usb-hid.h
+++ b/qemu/roms/seabios/src/hw/usb-hid.h
@@ -4,10 +4,10 @@
// usb-hid.c
struct usbdevice_s;
int usb_hid_setup(struct usbdevice_s *usbdev);
-inline int usb_kbd_active(void);
-inline int usb_kbd_command(int command, u8 *param);
-inline int usb_mouse_active(void);
-inline int usb_mouse_command(int command, u8 *param);
+int usb_kbd_active(void);
+int usb_kbd_command(int command, u8 *param);
+int usb_mouse_active(void);
+int usb_mouse_command(int command, u8 *param);
void usb_check_event(void);
diff --git a/qemu/roms/seabios/src/hw/usb-msc.c b/qemu/roms/seabios/src/hw/usb-msc.c
index d90319f51..a234f13be 100644
--- a/qemu/roms/seabios/src/hw/usb-msc.c
+++ b/qemu/roms/seabios/src/hw/usb-msc.c
@@ -63,25 +63,27 @@ usb_msc_send(struct usbdrive_s *udrive_gf, int dir, void *buf, u32 bytes)
// Low-level usb command transmit function.
int
-usb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
+usb_process_op(struct disk_op_s *op)
{
if (!CONFIG_USB_MSC)
return 0;
- dprintf(16, "usb_cmd_data id=%p write=%d count=%d bs=%d buf=%p\n"
- , op->drive_gf, 0, op->count, blocksize, op->buf_fl);
+ dprintf(16, "usb_cmd_data id=%p write=%d count=%d buf=%p\n"
+ , op->drive_gf, 0, op->count, op->buf_fl);
struct usbdrive_s *udrive_gf = container_of(
op->drive_gf, struct usbdrive_s, drive);
// Setup command block wrapper.
- u32 bytes = blocksize * op->count;
struct cbw_s cbw;
memset(&cbw, 0, sizeof(cbw));
- memcpy(cbw.CBWCB, cdbcmd, USB_CDB_SIZE);
+ int blocksize = scsi_fill_cmd(op, cbw.CBWCB, USB_CDB_SIZE);
+ if (blocksize < 0)
+ return default_process_op(op);
+ u32 bytes = blocksize * op->count;
cbw.dCBWSignature = CBW_SIGNATURE;
cbw.dCBWTag = 999; // XXX
cbw.dCBWDataTransferLength = bytes;
- cbw.bmCBWFlags = cdb_is_read(cdbcmd, blocksize) ? USB_DIR_IN : USB_DIR_OUT;
+ cbw.bmCBWFlags = scsi_is_read(op) ? USB_DIR_IN : USB_DIR_OUT;
cbw.bCBWLUN = GET_GLOBALFLAT(udrive_gf->lun);
cbw.bCBWCBLength = USB_CDB_SIZE;
diff --git a/qemu/roms/seabios/src/hw/usb-msc.h b/qemu/roms/seabios/src/hw/usb-msc.h
index c40d75556..ff3c38038 100644
--- a/qemu/roms/seabios/src/hw/usb-msc.h
+++ b/qemu/roms/seabios/src/hw/usb-msc.h
@@ -3,7 +3,7 @@
// usb-msc.c
struct disk_op_s;
-int usb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize);
+int usb_process_op(struct disk_op_s *op);
struct usbdevice_s;
int usb_msc_setup(struct usbdevice_s *usbdev);
diff --git a/qemu/roms/seabios/src/hw/usb-uas.c b/qemu/roms/seabios/src/hw/usb-uas.c
index 6ef8d0912..10e38454a 100644
--- a/qemu/roms/seabios/src/hw/usb-uas.c
+++ b/qemu/roms/seabios/src/hw/usb-uas.c
@@ -91,7 +91,7 @@ struct uasdrive_s {
};
int
-uas_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
+uas_process_op(struct disk_op_s *op)
{
if (!CONFIG_USB_UAS)
return DISK_RET_EBADTRACK;
@@ -104,7 +104,9 @@ uas_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
ui.hdr.id = UAS_UI_COMMAND;
ui.hdr.tag = 0xdead;
ui.command.lun[1] = GET_GLOBALFLAT(drive_gf->lun);
- memcpy(ui.command.cdb, cdbcmd, sizeof(ui.command.cdb));
+ int blocksize = scsi_fill_cmd(op, ui.command.cdb, sizeof(ui.command.cdb));
+ if (blocksize < 0)
+ return default_process_op(op);
int ret = usb_send_bulk(GET_GLOBALFLAT(drive_gf->command),
USB_DIR_OUT, MAKE_FLATPTR(GET_SEG(SS), &ui),
sizeof(ui.hdr) + sizeof(ui.command));
diff --git a/qemu/roms/seabios/src/hw/usb-uas.h b/qemu/roms/seabios/src/hw/usb-uas.h
index ad91c5f60..8b2f810e9 100644
--- a/qemu/roms/seabios/src/hw/usb-uas.h
+++ b/qemu/roms/seabios/src/hw/usb-uas.h
@@ -2,7 +2,7 @@
#define __USB_UAS_H
struct disk_op_s;
-int uas_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize);
+int uas_process_op(struct disk_op_s *op);
struct usbdevice_s;
int usb_uas_setup(struct usbdevice_s *usbdev);
diff --git a/qemu/roms/seabios/src/hw/usb-xhci.c b/qemu/roms/seabios/src/hw/usb-xhci.c
index fd58334dc..654febaad 100644
--- a/qemu/roms/seabios/src/hw/usb-xhci.c
+++ b/qemu/roms/seabios/src/hw/usb-xhci.c
@@ -350,26 +350,41 @@ xhci_hub_reset(struct usbhub_s *hub, u32 port)
{
struct usb_xhci_s *xhci = container_of(hub->cntl, struct usb_xhci_s, usb);
u32 portsc = readl(&xhci->pr[port].portsc);
- int rc;
+ if (!(portsc & XHCI_PORTSC_CCS))
+ // Device no longer connected?!
+ return -1;
switch (xhci_get_field(portsc, XHCI_PORTSC_PLS)) {
case PLS_U0:
- rc = speed_from_xhci[xhci_get_field(portsc, XHCI_PORTSC_SPEED)];
+ // A USB3 port - controller automatically performs reset
break;
case PLS_POLLING:
+ // A USB2 port - perform device reset
xhci_print_port_state(3, __func__, port, portsc);
- portsc |= XHCI_PORTSC_PR;
- writel(&xhci->pr[port].portsc, portsc);
- if (wait_bit(&xhci->pr[port].portsc, XHCI_PORTSC_PED, XHCI_PORTSC_PED, 100) != 0)
- return -1;
- portsc = readl(&xhci->pr[port].portsc);
- rc = speed_from_xhci[xhci_get_field(portsc, XHCI_PORTSC_SPEED)];
+ writel(&xhci->pr[port].portsc, portsc | XHCI_PORTSC_PR);
break;
default:
- rc = -1;
- break;
+ return -1;
}
+ // Wait for device to complete reset and be enabled
+ u32 end = timer_calc(100);
+ for (;;) {
+ portsc = readl(&xhci->pr[port].portsc);
+ if (!(portsc & XHCI_PORTSC_CCS))
+ // Device disconnected during reset
+ return -1;
+ if (portsc & XHCI_PORTSC_PED)
+ // Reset complete
+ break;
+ if (timer_check(end)) {
+ warn_timeout();
+ return -1;
+ }
+ yield();
+ }
+
+ int rc = speed_from_xhci[xhci_get_field(portsc, XHCI_PORTSC_SPEED)];
xhci_print_port_state(1, "XHCI", port, portsc);
return rc;
}
@@ -465,7 +480,7 @@ configure_xhci(void *data)
xhci->evts->cs = 1;
reg = readl(&xhci->caps->hcsparams2);
- u32 spb = reg >> 27;
+ u32 spb = (reg >> 21 & 0x1f) << 5 | reg >> 27;
if (spb) {
dprintf(3, "%s: setup %d scratch pad buffers\n", __func__, spb);
u64 *spba = memalign_high(64, sizeof(*spba) * spb);
@@ -921,8 +936,14 @@ xhci_alloc_pipe(struct usbdevice_s *usbdev
usb_desc2pipe(&pipe->pipe, usbdev, epdesc);
pipe->epid = epid;
pipe->reqs.cs = 1;
- if (eptype == USB_ENDPOINT_XFER_INT)
+ if (eptype == USB_ENDPOINT_XFER_INT) {
pipe->buf = malloc_high(pipe->pipe.maxpacket);
+ if (!pipe->buf) {
+ warn_noalloc();
+ free(pipe);
+ return NULL;
+ }
+ }
// Allocate input context and initialize endpoint info.
struct xhci_inctx *in = xhci_alloc_inctx(usbdev, epid);
@@ -988,6 +1009,7 @@ xhci_alloc_pipe(struct usbdevice_s *usbdev
return &pipe->pipe;
fail:
+ free(pipe->buf);
free(pipe);
free(in);
return NULL;
diff --git a/qemu/roms/seabios/src/hw/usb.c b/qemu/roms/seabios/src/hw/usb.c
index 1b4ea8bed..e46092c63 100644
--- a/qemu/roms/seabios/src/hw/usb.c
+++ b/qemu/roms/seabios/src/hw/usb.c
@@ -79,9 +79,8 @@ usb_poll_intr(struct usb_pipe *pipe_fl, void *data)
case USB_TYPE_EHCI:
return ehci_poll_intr(pipe_fl, data);
case USB_TYPE_XHCI: ;
- extern void _cfunc32flat_xhci_poll_intr(void);
- return call32_params(_cfunc32flat_xhci_poll_intr, (u32)pipe_fl
- , (u32)MAKE_FLATPTR(GET_SEG(SS), (u32)data), 0, -1);
+ return call32_params(xhci_poll_intr, pipe_fl
+ , MAKE_FLATPTR(GET_SEG(SS), data), 0, -1);
}
}
@@ -249,8 +248,10 @@ get_device_config(struct usb_pipe *pipe)
return NULL;
void *config = malloc_tmphigh(cfg.wTotalLength);
- if (!config)
+ if (!config) {
+ warn_noalloc();
return NULL;
+ }
req.wLength = cfg.wTotalLength;
ret = usb_send_default_control(pipe, &req, config);
if (ret) {
diff --git a/qemu/roms/seabios/src/hw/virtio-blk.c b/qemu/roms/seabios/src/hw/virtio-blk.c
index e2dbd3c94..20a79ebba 100644
--- a/qemu/roms/seabios/src/hw/virtio-blk.c
+++ b/qemu/roms/seabios/src/hw/virtio-blk.c
@@ -25,7 +25,7 @@
struct virtiodrive_s {
struct drive_s drive;
struct vring_virtqueue *vq;
- u16 ioaddr;
+ struct vp_device vp;
};
static int
@@ -33,7 +33,7 @@ virtio_blk_op(struct disk_op_s *op, int write)
{
struct virtiodrive_s *vdrive_gf =
container_of(op->drive_gf, struct virtiodrive_s, drive);
- struct vring_virtqueue *vq = GET_GLOBALFLAT(vdrive_gf->vq);
+ struct vring_virtqueue *vq = vdrive_gf->vq;
struct virtio_blk_outhdr hdr = {
.type = write ? VIRTIO_BLK_T_OUT : VIRTIO_BLK_T_IN,
.ioprio = 0,
@@ -42,15 +42,15 @@ virtio_blk_op(struct disk_op_s *op, int write)
u8 status = VIRTIO_BLK_S_UNSUPP;
struct vring_list sg[] = {
{
- .addr = MAKE_FLATPTR(GET_SEG(SS), &hdr),
+ .addr = (void*)(&hdr),
.length = sizeof(hdr),
},
{
.addr = op->buf_fl,
- .length = GET_GLOBALFLAT(vdrive_gf->drive.blksize) * op->count,
+ .length = vdrive_gf->drive.blksize * op->count,
},
{
- .addr = MAKE_FLATPTR(GET_SEG(SS), &status),
+ .addr = (void*)(&status),
.length = sizeof(status),
},
};
@@ -60,7 +60,7 @@ virtio_blk_op(struct disk_op_s *op, int write)
vring_add_buf(vq, sg, 2, 1, 0, 0);
else
vring_add_buf(vq, sg, 1, 2, 0, 0);
- vring_kick(GET_GLOBALFLAT(vdrive_gf->ioaddr), vq, 1);
+ vring_kick(&vdrive_gf->vp, vq, 1);
/* Wait for reply */
while (!vring_more_used(vq))
@@ -72,13 +72,13 @@ virtio_blk_op(struct disk_op_s *op, int write)
/* Clear interrupt status register. Avoid leaving interrupts stuck if
* VRING_AVAIL_F_NO_INTERRUPT was ignored and interrupts were raised.
*/
- vp_get_isr(GET_GLOBALFLAT(vdrive_gf->ioaddr));
+ vp_get_isr(&vdrive_gf->vp);
return status == VIRTIO_BLK_S_OK ? DISK_RET_SUCCESS : DISK_RET_EBADTRACK;
}
int
-process_virtio_blk_op(struct disk_op_s *op)
+virtio_blk_process_op(struct disk_op_s *op)
{
if (! CONFIG_VIRTIO_BLK)
return 0;
@@ -87,14 +87,8 @@ process_virtio_blk_op(struct disk_op_s *op)
return virtio_blk_op(op, 0);
case CMD_WRITE:
return virtio_blk_op(op, 1);
- case CMD_FORMAT:
- case CMD_RESET:
- case CMD_ISREADY:
- case CMD_VERIFY:
- case CMD_SEEK:
- return DISK_RET_SUCCESS;
default:
- return DISK_RET_EPARAM;
+ return default_process_op(op);
}
}
@@ -102,6 +96,7 @@ static void
init_virtio_blk(struct pci_device *pci)
{
u16 bdf = pci->bdf;
+ u8 status = VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER;
dprintf(1, "found virtio-blk at %x:%x\n", pci_bdf_to_bus(bdf),
pci_bdf_to_dev(bdf));
struct virtiodrive_s *vdrive = malloc_fseg(sizeof(*vdrive));
@@ -113,47 +108,93 @@ init_virtio_blk(struct pci_device *pci)
vdrive->drive.type = DTYPE_VIRTIO_BLK;
vdrive->drive.cntl_id = bdf;
- u16 ioaddr = vp_init_simple(bdf);
- vdrive->ioaddr = ioaddr;
- if (vp_find_vq(ioaddr, 0, &vdrive->vq) < 0 ) {
+ vp_init_simple(&vdrive->vp, pci);
+ if (vp_find_vq(&vdrive->vp, 0, &vdrive->vq) < 0 ) {
dprintf(1, "fail to find vq for virtio-blk %x:%x\n",
pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf));
goto fail;
}
- struct virtio_blk_config cfg;
- vp_get(ioaddr, 0, &cfg, sizeof(cfg));
-
- u32 f = vp_get_features(ioaddr);
- vdrive->drive.blksize = (f & (1 << VIRTIO_BLK_F_BLK_SIZE)) ?
- cfg.blk_size : DISK_SECTOR_SIZE;
-
- vdrive->drive.sectors = cfg.capacity;
- dprintf(3, "virtio-blk %x:%x blksize=%d sectors=%u\n",
- pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf),
- vdrive->drive.blksize, (u32)vdrive->drive.sectors);
-
- if (vdrive->drive.blksize != DISK_SECTOR_SIZE) {
- dprintf(1, "virtio-blk %x:%x block size %d is unsupported\n",
+ if (vdrive->vp.use_modern) {
+ struct vp_device *vp = &vdrive->vp;
+ u64 features = vp_get_features(vp);
+ u64 version1 = 1ull << VIRTIO_F_VERSION_1;
+ u64 blk_size = 1ull << VIRTIO_BLK_F_BLK_SIZE;
+ if (!(features & version1)) {
+ dprintf(1, "modern device without virtio_1 feature bit: %x:%x\n",
+ pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf));
+ goto fail;
+ }
+
+ features = features & (version1 | blk_size);
+ vp_set_features(vp, features);
+ status |= VIRTIO_CONFIG_S_FEATURES_OK;
+ vp_set_status(vp, status);
+ if (!(vp_get_status(vp) & VIRTIO_CONFIG_S_FEATURES_OK)) {
+ dprintf(1, "device didn't accept features: %x:%x\n",
+ pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf));
+ goto fail;
+ }
+
+ vdrive->drive.sectors =
+ vp_read(&vp->device, struct virtio_blk_config, capacity);
+ if (features & blk_size) {
+ vdrive->drive.blksize =
+ vp_read(&vp->device, struct virtio_blk_config, blk_size);
+ } else {
+ vdrive->drive.blksize = DISK_SECTOR_SIZE;
+ }
+ if (vdrive->drive.blksize != DISK_SECTOR_SIZE) {
+ dprintf(1, "virtio-blk %x:%x block size %d is unsupported\n",
+ pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf),
+ vdrive->drive.blksize);
+ goto fail;
+ }
+ dprintf(3, "virtio-blk %x:%x blksize=%d sectors=%u\n",
pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf),
- vdrive->drive.blksize);
- goto fail;
+ vdrive->drive.blksize, (u32)vdrive->drive.sectors);
+
+ vdrive->drive.pchs.cylinder =
+ vp_read(&vp->device, struct virtio_blk_config, cylinders);
+ vdrive->drive.pchs.head =
+ vp_read(&vp->device, struct virtio_blk_config, heads);
+ vdrive->drive.pchs.sector =
+ vp_read(&vp->device, struct virtio_blk_config, sectors);
+ } else {
+ struct virtio_blk_config cfg;
+ vp_get_legacy(&vdrive->vp, 0, &cfg, sizeof(cfg));
+
+ u64 f = vp_get_features(&vdrive->vp);
+ vdrive->drive.blksize = (f & (1 << VIRTIO_BLK_F_BLK_SIZE)) ?
+ cfg.blk_size : DISK_SECTOR_SIZE;
+
+ vdrive->drive.sectors = cfg.capacity;
+ dprintf(3, "virtio-blk %x:%x blksize=%d sectors=%u\n",
+ pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf),
+ vdrive->drive.blksize, (u32)vdrive->drive.sectors);
+
+ if (vdrive->drive.blksize != DISK_SECTOR_SIZE) {
+ dprintf(1, "virtio-blk %x:%x block size %d is unsupported\n",
+ pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf),
+ vdrive->drive.blksize);
+ goto fail;
+ }
+ vdrive->drive.pchs.cylinder = cfg.cylinders;
+ vdrive->drive.pchs.head = cfg.heads;
+ vdrive->drive.pchs.sector = cfg.sectors;
}
- vdrive->drive.pchs.cylinder = cfg.cylinders;
- vdrive->drive.pchs.head = cfg.heads;
- vdrive->drive.pchs.sector = cfg.sectors;
char *desc = znprintf(MAXDESCSIZE, "Virtio disk PCI:%x:%x",
pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf));
boot_add_hd(&vdrive->drive, desc, bootprio_find_pci_device(pci));
- vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE |
- VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK);
+ status |= VIRTIO_CONFIG_S_DRIVER_OK;
+ vp_set_status(&vdrive->vp, status);
return;
fail:
- vp_reset(ioaddr);
+ vp_reset(&vdrive->vp);
free(vdrive->vq);
free(vdrive);
}
@@ -169,8 +210,9 @@ virtio_blk_setup(void)
struct pci_device *pci;
foreachpci(pci) {
- if (pci->vendor != PCI_VENDOR_ID_REDHAT_QUMRANET
- || pci->device != PCI_DEVICE_ID_VIRTIO_BLK)
+ if (pci->vendor != PCI_VENDOR_ID_REDHAT_QUMRANET ||
+ (pci->device != PCI_DEVICE_ID_VIRTIO_BLK_09 &&
+ pci->device != PCI_DEVICE_ID_VIRTIO_BLK_10))
continue;
init_virtio_blk(pci);
}
diff --git a/qemu/roms/seabios/src/hw/virtio-blk.h b/qemu/roms/seabios/src/hw/virtio-blk.h
index b233c744b..157bed627 100644
--- a/qemu/roms/seabios/src/hw/virtio-blk.h
+++ b/qemu/roms/seabios/src/hw/virtio-blk.h
@@ -37,7 +37,7 @@ struct virtio_blk_outhdr {
#define VIRTIO_BLK_S_UNSUPP 2
struct disk_op_s;
-int process_virtio_blk_op(struct disk_op_s *op);
+int virtio_blk_process_op(struct disk_op_s *op);
void virtio_blk_setup(void);
#endif /* _VIRTIO_BLK_H */
diff --git a/qemu/roms/seabios/src/hw/virtio-pci.c b/qemu/roms/seabios/src/hw/virtio-pci.c
index b9b3ab1e3..6df519489 100644
--- a/qemu/roms/seabios/src/hw/virtio-pci.c
+++ b/qemu/roms/seabios/src/hw/virtio-pci.c
@@ -24,47 +24,153 @@
#include "virtio-pci.h"
#include "virtio-ring.h"
-int vp_find_vq(unsigned int ioaddr, int queue_index,
+u64 vp_get_features(struct vp_device *vp)
+{
+ u32 f0, f1;
+
+ if (vp->use_modern) {
+ vp_write(&vp->common, virtio_pci_common_cfg, device_feature_select, 0);
+ f0 = vp_read(&vp->common, virtio_pci_common_cfg, device_feature);
+ vp_write(&vp->common, virtio_pci_common_cfg, device_feature_select, 1);
+ f1 = vp_read(&vp->common, virtio_pci_common_cfg, device_feature);
+ } else {
+ f0 = vp_read(&vp->legacy, virtio_pci_legacy, host_features);
+ f1 = 0;
+ }
+ return ((u64)f1 << 32) | f0;
+}
+
+void vp_set_features(struct vp_device *vp, u64 features)
+{
+ u32 f0, f1;
+
+ f0 = features;
+ f1 = features >> 32;
+
+ if (vp->use_modern) {
+ vp_write(&vp->common, virtio_pci_common_cfg, guest_feature_select, 0);
+ vp_write(&vp->common, virtio_pci_common_cfg, guest_feature, f0);
+ vp_write(&vp->common, virtio_pci_common_cfg, guest_feature_select, 1);
+ vp_write(&vp->common, virtio_pci_common_cfg, guest_feature, f1);
+ } else {
+ vp_write(&vp->legacy, virtio_pci_legacy, guest_features, f0);
+ }
+}
+
+u8 vp_get_status(struct vp_device *vp)
+{
+ if (vp->use_modern) {
+ return vp_read(&vp->common, virtio_pci_common_cfg, device_status);
+ } else {
+ return vp_read(&vp->legacy, virtio_pci_legacy, status);
+ }
+}
+
+void vp_set_status(struct vp_device *vp, u8 status)
+{
+ if (status == 0) /* reset */
+ return;
+ if (vp->use_modern) {
+ vp_write(&vp->common, virtio_pci_common_cfg, device_status, status);
+ } else {
+ vp_write(&vp->legacy, virtio_pci_legacy, status, status);
+ }
+}
+
+u8 vp_get_isr(struct vp_device *vp)
+{
+ if (vp->use_modern) {
+ return vp_read(&vp->isr, virtio_pci_isr, isr);
+ } else {
+ return vp_read(&vp->legacy, virtio_pci_legacy, isr);
+ }
+}
+
+void vp_reset(struct vp_device *vp)
+{
+ if (vp->use_modern) {
+ vp_write(&vp->common, virtio_pci_common_cfg, device_status, 0);
+ vp_read(&vp->isr, virtio_pci_isr, isr);
+ } else {
+ vp_write(&vp->legacy, virtio_pci_legacy, status, 0);
+ vp_read(&vp->legacy, virtio_pci_legacy, isr);
+ }
+}
+
+void vp_notify(struct vp_device *vp, struct vring_virtqueue *vq)
+{
+ if (vp->use_modern) {
+ u32 addr = vp->notify.addr +
+ vq->queue_notify_off *
+ vp->notify_off_multiplier;
+ if (vp->notify.is_io) {
+ outw(vq->queue_index, addr);
+ } else {
+ writew((void*)addr, vq->queue_index);
+ }
+ dprintf(9, "vp notify %x (%d) -- 0x%x\n",
+ addr, 2, vq->queue_index);
+ } else {
+ vp_write(&vp->legacy, virtio_pci_legacy, queue_notify, vq->queue_index);
+ }
+}
+
+int vp_find_vq(struct vp_device *vp, int queue_index,
struct vring_virtqueue **p_vq)
{
u16 num;
ASSERT32FLAT();
- struct vring_virtqueue *vq = *p_vq = memalign_low(PAGE_SIZE, sizeof(*vq));
+ struct vring_virtqueue *vq = *p_vq = memalign_high(PAGE_SIZE, sizeof(*vq));
if (!vq) {
warn_noalloc();
goto fail;
}
memset(vq, 0, sizeof(*vq));
- /* select the queue */
- outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_SEL);
+ /* select the queue */
+ if (vp->use_modern) {
+ vp_write(&vp->common, virtio_pci_common_cfg, queue_select, queue_index);
+ } else {
+ vp_write(&vp->legacy, virtio_pci_legacy, queue_sel, queue_index);
+ }
/* check if the queue is available */
-
- num = inw(ioaddr + VIRTIO_PCI_QUEUE_NUM);
+ if (vp->use_modern) {
+ num = vp_read(&vp->common, virtio_pci_common_cfg, queue_size);
+ if (num > MAX_QUEUE_NUM) {
+ vp_write(&vp->common, virtio_pci_common_cfg, queue_size,
+ MAX_QUEUE_NUM);
+ num = vp_read(&vp->common, virtio_pci_common_cfg, queue_size);
+ }
+ } else {
+ num = vp_read(&vp->legacy, virtio_pci_legacy, queue_num);
+ }
if (!num) {
dprintf(1, "ERROR: queue size is 0\n");
goto fail;
}
-
if (num > MAX_QUEUE_NUM) {
dprintf(1, "ERROR: queue size %d > %d\n", num, MAX_QUEUE_NUM);
goto fail;
}
/* check if the queue is already active */
-
- if (inl(ioaddr + VIRTIO_PCI_QUEUE_PFN)) {
- dprintf(1, "ERROR: queue already active\n");
- goto fail;
+ if (vp->use_modern) {
+ if (vp_read(&vp->common, virtio_pci_common_cfg, queue_enable)) {
+ dprintf(1, "ERROR: queue already active\n");
+ goto fail;
+ }
+ } else {
+ if (vp_read(&vp->legacy, virtio_pci_legacy, queue_pfn)) {
+ dprintf(1, "ERROR: queue already active\n");
+ goto fail;
+ }
}
-
vq->queue_index = queue_index;
/* initialize the queue */
-
struct vring * vr = &vq->vring;
vring_init(vr, num, (unsigned char*)&vq->queue);
@@ -73,9 +179,23 @@ int vp_find_vq(unsigned int ioaddr, int queue_index,
* NOTE: vr->desc is initialized by vring_init()
*/
- outl((unsigned long)virt_to_phys(vr->desc) >> PAGE_SHIFT,
- ioaddr + VIRTIO_PCI_QUEUE_PFN);
-
+ if (vp->use_modern) {
+ vp_write(&vp->common, virtio_pci_common_cfg, queue_desc_lo,
+ (unsigned long)virt_to_phys(vr->desc));
+ vp_write(&vp->common, virtio_pci_common_cfg, queue_desc_hi, 0);
+ vp_write(&vp->common, virtio_pci_common_cfg, queue_avail_lo,
+ (unsigned long)virt_to_phys(vr->avail));
+ vp_write(&vp->common, virtio_pci_common_cfg, queue_avail_hi, 0);
+ vp_write(&vp->common, virtio_pci_common_cfg, queue_used_lo,
+ (unsigned long)virt_to_phys(vr->used));
+ vp_write(&vp->common, virtio_pci_common_cfg, queue_used_hi, 0);
+ vp_write(&vp->common, virtio_pci_common_cfg, queue_enable, 1);
+ vq->queue_notify_off = vp_read(&vp->common, virtio_pci_common_cfg,
+ queue_notify_off);
+ } else {
+ vp_write(&vp->legacy, virtio_pci_legacy, queue_pfn,
+ (unsigned long)virt_to_phys(vr->desc) >> PAGE_SHIFT);
+ }
return num;
fail:
@@ -84,14 +204,76 @@ fail:
return -1;
}
-u16 vp_init_simple(u16 bdf)
+void vp_init_simple(struct vp_device *vp, struct pci_device *pci)
{
- u16 ioaddr = pci_config_readl(bdf, PCI_BASE_ADDRESS_0) &
- PCI_BASE_ADDRESS_IO_MASK;
+ u8 cap = pci_find_capability(pci, PCI_CAP_ID_VNDR, 0);
+ struct vp_cap *vp_cap;
+ u32 addr, offset, mul;
+ u8 type;
+
+ memset(vp, 0, sizeof(*vp));
+ while (cap != 0) {
+ type = pci_config_readb(pci->bdf, cap +
+ offsetof(struct virtio_pci_cap, cfg_type));
+ switch (type) {
+ case VIRTIO_PCI_CAP_COMMON_CFG:
+ vp_cap = &vp->common;
+ break;
+ case VIRTIO_PCI_CAP_NOTIFY_CFG:
+ vp_cap = &vp->notify;
+ mul = offsetof(struct virtio_pci_notify_cap, notify_off_multiplier);
+ vp->notify_off_multiplier = pci_config_readl(pci->bdf, cap + mul);
+ break;
+ case VIRTIO_PCI_CAP_ISR_CFG:
+ vp_cap = &vp->isr;
+ break;
+ case VIRTIO_PCI_CAP_DEVICE_CFG:
+ vp_cap = &vp->device;
+ break;
+ default:
+ vp_cap = NULL;
+ break;
+ }
+ if (vp_cap && !vp_cap->cap) {
+ vp_cap->cap = cap;
+ vp_cap->bar = pci_config_readb(pci->bdf, cap +
+ offsetof(struct virtio_pci_cap, bar));
+ offset = pci_config_readl(pci->bdf, cap +
+ offsetof(struct virtio_pci_cap, offset));
+ addr = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0 + 4 * vp_cap->bar);
+ if (addr & PCI_BASE_ADDRESS_SPACE_IO) {
+ vp_cap->is_io = 1;
+ addr &= PCI_BASE_ADDRESS_IO_MASK;
+ } else {
+ vp_cap->is_io = 0;
+ addr &= PCI_BASE_ADDRESS_MEM_MASK;
+ }
+ vp_cap->addr = addr + offset;
+ dprintf(3, "pci dev %x:%x virtio cap at 0x%x type %d "
+ "bar %d at 0x%08x off +0x%04x [%s]\n",
+ pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf),
+ vp_cap->cap, type, vp_cap->bar, addr, offset,
+ vp_cap->is_io ? "io" : "mmio");
+ }
+
+ cap = pci_find_capability(pci, PCI_CAP_ID_VNDR, cap);
+ }
+
+ if (vp->common.cap && vp->notify.cap && vp->isr.cap && vp->device.cap) {
+ dprintf(1, "pci dev %x:%x using modern (1.0) virtio mode\n",
+ pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf));
+ vp->use_modern = 1;
+ } else {
+ dprintf(1, "pci dev %x:%x using legacy (0.9.5) virtio mode\n",
+ pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf));
+ vp->legacy.bar = 0;
+ vp->legacy.addr = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0) &
+ PCI_BASE_ADDRESS_IO_MASK;
+ vp->legacy.is_io = 1;
+ }
- vp_reset(ioaddr);
- pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
- vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE |
+ vp_reset(vp);
+ pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
+ vp_set_status(vp, VIRTIO_CONFIG_S_ACKNOWLEDGE |
VIRTIO_CONFIG_S_DRIVER );
- return ioaddr;
}
diff --git a/qemu/roms/seabios/src/hw/virtio-pci.h b/qemu/roms/seabios/src/hw/virtio-pci.h
index bc04b039e..b11c3555e 100644
--- a/qemu/roms/seabios/src/hw/virtio-pci.h
+++ b/qemu/roms/seabios/src/hw/virtio-pci.h
@@ -2,104 +2,210 @@
#define _VIRTIO_PCI_H
#include "x86.h" // inl
-
-/* A 32-bit r/o bitmask of the features supported by the host */
-#define VIRTIO_PCI_HOST_FEATURES 0
-
-/* A 32-bit r/w bitmask of features activated by the guest */
-#define VIRTIO_PCI_GUEST_FEATURES 4
-
-/* A 32-bit r/w PFN for the currently selected queue */
-#define VIRTIO_PCI_QUEUE_PFN 8
-
-/* A 16-bit r/o queue size for the currently selected queue */
-#define VIRTIO_PCI_QUEUE_NUM 12
-
-/* A 16-bit r/w queue selector */
-#define VIRTIO_PCI_QUEUE_SEL 14
-
-/* A 16-bit r/w queue notifier */
-#define VIRTIO_PCI_QUEUE_NOTIFY 16
-
-/* An 8-bit device status register. */
-#define VIRTIO_PCI_STATUS 18
-
-/* An 8-bit r/o interrupt status register. Reading the value will return the
- * current contents of the ISR and will also clear it. This is effectively
- * a read-and-acknowledge. */
-#define VIRTIO_PCI_ISR 19
+#include "biosvar.h" // GET_LOWFLAT
/* The bit of the ISR which indicates a device configuration change. */
#define VIRTIO_PCI_ISR_CONFIG 0x2
-/* The remaining space is defined by each driver as the per-driver
- * configuration space */
-#define VIRTIO_PCI_CONFIG 20
-
/* Virtio ABI version, this must match exactly */
#define VIRTIO_PCI_ABI_VERSION 0
-static inline u32 vp_get_features(unsigned int ioaddr)
-{
- return inl(ioaddr + VIRTIO_PCI_HOST_FEATURES);
-}
-
-static inline void vp_set_features(unsigned int ioaddr, u32 features)
+/* --- virtio 0.9.5 (legacy) struct --------------------------------- */
+
+typedef struct virtio_pci_legacy {
+ u32 host_features;
+ u32 guest_features;
+ u32 queue_pfn;
+ u16 queue_num;
+ u16 queue_sel;
+ u16 queue_notify;
+ u8 status;
+ u8 isr;
+ u8 device[];
+} virtio_pci_legacy;
+
+/* --- virtio 1.0 (modern) structs ---------------------------------- */
+
+/* Common configuration */
+#define VIRTIO_PCI_CAP_COMMON_CFG 1
+/* Notifications */
+#define VIRTIO_PCI_CAP_NOTIFY_CFG 2
+/* ISR access */
+#define VIRTIO_PCI_CAP_ISR_CFG 3
+/* Device specific configuration */
+#define VIRTIO_PCI_CAP_DEVICE_CFG 4
+/* PCI configuration access */
+#define VIRTIO_PCI_CAP_PCI_CFG 5
+
+/* This is the PCI capability header: */
+struct virtio_pci_cap {
+ u8 cap_vndr; /* Generic PCI field: PCI_CAP_ID_VNDR */
+ u8 cap_next; /* Generic PCI field: next ptr. */
+ u8 cap_len; /* Generic PCI field: capability length */
+ u8 cfg_type; /* Identifies the structure. */
+ u8 bar; /* Where to find it. */
+ u8 padding[3]; /* Pad to full dword. */
+ u32 offset; /* Offset within bar. */
+ u32 length; /* Length of the structure, in bytes. */
+};
+
+struct virtio_pci_notify_cap {
+ struct virtio_pci_cap cap;
+ u32 notify_off_multiplier; /* Multiplier for queue_notify_off. */
+};
+
+typedef struct virtio_pci_common_cfg {
+ /* About the whole device. */
+ u32 device_feature_select; /* read-write */
+ u32 device_feature; /* read-only */
+ u32 guest_feature_select; /* read-write */
+ u32 guest_feature; /* read-write */
+ u16 msix_config; /* read-write */
+ u16 num_queues; /* read-only */
+ u8 device_status; /* read-write */
+ u8 config_generation; /* read-only */
+
+ /* About a specific virtqueue. */
+ u16 queue_select; /* read-write */
+ u16 queue_size; /* read-write, power of 2. */
+ u16 queue_msix_vector; /* read-write */
+ u16 queue_enable; /* read-write */
+ u16 queue_notify_off; /* read-only */
+ u32 queue_desc_lo; /* read-write */
+ u32 queue_desc_hi; /* read-write */
+ u32 queue_avail_lo; /* read-write */
+ u32 queue_avail_hi; /* read-write */
+ u32 queue_used_lo; /* read-write */
+ u32 queue_used_hi; /* read-write */
+} virtio_pci_common_cfg;
+
+typedef struct virtio_pci_isr {
+ u8 isr;
+} virtio_pci_isr;
+
+/* --- driver structs ----------------------------------------------- */
+
+struct vp_cap {
+ u32 addr;
+ u8 cap;
+ u8 bar;
+ u8 is_io;
+};
+
+struct vp_device {
+ struct vp_cap common, notify, isr, device, legacy;
+ u32 notify_off_multiplier;
+ u8 use_modern;
+};
+
+static inline u64 _vp_read(struct vp_cap *cap, u32 offset, u8 size)
{
- outl(features, ioaddr + VIRTIO_PCI_GUEST_FEATURES);
+ u32 addr = cap->addr + offset;
+ u64 var;
+
+ if (cap->is_io) {
+ switch (size) {
+ case 8:
+ var = inl(addr);
+ var |= (u64)inl(addr+4) << 32;
+ break;
+ case 4:
+ var = inl(addr);
+ break;
+ case 2:
+ var = inw(addr);
+ break;
+ case 1:
+ var = inb(addr);
+ break;
+ default:
+ var = 0;
+ }
+ } else {
+ switch (size) {
+ case 8:
+ var = readl((void*)addr);
+ var |= (u64)readl((void*)(addr+4)) << 32;
+ break;
+ case 4:
+ var = readl((void*)addr);
+ break;
+ case 2:
+ var = readw((void*)addr);
+ break;
+ case 1:
+ var = readb((void*)addr);
+ break;
+ default:
+ var = 0;
+ }
+ }
+ dprintf(9, "vp read %x (%d) -> 0x%llx\n", addr, size, var);
+ return var;
}
-static inline void vp_get(unsigned int ioaddr, unsigned offset,
- void *buf, unsigned len)
+static inline void _vp_write(struct vp_cap *cap, u32 offset, u8 size, u64 var)
{
- u8 *ptr = buf;
- unsigned i;
-
- for (i = 0; i < len; i++)
- ptr[i] = inb(ioaddr + VIRTIO_PCI_CONFIG + offset + i);
+ u32 addr = cap->addr + offset;
+
+ dprintf(9, "vp write %x (%d) <- 0x%llx\n", addr, size, var);
+ if (cap->is_io) {
+ switch (size) {
+ case 4:
+ outl(var, addr);
+ break;
+ case 2:
+ outw(var, addr);
+ break;
+ case 1:
+ outb(var, addr);
+ break;
+ }
+ } else {
+ switch (size) {
+ case 4:
+ writel((void*)addr, var);
+ break;
+ case 2:
+ writew((void*)addr, var);
+ break;
+ case 1:
+ writeb((void*)addr, var);
+ break;
+ }
+ }
}
-static inline u8 vp_get_status(unsigned int ioaddr)
-{
- return inb(ioaddr + VIRTIO_PCI_STATUS);
-}
+#define vp_read(_cap, _struct, _field) \
+ _vp_read(_cap, offsetof(_struct, _field), \
+ sizeof(((_struct *)0)->_field))
-static inline void vp_set_status(unsigned int ioaddr, u8 status)
-{
- if (status == 0) /* reset */
- return;
- outb(status, ioaddr + VIRTIO_PCI_STATUS);
-}
+#define vp_write(_cap, _struct, _field, _var) \
+ _vp_write(_cap, offsetof(_struct, _field), \
+ sizeof(((_struct *)0)->_field), _var)
-static inline u8 vp_get_isr(unsigned int ioaddr)
-{
- return inb(ioaddr + VIRTIO_PCI_ISR);
-}
+u64 vp_get_features(struct vp_device *vp);
+void vp_set_features(struct vp_device *vp, u64 features);
-static inline void vp_reset(unsigned int ioaddr)
+static inline void vp_get_legacy(struct vp_device *vp, unsigned offset,
+ void *buf, unsigned len)
{
- outb(0, ioaddr + VIRTIO_PCI_STATUS);
- (void)inb(ioaddr + VIRTIO_PCI_ISR);
-}
+ u8 *ptr = buf;
+ unsigned i;
-static inline void vp_notify(unsigned int ioaddr, int queue_index)
-{
- outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_NOTIFY);
+ for (i = 0; i < len; i++)
+ ptr[i] = vp_read(&vp->legacy, virtio_pci_legacy, device[i]);
}
-static inline void vp_del_vq(unsigned int ioaddr, int queue_index)
-{
- /* select the queue */
-
- outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_SEL);
-
- /* deactivate the queue */
-
- outl(0, ioaddr + VIRTIO_PCI_QUEUE_PFN);
-}
+u8 vp_get_status(struct vp_device *vp);
+void vp_set_status(struct vp_device *vp, u8 status);
+u8 vp_get_isr(struct vp_device *vp);
+void vp_reset(struct vp_device *vp);
+struct pci_device;
struct vring_virtqueue;
-u16 vp_init_simple(u16 bdf);
-int vp_find_vq(unsigned int ioaddr, int queue_index,
+void vp_init_simple(struct vp_device *vp, struct pci_device *pci);
+void vp_notify(struct vp_device *vp, struct vring_virtqueue *vq);
+int vp_find_vq(struct vp_device *vp, int queue_index,
struct vring_virtqueue **p_vq);
#endif /* _VIRTIO_PCI_H_ */
diff --git a/qemu/roms/seabios/src/hw/virtio-ring.c b/qemu/roms/seabios/src/hw/virtio-ring.c
index 97e0b3487..7205a0acd 100644
--- a/qemu/roms/seabios/src/hw/virtio-ring.c
+++ b/qemu/roms/seabios/src/hw/virtio-ring.c
@@ -35,8 +35,8 @@
int vring_more_used(struct vring_virtqueue *vq)
{
- struct vring_used *used = GET_LOWFLAT(vq->vring.used);
- int more = GET_LOWFLAT(vq->last_used_idx) != GET_LOWFLAT(used->idx);
+ struct vring_used *used = vq->vring.used;
+ int more = vq->last_used_idx != used->idx;
/* Make sure ring reads are done after idx read above. */
smp_rmb();
return more;
@@ -57,13 +57,13 @@ void vring_detach(struct vring_virtqueue *vq, unsigned int head)
/* find end of given descriptor */
i = head;
- while (GET_LOWFLAT(desc[i].flags) & VRING_DESC_F_NEXT)
- i = GET_LOWFLAT(desc[i].next);
+ while (desc[i].flags & VRING_DESC_F_NEXT)
+ i = desc[i].next;
/* link it with free list and point to it */
- SET_LOWFLAT(desc[i].next, GET_LOWFLAT(vq->free_head));
- SET_LOWFLAT(vq->free_head, head);
+ desc[i].next = vq->free_head;
+ vq->free_head = head;
}
/*
@@ -77,22 +77,22 @@ int vring_get_buf(struct vring_virtqueue *vq, unsigned int *len)
{
struct vring *vr = &vq->vring;
struct vring_used_elem *elem;
- struct vring_used *used = GET_LOWFLAT(vq->vring.used);
+ struct vring_used *used = vq->vring.used;
u32 id;
int ret;
// BUG_ON(!vring_more_used(vq));
- elem = &used->ring[GET_LOWFLAT(vq->last_used_idx) % GET_LOWFLAT(vr->num)];
- id = GET_LOWFLAT(elem->id);
+ elem = &used->ring[vq->last_used_idx % vr->num];
+ id = elem->id;
if (len != NULL)
- *len = GET_LOWFLAT(elem->len);
+ *len = elem->len;
- ret = GET_LOWFLAT(vq->vdata[id]);
+ ret = vq->vdata[id];
vring_detach(vq, id);
- SET_LOWFLAT(vq->last_used_idx, GET_LOWFLAT(vq->last_used_idx) + 1);
+ vq->last_used_idx = vq->last_used_idx + 1;
return ret;
}
@@ -104,46 +104,45 @@ void vring_add_buf(struct vring_virtqueue *vq,
{
struct vring *vr = &vq->vring;
int i, av, head, prev;
- struct vring_desc *desc = GET_LOWFLAT(vr->desc);
- struct vring_avail *avail = GET_LOWFLAT(vr->avail);
+ struct vring_desc *desc = vr->desc;
+ struct vring_avail *avail = vr->avail;
BUG_ON(out + in == 0);
prev = 0;
- head = GET_LOWFLAT(vq->free_head);
- for (i = head; out; i = GET_LOWFLAT(desc[i].next), out--) {
- SET_LOWFLAT(desc[i].flags, VRING_DESC_F_NEXT);
- SET_LOWFLAT(desc[i].addr, (u64)virt_to_phys(list->addr));
- SET_LOWFLAT(desc[i].len, list->length);
+ head = vq->free_head;
+ for (i = head; out; i = desc[i].next, out--) {
+ desc[i].flags = VRING_DESC_F_NEXT;
+ desc[i].addr = (u64)virt_to_phys(list->addr);
+ desc[i].len = list->length;
prev = i;
list++;
}
- for ( ; in; i = GET_LOWFLAT(desc[i].next), in--) {
- SET_LOWFLAT(desc[i].flags, VRING_DESC_F_NEXT|VRING_DESC_F_WRITE);
- SET_LOWFLAT(desc[i].addr, (u64)virt_to_phys(list->addr));
- SET_LOWFLAT(desc[i].len, list->length);
+ for ( ; in; i = desc[i].next, in--) {
+ desc[i].flags = VRING_DESC_F_NEXT|VRING_DESC_F_WRITE;
+ desc[i].addr = (u64)virt_to_phys(list->addr);
+ desc[i].len = list->length;
prev = i;
list++;
}
- SET_LOWFLAT(desc[prev].flags,
- GET_LOWFLAT(desc[prev].flags) & ~VRING_DESC_F_NEXT);
+ desc[prev].flags = desc[prev].flags & ~VRING_DESC_F_NEXT;
- SET_LOWFLAT(vq->free_head, i);
+ vq->free_head = i;
- SET_LOWFLAT(vq->vdata[head], index);
+ vq->vdata[head] = index;
- av = (GET_LOWFLAT(avail->idx) + num_added) % GET_LOWFLAT(vr->num);
- SET_LOWFLAT(avail->ring[av], head);
+ av = (avail->idx + num_added) % vr->num;
+ avail->ring[av] = head;
}
-void vring_kick(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added)
+void vring_kick(struct vp_device *vp, struct vring_virtqueue *vq, int num_added)
{
struct vring *vr = &vq->vring;
- struct vring_avail *avail = GET_LOWFLAT(vr->avail);
+ struct vring_avail *avail = vr->avail;
/* Make sure idx update is done after ring write. */
smp_wmb();
- SET_LOWFLAT(avail->idx, GET_LOWFLAT(avail->idx) + num_added);
+ avail->idx = avail->idx + num_added;
- vp_notify(ioaddr, GET_LOWFLAT(vq->queue_index));
+ vp_notify(vp, vq);
}
diff --git a/qemu/roms/seabios/src/hw/virtio-ring.h b/qemu/roms/seabios/src/hw/virtio-ring.h
index b7a7aafb2..7665fd54b 100644
--- a/qemu/roms/seabios/src/hw/virtio-ring.h
+++ b/qemu/roms/seabios/src/hw/virtio-ring.h
@@ -4,15 +4,6 @@
#include "types.h" // u64
#include "memmap.h" // PAGE_SIZE
-#define PAGE_SHIFT 12
-#define PAGE_MASK (PAGE_SIZE-1)
-
-#define virt_to_phys(v) (unsigned long)(v)
-#define phys_to_virt(p) (void*)(p)
-/* Compiler barrier is enough as an x86 CPU does not reorder reads or writes */
-#define smp_rmb() barrier()
-#define smp_wmb() barrier()
-
/* Status byte for guest to report progress, and synchronize features. */
/* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */
#define VIRTIO_CONFIG_S_ACKNOWLEDGE 1
@@ -20,9 +11,14 @@
#define VIRTIO_CONFIG_S_DRIVER 2
/* Driver has used its parts of the config, and is happy */
#define VIRTIO_CONFIG_S_DRIVER_OK 4
+/* Driver has finished configuring features */
+#define VIRTIO_CONFIG_S_FEATURES_OK 8
/* We've given up on this device. */
#define VIRTIO_CONFIG_S_FAILED 0x80
+/* v1.0 compliant. */
+#define VIRTIO_F_VERSION_1 32
+
#define MAX_QUEUE_NUM (128)
#define VRING_DESC_F_NEXT 1
@@ -68,10 +64,9 @@ struct vring {
};
#define vring_size(num) \
- (((((sizeof(struct vring_desc) * num) + \
- (sizeof(struct vring_avail) + sizeof(u16) * num)) \
- + PAGE_MASK) & ~PAGE_MASK) + \
- (sizeof(struct vring_used) + sizeof(struct vring_used_elem) * num))
+ (ALIGN(sizeof(struct vring_desc) * num + sizeof(struct vring_avail) \
+ + sizeof(u16) * num, PAGE_SIZE) \
+ + sizeof(struct vring_used) + sizeof(struct vring_used_elem) * num)
typedef unsigned char virtio_queue_t[vring_size(MAX_QUEUE_NUM)];
@@ -83,6 +78,7 @@ struct vring_virtqueue {
u16 vdata[MAX_QUEUE_NUM];
/* PCI */
int queue_index;
+ int queue_notify_off;
};
struct vring_list {
@@ -90,42 +86,35 @@ struct vring_list {
unsigned int length;
};
-static inline void vring_init(struct vring *vr,
- unsigned int num, unsigned char *queue)
+static inline void
+vring_init(struct vring *vr, unsigned int num, unsigned char *queue)
{
- unsigned int i;
- unsigned long pa;
-
ASSERT32FLAT();
vr->num = num;
/* physical address of desc must be page aligned */
-
- pa = virt_to_phys(queue);
- pa = (pa + PAGE_MASK) & ~PAGE_MASK;
- vr->desc = phys_to_virt(pa);
+ vr->desc = (void*)ALIGN((u32)queue, PAGE_SIZE);
vr->avail = (struct vring_avail *)&vr->desc[num];
/* disable interrupts */
vr->avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
/* physical address of used must be page aligned */
+ vr->used = (void*)ALIGN((u32)&vr->avail->ring[num], PAGE_SIZE);
- pa = virt_to_phys(&vr->avail->ring[num]);
- pa = (pa + PAGE_MASK) & ~PAGE_MASK;
- vr->used = phys_to_virt(pa);
-
+ int i;
for (i = 0; i < num - 1; i++)
- vr->desc[i].next = i + 1;
+ vr->desc[i].next = i + 1;
vr->desc[i].next = 0;
}
+struct vp_device;
int vring_more_used(struct vring_virtqueue *vq);
void vring_detach(struct vring_virtqueue *vq, unsigned int head);
int vring_get_buf(struct vring_virtqueue *vq, unsigned int *len);
void vring_add_buf(struct vring_virtqueue *vq, struct vring_list list[],
unsigned int out, unsigned int in,
int index, int num_added);
-void vring_kick(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added);
+void vring_kick(struct vp_device *vp, struct vring_virtqueue *vq, int num_added);
#endif /* _VIRTIO_RING_H_ */
diff --git a/qemu/roms/seabios/src/hw/virtio-scsi.c b/qemu/roms/seabios/src/hw/virtio-scsi.c
index 8f966875b..80afd04ca 100644
--- a/qemu/roms/seabios/src/hw/virtio-scsi.c
+++ b/qemu/roms/seabios/src/hw/virtio-scsi.c
@@ -27,35 +27,42 @@ struct virtio_lun_s {
struct drive_s drive;
struct pci_device *pci;
struct vring_virtqueue *vq;
- u16 ioaddr;
+ struct vp_device *vp;
u16 target;
u16 lun;
};
-static int
-virtio_scsi_cmd(u16 ioaddr, struct vring_virtqueue *vq, struct disk_op_s *op,
- void *cdbcmd, u16 target, u16 lun, u16 blocksize)
+int
+virtio_scsi_process_op(struct disk_op_s *op)
{
+ if (! CONFIG_VIRTIO_SCSI)
+ return 0;
+ struct virtio_lun_s *vlun =
+ container_of(op->drive_gf, struct virtio_lun_s, drive);
+ struct vp_device *vp = vlun->vp;
+ struct vring_virtqueue *vq = vlun->vq;
struct virtio_scsi_req_cmd req;
struct virtio_scsi_resp_cmd resp;
struct vring_list sg[3];
memset(&req, 0, sizeof(req));
+ int blocksize = scsi_fill_cmd(op, req.cdb, 16);
+ if (blocksize < 0)
+ return default_process_op(op);
req.lun[0] = 1;
- req.lun[1] = target;
- req.lun[2] = (lun >> 8) | 0x40;
- req.lun[3] = (lun & 0xff);
- memcpy(req.cdb, cdbcmd, 16);
+ req.lun[1] = vlun->target;
+ req.lun[2] = (vlun->lun >> 8) | 0x40;
+ req.lun[3] = (vlun->lun & 0xff);
u32 len = op->count * blocksize;
- int datain = cdb_is_read(cdbcmd, blocksize);
+ int datain = scsi_is_read(op);
int in_num = (datain ? 2 : 1);
int out_num = (len ? 3 : 2) - in_num;
- sg[0].addr = MAKE_FLATPTR(GET_SEG(SS), &req);
+ sg[0].addr = (void*)(&req);
sg[0].length = sizeof(req);
- sg[out_num].addr = MAKE_FLATPTR(GET_SEG(SS), &resp);
+ sg[out_num].addr = (void*)(&resp);
sg[out_num].length = sizeof(resp);
if (len) {
@@ -66,7 +73,7 @@ virtio_scsi_cmd(u16 ioaddr, struct vring_virtqueue *vq, struct disk_op_s *op,
/* Add to virtqueue and kick host */
vring_add_buf(vq, sg, out_num, in_num, 0, 0);
- vring_kick(ioaddr, vq, 1);
+ vring_kick(vp, vq, 1);
/* Wait for reply */
while (!vring_more_used(vq))
@@ -78,7 +85,7 @@ virtio_scsi_cmd(u16 ioaddr, struct vring_virtqueue *vq, struct disk_op_s *op,
/* Clear interrupt status register. Avoid leaving interrupts stuck if
* VRING_AVAIL_F_NO_INTERRUPT was ignored and interrupts were raised.
*/
- vp_get_isr(ioaddr);
+ vp_get_isr(vp);
if (resp.response == VIRTIO_SCSI_S_OK && resp.status == 0) {
return DISK_RET_SUCCESS;
@@ -86,21 +93,8 @@ virtio_scsi_cmd(u16 ioaddr, struct vring_virtqueue *vq, struct disk_op_s *op,
return DISK_RET_EBADTRACK;
}
-int
-virtio_scsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
-{
- struct virtio_lun_s *vlun_gf =
- container_of(op->drive_gf, struct virtio_lun_s, drive);
-
- return virtio_scsi_cmd(GET_GLOBALFLAT(vlun_gf->ioaddr),
- GET_GLOBALFLAT(vlun_gf->vq), op, cdbcmd,
- GET_GLOBALFLAT(vlun_gf->target),
- GET_GLOBALFLAT(vlun_gf->lun),
- blocksize);
-}
-
static int
-virtio_scsi_add_lun(struct pci_device *pci, u16 ioaddr,
+virtio_scsi_add_lun(struct pci_device *pci, struct vp_device *vp,
struct vring_virtqueue *vq, u16 target, u16 lun)
{
struct virtio_lun_s *vlun = malloc_fseg(sizeof(*vlun));
@@ -112,7 +106,7 @@ virtio_scsi_add_lun(struct pci_device *pci, u16 ioaddr,
vlun->drive.type = DTYPE_VIRTIO_SCSI;
vlun->drive.cntl_id = pci->bdf;
vlun->pci = pci;
- vlun->ioaddr = ioaddr;
+ vlun->vp = vp;
vlun->vq = vq;
vlun->target = target;
vlun->lun = lun;
@@ -129,11 +123,11 @@ fail:
}
static int
-virtio_scsi_scan_target(struct pci_device *pci, u16 ioaddr,
+virtio_scsi_scan_target(struct pci_device *pci, struct vp_device *vp,
struct vring_virtqueue *vq, u16 target)
{
/* TODO: send REPORT LUNS. For now, only LUN 0 is recognized. */
- int ret = virtio_scsi_add_lun(pci, ioaddr, vq, target, 0);
+ int ret = virtio_scsi_add_lun(pci, vp, vq, target, 0);
return ret < 0 ? 0 : 1;
}
@@ -144,19 +138,45 @@ init_virtio_scsi(struct pci_device *pci)
dprintf(1, "found virtio-scsi at %x:%x\n", pci_bdf_to_bus(bdf),
pci_bdf_to_dev(bdf));
struct vring_virtqueue *vq = NULL;
- u16 ioaddr = vp_init_simple(bdf);
- if (vp_find_vq(ioaddr, 2, &vq) < 0 ) {
+ struct vp_device *vp = malloc_high(sizeof(*vp));
+ if (!vp) {
+ warn_noalloc();
+ return;
+ }
+ vp_init_simple(vp, pci);
+ u8 status = VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER;
+
+ if (vp->use_modern) {
+ u64 features = vp_get_features(vp);
+ u64 version1 = 1ull << VIRTIO_F_VERSION_1;
+ if (!(features & version1)) {
+ dprintf(1, "modern device without virtio_1 feature bit: %x:%x\n",
+ pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf));
+ goto fail;
+ }
+
+ vp_set_features(vp, version1);
+ status |= VIRTIO_CONFIG_S_FEATURES_OK;
+ vp_set_status(vp, status);
+ if (!(vp_get_status(vp) & VIRTIO_CONFIG_S_FEATURES_OK)) {
+ dprintf(1, "device didn't accept features: %x:%x\n",
+ pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf));
+ goto fail;
+ }
+ }
+
+ if (vp_find_vq(vp, 2, &vq) < 0 ) {
dprintf(1, "fail to find vq for virtio-scsi %x:%x\n",
pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf));
goto fail;
}
- vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE |
- VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK);
+ status |= VIRTIO_CONFIG_S_DRIVER_OK;
+ vp_set_status(vp, status);
int i, tot;
for (tot = 0, i = 0; i < 256; i++)
- tot += virtio_scsi_scan_target(pci, ioaddr, vq, i);
+ tot += virtio_scsi_scan_target(pci, vp, vq, i);
if (!tot)
goto fail;
@@ -164,7 +184,8 @@ init_virtio_scsi(struct pci_device *pci)
return;
fail:
- vp_reset(ioaddr);
+ vp_reset(vp);
+ free(vp);
free(vq);
}
@@ -179,8 +200,9 @@ virtio_scsi_setup(void)
struct pci_device *pci;
foreachpci(pci) {
- if (pci->vendor != PCI_VENDOR_ID_REDHAT_QUMRANET
- || pci->device != PCI_DEVICE_ID_VIRTIO_SCSI)
+ if (pci->vendor != PCI_VENDOR_ID_REDHAT_QUMRANET ||
+ (pci->device != PCI_DEVICE_ID_VIRTIO_SCSI_09 &&
+ pci->device != PCI_DEVICE_ID_VIRTIO_SCSI_10))
continue;
init_virtio_scsi(pci);
}
diff --git a/qemu/roms/seabios/src/hw/virtio-scsi.h b/qemu/roms/seabios/src/hw/virtio-scsi.h
index 96c3701d2..7532cc98e 100644
--- a/qemu/roms/seabios/src/hw/virtio-scsi.h
+++ b/qemu/roms/seabios/src/hw/virtio-scsi.h
@@ -41,7 +41,7 @@ struct virtio_scsi_resp_cmd {
#define VIRTIO_SCSI_S_OK 0
struct disk_op_s;
-int virtio_scsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize);
+int virtio_scsi_process_op(struct disk_op_s *op);
void virtio_scsi_setup(void);
#endif /* _VIRTIO_SCSI_H */
diff --git a/qemu/roms/seabios/src/list.h b/qemu/roms/seabios/src/list.h
index de656b9d6..94512e306 100644
--- a/qemu/roms/seabios/src/list.h
+++ b/qemu/roms/seabios/src/list.h
@@ -61,6 +61,16 @@ hlist_add_after(struct hlist_node *n, struct hlist_node *prev)
hlist_add(n, &prev->next);
}
+static inline void
+hlist_replace(struct hlist_node *old, struct hlist_node *new)
+{
+ new->next = old->next;
+ if (new->next)
+ new->next->pprev = &new->next;
+ new->pprev = old->pprev;
+ *new->pprev = new;
+}
+
#define hlist_for_each_entry(pos, head, member) \
for (pos = container_of((head)->first, typeof(*pos), member) \
; pos != container_of(NULL, typeof(*pos), member) \
diff --git a/qemu/roms/seabios/src/malloc.c b/qemu/roms/seabios/src/malloc.c
index c4cb17149..3733855ca 100644
--- a/qemu/roms/seabios/src/malloc.c
+++ b/qemu/roms/seabios/src/malloc.c
@@ -6,9 +6,10 @@
#include "biosvar.h" // GET_BDA
#include "config.h" // BUILD_BIOS_ADDR
+#include "e820map.h" // struct e820entry
#include "list.h" // hlist_node
#include "malloc.h" // _malloc
-#include "memmap.h" // struct e820entry
+#include "memmap.h" // PAGE_SIZE
#include "output.h" // dprintf
#include "stacks.h" // wait_preempt
#include "std/optionrom.h" // OPTION_ROM_ALIGN
@@ -17,7 +18,7 @@
// Information on a reserved area.
struct allocinfo_s {
struct hlist_node node;
- void *data, *dataend, *allocend;
+ u32 range_start, range_end, alloc_size;
};
// Information on a tracked memory allocation.
@@ -46,98 +47,106 @@ static struct zone_s *Zones[] VARVERIFY32INIT = {
****************************************************************/
// Find and reserve space from a given zone
-static void *
-allocSpace(struct zone_s *zone, u32 size, u32 align, struct allocinfo_s *fill)
+static u32
+alloc_new(struct zone_s *zone, u32 size, u32 align, struct allocinfo_s *fill)
{
struct allocinfo_s *info;
hlist_for_each_entry(info, &zone->head, node) {
- void *dataend = info->dataend;
- void *allocend = info->allocend;
- void *newallocend = (void*)ALIGN_DOWN((u32)allocend - size, align);
- if (newallocend >= dataend && newallocend <= allocend) {
+ u32 alloc_end = info->range_start + info->alloc_size;
+ u32 range_end = info->range_end;
+ u32 new_range_end = ALIGN_DOWN(range_end - size, align);
+ if (new_range_end >= alloc_end && new_range_end <= range_end) {
// Found space - now reserve it.
- if (!fill)
- fill = newallocend;
- fill->data = newallocend;
- fill->dataend = newallocend + size;
- fill->allocend = allocend;
+ fill->range_start = new_range_end;
+ fill->range_end = range_end;
+ fill->alloc_size = size;
- info->allocend = newallocend;
+ info->range_end = new_range_end;
hlist_add_before(&fill->node, &info->node);
- return newallocend;
+ return new_range_end;
}
}
- return NULL;
+ return 0;
}
-// Release space allocated with allocSpace()
-static void
-freeSpace(struct allocinfo_s *info)
+// Reserve space for a 'struct allocdetail_s' and fill
+static struct allocdetail_s *
+alloc_new_detail(struct allocdetail_s *temp)
{
- struct allocinfo_s *next = container_of_or_null(
- info->node.next, struct allocinfo_s, node);
- if (next && next->allocend == info->data)
- next->allocend = info->allocend;
- hlist_del(&info->node);
+ u32 detail_addr = alloc_new(&ZoneTmpHigh, sizeof(struct allocdetail_s)
+ , MALLOC_MIN_ALIGN, &temp->detailinfo);
+ if (!detail_addr) {
+ detail_addr = alloc_new(&ZoneTmpLow, sizeof(struct allocdetail_s)
+ , MALLOC_MIN_ALIGN, &temp->detailinfo);
+ if (!detail_addr) {
+ warn_noalloc();
+ return NULL;
+ }
+ }
+ struct allocdetail_s *detail = memremap(detail_addr, sizeof(*detail));
+
+ // Fill final 'detail' allocation from data in 'temp'
+ memcpy(detail, temp, sizeof(*detail));
+ hlist_replace(&temp->detailinfo.node, &detail->detailinfo.node);
+ hlist_replace(&temp->datainfo.node, &detail->datainfo.node);
+ return detail;
}
// Add new memory to a zone
static void
-addSpace(struct zone_s *zone, void *start, void *end)
+alloc_add(struct zone_s *zone, u32 start, u32 end)
{
// Find position to add space
struct allocinfo_s *info;
struct hlist_node **pprev;
hlist_for_each_entry_pprev(info, pprev, &zone->head, node) {
- if (info->data < start)
+ if (info->range_start < start)
break;
}
// Add space using temporary allocation info.
struct allocdetail_s tempdetail;
- tempdetail.datainfo.data = tempdetail.datainfo.dataend = start;
- tempdetail.datainfo.allocend = end;
+ tempdetail.handle = MALLOC_DEFAULT_HANDLE;
+ tempdetail.datainfo.range_start = start;
+ tempdetail.datainfo.range_end = end;
+ tempdetail.datainfo.alloc_size = 0;
hlist_add(&tempdetail.datainfo.node, pprev);
// Allocate final allocation info.
- struct allocdetail_s *detail = allocSpace(
- &ZoneTmpHigh, sizeof(*detail), MALLOC_MIN_ALIGN, NULL);
- if (!detail) {
- detail = allocSpace(&ZoneTmpLow, sizeof(*detail)
- , MALLOC_MIN_ALIGN, NULL);
- if (!detail) {
- hlist_del(&tempdetail.datainfo.node);
- warn_noalloc();
- return;
- }
- }
+ struct allocdetail_s *detail = alloc_new_detail(&tempdetail);
+ if (!detail)
+ hlist_del(&tempdetail.datainfo.node);
+}
- // Replace temp alloc space with final alloc space
- pprev = tempdetail.datainfo.node.pprev;
- hlist_del(&tempdetail.datainfo.node);
- memcpy(&detail->datainfo, &tempdetail.datainfo, sizeof(detail->datainfo));
- detail->handle = MALLOC_DEFAULT_HANDLE;
- hlist_add(&detail->datainfo.node, pprev);
+// Release space allocated with alloc_new()
+static void
+alloc_free(struct allocinfo_s *info)
+{
+ struct allocinfo_s *next = container_of_or_null(
+ info->node.next, struct allocinfo_s, node);
+ if (next && next->range_end == info->range_start)
+ next->range_end = info->range_end;
+ hlist_del(&info->node);
}
-// Search all zones for an allocation obtained from allocSpace()
+// Search all zones for an allocation obtained from alloc_new()
static struct allocinfo_s *
-findAlloc(void *data)
+alloc_find(u32 data)
{
int i;
for (i=0; i<ARRAY_SIZE(Zones); i++) {
struct allocinfo_s *info;
hlist_for_each_entry(info, &Zones[i]->head, node) {
- if (info->data == data)
+ if (info->range_start == data)
return info;
}
}
return NULL;
}
-// Return the last sentinal node of a zone
+// Find the lowest memory range added by alloc_add()
static struct allocinfo_s *
-findLast(struct zone_s *zone)
+alloc_find_lowest(struct zone_s *zone)
{
struct allocinfo_s *info, *last = NULL;
hlist_for_each_entry(info, &zone->head, node) {
@@ -171,25 +180,25 @@ relocate_ebda(u32 newebda, u32 oldebda, u8 ebda_size)
}
// Support expanding the ZoneLow dynamically.
-static void *
+static u32
zonelow_expand(u32 size, u32 align, struct allocinfo_s *fill)
{
// Make sure to not move ebda while an optionrom is running.
if (unlikely(wait_preempt())) {
- void *data = allocSpace(&ZoneLow, size, align, fill);
+ u32 data = alloc_new(&ZoneLow, size, align, fill);
if (data)
return data;
}
- struct allocinfo_s *info = findLast(&ZoneLow);
+ struct allocinfo_s *info = alloc_find_lowest(&ZoneLow);
if (!info)
- return NULL;
- u32 oldpos = (u32)info->allocend;
+ return 0;
+ u32 oldpos = info->range_end;
u32 newpos = ALIGN_DOWN(oldpos - size, align);
- u32 bottom = (u32)info->dataend;
+ u32 bottom = info->range_start + info->alloc_size;
if (newpos >= bottom && newpos <= oldpos)
// Space already present.
- return allocSpace(&ZoneLow, size, align, fill);
+ return alloc_new(&ZoneLow, size, align, fill);
u16 ebda_seg = get_ebda_seg();
u32 ebda_pos = (u32)MAKE_FLATPTR(ebda_seg, 0);
u8 ebda_size = GET_EBDA(ebda_seg, size);
@@ -201,21 +210,20 @@ zonelow_expand(u32 size, u32 align, struct allocinfo_s *fill)
u32 newebda = ALIGN_DOWN(newbottom - ebda_size * 1024, 1024);
if (newebda < BUILD_EBDA_MINIMUM)
// Not enough space.
- return NULL;
+ return 0;
// Move ebda
int ret = relocate_ebda(newebda, ebda_pos, ebda_size);
if (ret)
- return NULL;
+ return 0;
// Update zone
- if (ebda_end == bottom) {
- info->data = (void*)newbottom;
- info->dataend = (void*)newbottom;
- } else
- addSpace(&ZoneLow, (void*)newbottom, (void*)ebda_end);
+ if (ebda_end == bottom)
+ info->range_start = newbottom;
+ else
+ alloc_add(&ZoneLow, newbottom, ebda_end);
- return allocSpace(&ZoneLow, size, align, fill);
+ return alloc_new(&ZoneLow, size, align, fill);
}
@@ -223,56 +231,69 @@ zonelow_expand(u32 size, u32 align, struct allocinfo_s *fill)
* tracked memory allocations
****************************************************************/
-// Allocate memory from the given zone and track it as a PMM allocation
-void * __malloc
-_malloc(struct zone_s *zone, u32 size, u32 align)
+// Allocate physical memory from the given zone and track it as a PMM allocation
+u32
+malloc_palloc(struct zone_s *zone, u32 size, u32 align)
{
ASSERT32FLAT();
if (!size)
- return NULL;
-
- // Find and reserve space for bookkeeping.
- struct allocdetail_s *detail = allocSpace(
- &ZoneTmpHigh, sizeof(*detail), MALLOC_MIN_ALIGN, NULL);
- if (!detail) {
- detail = allocSpace(&ZoneTmpLow, sizeof(*detail)
- , MALLOC_MIN_ALIGN, NULL);
- if (!detail)
- return NULL;
- }
- detail->handle = MALLOC_DEFAULT_HANDLE;
+ return 0;
// Find and reserve space for main allocation
- void *data = allocSpace(zone, size, align, &detail->datainfo);
+ struct allocdetail_s tempdetail;
+ tempdetail.handle = MALLOC_DEFAULT_HANDLE;
+ u32 data = alloc_new(zone, size, align, &tempdetail.datainfo);
if (!CONFIG_MALLOC_UPPERMEMORY && !data && zone == &ZoneLow)
- data = zonelow_expand(size, align, &detail->datainfo);
- if (!data) {
- freeSpace(&detail->detailinfo);
- return NULL;
+ data = zonelow_expand(size, align, &tempdetail.datainfo);
+ if (!data)
+ return 0;
+
+ // Find and reserve space for bookkeeping.
+ struct allocdetail_s *detail = alloc_new_detail(&tempdetail);
+ if (!detail) {
+ alloc_free(&tempdetail.datainfo);
+ return 0;
}
- dprintf(8, "_malloc zone=%p size=%d align=%x ret=%p (detail=%p)\n"
+ dprintf(8, "phys_alloc zone=%p size=%d align=%x ret=%x (detail=%p)\n"
, zone, size, align, data, detail);
return data;
}
-// Free a data block allocated with _malloc
+// Allocate virtual memory from the given zone
+void * __malloc
+_malloc(struct zone_s *zone, u32 size, u32 align)
+{
+ return memremap(malloc_palloc(zone, size, align), size);
+}
+
+// Free a data block allocated with phys_alloc
int
-_free(void *data)
+malloc_pfree(u32 data)
{
ASSERT32FLAT();
- struct allocinfo_s *info = findAlloc(data);
- if (!info || data == (void*)info || data == info->dataend)
+ struct allocinfo_s *info = alloc_find(data);
+ if (!info || data == virt_to_phys(info) || !info->alloc_size)
return -1;
struct allocdetail_s *detail = container_of(
info, struct allocdetail_s, datainfo);
- dprintf(8, "_free %p (detail=%p)\n", data, detail);
- freeSpace(info);
- freeSpace(&detail->detailinfo);
+ dprintf(8, "phys_free %x (detail=%p)\n", data, detail);
+ alloc_free(info);
+ alloc_free(&detail->detailinfo);
return 0;
}
+void
+free(void *data)
+{
+ if (!data)
+ return;
+ int ret = malloc_pfree(virt_to_phys(data));
+ if (ret)
+ warn_internalerror();
+}
+
// Find the amount of free space in a given zone.
u32
malloc_getspace(struct zone_s *zone)
@@ -282,7 +303,7 @@ malloc_getspace(struct zone_s *zone)
u32 maxspace = 0;
struct allocinfo_s *info;
hlist_for_each_entry(info, &zone->head, node) {
- u32 space = info->allocend - info->dataend;
+ u32 space = info->range_end - info->range_start - info->alloc_size;
if (space > maxspace)
maxspace = space;
}
@@ -298,34 +319,34 @@ malloc_getspace(struct zone_s *zone)
// Set a handle associated with an allocation.
void
-malloc_sethandle(void *data, u32 handle)
+malloc_sethandle(u32 data, u32 handle)
{
ASSERT32FLAT();
- struct allocinfo_s *info = findAlloc(data);
- if (!info || data == (void*)info || data == info->dataend)
+ struct allocinfo_s *info = alloc_find(data);
+ if (!info || data == virt_to_phys(info) || !info->alloc_size)
return;
struct allocdetail_s *detail = container_of(
info, struct allocdetail_s, datainfo);
detail->handle = handle;
}
-// Find the data block allocated with _malloc with a given handle.
-void *
+// Find the data block allocated with phys_alloc with a given handle.
+u32
malloc_findhandle(u32 handle)
{
int i;
for (i=0; i<ARRAY_SIZE(Zones); i++) {
struct allocinfo_s *info;
hlist_for_each_entry(info, &Zones[i]->head, node) {
- if (info->data != (void*)info)
+ if (info->range_start != virt_to_phys(info))
continue;
struct allocdetail_s *detail = container_of(
info, struct allocdetail_s, detailinfo);
if (detail->handle == handle)
- return detail->datainfo.data;
+ return detail->datainfo.range_start;
}
}
- return NULL;
+ return 0;
}
@@ -343,10 +364,9 @@ u32
rom_get_max(void)
{
if (CONFIG_MALLOC_UPPERMEMORY)
- return ALIGN_DOWN((u32)RomBase->allocend - OPROM_HEADER_RESERVE
+ return ALIGN_DOWN(RomBase->range_end - OPROM_HEADER_RESERVE
, OPTION_ROM_ALIGN);
- extern u8 final_readonly_start[];
- return (u32)final_readonly_start;
+ return SYMBOL(final_readonly_start);
}
// Return the end of the last deployed option rom.
@@ -364,9 +384,9 @@ rom_reserve(u32 size)
if (newend > rom_get_max())
return NULL;
if (CONFIG_MALLOC_UPPERMEMORY) {
- if (newend < (u32)zonelow_base)
- newend = (u32)zonelow_base;
- RomBase->data = RomBase->dataend = (void*)newend + OPROM_HEADER_RESERVE;
+ if (newend < SYMBOL(zonelow_base))
+ newend = SYMBOL(zonelow_base);
+ RomBase->range_start = newend + OPROM_HEADER_RESERVE;
}
return (void*)RomEnd;
}
@@ -396,10 +416,10 @@ malloc_preinit(void)
dprintf(3, "malloc preinit\n");
// Don't declare any memory between 0xa0000 and 0x100000
- add_e820(BUILD_LOWRAM_END, BUILD_BIOS_ADDR-BUILD_LOWRAM_END, E820_HOLE);
+ e820_remove(BUILD_LOWRAM_END, BUILD_BIOS_ADDR-BUILD_LOWRAM_END);
// Mark known areas as reserved.
- add_e820(BUILD_BIOS_ADDR, BUILD_BIOS_SIZE, E820_RESERVED);
+ e820_add(BUILD_BIOS_ADDR, BUILD_BIOS_SIZE, E820_RESERVED);
// Populate temp high ram
u32 highram = 0;
@@ -419,31 +439,30 @@ malloc_preinit(void)
e = newe;
}
}
- addSpace(&ZoneTmpHigh, (void*)s, (void*)e);
+ alloc_add(&ZoneTmpHigh, s, e);
}
// Populate regions
- addSpace(&ZoneTmpLow, (void*)BUILD_STACK_ADDR, (void*)BUILD_EBDA_MINIMUM);
+ alloc_add(&ZoneTmpLow, BUILD_STACK_ADDR, BUILD_EBDA_MINIMUM);
if (highram) {
- addSpace(&ZoneHigh, (void*)highram
- , (void*)highram + BUILD_MAX_HIGHTABLE);
- add_e820(highram, BUILD_MAX_HIGHTABLE, E820_RESERVED);
+ alloc_add(&ZoneHigh, highram, highram + BUILD_MAX_HIGHTABLE);
+ e820_add(highram, BUILD_MAX_HIGHTABLE, E820_RESERVED);
}
}
void
-csm_malloc_preinit(u32 low_pmm, u32 low_pmm_size, u32 hi_pmm, u32 hi_pmm_size)
+malloc_csm_preinit(u32 low_pmm, u32 low_pmm_size, u32 hi_pmm, u32 hi_pmm_size)
{
ASSERT32FLAT();
if (hi_pmm_size > BUILD_MAX_HIGHTABLE) {
- void *hi_pmm_end = (void *)hi_pmm + hi_pmm_size;
- addSpace(&ZoneTmpHigh, (void *)hi_pmm, hi_pmm_end - BUILD_MAX_HIGHTABLE);
- addSpace(&ZoneHigh, hi_pmm_end - BUILD_MAX_HIGHTABLE, hi_pmm_end);
+ u32 hi_pmm_end = hi_pmm + hi_pmm_size;
+ alloc_add(&ZoneTmpHigh, hi_pmm, hi_pmm_end - BUILD_MAX_HIGHTABLE);
+ alloc_add(&ZoneHigh, hi_pmm_end - BUILD_MAX_HIGHTABLE, hi_pmm_end);
} else {
- addSpace(&ZoneTmpHigh, (void *)hi_pmm, (void *)hi_pmm + hi_pmm_size);
+ alloc_add(&ZoneTmpHigh, hi_pmm, hi_pmm + hi_pmm_size);
}
- addSpace(&ZoneTmpLow, (void *)low_pmm, (void *)low_pmm + low_pmm_size);
+ alloc_add(&ZoneTmpLow, low_pmm, low_pmm + low_pmm_size);
}
u32 LegacyRamSize VARFSEG;
@@ -484,21 +503,21 @@ malloc_init(void)
}
// Initialize low-memory region
- extern u8 varlow_start[], varlow_end[], final_varlow_start[];
- memmove(final_varlow_start, varlow_start, varlow_end - varlow_start);
+ memmove(VSYMBOL(final_varlow_start), VSYMBOL(varlow_start)
+ , SYMBOL(varlow_end) - SYMBOL(varlow_start));
if (CONFIG_MALLOC_UPPERMEMORY) {
- addSpace(&ZoneLow, zonelow_base + OPROM_HEADER_RESERVE
- , final_varlow_start);
- RomBase = findLast(&ZoneLow);
+ alloc_add(&ZoneLow, SYMBOL(zonelow_base) + OPROM_HEADER_RESERVE
+ , SYMBOL(final_varlow_start));
+ RomBase = alloc_find_lowest(&ZoneLow);
} else {
- addSpace(&ZoneLow, (void*)ALIGN_DOWN((u32)final_varlow_start, 1024)
- , final_varlow_start);
+ alloc_add(&ZoneLow, ALIGN_DOWN(SYMBOL(final_varlow_start), 1024)
+ , SYMBOL(final_varlow_start));
}
// Add space available in f-segment to ZoneFSeg
- extern u8 zonefseg_start[], zonefseg_end[];
- memset(zonefseg_start, 0, zonefseg_end - zonefseg_start);
- addSpace(&ZoneFSeg, zonefseg_start, zonefseg_end);
+ memset(VSYMBOL(zonefseg_start), 0
+ , SYMBOL(zonefseg_end) - SYMBOL(zonefseg_start));
+ alloc_add(&ZoneFSeg, SYMBOL(zonefseg_start), SYMBOL(zonefseg_end));
calcRamSize();
}
@@ -521,19 +540,20 @@ malloc_prepboot(void)
// Reserve more low-mem if needed.
u32 endlow = GET_BDA(mem_size_kb)*1024;
- add_e820(endlow, BUILD_LOWRAM_END-endlow, E820_RESERVED);
+ e820_add(endlow, BUILD_LOWRAM_END-endlow, E820_RESERVED);
// Clear unused f-seg ram.
- struct allocinfo_s *info = findLast(&ZoneFSeg);
- memset(info->dataend, 0, info->allocend - info->dataend);
+ struct allocinfo_s *info = alloc_find_lowest(&ZoneFSeg);
+ u32 size = info->range_end - info->range_start;
+ memset(memremap(info->range_start, size), 0, size);
dprintf(1, "Space available for UMB: %x-%x, %x-%x\n"
- , RomEnd, base, (u32)info->dataend, (u32)info->allocend);
+ , RomEnd, base, info->range_start, info->range_end);
// Give back unused high ram.
- info = findLast(&ZoneHigh);
+ info = alloc_find_lowest(&ZoneHigh);
if (info) {
- u32 giveback = ALIGN_DOWN(info->allocend - info->dataend, PAGE_SIZE);
- add_e820((u32)info->dataend, giveback, E820_RAM);
+ u32 giveback = ALIGN_DOWN(info->range_end-info->range_start, PAGE_SIZE);
+ e820_add(info->range_start, giveback, E820_RAM);
dprintf(1, "Returned %d bytes of ZoneHigh\n", giveback);
}
diff --git a/qemu/roms/seabios/src/malloc.h b/qemu/roms/seabios/src/malloc.h
index 2bcb5bf6d..960a7f800 100644
--- a/qemu/roms/seabios/src/malloc.h
+++ b/qemu/roms/seabios/src/malloc.h
@@ -9,17 +9,19 @@ u32 rom_get_max(void);
u32 rom_get_last(void);
struct rom_header *rom_reserve(u32 size);
int rom_confirm(u32 size);
-void csm_malloc_preinit(u32 low_pmm, u32 low_pmm_size, u32 hi_pmm,
+void malloc_csm_preinit(u32 low_pmm, u32 low_pmm_size, u32 hi_pmm,
u32 hi_pmm_size);
void malloc_preinit(void);
extern u32 LegacyRamSize;
void malloc_init(void);
void malloc_prepboot(void);
+u32 malloc_palloc(struct zone_s *zone, u32 size, u32 align);
void *_malloc(struct zone_s *zone, u32 size, u32 align);
-int _free(void *data);
+int malloc_pfree(u32 data);
+void free(void *data);
u32 malloc_getspace(struct zone_s *zone);
-void malloc_sethandle(void *data, u32 handle);
-void *malloc_findhandle(u32 handle);
+void malloc_sethandle(u32 data, u32 handle);
+u32 malloc_findhandle(u32 handle);
#define MALLOC_DEFAULT_HANDLE 0xFFFFFFFF
// Minimum alignment of malloc'd memory
@@ -64,8 +66,5 @@ static inline void *memalign_tmp(u32 align, u32 size) {
return ret;
return memalign_tmplow(align, size);
}
-static inline void free(void *data) {
- _free(data);
-}
#endif // malloc.h
diff --git a/qemu/roms/seabios/src/memmap.h b/qemu/roms/seabios/src/memmap.h
index 7bda56e2b..22bd4bcb8 100644
--- a/qemu/roms/seabios/src/memmap.h
+++ b/qemu/roms/seabios/src/memmap.h
@@ -1,29 +1,21 @@
-#ifndef __E820MAP_H
-#define __E820MAP_H
+#ifndef __MEMMAP_H
+#define __MEMMAP_H
-#include "types.h" // u64
-
-#define E820_RAM 1
-#define E820_RESERVED 2
-#define E820_ACPI 3
-#define E820_NVS 4
-#define E820_UNUSABLE 5
-#define E820_HOLE ((u32)-1) // Useful for removing entries
-
-struct e820entry {
- u64 start;
- u64 size;
- u32 type;
-};
-
-void add_e820(u64 start, u64 size, u32 type);
-void memmap_prepboot(void);
+#include "types.h" // u32
// A typical OS page size
#define PAGE_SIZE 4096
+#define PAGE_SHIFT 12
+
+static inline u32 virt_to_phys(void *v) {
+ return (u32)v;
+}
+static inline void *memremap(u32 addr, u32 len) {
+ return (void*)addr;
+}
-// e820 map storage
-extern struct e820entry e820_list[];
-extern int e820_count;
+// Return the value of a linker script symbol (see scripts/layoutrom.py)
+#define SYMBOL(SYM) ({ extern char SYM; (u32)&SYM; })
+#define VSYMBOL(SYM) ((void*)SYMBOL(SYM))
-#endif // e820map.h
+#endif // memmap.h
diff --git a/qemu/roms/seabios/src/misc.c b/qemu/roms/seabios/src/misc.c
index 8caaf31d8..f02237c36 100644
--- a/qemu/roms/seabios/src/misc.c
+++ b/qemu/roms/seabios/src/misc.c
@@ -56,7 +56,7 @@ void VISIBLE16
handle_10(struct bregs *regs)
{
debug_enter(regs, DEBUG_HDL_10);
- // dont do anything, since the VGA BIOS handles int10h requests
+ // don't do anything, since the VGA BIOS handles int10h requests
}
// NMI handler
diff --git a/qemu/roms/seabios/src/mouse.c b/qemu/roms/seabios/src/mouse.c
index 6d1f5b77e..b7ad7c62a 100644
--- a/qemu/roms/seabios/src/mouse.c
+++ b/qemu/roms/seabios/src/mouse.c
@@ -280,8 +280,7 @@ invoke_mouse_handler(void)
if (!CONFIG_MOUSE)
return;
if (need_hop_back()) {
- extern void _cfunc16_invoke_mouse_handler(void);
- stack_hop_back(0, 0, _cfunc16_invoke_mouse_handler);
+ stack_hop_back(invoke_mouse_handler, 0, 0);
return;
}
ASSERT16();
diff --git a/qemu/roms/seabios/src/optionroms.c b/qemu/roms/seabios/src/optionroms.c
index 93d9d2fe6..c81eff2d2 100644
--- a/qemu/roms/seabios/src/optionroms.c
+++ b/qemu/roms/seabios/src/optionroms.c
@@ -19,6 +19,9 @@
#include "std/pnpbios.h" // PNP_SIGNATURE
#include "string.h" // memset
#include "util.h" // get_pnp_offset
+#include "tcgbios.h" // tpm_*
+
+static int EnforceChecksum, S3ResumeVga, RunPCIroms;
/****************************************************************
@@ -60,8 +63,6 @@ call_bcv(u16 seg, u16 ip)
__callrom(MAKE_FLATPTR(seg, 0), ip, 0);
}
-static int EnforceChecksum;
-
// Verify that an option rom looks valid
static int
is_valid_rom(struct rom_header *rom)
@@ -132,6 +133,8 @@ init_optionrom(struct rom_header *rom, u16 bdf, int isvga)
if (newrom != rom)
memmove(newrom, rom, rom->size * 512);
+ tpm_option_rom(newrom, rom->size * 512);
+
if (isvga || get_pnp_rom(newrom))
// Only init vga and PnP roms here.
callrom(newrom, bdf);
@@ -180,19 +183,6 @@ deploy_romfile(struct romfile_s *file)
return rom;
}
-// Check if an option rom is at a hardcoded location or in CBFS.
-static struct rom_header *
-lookup_hardcode(struct pci_device *pci)
-{
- char fname[17];
- snprintf(fname, sizeof(fname), "pci%04x,%04x.rom"
- , pci->vendor, pci->device);
- struct romfile_s *file = romfile_find(fname);
- if (file)
- return deploy_romfile(file);
- return NULL;
-}
-
// Run all roms in a given CBFS directory.
static void
run_file_roms(const char *prefix, int isvga, u64 *sources)
@@ -321,21 +311,28 @@ fail:
}
// Attempt to map and initialize the option rom on a given PCI device.
-static int
+static void
init_pcirom(struct pci_device *pci, int isvga, u64 *sources)
{
u16 bdf = pci->bdf;
dprintf(4, "Attempting to init PCI bdf %02x:%02x.%x (vd %04x:%04x)\n"
, pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf)
, pci->vendor, pci->device);
- struct rom_header *rom = lookup_hardcode(pci);
- if (! rom)
+
+ char fname[17];
+ snprintf(fname, sizeof(fname), "pci%04x,%04x.rom"
+ , pci->vendor, pci->device);
+ struct romfile_s *file = romfile_find(fname);
+ struct rom_header *rom = NULL;
+ if (file)
+ rom = deploy_romfile(file);
+ else if (RunPCIroms > 1 || (RunPCIroms == 1 && isvga))
rom = map_pcirom(pci);
if (! rom)
// No ROM present.
- return -1;
+ return;
setRomSource(sources, rom, RS_PCIROM | (u32)pci);
- return init_optionrom(rom, bdf, isvga);
+ init_optionrom(rom, bdf, isvga);
}
@@ -416,7 +413,6 @@ optionrom_setup(void)
* VGA init
****************************************************************/
-static int S3ResumeVga;
int ScreenAndDebug;
struct rom_header *VgaROM;
@@ -432,6 +428,7 @@ vgarom_setup(void)
// Load some config settings that impact VGA.
EnforceChecksum = romfile_loadint("etc/optionroms-checksum", 1);
S3ResumeVga = romfile_loadint("etc/s3-resume-vga-init", CONFIG_QEMU);
+ RunPCIroms = romfile_loadint("etc/pci-optionrom-exec", 2);
ScreenAndDebug = romfile_loadint("etc/screen-and-debug", 1);
if (CONFIG_OPTIONROMS_DEPLOYED) {
diff --git a/qemu/roms/seabios/src/output.c b/qemu/roms/seabios/src/output.c
index 45397b3f6..8a883889c 100644
--- a/qemu/roms/seabios/src/output.c
+++ b/qemu/roms/seabios/src/output.c
@@ -30,6 +30,7 @@ void
debug_banner(void)
{
dprintf(1, "SeaBIOS (version %s)\n", VERSION);
+ dprintf(1, "BUILD: %s\n", BUILDINFO);
}
// Write a character to debug port(s).
diff --git a/qemu/roms/seabios/src/pmm.c b/qemu/roms/seabios/src/pmm.c
index 304faab2c..640341472 100644
--- a/qemu/roms/seabios/src/pmm.c
+++ b/qemu/roms/seabios/src/pmm.c
@@ -65,26 +65,26 @@ handle_pmm00(u16 *args)
if (align < MALLOC_MIN_ALIGN)
align = MALLOC_MIN_ALIGN;
}
- void *data;
+ u32 data;
switch (flags & 3) {
default:
case 0:
return 0;
case 1:
- data = _malloc(lowzone, size, align);
+ data = malloc_palloc(lowzone, size, align);
break;
case 2:
- data = _malloc(highzone, size, align);
+ data = malloc_palloc(highzone, size, align);
break;
case 3: {
- data = _malloc(lowzone, size, align);
+ data = malloc_palloc(lowzone, size, align);
if (!data)
- data = _malloc(highzone, size, align);
+ data = malloc_palloc(highzone, size, align);
}
}
if (data && handle != MALLOC_DEFAULT_HANDLE)
malloc_sethandle(data, handle);
- return (u32)data;
+ return data;
}
// PMM - find
@@ -95,7 +95,7 @@ handle_pmm01(u16 *args)
dprintf(3, "pmm01: handle=%x\n", handle);
if (handle == MALLOC_DEFAULT_HANDLE)
return 0;
- return (u32)malloc_findhandle(handle);
+ return malloc_findhandle(handle);
}
// PMM - deallocate
@@ -104,7 +104,7 @@ handle_pmm02(u16 *args)
{
u32 buffer = *(u32*)&args[1];
dprintf(3, "pmm02: buffer=%x\n", buffer);
- int ret = _free((void*)buffer);
+ int ret = malloc_pfree(buffer);
if (ret)
// Error
return 1;
diff --git a/qemu/roms/seabios/src/post.c b/qemu/roms/seabios/src/post.c
index 9ea5620c9..49c22b875 100644
--- a/qemu/roms/seabios/src/post.c
+++ b/qemu/roms/seabios/src/post.c
@@ -8,6 +8,7 @@
#include "biosvar.h" // SET_BDA
#include "bregs.h" // struct bregs
#include "config.h" // CONFIG_*
+#include "e820map.h" // e820_add
#include "fw/paravirt.h" // qemu_cfg_preinit
#include "fw/xen.h" // xen_preinit
#include "hw/ahci.h" // ahci_setup
@@ -24,10 +25,11 @@
#include "hw/virtio-blk.h" // virtio_blk_setup
#include "hw/virtio-scsi.h" // virtio_scsi_setup
#include "malloc.h" // malloc_init
-#include "memmap.h" // add_e820
+#include "memmap.h" // SYMBOL
#include "output.h" // dprintf
#include "string.h" // memset
#include "util.h" // kbd_init
+#include "tcgbios.h" // tpm_*
/****************************************************************
@@ -88,9 +90,8 @@ bda_init(void)
int esize = EBDA_SIZE_START;
u16 ebda_seg = EBDA_SEGMENT_START;
- extern u8 final_varlow_start[];
if (!CONFIG_MALLOC_UPPERMEMORY)
- ebda_seg = FLATPTR_TO_SEG(ALIGN_DOWN((u32)final_varlow_start, 1024)
+ ebda_seg = FLATPTR_TO_SEG(ALIGN_DOWN(SYMBOL(final_varlow_start), 1024)
- EBDA_SIZE_START*1024);
SET_BDA(ebda_seg, ebda_seg);
@@ -101,10 +102,10 @@ bda_init(void)
memset(ebda, 0, sizeof(*ebda));
ebda->size = esize;
- add_e820((u32)ebda, BUILD_LOWRAM_END-(u32)ebda, E820_RESERVED);
+ e820_add((u32)ebda, BUILD_LOWRAM_END-(u32)ebda, E820_RESERVED);
// Init extra stack
- StackPos = (void*)(&ExtraStack[BUILD_EXTRA_STACK_SIZE] - zonelow_base);
+ StackPos = &ExtraStack[BUILD_EXTRA_STACK_SIZE] - SYMBOL(zonelow_base);
}
void
@@ -116,13 +117,13 @@ interface_init(void)
// Setup romfile items.
qemu_cfg_init();
coreboot_cbfs_init();
+ multiboot_init();
// Setup ivt/bda/ebda
ivt_init();
bda_init();
// Other interfaces
- thread_init();
boot_init();
bios32_init();
pmm_init();
@@ -157,26 +158,32 @@ device_hardware_setup(void)
static void
platform_hardware_setup(void)
{
- // Enable CPU caching
- setcr0(getcr0() & ~(CR0_CD|CR0_NW));
-
// Make sure legacy DMA isn't running.
dma_setup();
// Init base pc hardware.
pic_setup();
+ thread_setup();
mathcp_setup();
- timer_setup();
- clock_setup();
// Platform specific setup
qemu_platform_setup();
coreboot_platform_setup();
+
+ // Setup timers and periodic clock interrupt
+ timer_setup();
+ clock_setup();
+
+ // Initialize TPM
+ tpm_setup();
}
void
prepareboot(void)
{
+ // Change TPM phys. presence state befor leaving BIOS
+ tpm_prepboot();
+
// Run BCVs
bcv_prepboot();
@@ -184,7 +191,7 @@ prepareboot(void)
cdrom_prepboot();
pmm_prepboot();
malloc_prepboot();
- memmap_prepboot();
+ e820_prepboot();
HaveRunPost = 2;
@@ -269,30 +276,27 @@ reloc_preinit(void *f, void *arg)
void (*func)(void *) __noreturn = f;
if (!CONFIG_RELOCATE_INIT)
func(arg);
- // Symbols populated by the build.
- extern u8 code32flat_start[];
- extern u8 _reloc_min_align;
- extern u32 _reloc_abs_start[], _reloc_abs_end[];
- extern u32 _reloc_rel_start[], _reloc_rel_end[];
- extern u32 _reloc_init_start[], _reloc_init_end[];
- extern u8 code32init_start[], code32init_end[];
// Allocate space for init code.
- u32 initsize = code32init_end - code32init_start;
- u32 codealign = (u32)&_reloc_min_align;
+ u32 initsize = SYMBOL(code32init_end) - SYMBOL(code32init_start);
+ u32 codealign = SYMBOL(_reloc_min_align);
void *codedest = memalign_tmp(codealign, initsize);
+ void *codesrc = VSYMBOL(code32init_start);
if (!codedest)
panic("No space for init relocation.\n");
// Copy code and update relocs (init absolute, init relative, and runtime)
dprintf(1, "Relocating init from %p to %p (size %d)\n"
- , code32init_start, codedest, initsize);
- s32 delta = codedest - (void*)code32init_start;
- memcpy(codedest, code32init_start, initsize);
- updateRelocs(codedest, _reloc_abs_start, _reloc_abs_end, delta);
- updateRelocs(codedest, _reloc_rel_start, _reloc_rel_end, -delta);
- updateRelocs(code32flat_start, _reloc_init_start, _reloc_init_end, delta);
- if (f >= (void*)code32init_start && f < (void*)code32init_end)
+ , codesrc, codedest, initsize);
+ s32 delta = codedest - codesrc;
+ memcpy(codedest, codesrc, initsize);
+ updateRelocs(codedest, VSYMBOL(_reloc_abs_start), VSYMBOL(_reloc_abs_end)
+ , delta);
+ updateRelocs(codedest, VSYMBOL(_reloc_rel_start), VSYMBOL(_reloc_rel_end)
+ , -delta);
+ updateRelocs(VSYMBOL(code32flat_start), VSYMBOL(_reloc_init_start)
+ , VSYMBOL(_reloc_init_end), delta);
+ if (f >= codesrc && f < VSYMBOL(code32init_end))
func = f + delta;
// Call function in relocated code.
diff --git a/qemu/roms/seabios/src/resume.c b/qemu/roms/seabios/src/resume.c
index 19031747c..a5465d877 100644
--- a/qemu/roms/seabios/src/resume.c
+++ b/qemu/roms/seabios/src/resume.c
@@ -16,6 +16,7 @@
#include "std/bda.h" // struct bios_data_area_s
#include "string.h" // memset
#include "util.h" // dma_setup
+#include "tcgbios.h" // tpm_s3_resume
// Handler for post calls that look like a resume.
void VISIBLE16
@@ -99,6 +100,8 @@ s3_resume(void)
pci_resume();
+ /* resume TPM before we may measure option roms */
+ tpm_s3_resume();
s3_resume_vga();
make_bios_readonly();
diff --git a/qemu/roms/seabios/src/romlayout.S b/qemu/roms/seabios/src/romlayout.S
index 93b6874e7..53cc0f5e3 100644
--- a/qemu/roms/seabios/src/romlayout.S
+++ b/qemu/roms/seabios/src/romlayout.S
@@ -22,18 +22,14 @@
// %edx = return location (in 32bit mode)
// Clobbers: ecx, flags, segment registers, cr0, idt/gdt
DECLFUNC transition32
-transition32_nmi_off:
- // transition32 when NMI and A20 are already initialized
- movl %eax, %ecx
- jmp 1f
+ .global transition32_nmi_off
transition32:
- movl %eax, %ecx
-
// Disable irqs (and clear direction flag)
cli
cld
// Disable nmi
+ movl %eax, %ecx
movl $CMOS_RESET_CODE|NMI_DISABLE_BIT, %eax
outb %al, $PORT_CMOS_INDEX
inb $PORT_CMOS_DATA, %al
@@ -42,29 +38,31 @@ transition32:
inb $PORT_A20, %al
orb $A20_ENABLE_BIT, %al
outb %al, $PORT_A20
+ movl %ecx, %eax
+transition32_nmi_off:
// Set segment descriptors
-1: lidtw %cs:pmode_IDT_info
+ lidtw %cs:pmode_IDT_info
lgdtw %cs:rombios32_gdt_48
// Enable protected mode
- movl %cr0, %eax
- orl $CR0_PE, %eax
- movl %eax, %cr0
+ movl %cr0, %ecx
+ andl $~(CR0_PG|CR0_CD|CR0_NW), %ecx
+ orl $CR0_PE, %ecx
+ movl %ecx, %cr0
// start 32bit protected mode code
- ljmpl $SEG32_MODE32_CS, $(BUILD_BIOS_ADDR + 2f)
+ ljmpl $SEG32_MODE32_CS, $(BUILD_BIOS_ADDR + 1f)
.code32
// init data segments
-2: movl $SEG32_MODE32_DS, %eax
- movw %ax, %ds
- movw %ax, %es
- movw %ax, %ss
- movw %ax, %fs
- movw %ax, %gs
+1: movl $SEG32_MODE32_DS, %ecx
+ movw %cx, %ds
+ movw %cx, %es
+ movw %cx, %ss
+ movw %cx, %fs
+ movw %cx, %gs
- movl %ecx, %eax
jmpl *%edx
.code16
@@ -75,61 +73,47 @@ transition32:
.global transition16big
.code32
transition16:
- movl %eax, %ecx
-
- // restore data segment limits to 0xffff
- movl $SEG32_MODE16_DS, %eax
- movw %ax, %ds
- movw %ax, %es
- movw %ax, %ss
- movw %ax, %fs
- movw %ax, %gs
-
-#if CONFIG_DISABLE_A20
- // disable a20
- inb $PORT_A20, %al
- andb $~A20_ENABLE_BIT, %al
- outb %al, $PORT_A20
-#endif
+ // Reset data segment limits
+ movl $SEG32_MODE16_DS, %ecx
+ movw %cx, %ds
+ movw %cx, %es
+ movw %cx, %ss
+ movw %cx, %fs
+ movw %cx, %gs
// Jump to 16bit mode
ljmpw $SEG32_MODE16_CS, $1f
transition16big:
- movl %eax, %ecx
-
- movl $SEG32_MODE16BIG_DS, %eax
- movw %ax, %ds
- movw %ax, %es
- movw %ax, %ss
- movw %ax, %fs
- movw %ax, %gs
+ movl $SEG32_MODE16BIG_DS, %ecx
+ movw %cx, %ds
+ movw %cx, %es
+ movw %cx, %ss
+ movw %cx, %fs
+ movw %cx, %gs
ljmpw $SEG32_MODE16BIG_CS, $1f
.code16
-1:
// Disable protected mode
- movl %cr0, %eax
- andl $~CR0_PE, %eax
- movl %eax, %cr0
+1: movl %cr0, %ecx
+ andl $~CR0_PE, %ecx
+ movl %ecx, %cr0
// far jump to flush CPU queue after transition to real mode
ljmpw $SEG_BIOS, $2f
-2:
// restore IDT to normal real-mode defaults
- lidtw %cs:rmode_IDT_info
+2: lidtw %cs:rmode_IDT_info
// Clear segment registers
- xorw %ax, %ax
- movw %ax, %fs
- movw %ax, %gs
- movw %ax, %es
- movw %ax, %ds
- movw %ax, %ss // Assume stack is in segment 0
+ xorw %cx, %cx
+ movw %cx, %fs
+ movw %cx, %gs
+ movw %cx, %es
+ movw %cx, %ds
+ movw %cx, %ss // Assume stack is in segment 0
- movl %ecx, %eax
jmpl *%edx
@@ -264,7 +248,7 @@ entry_pmm:
movl $_cfunc32flat_handle_pmm, %eax // Setup: call32(handle_pmm, args, -1)
leal PUSHBREGS_size+12(%esp, %ecx), %edx // %edx points to start of args
movl $-1, %ecx
- calll call32
+ calll __call32
movw %ax, BREGS_eax(%esp) // Modify %ax:%dx to return %eax
shrl $16, %eax
movw %ax, BREGS_edx(%esp)
@@ -374,6 +358,8 @@ entry_bios32:
entry_elf:
cli
cld
+ movl %eax, entry_elf_eax
+ movl %ebx, entry_elf_ebx
lidtl (BUILD_BIOS_ADDR + pmode_IDT_info)
lgdtl (BUILD_BIOS_ADDR + rombios32_gdt_48)
movl $SEG32_MODE32_DS, %eax
@@ -562,7 +548,10 @@ entry_post:
ENTRY_INTO32 _cfunc32flat_handle_post // Normal entry point
ORG 0xe2c3
- IRQ_ENTRY 02
+ .global entry_02
+entry_02:
+ ENTRY handle_02 // NMI handler does not switch onto extra stack
+ iretw
ORG 0xe3fe
.global entry_13_official
diff --git a/qemu/roms/seabios/src/sha1.c b/qemu/roms/seabios/src/sha1.c
new file mode 100644
index 000000000..2ecb3cb89
--- /dev/null
+++ b/qemu/roms/seabios/src/sha1.c
@@ -0,0 +1,147 @@
+// Support for Calculation of SHA1 in SW
+//
+// Copyright (C) 2006-2011 IBM Corporation
+//
+// Authors:
+// Stefan Berger <stefanb@linux.vnet.ibm.com>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+//
+// See: http://www.itl.nist.gov/fipspubs/fip180-1.htm
+// RFC3174, Wikipedia's SHA1 alogrithm description
+//
+
+#include "config.h"
+#include "byteorder.h" // cpu_to_*, __swab64
+#include "sha1.h" // sha1
+#include "string.h" // memcpy
+#include "x86.h" // rol
+
+typedef struct _sha1_ctx {
+ u32 h[5];
+} sha1_ctx;
+
+
+static void
+sha1_block(u32 *w, sha1_ctx *ctx)
+{
+ u32 i;
+ u32 a,b,c,d,e,f;
+ u32 tmp;
+ u32 idx;
+
+ static const u32 sha_ko[4] = {
+ 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 };
+
+ /* change endianness of given data */
+ for (i = 0; i < 16; i++)
+ w[i] = be32_to_cpu(w[i]);
+
+ for (i = 16; i <= 79; i++) {
+ tmp = w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16];
+ w[i] = rol(tmp,1);
+ }
+
+ a = ctx->h[0];
+ b = ctx->h[1];
+ c = ctx->h[2];
+ d = ctx->h[3];
+ e = ctx->h[4];
+
+ for (i = 0; i <= 79; i++) {
+ if (i <= 19) {
+ f = (b & c) | ((b ^ 0xffffffff) & d);
+ idx = 0;
+ } else if (i <= 39) {
+ f = b ^ c ^ d;
+ idx = 1;
+ } else if (i <= 59) {
+ f = (b & c) | (b & d) | (c & d);
+ idx = 2;
+ } else {
+ f = b ^ c ^ d;
+ idx = 3;
+ }
+
+ tmp = rol(a, 5) +
+ f +
+ e +
+ sha_ko[idx] +
+ w[i];
+ e = d;
+ d = c;
+ c = rol(b, 30);
+ b = a;
+ a = tmp;
+ }
+
+ ctx->h[0] += a;
+ ctx->h[1] += b;
+ ctx->h[2] += c;
+ ctx->h[3] += d;
+ ctx->h[4] += e;
+}
+
+
+static void
+sha1_do(sha1_ctx *ctx, const u8 *data32, u32 length)
+{
+ u32 offset;
+ u16 num;
+ u32 bits = 0;
+ u32 w[80];
+ u64 tmp;
+
+ /* treat data in 64-byte chunks */
+ for (offset = 0; length - offset >= 64; offset += 64) {
+ memcpy(w, data32 + offset, 64);
+ sha1_block((u32 *)w, ctx);
+ bits += (64 * 8);
+ }
+
+ /* last block with less than 64 bytes */
+ num = length - offset;
+ bits += (num << 3);
+
+ memcpy(w, data32 + offset, num);
+ ((u8 *)w)[num] = 0x80;
+ if (64 - (num + 1) > 0)
+ memset( &((u8 *)w)[num + 1], 0x0, 64 - (num + 1));
+
+ if (num >= 56) {
+ /* cannot append number of bits here */
+ sha1_block((u32 *)w, ctx);
+ memset(w, 0x0, 60);
+ }
+
+ /* write number of bits to end of block */
+ tmp = __swab64(bits);
+ memcpy(&w[14], &tmp, 8);
+
+ sha1_block(w, ctx);
+
+ /* need to switch result's endianness */
+ for (num = 0; num < 5; num++)
+ ctx->h[num] = cpu_to_be32(ctx->h[num]);
+}
+
+
+u32
+sha1(const u8 *data, u32 length, u8 *hash)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ sha1_ctx ctx = {
+ .h[0] = 0x67452301,
+ .h[1] = 0xefcdab89,
+ .h[2] = 0x98badcfe,
+ .h[3] = 0x10325476,
+ .h[4] = 0xc3d2e1f0,
+ };
+
+ sha1_do(&ctx, data, length);
+ memcpy(hash, &ctx.h[0], 20);
+
+ return 0;
+}
diff --git a/qemu/roms/seabios/src/sha1.h b/qemu/roms/seabios/src/sha1.h
new file mode 100644
index 000000000..07aabf34f
--- /dev/null
+++ b/qemu/roms/seabios/src/sha1.h
@@ -0,0 +1,8 @@
+#ifndef __SHA1_H
+#define __SHA1_H
+
+#include "types.h" // u32
+
+u32 sha1(const u8 *data, u32 length, u8 *hash);
+
+#endif // sha1.h
diff --git a/qemu/roms/seabios/src/stacks.c b/qemu/roms/seabios/src/stacks.c
index 1dbdfe9bb..ef6a70775 100644
--- a/qemu/roms/seabios/src/stacks.c
+++ b/qemu/roms/seabios/src/stacks.c
@@ -1,6 +1,6 @@
// Code for manipulating stack locations.
//
-// Copyright (C) 2009-2014 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2009-2015 Kevin O'Connor <kevin@koconnor.net>
//
// This file may be distributed under the terms of the GNU LGPLv3 license.
@@ -13,6 +13,7 @@
#include "output.h" // dprintf
#include "romfile.h" // romfile_loadint
#include "stacks.h" // struct mutex_s
+#include "string.h" // memset
#include "util.h" // useRTC
#define MAIN_STACK_MAX (1024*1024)
@@ -27,40 +28,108 @@ struct {
u8 cmosindex;
u8 a20;
u16 ss, fs, gs;
+ u32 cr0;
struct descloc_s gdt;
-} Call32Data VARLOW;
+} Call16Data VARLOW;
-#define C32_SLOPPY 1
-#define C32_SMM 2
+#define C16_BIG 1
+#define C16_SMM 2
int HaveSmmCall32 VARFSEG;
-// Backup state in preparation for call32_smm()
-static void
-call32_smm_prep(void)
-{
+// Backup state in preparation for call32
+static int
+call32_prep(u8 method)
+{
+ if (!CONFIG_CALL32_SMM || method != C16_SMM) {
+ // Backup cr0
+ u32 cr0 = cr0_read();
+ if (cr0 & CR0_PE)
+ // Called in 16bit protected mode?!
+ return -1;
+ SET_LOW(Call16Data.cr0, cr0);
+
+ // Backup fs/gs and gdt
+ SET_LOW(Call16Data.fs, GET_SEG(FS));
+ SET_LOW(Call16Data.gs, GET_SEG(GS));
+ struct descloc_s gdt;
+ sgdt(&gdt);
+ SET_LOW(Call16Data.gdt.length, gdt.length);
+ SET_LOW(Call16Data.gdt.addr, gdt.addr);
+
+ // Enable a20 and backup its previous state
+ SET_LOW(Call16Data.a20, set_a20(1));
+ }
+
+ // Backup ss
+ SET_LOW(Call16Data.ss, GET_SEG(SS));
+
// Backup cmos index register and disable nmi
u8 cmosindex = inb(PORT_CMOS_INDEX);
outb(cmosindex | NMI_DISABLE_BIT, PORT_CMOS_INDEX);
inb(PORT_CMOS_DATA);
- SET_LOW(Call32Data.cmosindex, cmosindex);
-
- // Backup ss
- SET_LOW(Call32Data.ss, GET_SEG(SS));
+ SET_LOW(Call16Data.cmosindex, cmosindex);
- SET_LOW(Call32Data.method, C32_SMM);
+ SET_LOW(Call16Data.method, method);
+ return 0;
}
-// Restore state backed up during call32_smm()
-static void
-call32_smm_post(void)
+// Restore state backed up during call32
+static u8
+call32_post(void)
{
- SET_LOW(Call32Data.method, 0);
- SET_LOW(Call32Data.ss, 0);
+ u8 method = GET_LOW(Call16Data.method);
+ SET_LOW(Call16Data.method, 0);
+ SET_LOW(Call16Data.ss, 0);
+
+ if (!CONFIG_CALL32_SMM || method != C16_SMM) {
+ // Restore a20
+ set_a20(GET_LOW(Call16Data.a20));
+
+ // Restore gdt and fs/gs
+ struct descloc_s gdt;
+ gdt.length = GET_LOW(Call16Data.gdt.length);
+ gdt.addr = GET_LOW(Call16Data.gdt.addr);
+ lgdt(&gdt);
+ SET_SEG(FS, GET_LOW(Call16Data.fs));
+ SET_SEG(GS, GET_LOW(Call16Data.gs));
+
+ // Restore cr0
+ u32 cr0_caching = GET_LOW(Call16Data.cr0) & (CR0_CD|CR0_NW);
+ if (cr0_caching)
+ cr0_mask(CR0_CD|CR0_NW, cr0_caching);
+ }
// Restore cmos index register
- outb(GET_LOW(Call32Data.cmosindex), PORT_CMOS_INDEX);
+ outb(GET_LOW(Call16Data.cmosindex), PORT_CMOS_INDEX);
inb(PORT_CMOS_DATA);
+ return method;
+}
+
+// Force next call16() to restore to a pristine cpu environment state
+static void
+call16_override(int big)
+{
+ ASSERT32FLAT();
+ if (getesp() > BUILD_STACK_ADDR)
+ panic("call16_override with invalid stack\n");
+ memset(&Call16Data, 0, sizeof(Call16Data));
+ if (big) {
+ Call16Data.method = C16_BIG;
+ Call16Data.a20 = 1;
+ } else {
+ Call16Data.a20 = !CONFIG_DISABLE_A20;
+ }
+}
+
+// 16bit handler code called from call16() / call16_smm()
+u32 VISIBLE16
+call16_helper(u32 eax, u32 edx, u32 (*func)(u32 eax, u32 edx))
+{
+ u8 method = call32_post();
+ u32 ret = func(eax, edx);
+ call32_prep(method);
+ return ret;
}
#define ASM32_SWITCH16 " .pushsection .text.32fseg." UNIQSEC "\n .code16\n"
@@ -74,7 +143,7 @@ call32_smm(void *func, u32 eax)
{
ASSERT16();
dprintf(9, "call32_smm %p %x\n", func, eax);
- call32_smm_prep();
+ call32_prep(C16_SMM);
u32 bkup_esp;
asm volatile(
// Backup esp / set esp to flat stack location
@@ -109,24 +178,12 @@ call32_smm(void *func, u32 eax)
: "=&r" (bkup_esp), "+r" (eax)
: "r" (func)
: "eax", "ecx", "edx", "ebx", "cc", "memory");
- call32_smm_post();
+ call32_post();
dprintf(9, "call32_smm done %p %x\n", func, eax);
return eax;
}
-// 16bit handler code called from call16_smm()
-u32 VISIBLE16
-call16_smm_helper(u32 eax, u32 edx, u32 (*func)(u32 eax, u32 edx))
-{
- if (!CONFIG_CALL32_SMM)
- return eax;
- call32_smm_post();
- u32 ret = func(eax, edx);
- call32_smm_prep();
- return ret;
-}
-
static u32
call16_smm(u32 eax, u32 edx, void *func)
{
@@ -135,7 +192,7 @@ call16_smm(u32 eax, u32 edx, void *func)
return eax;
func -= BUILD_BIOS_ADDR;
dprintf(9, "call16_smm %p %x %x\n", func, eax, edx);
- u32 stackoffset = Call32Data.ss << 4;
+ u32 stackoffset = Call16Data.ss << 4;
asm volatile(
// Restore esp
" subl %0, %%esp\n"
@@ -151,7 +208,7 @@ call16_smm(u32 eax, u32 edx, void *func)
ASM32_SWITCH16
"1:movl %1, %%eax\n"
" movl %3, %%ecx\n"
- " calll _cfunc16_call16_smm_helper\n"
+ " calll _cfunc16_call16_helper\n"
" movl %%eax, %1\n"
" movl $" __stringify(CALL32SMM_CMDID) ", %%eax\n"
@@ -170,61 +227,18 @@ call16_smm(u32 eax, u32 edx, void *func)
return eax;
}
-// Backup state in preparation for call32_sloppy()
-static void
-call32_sloppy_prep(void)
-{
- // Backup cmos index register and disable nmi
- u8 cmosindex = inb(PORT_CMOS_INDEX);
- outb(cmosindex | NMI_DISABLE_BIT, PORT_CMOS_INDEX);
- inb(PORT_CMOS_DATA);
- SET_LOW(Call32Data.cmosindex, cmosindex);
-
- // Enable a20 and backup it's previous state
- SET_LOW(Call32Data.a20, set_a20(1));
-
- // Backup ss/fs/gs and gdt
- SET_LOW(Call32Data.ss, GET_SEG(SS));
- SET_LOW(Call32Data.fs, GET_SEG(FS));
- SET_LOW(Call32Data.gs, GET_SEG(GS));
- struct descloc_s gdt;
- sgdt(&gdt);
- SET_LOW(Call32Data.gdt.length, gdt.length);
- SET_LOW(Call32Data.gdt.addr, gdt.addr);
-
- SET_LOW(Call32Data.method, C32_SLOPPY);
-}
-
-// Restore state backed up during call32_sloppy()
-static void
-call32_sloppy_post(void)
-{
- SET_LOW(Call32Data.method, 0);
- SET_LOW(Call32Data.ss, 0);
-
- // Restore gdt and fs/gs
- struct descloc_s gdt;
- gdt.length = GET_LOW(Call32Data.gdt.length);
- gdt.addr = GET_LOW(Call32Data.gdt.addr);
- lgdt(&gdt);
- SET_SEG(FS, GET_LOW(Call32Data.fs));
- SET_SEG(GS, GET_LOW(Call32Data.gs));
-
- // Restore a20
- set_a20(GET_LOW(Call32Data.a20));
-
- // Restore cmos index register
- outb(GET_LOW(Call32Data.cmosindex), PORT_CMOS_INDEX);
- inb(PORT_CMOS_DATA);
-}
-
-// Call a C function in 32bit mode. This clobbers the 16bit segment
-// selector registers.
-static u32
-call32_sloppy(void *func, u32 eax)
+// Call a 32bit SeaBIOS function from a 16bit SeaBIOS function.
+u32 VISIBLE16
+__call32(void *func, u32 eax, u32 errret)
{
ASSERT16();
- call32_sloppy_prep();
+ if (CONFIG_CALL32_SMM && GET_GLOBAL(HaveSmmCall32))
+ return call32_smm(func, eax);
+ // Jump direclty to 32bit mode - this clobbers the 16bit segment
+ // selector registers.
+ int ret = call32_prep(C16_BIG);
+ if (ret)
+ return errret;
u32 bkup_ss, bkup_esp;
asm volatile(
// Backup ss/esp / set esp to flat stack location
@@ -236,7 +250,7 @@ call32_sloppy(void *func, u32 eax)
// Transition to 32bit mode, call func, return to 16bit
" movl $(" __stringify(BUILD_BIOS_ADDR) " + 1f), %%edx\n"
- " jmp transition32\n"
+ " jmp transition32_nmi_off\n"
ASM16_SWITCH32
"1:calll *%3\n"
" movl $2f, %%edx\n"
@@ -250,136 +264,52 @@ call32_sloppy(void *func, u32 eax)
: "=&r" (bkup_ss), "=&r" (bkup_esp), "+a" (eax)
: "r" (func)
: "ecx", "edx", "cc", "memory");
- call32_sloppy_post();
+ call32_post();
return eax;
}
-// 16bit handler code called from call16_sloppy()
-u32 VISIBLE16
-call16_sloppy_helper(u32 eax, u32 edx, u32 (*func)(u32 eax, u32 edx))
-{
- call32_sloppy_post();
- u32 ret = func(eax, edx);
- call32_sloppy_prep();
- return ret;
-}
-
-// Jump back to 16bit mode while in 32bit mode from call32_sloppy()
+// Call a 16bit SeaBIOS function, restoring the mode from last call32().
static u32
-call16_sloppy(u32 eax, u32 edx, void *func)
+call16(u32 eax, u32 edx, void *func)
{
ASSERT32FLAT();
if (getesp() > MAIN_STACK_MAX)
- panic("call16_sloppy with invalid stack\n");
+ panic("call16 with invalid stack\n");
+ if (CONFIG_CALL32_SMM && Call16Data.method == C16_SMM)
+ return call16_smm(eax, edx, func);
+
+ extern void transition16big(void);
+ extern void transition16(void);
+ void *thunk = transition16;
+ if (Call16Data.method == C16_BIG || in_post())
+ thunk = transition16big;
func -= BUILD_BIOS_ADDR;
- u32 stackseg = Call32Data.ss;
+ u32 stackseg = Call16Data.ss;
asm volatile(
// Transition to 16bit mode
" movl $(1f - " __stringify(BUILD_BIOS_ADDR) "), %%edx\n"
- " jmp transition16big\n"
+ " jmp *%%ecx\n"
// Setup ss/esp and call func
ASM32_SWITCH16
- "1:movl %3, %%ecx\n"
- " shll $4, %3\n"
+ "1:movl %2, %%ecx\n"
+ " shll $4, %2\n"
" movw %%cx, %%ss\n"
- " subl %3, %%esp\n"
+ " subl %2, %%esp\n"
" movw %%cx, %%ds\n"
- " movl %2, %%edx\n"
- " movl %1, %%ecx\n"
- " calll _cfunc16_call16_sloppy_helper\n"
+ " movl %4, %%edx\n"
+ " movl %3, %%ecx\n"
+ " calll _cfunc16_call16_helper\n"
// Return to 32bit and restore esp
" movl $2f, %%edx\n"
- " jmp transition32\n"
- ASM32_BACK32
- "2:addl %3, %%esp\n"
- : "+a" (eax)
- : "r" (func), "r" (edx), "r" (stackseg)
- : "edx", "ecx", "cc", "memory");
- return eax;
-}
-
-// Call a 32bit SeaBIOS function from a 16bit SeaBIOS function.
-u32 VISIBLE16
-call32(void *func, u32 eax, u32 errret)
-{
- ASSERT16();
- if (CONFIG_CALL32_SMM && GET_GLOBAL(HaveSmmCall32))
- return call32_smm(func, eax);
- u32 cr0 = getcr0();
- if (cr0 & CR0_PE)
- // Called in 16bit protected mode?!
- return errret;
- return call32_sloppy(func, eax);
-}
-
-// Call a 16bit SeaBIOS function from a 32bit SeaBIOS function.
-static u32
-call16(u32 eax, u32 edx, void *func)
-{
- ASSERT32FLAT();
- if (getesp() > BUILD_STACK_ADDR)
- panic("call16 with invalid stack\n");
- func -= BUILD_BIOS_ADDR;
- asm volatile(
- // Transition to 16bit mode
- " movl $(1f - " __stringify(BUILD_BIOS_ADDR) "), %%edx\n"
- " jmp transition16\n"
- // Call func
- ASM32_SWITCH16
- "1:movl %2, %%edx\n"
- " calll *%1\n"
- // Return to 32bit
- " movl $2f, %%edx\n"
- " jmp transition32\n"
- ASM32_BACK32
- "2:\n"
- : "+a" (eax)
- : "r" (func), "r" (edx)
- : "edx", "ecx", "cc", "memory");
- return eax;
-}
-
-// Call a 16bit SeaBIOS function in "big real" mode.
-static u32
-call16big(u32 eax, u32 edx, void *func)
-{
- ASSERT32FLAT();
- if (getesp() > BUILD_STACK_ADDR)
- panic("call16big with invalid stack\n");
- func -= BUILD_BIOS_ADDR;
- asm volatile(
- // Transition to 16bit mode
- " movl $(1f - " __stringify(BUILD_BIOS_ADDR) "), %%edx\n"
- " jmp transition16big\n"
- // Call func
- ASM32_SWITCH16
- "1:movl %2, %%edx\n"
- " calll *%1\n"
- // Return to 32bit
- " movl $2f, %%edx\n"
- " jmp transition32\n"
+ " jmp transition32_nmi_off\n"
ASM32_BACK32
- "2:\n"
- : "+a" (eax)
+ "2:addl %2, %%esp\n"
+ : "+a" (eax), "+c"(thunk), "+r"(stackseg)
: "r" (func), "r" (edx)
- : "edx", "ecx", "cc", "memory");
+ : "edx", "cc", "memory");
return eax;
}
-// Call a 16bit SeaBIOS function, restoring the mode from last call32().
-static u32
-call16_back(u32 eax, u32 edx, void *func)
-{
- ASSERT32FLAT();
- if (CONFIG_CALL32_SMM && Call32Data.method == C32_SMM)
- return call16_smm(eax, edx, func);
- if (Call32Data.method == C32_SLOPPY)
- return call16_sloppy(eax, edx, func);
- if (in_post())
- return call16big(eax, edx, func);
- return call16(eax, edx, func);
-}
-
/****************************************************************
* Extra 16bit stack
@@ -398,7 +328,7 @@ on_extra_stack(void)
// Switch to the extra stack and call a function.
u32
-stack_hop(u32 eax, u32 edx, void *func)
+__stack_hop(u32 eax, u32 edx, void *func)
{
if (on_extra_stack())
return ((u32 (*)(u32, u32))func)(eax, edx);
@@ -431,10 +361,10 @@ stack_hop(u32 eax, u32 edx, void *func)
// Switch back to original caller's stack and call a function.
u32
-stack_hop_back(u32 eax, u32 edx, void *func)
+__stack_hop_back(u32 eax, u32 edx, void *func)
{
if (!MODESEGMENT)
- return call16_back(eax, edx, func);
+ return call16(eax, edx, func);
if (!MODE16 || !on_extra_stack())
return ((u32 (*)(u32, u32))func)(eax, edx);
ASSERT16();
@@ -474,8 +404,7 @@ void VISIBLE16
_farcall16(struct bregs *callregs, u16 callregseg)
{
if (need_hop_back()) {
- extern void _cfunc16__farcall16(void);
- stack_hop_back((u32)callregs, callregseg, _cfunc16__farcall16);
+ stack_hop_back(_farcall16, callregs, callregseg);
return;
}
ASSERT16();
@@ -486,18 +415,20 @@ _farcall16(struct bregs *callregs, u16 callregseg)
: "ebx", "ecx", "esi", "edi", "cc", "memory");
}
+// Invoke external 16bit code.
void
farcall16(struct bregs *callregs)
{
- extern void _cfunc16__farcall16(void);
- call16((u32)callregs, 0, _cfunc16__farcall16);
+ call16_override(0);
+ _farcall16(callregs, 0);
}
+// Invoke external 16bit code in "big real" mode.
void
farcall16big(struct bregs *callregs)
{
- extern void _cfunc16__farcall16(void);
- call16big((u32)callregs, 0, _cfunc16__farcall16);
+ call16_override(1);
+ _farcall16(callregs, 0);
}
// Invoke a 16bit software interrupt.
@@ -507,7 +438,7 @@ __call16_int(struct bregs *callregs, u16 offset)
callregs->code.offset = offset;
if (!MODESEGMENT) {
callregs->code.seg = SEG_BIOS;
- _farcall16((void*)callregs - Call32Data.ss * 16, Call32Data.ss);
+ _farcall16((void*)callregs - Call16Data.ss * 16, Call16Data.ss);
return;
}
callregs->code.seg = GET_SEG(CS);
@@ -520,7 +451,7 @@ reset(void)
{
extern void reset_vector(void) __noreturn;
if (!MODE16)
- call16_back(0, 0, reset_vector);
+ call16(0, 0, reset_vector);
reset_vector();
}
@@ -558,12 +489,13 @@ getCurThread(void)
return (void*)ALIGN_DOWN(esp, THREADSTACKSIZE);
}
-static int ThreadControl;
+static u8 CanInterrupt, ThreadControl;
// Initialize the support for internal threads.
void
-thread_init(void)
+thread_setup(void)
{
+ CanInterrupt = 1;
if (! CONFIG_THREADS)
return;
ThreadControl = romfile_loadint("etc/threads", 1);
@@ -573,7 +505,7 @@ thread_init(void)
int
threads_during_optionroms(void)
{
- return CONFIG_THREADS && ThreadControl == 2 && in_post();
+ return CONFIG_THREADS && CONFIG_RTC_TIMER && ThreadControl == 2 && in_post();
}
// Switch to next thread stack.
@@ -660,11 +592,17 @@ fail:
void VISIBLE16
check_irqs(void)
{
+ if (!MODESEGMENT && !CanInterrupt) {
+ // Can't enable interrupts (PIC and/or IVT not yet setup)
+ cpu_relax();
+ return;
+ }
if (need_hop_back()) {
- extern void _cfunc16_check_irqs(void);
- stack_hop_back(0, 0, _cfunc16_check_irqs);
+ stack_hop_back(check_irqs, 0, 0);
return;
}
+ if (MODE16)
+ clock_poll_irq();
asm volatile("sti ; nop ; rep ; nop ; cli ; cld" : : :"memory");
}
@@ -689,8 +627,7 @@ void VISIBLE16
wait_irq(void)
{
if (need_hop_back()) {
- extern void _cfunc16_wait_irq(void);
- stack_hop_back(0, 0, _cfunc16_wait_irq);
+ stack_hop_back(wait_irq, 0, 0);
return;
}
asm volatile("sti ; hlt ; cli ; cld": : :"memory");
@@ -700,8 +637,9 @@ wait_irq(void)
void
yield_toirq(void)
{
- if (!MODESEGMENT && have_threads()) {
- // Threads still active - do a yield instead.
+ if (!CONFIG_HARDWARE_IRQ
+ || (!MODESEGMENT && (have_threads() || !CanInterrupt))) {
+ // Threads still active or irqs not available - do a yield instead.
yield();
return;
}
@@ -794,9 +732,8 @@ yield_preempt(void)
void
check_preempt(void)
{
- extern void _cfunc32flat_yield_preempt(void);
if (CONFIG_THREADS && GET_GLOBAL(CanPreempt) && have_threads())
- call32(_cfunc32flat_yield_preempt, 0, 0);
+ call32(yield_preempt, 0, 0);
}
@@ -817,11 +754,10 @@ call32_params_helper(struct call32_params_s *params)
}
u32
-call32_params(void *func, u32 eax, u32 edx, u32 ecx, u32 errret)
+__call32_params(void *func, u32 eax, u32 edx, u32 ecx, u32 errret)
{
ASSERT16();
struct call32_params_s params = {func, eax, edx, ecx};
- extern void _cfunc32flat_call32_params_helper(void);
- return call32(_cfunc32flat_call32_params_helper
- , (u32)MAKE_FLATPTR(GET_SEG(SS), &params), errret);
+ return call32(call32_params_helper, MAKE_FLATPTR(GET_SEG(SS), &params)
+ , errret);
}
diff --git a/qemu/roms/seabios/src/stacks.h b/qemu/roms/seabios/src/stacks.h
index 82c4c3c85..c71bdc8e3 100644
--- a/qemu/roms/seabios/src/stacks.h
+++ b/qemu/roms/seabios/src/stacks.h
@@ -10,17 +10,27 @@
// stacks.c
extern int HaveSmmCall32;
-u32 call32(void *func, u32 eax, u32 errret);
+u32 __call32(void *func, u32 eax, u32 errret);
+#define call32(func, eax, errret) ({ \
+ extern void _cfunc32flat_ ##func (void); \
+ __call32( _cfunc32flat_ ##func , (u32)(eax), (errret)); \
+ })
extern u8 ExtraStack[], *StackPos;
-u32 stack_hop(u32 eax, u32 edx, void *func);
-u32 stack_hop_back(u32 eax, u32 edx, void *func);
+u32 __stack_hop(u32 eax, u32 edx, void *func);
+#define stack_hop(func, eax, edx) \
+ __stack_hop((u32)(eax), (u32)(edx), (func))
+u32 __stack_hop_back(u32 eax, u32 edx, void *func);
+#define stack_hop_back(func, eax, edx) ({ \
+ extern void _cfunc16_ ##func (void); \
+ __stack_hop_back((u32)(eax), (u32)(edx), _cfunc16_ ##func ); \
+ })
int on_extra_stack(void);
struct bregs;
void farcall16(struct bregs *callregs);
void farcall16big(struct bregs *callregs);
void __call16_int(struct bregs *callregs, u16 offset);
#define call16_int(nr, callregs) do { \
- extern void irq_trampoline_ ##nr (); \
+ extern void irq_trampoline_ ##nr (void); \
__call16_int((callregs), (u32)&irq_trampoline_ ##nr ); \
} while (0)
void reset(void);
@@ -28,7 +38,7 @@ extern struct thread_info MainThread;
struct thread_info *getCurThread(void);
void yield(void);
void yield_toirq(void);
-void thread_init(void);
+void thread_setup(void);
int threads_during_optionroms(void);
void run_thread(void (*func)(void*), void *data);
void wait_threads(void);
@@ -39,7 +49,12 @@ void start_preempt(void);
void finish_preempt(void);
int wait_preempt(void);
void check_preempt(void);
-u32 call32_params(void *func, u32 eax, u32 edx, u32 ecx, u32 errret);
+u32 __call32_params(void *func, u32 eax, u32 edx, u32 ecx, u32 errret);
+#define call32_params(func, eax, edx, ecx, errret) ({ \
+ extern void _cfunc32flat_ ##func (void); \
+ __call32_params( _cfunc32flat_ ##func , (u32)(eax), (u32)(edx) \
+ , (u32)(ecx), (errret)); \
+ })
// Inline functions
diff --git a/qemu/roms/seabios/src/std/acpi.h b/qemu/roms/seabios/src/std/acpi.h
index e0d9516ba..b672bbee4 100644
--- a/qemu/roms/seabios/src/std/acpi.h
+++ b/qemu/roms/seabios/src/std/acpi.h
@@ -294,4 +294,24 @@ struct acpi_table_mcfg {
struct acpi_mcfg_allocation allocation[0];
} PACKED;
+
+struct rsdt_descriptor {
+ ACPI_TABLE_HEADER_DEF
+ u32 entry[1];
+} PACKED;
+
+#define TCPA_SIGNATURE 0x41504354
+struct tcpa_descriptor_rev2
+{
+ ACPI_TABLE_HEADER_DEF
+ u16 platform_class;
+ u32 log_area_minimum_length;
+ u64 log_area_start_address;
+} PACKED;
+
+/* TCPA ACPI definitions */
+#define TCPA_ACPI_CLASS_CLIENT 0
+#define TCPA_ACPI_CLASS_SERVER 1
+
+
#endif // acpi.h
diff --git a/qemu/roms/seabios/src/std/bda.h b/qemu/roms/seabios/src/std/bda.h
index c321266e2..4ad6605d4 100644
--- a/qemu/roms/seabios/src/std/bda.h
+++ b/qemu/roms/seabios/src/std/bda.h
@@ -7,7 +7,7 @@
/****************************************************************
- * Interupt vector table
+ * Interrupt vector table
****************************************************************/
struct rmode_IVT {
diff --git a/qemu/roms/seabios/src/std/multiboot.h b/qemu/roms/seabios/src/std/multiboot.h
new file mode 100644
index 000000000..6c9512703
--- /dev/null
+++ b/qemu/roms/seabios/src/std/multiboot.h
@@ -0,0 +1,260 @@
+/* multiboot.h - Multiboot header file. */
+/* Copyright (C) 1999,2003,2007,2008,2009,2010 Free Software Foundation, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY
+ * DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+ * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef MULTIBOOT_HEADER
+#define MULTIBOOT_HEADER 1
+
+/* How many bytes from the start of the file we search for the header. */
+#define MULTIBOOT_SEARCH 8192
+#define MULTIBOOT_HEADER_ALIGN 4
+
+/* The magic field should contain this. */
+#define MULTIBOOT_HEADER_MAGIC 0x1BADB002
+
+/* This should be in %eax. */
+#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002
+
+/* Alignment of multiboot modules. */
+#define MULTIBOOT_MOD_ALIGN 0x00001000
+
+/* Alignment of the multiboot info structure. */
+#define MULTIBOOT_INFO_ALIGN 0x00000004
+
+/* Flags set in the 'flags' member of the multiboot header. */
+
+/* Align all boot modules on i386 page (4KB) boundaries. */
+#define MULTIBOOT_PAGE_ALIGN 0x00000001
+
+/* Must pass memory information to OS. */
+#define MULTIBOOT_MEMORY_INFO 0x00000002
+
+/* Must pass video information to OS. */
+#define MULTIBOOT_VIDEO_MODE 0x00000004
+
+/* This flag indicates the use of the address fields in the header. */
+#define MULTIBOOT_AOUT_KLUDGE 0x00010000
+
+/* Flags to be set in the 'flags' member of the multiboot info structure. */
+
+/* is there basic lower/upper memory information? */
+#define MULTIBOOT_INFO_MEMORY 0x00000001
+/* is there a boot device set? */
+#define MULTIBOOT_INFO_BOOTDEV 0x00000002
+/* is the command-line defined? */
+#define MULTIBOOT_INFO_CMDLINE 0x00000004
+/* are there modules to do something with? */
+#define MULTIBOOT_INFO_MODS 0x00000008
+
+/* These next two are mutually exclusive */
+
+/* is there a symbol table loaded? */
+#define MULTIBOOT_INFO_AOUT_SYMS 0x00000010
+/* is there an ELF section header table? */
+#define MULTIBOOT_INFO_ELF_SHDR 0X00000020
+
+/* is there a full memory map? */
+#define MULTIBOOT_INFO_MEM_MAP 0x00000040
+
+/* Is there drive info? */
+#define MULTIBOOT_INFO_DRIVE_INFO 0x00000080
+
+/* Is there a config table? */
+#define MULTIBOOT_INFO_CONFIG_TABLE 0x00000100
+
+/* Is there a boot loader name? */
+#define MULTIBOOT_INFO_BOOT_LOADER_NAME 0x00000200
+
+/* Is there a APM table? */
+#define MULTIBOOT_INFO_APM_TABLE 0x00000400
+
+/* Is there video information? */
+#define MULTIBOOT_INFO_VBE_INFO 0x00000800
+#define MULTIBOOT_INFO_FRAMEBUFFER_INFO 0x00001000
+
+#ifndef ASM_FILE
+
+typedef unsigned char multiboot_uint8_t;
+typedef unsigned short multiboot_uint16_t;
+typedef unsigned int multiboot_uint32_t;
+typedef unsigned long long multiboot_uint64_t;
+
+struct multiboot_header
+{
+ /* Must be MULTIBOOT_MAGIC - see above. */
+ multiboot_uint32_t magic;
+
+ /* Feature flags. */
+ multiboot_uint32_t flags;
+
+ /* The above fields plus this one must equal 0 mod 2^32. */
+ multiboot_uint32_t checksum;
+
+ /* These are only valid if MULTIBOOT_AOUT_KLUDGE is set. */
+ multiboot_uint32_t header_addr;
+ multiboot_uint32_t load_addr;
+ multiboot_uint32_t load_end_addr;
+ multiboot_uint32_t bss_end_addr;
+ multiboot_uint32_t entry_addr;
+
+ /* These are only valid if MULTIBOOT_VIDEO_MODE is set. */
+ multiboot_uint32_t mode_type;
+ multiboot_uint32_t width;
+ multiboot_uint32_t height;
+ multiboot_uint32_t depth;
+};
+
+/* The symbol table for a.out. */
+struct multiboot_aout_symbol_table
+{
+ multiboot_uint32_t tabsize;
+ multiboot_uint32_t strsize;
+ multiboot_uint32_t addr;
+ multiboot_uint32_t reserved;
+};
+typedef struct multiboot_aout_symbol_table multiboot_aout_symbol_table_t;
+
+/* The section header table for ELF. */
+struct multiboot_elf_section_header_table
+{
+ multiboot_uint32_t num;
+ multiboot_uint32_t size;
+ multiboot_uint32_t addr;
+ multiboot_uint32_t shndx;
+};
+typedef struct multiboot_elf_section_header_table multiboot_elf_section_header_table_t;
+
+struct multiboot_info
+{
+ /* Multiboot info version number */
+ multiboot_uint32_t flags;
+
+ /* Available memory from BIOS */
+ multiboot_uint32_t mem_lower;
+ multiboot_uint32_t mem_upper;
+
+ /* "root" partition */
+ multiboot_uint32_t boot_device;
+
+ /* Kernel command line */
+ multiboot_uint32_t cmdline;
+
+ /* Boot-Module list */
+ multiboot_uint32_t mods_count;
+ multiboot_uint32_t mods_addr;
+
+ union
+ {
+ multiboot_aout_symbol_table_t aout_sym;
+ multiboot_elf_section_header_table_t elf_sec;
+ } u;
+
+ /* Memory Mapping buffer */
+ multiboot_uint32_t mmap_length;
+ multiboot_uint32_t mmap_addr;
+
+ /* Drive Info buffer */
+ multiboot_uint32_t drives_length;
+ multiboot_uint32_t drives_addr;
+
+ /* ROM configuration table */
+ multiboot_uint32_t config_table;
+
+ /* Boot Loader Name */
+ multiboot_uint32_t boot_loader_name;
+
+ /* APM table */
+ multiboot_uint32_t apm_table;
+
+ /* Video */
+ multiboot_uint32_t vbe_control_info;
+ multiboot_uint32_t vbe_mode_info;
+ multiboot_uint16_t vbe_mode;
+ multiboot_uint16_t vbe_interface_seg;
+ multiboot_uint16_t vbe_interface_off;
+ multiboot_uint16_t vbe_interface_len;
+
+ multiboot_uint64_t framebuffer_addr;
+ multiboot_uint32_t framebuffer_pitch;
+ multiboot_uint32_t framebuffer_width;
+ multiboot_uint32_t framebuffer_height;
+ multiboot_uint8_t framebuffer_bpp;
+#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0
+#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1
+#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2
+ multiboot_uint8_t framebuffer_type;
+ union
+ {
+ struct
+ {
+ multiboot_uint32_t framebuffer_palette_addr;
+ multiboot_uint16_t framebuffer_palette_num_colors;
+ };
+ struct
+ {
+ multiboot_uint8_t framebuffer_red_field_position;
+ multiboot_uint8_t framebuffer_red_mask_size;
+ multiboot_uint8_t framebuffer_green_field_position;
+ multiboot_uint8_t framebuffer_green_mask_size;
+ multiboot_uint8_t framebuffer_blue_field_position;
+ multiboot_uint8_t framebuffer_blue_mask_size;
+ };
+ };
+};
+typedef struct multiboot_info multiboot_info_t;
+
+struct multiboot_color
+{
+ multiboot_uint8_t red;
+ multiboot_uint8_t green;
+ multiboot_uint8_t blue;
+};
+
+struct multiboot_mmap_entry
+{
+ multiboot_uint32_t size;
+ multiboot_uint64_t addr;
+ multiboot_uint64_t len;
+#define MULTIBOOT_MEMORY_AVAILABLE 1
+#define MULTIBOOT_MEMORY_RESERVED 2
+#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3
+#define MULTIBOOT_MEMORY_NVS 4
+#define MULTIBOOT_MEMORY_BADRAM 5
+ multiboot_uint32_t type;
+} __attribute__((packed));
+typedef struct multiboot_mmap_entry multiboot_memory_map_t;
+
+struct multiboot_mod_list
+{
+ /* the memory used goes from bytes 'mod_start' to 'mod_end-1' inclusive */
+ multiboot_uint32_t mod_start;
+ multiboot_uint32_t mod_end;
+
+ /* Module command line */
+ multiboot_uint32_t cmdline;
+
+ /* padding to take it to 16 bytes (must be zero) */
+ multiboot_uint32_t pad;
+};
+typedef struct multiboot_mod_list multiboot_module_t;
+
+#endif /* ! ASM_FILE */
+
+#endif /* ! MULTIBOOT_HEADER */
diff --git a/qemu/roms/seabios/src/std/smbios.h b/qemu/roms/seabios/src/std/smbios.h
index 05137167a..4ccf2ea34 100644
--- a/qemu/roms/seabios/src/std/smbios.h
+++ b/qemu/roms/seabios/src/std/smbios.h
@@ -3,11 +3,13 @@
#include "types.h" // u32
+#define SMBIOS_SIGNATURE 0x5f4d535f // "_SM_"
+
/* SMBIOS entry point -- must be written to a 16-bit aligned address
between 0xf0000 and 0xfffff.
*/
struct smbios_entry_point {
- char anchor_string[4];
+ u32 signature;
u8 checksum;
u8 length;
u8 smbios_major_version;
diff --git a/qemu/roms/seabios/src/string.c b/qemu/roms/seabios/src/string.c
index 2e4e43746..adb8198f8 100644
--- a/qemu/roms/seabios/src/string.c
+++ b/qemu/roms/seabios/src/string.c
@@ -227,7 +227,7 @@ strtcpy(char *dest, const char *src, size_t len)
return dest;
}
-// locate first occurance of character c in the string s
+// locate first occurrence of character c in the string s
char *
strchr(const char *s, int c)
{
diff --git a/qemu/roms/seabios/src/string.h b/qemu/roms/seabios/src/string.h
index a557d6a44..d069989db 100644
--- a/qemu/roms/seabios/src/string.h
+++ b/qemu/roms/seabios/src/string.h
@@ -11,12 +11,12 @@ size_t strlen(const char *s);
int memcmp_far(u16 s1seg, const void *s1, u16 s2seg, const void *s2, size_t n);
int memcmp(const void *s1, const void *s2, size_t n);
int strcmp(const char *s1, const char *s2);
-inline void memset_far(u16 d_seg, void *d_far, u8 c, size_t len);
-inline void memset16_far(u16 d_seg, void *d_far, u16 c, size_t len);
+void memset_far(u16 d_seg, void *d_far, u8 c, size_t len);
+void memset16_far(u16 d_seg, void *d_far, u16 c, size_t len);
void *memset(void *s, int c, size_t n);
void memset_fl(void *ptr, u8 val, size_t size);
-inline void memcpy_far(u16 d_seg, void *d_far
- , u16 s_seg, const void *s_far, size_t len);
+void memcpy_far(u16 d_seg, void *d_far
+ , u16 s_seg, const void *s_far, size_t len);
void memcpy_fl(void *d_fl, const void *s_fl, size_t len);
void *memcpy(void *d1, const void *s1, size_t len);
#if MODESEGMENT == 0
diff --git a/qemu/roms/seabios/src/system.c b/qemu/roms/seabios/src/system.c
index 60a6fce58..438e60e2c 100644
--- a/qemu/roms/seabios/src/system.c
+++ b/qemu/roms/seabios/src/system.c
@@ -7,9 +7,9 @@
#include "biosvar.h" // GET_GLOBAL
#include "bregs.h" // struct bregs
+#include "e820map.h" // E820_RAM
#include "hw/pic.h" // pic_reset
#include "malloc.h" // LegacyRamSize
-#include "memmap.h" // E820_RAM
#include "output.h" // debug_enter
#include "string.h" // memcpy_far
#include "util.h" // handle_1553
diff --git a/qemu/roms/seabios/src/tcgbios.c b/qemu/roms/seabios/src/tcgbios.c
new file mode 100644
index 000000000..09954825c
--- /dev/null
+++ b/qemu/roms/seabios/src/tcgbios.c
@@ -0,0 +1,1480 @@
+// Implementation of the TCG BIOS extension according to the specification
+// described in specs found at
+// http://www.trustedcomputinggroup.org/resources/pc_client_work_group_specific_implementation_specification_for_conventional_bios
+//
+// Copyright (C) 2006-2011, 2014, 2015 IBM Corporation
+//
+// Authors:
+// Stefan Berger <stefanb@linux.vnet.ibm.com>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+
+#include "config.h"
+
+#include "types.h"
+#include "byteorder.h" // cpu_to_*
+#include "hw/tpm_drivers.h" // tpm_drivers[]
+#include "farptr.h" // MAKE_FLATPTR
+#include "string.h" // checksum
+#include "tcgbios.h"// tpm_*, prototypes
+#include "util.h" // printf, get_keystroke
+#include "output.h" // dprintf
+#include "std/acpi.h" // RSDP_SIGNATURE, rsdt_descriptor
+#include "bregs.h" // struct bregs
+#include "sha1.h" // sha1
+#include "fw/paravirt.h" // runningOnXen
+#include "std/smbios.h"
+
+static const u8 Startup_ST_CLEAR[] = { 0x00, TPM_ST_CLEAR };
+static const u8 Startup_ST_STATE[] = { 0x00, TPM_ST_STATE };
+
+static const u8 PhysicalPresence_CMD_ENABLE[] = { 0x00, 0x20 };
+static const u8 PhysicalPresence_CMD_DISABLE[] = { 0x01, 0x00 };
+static const u8 PhysicalPresence_PRESENT[] = { 0x00, 0x08 };
+static const u8 PhysicalPresence_NOT_PRESENT_LOCK[] = { 0x00, 0x14 };
+
+static const u8 CommandFlag_FALSE[1] = { 0x00 };
+static const u8 CommandFlag_TRUE[1] = { 0x01 };
+
+static const u8 GetCapability_Permanent_Flags[] = {
+ 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04,
+ 0x00, 0x00, 0x01, 0x08
+};
+
+static const u8 GetCapability_OwnerAuth[] = {
+ 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04,
+ 0x00, 0x00, 0x01, 0x11
+};
+
+static const u8 GetCapability_Timeouts[] = {
+ 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04,
+ 0x00, 0x00, 0x01, 0x15
+};
+
+static const u8 GetCapability_Durations[] = {
+ 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04,
+ 0x00, 0x00, 0x01, 0x20
+};
+
+static u8 evt_separator[] = {0xff,0xff,0xff,0xff};
+
+
+#define RSDP_CAST(ptr) ((struct rsdp_descriptor *)ptr)
+
+/* local function prototypes */
+
+static u32 tpm_calling_int19h(void);
+static u32 tpm_add_event_separators(void);
+static u32 tpm_start_option_rom_scan(void);
+static u32 tpm_smbios_measure(void);
+
+/* helper functions */
+
+static inline void *input_buf32(struct bregs *regs)
+{
+ return MAKE_FLATPTR(regs->es, regs->di);
+}
+
+static inline void *output_buf32(struct bregs *regs)
+{
+ return MAKE_FLATPTR(regs->ds, regs->si);
+}
+
+
+typedef struct {
+ u8 tpm_probed:1;
+ u8 tpm_found:1;
+ u8 tpm_working:1;
+ u8 if_shutdown:1;
+ u8 tpm_driver_to_use:4;
+} tpm_state_t;
+
+
+static tpm_state_t tpm_state = {
+ .tpm_driver_to_use = TPM_INVALID_DRIVER,
+};
+
+
+/********************************************************
+ Extensions for TCG-enabled BIOS
+ *******************************************************/
+
+
+static u32
+is_tpm_present(void)
+{
+ u32 rc = 0;
+ unsigned int i;
+
+ for (i = 0; i < TPM_NUM_DRIVERS; i++) {
+ struct tpm_driver *td = &tpm_drivers[i];
+ if (td->probe() != 0) {
+ td->init();
+ tpm_state.tpm_driver_to_use = i;
+ rc = 1;
+ break;
+ }
+ }
+
+ return rc;
+}
+
+static void
+probe_tpm(void)
+{
+ if (!tpm_state.tpm_probed) {
+ tpm_state.tpm_probed = 1;
+ tpm_state.tpm_found = (is_tpm_present() != 0);
+ tpm_state.tpm_working = tpm_state.tpm_found;
+ }
+}
+
+static int
+has_working_tpm(void)
+{
+ probe_tpm();
+
+ return tpm_state.tpm_working;
+}
+
+static struct tcpa_descriptor_rev2 *
+find_tcpa_by_rsdp(struct rsdp_descriptor *rsdp)
+{
+ u32 ctr = 0;
+ struct tcpa_descriptor_rev2 *tcpa = NULL;
+ struct rsdt_descriptor *rsdt;
+ u32 length;
+ u16 off;
+
+ rsdt = (struct rsdt_descriptor *)rsdp->rsdt_physical_address;
+ if (!rsdt)
+ return NULL;
+
+ length = rsdt->length;
+ off = offsetof(struct rsdt_descriptor, entry);
+
+ while ((off + sizeof(rsdt->entry[0])) <= length) {
+ /* try all pointers to structures */
+ tcpa = (struct tcpa_descriptor_rev2 *)(int)rsdt->entry[ctr];
+
+ /* valid TCPA ACPI table ? */
+ if (tcpa->signature == TCPA_SIGNATURE &&
+ checksum((u8 *)tcpa, tcpa->length) == 0)
+ break;
+
+ tcpa = NULL;
+ off += sizeof(rsdt->entry[0]);
+ ctr++;
+ }
+
+ return tcpa;
+}
+
+
+static struct tcpa_descriptor_rev2 *
+find_tcpa_table(void)
+{
+ struct tcpa_descriptor_rev2 *tcpa = NULL;
+ struct rsdp_descriptor *rsdp = RsdpAddr;
+
+ if (rsdp)
+ tcpa = find_tcpa_by_rsdp(rsdp);
+ else
+ tpm_state.if_shutdown = 1;
+
+ if (!rsdp)
+ dprintf(DEBUG_tcg,
+ "TCGBIOS: RSDP was NOT found! -- Disabling interface.\n");
+ else if (!tcpa)
+ dprintf(DEBUG_tcg, "TCGBIOS: TCPA ACPI was NOT found!\n");
+
+ return tcpa;
+}
+
+
+static u8 *
+get_lasa_base_ptr(u32 *log_area_minimum_length)
+{
+ u8 *log_area_start_address = 0;
+ struct tcpa_descriptor_rev2 *tcpa = find_tcpa_table();
+
+ if (tcpa) {
+ log_area_start_address = (u8 *)(long)tcpa->log_area_start_address;
+ if (log_area_minimum_length)
+ *log_area_minimum_length = tcpa->log_area_minimum_length;
+ }
+
+ return log_area_start_address;
+}
+
+
+/* clear the ACPI log */
+static void
+reset_acpi_log(void)
+{
+ u32 log_area_minimum_length;
+ u8 *log_area_start_address = get_lasa_base_ptr(&log_area_minimum_length);
+
+ if (log_area_start_address)
+ memset(log_area_start_address, 0x0, log_area_minimum_length);
+}
+
+
+/*
+ initialize the TCPA ACPI subsystem; find the ACPI tables and determine
+ where the TCPA table is.
+ */
+static void
+tpm_acpi_init(void)
+{
+ tpm_state.if_shutdown = 0;
+ tpm_state.tpm_probed = 0;
+ tpm_state.tpm_found = 0;
+ tpm_state.tpm_working = 0;
+
+ if (!has_working_tpm()) {
+ tpm_state.if_shutdown = 1;
+ return;
+ }
+
+ reset_acpi_log();
+}
+
+
+static u32
+transmit(u8 locty, const struct iovec iovec[],
+ u8 *respbuffer, u32 *respbufferlen,
+ enum tpmDurationType to_t)
+{
+ u32 rc = 0;
+ u32 irc;
+ struct tpm_driver *td;
+ unsigned int i;
+
+ if (tpm_state.tpm_driver_to_use == TPM_INVALID_DRIVER)
+ return TCG_FATAL_COM_ERROR;
+
+ td = &tpm_drivers[tpm_state.tpm_driver_to_use];
+
+ irc = td->activate(locty);
+ if (irc != 0) {
+ /* tpm could not be activated */
+ return TCG_FATAL_COM_ERROR;
+ }
+
+ for (i = 0; iovec[i].length; i++) {
+ irc = td->senddata(iovec[i].data,
+ iovec[i].length);
+ if (irc != 0)
+ return TCG_FATAL_COM_ERROR;
+ }
+
+ irc = td->waitdatavalid();
+ if (irc != 0)
+ return TCG_FATAL_COM_ERROR;
+
+ irc = td->waitrespready(to_t);
+ if (irc != 0)
+ return TCG_FATAL_COM_ERROR;
+
+ irc = td->readresp(respbuffer,
+ respbufferlen);
+ if (irc != 0)
+ return TCG_FATAL_COM_ERROR;
+
+ td->ready();
+
+ return rc;
+}
+
+
+/*
+ * Send a TPM command with the given ordinal. Append the given buffer
+ * containing all data in network byte order to the command (this is
+ * the custom part per command) and expect a response of the given size.
+ * If a buffer is provided, the response will be copied into it.
+ */
+static u32
+build_and_send_cmd_od(u8 locty, u32 ordinal, const u8 *append, u32 append_size,
+ u8 *resbuffer, u32 return_size, u32 *returnCode,
+ const u8 *otherdata, u32 otherdata_size,
+ enum tpmDurationType to_t)
+{
+#define MAX_APPEND_SIZE sizeof(GetCapability_Timeouts)
+#define MAX_RESPONSE_SIZE sizeof(struct tpm_res_getcap_perm_flags)
+ u32 rc;
+ u8 ibuffer[TPM_REQ_HEADER_SIZE + MAX_APPEND_SIZE];
+ u8 obuffer[MAX_RESPONSE_SIZE];
+ struct tpm_req_header *trqh = (struct tpm_req_header *)ibuffer;
+ struct tpm_rsp_header *trsh = (struct tpm_rsp_header *)obuffer;
+ struct iovec iovec[3];
+ u32 obuffer_len = sizeof(obuffer);
+ u32 idx = 1;
+
+ if (append_size > MAX_APPEND_SIZE ||
+ return_size > MAX_RESPONSE_SIZE) {
+ dprintf(DEBUG_tcg, "TCGBIOS: size of requested buffers too big.");
+ return TCG_FIRMWARE_ERROR;
+ }
+
+ iovec[0].data = trqh;
+ iovec[0].length = TPM_REQ_HEADER_SIZE + append_size;
+
+ if (otherdata) {
+ iovec[1].data = (void *)otherdata;
+ iovec[1].length = otherdata_size;
+ idx = 2;
+ }
+
+ iovec[idx].data = NULL;
+ iovec[idx].length = 0;
+
+ memset(ibuffer, 0x0, sizeof(ibuffer));
+ memset(obuffer, 0x0, sizeof(obuffer));
+
+ trqh->tag = cpu_to_be16(TPM_TAG_RQU_CMD);
+ trqh->totlen = cpu_to_be32(TPM_REQ_HEADER_SIZE + append_size +
+ otherdata_size);
+ trqh->ordinal = cpu_to_be32(ordinal);
+
+ if (append_size)
+ memcpy((char *)trqh + sizeof(*trqh),
+ append, append_size);
+
+ rc = transmit(locty, iovec, obuffer, &obuffer_len, to_t);
+ if (rc)
+ return rc;
+
+ *returnCode = be32_to_cpu(trsh->errcode);
+
+ if (resbuffer)
+ memcpy(resbuffer, trsh, return_size);
+
+ return 0;
+}
+
+
+static u32
+build_and_send_cmd(u8 locty, u32 ordinal, const u8 *append, u32 append_size,
+ u8 *resbuffer, u32 return_size, u32 *returnCode,
+ enum tpmDurationType to_t)
+{
+ return build_and_send_cmd_od(locty, ordinal, append, append_size,
+ resbuffer, return_size, returnCode,
+ NULL, 0, to_t);
+}
+
+
+static u32
+determine_timeouts(void)
+{
+ u32 rc;
+ u32 returnCode;
+ struct tpm_res_getcap_timeouts timeouts;
+ struct tpm_res_getcap_durations durations;
+ struct tpm_driver *td = &tpm_drivers[tpm_state.tpm_driver_to_use];
+ u32 i;
+
+ rc = build_and_send_cmd(0, TPM_ORD_GetCapability,
+ GetCapability_Timeouts,
+ sizeof(GetCapability_Timeouts),
+ (u8 *)&timeouts, sizeof(timeouts),
+ &returnCode, TPM_DURATION_TYPE_SHORT);
+
+ dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(Timeouts)"
+ " = 0x%08x\n", returnCode);
+
+ if (rc || returnCode)
+ goto err_exit;
+
+ rc = build_and_send_cmd(0, TPM_ORD_GetCapability,
+ GetCapability_Durations,
+ sizeof(GetCapability_Durations),
+ (u8 *)&durations, sizeof(durations),
+ &returnCode, TPM_DURATION_TYPE_SHORT);
+
+ dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(Durations)"
+ " = 0x%08x\n", returnCode);
+
+ if (rc || returnCode)
+ goto err_exit;
+
+ for (i = 0; i < 3; i++)
+ durations.durations[i] = be32_to_cpu(durations.durations[i]);
+
+ for (i = 0; i < 4; i++)
+ timeouts.timeouts[i] = be32_to_cpu(timeouts.timeouts[i]);
+
+ dprintf(DEBUG_tcg, "TCGBIOS: timeouts: %u %u %u %u\n",
+ timeouts.timeouts[0],
+ timeouts.timeouts[1],
+ timeouts.timeouts[2],
+ timeouts.timeouts[3]);
+
+ dprintf(DEBUG_tcg, "TCGBIOS: durations: %u %u %u\n",
+ durations.durations[0],
+ durations.durations[1],
+ durations.durations[2]);
+
+
+ td->set_timeouts(timeouts.timeouts, durations.durations);
+
+ return 0;
+
+err_exit:
+ dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
+
+ tpm_state.tpm_working = 0;
+ if (rc)
+ return rc;
+ return TCG_TCG_COMMAND_ERROR;
+}
+
+
+static u32
+tpm_startup(void)
+{
+ u32 rc;
+ u32 returnCode;
+
+ if (!has_working_tpm())
+ return TCG_GENERAL_ERROR;
+
+ dprintf(DEBUG_tcg, "TCGBIOS: Starting with TPM_Startup(ST_CLEAR)\n");
+ rc = build_and_send_cmd(0, TPM_ORD_Startup,
+ Startup_ST_CLEAR, sizeof(Startup_ST_CLEAR),
+ NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
+
+ dprintf(DEBUG_tcg, "Return code from TPM_Startup = 0x%08x\n",
+ returnCode);
+
+ if (CONFIG_COREBOOT) {
+ /* with other firmware on the system the TPM may already have been
+ * initialized
+ */
+ if (returnCode == TPM_INVALID_POSTINIT)
+ returnCode = 0;
+ }
+
+ if (rc || returnCode)
+ goto err_exit;
+
+ rc = build_and_send_cmd(0, TPM_ORD_SelfTestFull, NULL, 0,
+ NULL, 0, &returnCode, TPM_DURATION_TYPE_LONG);
+
+ dprintf(DEBUG_tcg, "Return code from TPM_SelfTestFull = 0x%08x\n",
+ returnCode);
+
+ if (rc || returnCode)
+ goto err_exit;
+
+ rc = build_and_send_cmd(3, TSC_ORD_ResetEstablishmentBit, NULL, 0,
+ NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
+
+ dprintf(DEBUG_tcg, "Return code from TSC_ResetEstablishmentBit = 0x%08x\n",
+ returnCode);
+
+ if (rc || (returnCode != 0 && returnCode != TPM_BAD_LOCALITY))
+ goto err_exit;
+
+ rc = determine_timeouts();
+ if (rc)
+ goto err_exit;
+
+ rc = tpm_smbios_measure();
+ if (rc)
+ goto err_exit;
+
+ rc = tpm_start_option_rom_scan();
+ if (rc)
+ goto err_exit;
+
+ return 0;
+
+err_exit:
+ dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
+
+ tpm_state.tpm_working = 0;
+ if (rc)
+ return rc;
+ return TCG_TCG_COMMAND_ERROR;
+}
+
+
+void
+tpm_setup(void)
+{
+ if (!CONFIG_TCGBIOS)
+ return;
+
+ tpm_acpi_init();
+ if (runningOnXen())
+ return;
+
+ tpm_startup();
+}
+
+
+void
+tpm_prepboot(void)
+{
+ u32 rc;
+ u32 returnCode;
+
+ if (!CONFIG_TCGBIOS)
+ return;
+
+ if (!has_working_tpm())
+ return;
+
+ rc = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
+ PhysicalPresence_CMD_ENABLE,
+ sizeof(PhysicalPresence_CMD_ENABLE),
+ NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
+ if (rc || returnCode)
+ goto err_exit;
+
+ rc = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
+ PhysicalPresence_NOT_PRESENT_LOCK,
+ sizeof(PhysicalPresence_NOT_PRESENT_LOCK),
+ NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
+ if (rc || returnCode)
+ goto err_exit;
+
+ rc = tpm_calling_int19h();
+ if (rc)
+ goto err_exit;
+
+ rc = tpm_add_event_separators();
+ if (rc)
+ goto err_exit;
+
+ return;
+
+err_exit:
+ dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
+
+ tpm_state.tpm_working = 0;
+}
+
+static int
+is_valid_pcpes(struct pcpes *pcpes)
+{
+ return (pcpes->eventtype != 0);
+}
+
+
+static u8 *
+get_lasa_last_ptr(u16 *entry_count, u8 **log_area_start_address_next)
+{
+ struct pcpes *pcpes;
+ u32 log_area_minimum_length = 0;
+ u8 *log_area_start_address_base =
+ get_lasa_base_ptr(&log_area_minimum_length);
+ u8 *log_area_start_address_last = NULL;
+ u8 *end = log_area_start_address_base + log_area_minimum_length;
+ u32 size;
+
+ if (entry_count)
+ *entry_count = 0;
+
+ if (!log_area_start_address_base)
+ return NULL;
+
+ while (log_area_start_address_base < end) {
+ pcpes = (struct pcpes *)log_area_start_address_base;
+ if (!is_valid_pcpes(pcpes))
+ break;
+ if (entry_count)
+ (*entry_count)++;
+ size = pcpes->eventdatasize + offsetof(struct pcpes, event);
+ log_area_start_address_last = log_area_start_address_base;
+ log_area_start_address_base += size;
+ }
+
+ if (log_area_start_address_next)
+ *log_area_start_address_next = log_area_start_address_base;
+
+ return log_area_start_address_last;
+}
+
+
+static u32
+tpm_sha1_calc(const u8 *data, u32 length, u8 *hash)
+{
+ u32 rc;
+ u32 returnCode;
+ struct tpm_res_sha1start start;
+ struct tpm_res_sha1complete complete;
+ u32 blocks = length / 64;
+ u32 rest = length & 0x3f;
+ u32 numbytes, numbytes_no;
+ u32 offset = 0;
+
+ rc = build_and_send_cmd(0, TPM_ORD_SHA1Start,
+ NULL, 0,
+ (u8 *)&start, sizeof(start),
+ &returnCode, TPM_DURATION_TYPE_SHORT);
+
+ if (rc || returnCode)
+ goto err_exit;
+
+ while (blocks > 0) {
+
+ numbytes = be32_to_cpu(start.max_num_bytes);
+ if (numbytes > blocks * 64)
+ numbytes = blocks * 64;
+
+ numbytes_no = cpu_to_be32(numbytes);
+
+ rc = build_and_send_cmd_od(0, TPM_ORD_SHA1Update,
+ (u8 *)&numbytes_no, sizeof(numbytes_no),
+ NULL, 0, &returnCode,
+ &data[offset], numbytes,
+ TPM_DURATION_TYPE_SHORT);
+
+ if (rc || returnCode)
+ goto err_exit;
+
+ offset += numbytes;
+ blocks -= (numbytes / 64);
+ }
+
+ numbytes_no = cpu_to_be32(rest);
+
+ rc = build_and_send_cmd_od(0, TPM_ORD_SHA1Complete,
+ (u8 *)&numbytes_no, sizeof(numbytes_no),
+ (u8 *)&complete, sizeof(complete),
+ &returnCode,
+ &data[offset], rest, TPM_DURATION_TYPE_SHORT);
+
+ if (rc || returnCode)
+ goto err_exit;
+
+ memcpy(hash, complete.hash, sizeof(complete.hash));
+
+ return 0;
+
+err_exit:
+ dprintf(DEBUG_tcg, "TCGBIOS: TPM SHA1 malfunctioning.\n");
+
+ tpm_state.tpm_working = 0;
+ if (rc)
+ return rc;
+ return TCG_TCG_COMMAND_ERROR;
+}
+
+
+static u32
+sha1_calc(const u8 *data, u32 length, u8 *hash)
+{
+ if (length < tpm_drivers[tpm_state.tpm_driver_to_use].sha1threshold)
+ return tpm_sha1_calc(data, length, hash);
+
+ return sha1(data, length, hash);
+}
+
+
+/*
+ * Extend the ACPI log with the given entry by copying the
+ * entry data into the log.
+ * Input
+ * Pointer to the structure to be copied into the log
+ *
+ * Output:
+ * lower 16 bits of return code contain entry number
+ * if entry number is '0', then upper 16 bits contain error code.
+ */
+static u32
+tpm_extend_acpi_log(void *entry_ptr, u16 *entry_count)
+{
+ u32 log_area_minimum_length, size;
+ u8 *log_area_start_address_base =
+ get_lasa_base_ptr(&log_area_minimum_length);
+ u8 *log_area_start_address_next = NULL;
+ struct pcpes *pcpes = (struct pcpes *)entry_ptr;
+
+ get_lasa_last_ptr(entry_count, &log_area_start_address_next);
+
+ dprintf(DEBUG_tcg, "TCGBIOS: LASA_BASE = %p, LASA_NEXT = %p\n",
+ log_area_start_address_base, log_area_start_address_next);
+
+ if (log_area_start_address_next == NULL || log_area_minimum_length == 0)
+ return TCG_PC_LOGOVERFLOW;
+
+ size = pcpes->eventdatasize + offsetof(struct pcpes, event);
+
+ if ((log_area_start_address_next + size - log_area_start_address_base) >
+ log_area_minimum_length) {
+ dprintf(DEBUG_tcg, "TCGBIOS: LOG OVERFLOW: size = %d\n", size);
+ return TCG_PC_LOGOVERFLOW;
+ }
+
+ memcpy(log_area_start_address_next, entry_ptr, size);
+
+ (*entry_count)++;
+
+ return 0;
+}
+
+
+static u32
+is_preboot_if_shutdown(void)
+{
+ return tpm_state.if_shutdown;
+}
+
+
+static u32
+shutdown_preboot_interface(void)
+{
+ u32 rc = 0;
+
+ if (!is_preboot_if_shutdown()) {
+ tpm_state.if_shutdown = 1;
+ } else {
+ rc = TCG_INTERFACE_SHUTDOWN;
+ }
+
+ return rc;
+}
+
+
+static void
+tpm_shutdown(void)
+{
+ reset_acpi_log();
+ shutdown_preboot_interface();
+}
+
+
+static u32
+pass_through_to_tpm(struct pttti *pttti, struct pttto *pttto)
+{
+ u32 rc = 0;
+ u32 resbuflen = 0;
+ struct tpm_req_header *trh;
+ u8 locty = 0;
+ struct iovec iovec[2];
+ const u32 *tmp;
+
+ if (is_preboot_if_shutdown()) {
+ rc = TCG_INTERFACE_SHUTDOWN;
+ goto err_exit;
+ }
+
+ trh = (struct tpm_req_header *)pttti->tpmopin;
+
+ if (pttti->ipblength < sizeof(struct pttti) + TPM_REQ_HEADER_SIZE ||
+ pttti->opblength < sizeof(struct pttto) ||
+ be32_to_cpu(trh->totlen) + sizeof(struct pttti) > pttti->ipblength ) {
+ rc = TCG_INVALID_INPUT_PARA;
+ goto err_exit;
+ }
+
+ resbuflen = pttti->opblength - offsetof(struct pttto, tpmopout);
+
+ iovec[0].data = pttti->tpmopin;
+ tmp = (const u32 *)&((u8 *)iovec[0].data)[2];
+ iovec[0].length = cpu_to_be32(*tmp);
+
+ iovec[1].data = NULL;
+ iovec[1].length = 0;
+
+ rc = transmit(locty, iovec, pttto->tpmopout, &resbuflen,
+ TPM_DURATION_TYPE_LONG /* worst case */);
+ if (rc)
+ goto err_exit;
+
+ pttto->opblength = offsetof(struct pttto, tpmopout) + resbuflen;
+ pttto->reserved = 0;
+
+err_exit:
+ if (rc != 0) {
+ pttto->opblength = 4;
+ pttto->reserved = 0;
+ }
+
+ return rc;
+}
+
+
+static u32
+tpm_extend(u8 *hash, u32 pcrindex)
+{
+ u32 rc;
+ struct pttto_extend pttto;
+ struct pttti_extend pttti = {
+ .pttti = {
+ .ipblength = sizeof(struct pttti_extend),
+ .opblength = sizeof(struct pttto_extend),
+ },
+ .req = {
+ .tag = cpu_to_be16(0xc1),
+ .totlen = cpu_to_be32(sizeof(pttti.req)),
+ .ordinal = cpu_to_be32(TPM_ORD_Extend),
+ .pcrindex = cpu_to_be32(pcrindex),
+ },
+ };
+
+ memcpy(pttti.req.digest, hash, sizeof(pttti.req.digest));
+
+ rc = pass_through_to_tpm(&pttti.pttti, &pttto.pttto);
+
+ if (rc == 0) {
+ if (pttto.pttto.opblength < TPM_RSP_HEADER_SIZE ||
+ pttto.pttto.opblength !=
+ sizeof(struct pttto) + be32_to_cpu(pttto.rsp.totlen) ||
+ be16_to_cpu(pttto.rsp.tag) != 0xc4) {
+ rc = TCG_FATAL_COM_ERROR;
+ }
+ }
+
+ if (rc)
+ tpm_shutdown();
+
+ return rc;
+}
+
+
+static u32
+hash_all(const struct hai *hai, u8 *hash)
+{
+ if (is_preboot_if_shutdown() != 0)
+ return TCG_INTERFACE_SHUTDOWN;
+
+ if (hai->ipblength != sizeof(struct hai) ||
+ hai->hashdataptr == 0 ||
+ hai->hashdatalen == 0 ||
+ hai->algorithmid != TPM_ALG_SHA)
+ return TCG_INVALID_INPUT_PARA;
+
+ return sha1_calc((const u8 *)hai->hashdataptr, hai->hashdatalen, hash);
+}
+
+
+static u32
+hash_log_event(const struct hlei *hlei, struct hleo *hleo)
+{
+ u32 rc = 0;
+ u16 size;
+ struct pcpes *pcpes;
+ u16 entry_count;
+
+ if (is_preboot_if_shutdown() != 0) {
+ rc = TCG_INTERFACE_SHUTDOWN;
+ goto err_exit;
+ }
+
+ size = hlei->ipblength;
+ if (size != sizeof(*hlei)) {
+ rc = TCG_INVALID_INPUT_PARA;
+ goto err_exit;
+ }
+
+ pcpes = (struct pcpes *)hlei->logdataptr;
+
+ if (pcpes->pcrindex >= 24 ||
+ pcpes->pcrindex != hlei->pcrindex ||
+ pcpes->eventtype != hlei->logeventtype) {
+ rc = TCG_INVALID_INPUT_PARA;
+ goto err_exit;
+ }
+
+ if ((hlei->hashdataptr != 0) && (hlei->hashdatalen != 0)) {
+ rc = sha1_calc((const u8 *)hlei->hashdataptr,
+ hlei->hashdatalen, pcpes->digest);
+ if (rc)
+ return rc;
+ }
+
+ rc = tpm_extend_acpi_log((void *)hlei->logdataptr, &entry_count);
+ if (rc)
+ goto err_exit;
+
+ /* updating the log was fine */
+ hleo->opblength = sizeof(struct hleo);
+ hleo->reserved = 0;
+ hleo->eventnumber = entry_count;
+
+err_exit:
+ if (rc != 0) {
+ hleo->opblength = 2;
+ hleo->reserved = 0;
+ }
+
+ return rc;
+}
+
+
+static u32
+hash_log_extend_event(const struct hleei_short *hleei_s, struct hleeo *hleeo)
+{
+ u32 rc = 0;
+ struct hleo hleo;
+ struct hleei_long *hleei_l = (struct hleei_long *)hleei_s;
+ const void *logdataptr;
+ u32 logdatalen;
+ struct pcpes *pcpes;
+
+ /* short or long version? */
+ switch (hleei_s->ipblength) {
+ case sizeof(struct hleei_short):
+ /* short */
+ logdataptr = hleei_s->logdataptr;
+ logdatalen = hleei_s->logdatalen;
+ break;
+
+ case sizeof(struct hleei_long):
+ /* long */
+ logdataptr = hleei_l->logdataptr;
+ logdatalen = hleei_l->logdatalen;
+ break;
+
+ default:
+ /* bad input block */
+ rc = TCG_INVALID_INPUT_PARA;
+ goto err_exit;
+ }
+
+ pcpes = (struct pcpes *)logdataptr;
+
+ struct hlei hlei = {
+ .ipblength = sizeof(hlei),
+ .hashdataptr = hleei_s->hashdataptr,
+ .hashdatalen = hleei_s->hashdatalen,
+ .pcrindex = hleei_s->pcrindex,
+ .logeventtype= pcpes->eventtype,
+ .logdataptr = logdataptr,
+ .logdatalen = logdatalen,
+ };
+
+ rc = hash_log_event(&hlei, &hleo);
+ if (rc)
+ goto err_exit;
+
+ hleeo->opblength = sizeof(struct hleeo);
+ hleeo->reserved = 0;
+ hleeo->eventnumber = hleo.eventnumber;
+
+ rc = tpm_extend(pcpes->digest, hleei_s->pcrindex);
+
+err_exit:
+ if (rc != 0) {
+ hleeo->opblength = 4;
+ hleeo->reserved = 0;
+ }
+
+ return rc;
+
+}
+
+
+static u32
+tss(struct ti *ti, struct to *to)
+{
+ u32 rc = 0;
+
+ if (is_preboot_if_shutdown() == 0) {
+ rc = TCG_PC_UNSUPPORTED;
+ } else {
+ rc = TCG_INTERFACE_SHUTDOWN;
+ }
+
+ to->opblength = sizeof(struct to);
+ to->reserved = 0;
+
+ return rc;
+}
+
+
+static u32
+compact_hash_log_extend_event(u8 *buffer,
+ u32 info,
+ u32 length,
+ u32 pcrindex,
+ u32 *edx_ptr)
+{
+ u32 rc = 0;
+ struct hleeo hleeo;
+ struct pcpes pcpes = {
+ .pcrindex = pcrindex,
+ .eventtype = EV_COMPACT_HASH,
+ .eventdatasize = sizeof(info),
+ .event = info,
+ };
+ struct hleei_short hleei = {
+ .ipblength = sizeof(hleei),
+ .hashdataptr = buffer,
+ .hashdatalen = length,
+ .pcrindex = pcrindex,
+ .logdataptr = &pcpes,
+ .logdatalen = sizeof(pcpes),
+ };
+
+ rc = hash_log_extend_event(&hleei, &hleeo);
+ if (rc == 0)
+ *edx_ptr = hleeo.eventnumber;
+
+ return rc;
+}
+
+
+void VISIBLE32FLAT
+tpm_interrupt_handler32(struct bregs *regs)
+{
+ if (!CONFIG_TCGBIOS)
+ return;
+
+ set_cf(regs, 0);
+
+ if (!has_working_tpm()) {
+ regs->eax = TCG_GENERAL_ERROR;
+ return;
+ }
+
+ switch ((enum irq_ids)regs->al) {
+ case TCG_StatusCheck:
+ if (is_tpm_present() == 0) {
+ /* no TPM available */
+ regs->eax = TCG_PC_TPM_NOT_PRESENT;
+ } else {
+ regs->eax = 0;
+ regs->ebx = TCG_MAGIC;
+ regs->ch = TCG_VERSION_MAJOR;
+ regs->cl = TCG_VERSION_MINOR;
+ regs->edx = 0x0;
+ regs->esi = (u32)get_lasa_base_ptr(NULL);
+ regs->edi =
+ (u32)get_lasa_last_ptr(NULL, NULL);
+ }
+ break;
+
+ case TCG_HashLogExtendEvent:
+ regs->eax =
+ hash_log_extend_event(
+ (struct hleei_short *)input_buf32(regs),
+ (struct hleeo *)output_buf32(regs));
+ break;
+
+ case TCG_PassThroughToTPM:
+ regs->eax =
+ pass_through_to_tpm((struct pttti *)input_buf32(regs),
+ (struct pttto *)output_buf32(regs));
+ break;
+
+ case TCG_ShutdownPreBootInterface:
+ regs->eax = shutdown_preboot_interface();
+ break;
+
+ case TCG_HashLogEvent:
+ regs->eax = hash_log_event((struct hlei*)input_buf32(regs),
+ (struct hleo*)output_buf32(regs));
+ break;
+
+ case TCG_HashAll:
+ regs->eax =
+ hash_all((struct hai*)input_buf32(regs),
+ (u8 *)output_buf32(regs));
+ break;
+
+ case TCG_TSS:
+ regs->eax = tss((struct ti*)input_buf32(regs),
+ (struct to*)output_buf32(regs));
+ break;
+
+ case TCG_CompactHashLogExtendEvent:
+ regs->eax =
+ compact_hash_log_extend_event((u8 *)input_buf32(regs),
+ regs->esi,
+ regs->ecx,
+ regs->edx,
+ &regs->edx);
+ break;
+
+ default:
+ set_cf(regs, 1);
+ }
+
+ return;
+}
+
+/*
+ * Add a measurement to the log; the data at data_seg:data/length are
+ * appended to the TCG_PCClientPCREventStruct
+ *
+ * Input parameters:
+ * pcrIndex : which PCR to extend
+ * event_type : type of event; specs section on 'Event Types'
+ * info : pointer to info (e.g., string) to be added to log as-is
+ * info_length: length of the info
+ * data : pointer to the data (i.e., string) to be added to the log
+ * data_length: length of the data
+ */
+static u32
+tpm_add_measurement_to_log(u32 pcrIndex, u32 event_type,
+ const char *info, u32 info_length,
+ const u8 *data, u32 data_length)
+{
+ u32 rc = 0;
+ struct hleeo hleeo;
+ u8 _pcpes[offsetof(struct pcpes, event) + 400];
+ struct pcpes *pcpes = (struct pcpes *)_pcpes;
+
+ if (info_length < sizeof(_pcpes) - offsetof(struct pcpes, event)) {
+
+ pcpes->pcrindex = pcrIndex;
+ pcpes->eventtype = event_type;
+ memset(&pcpes->digest, 0x0, sizeof(pcpes->digest));
+ pcpes->eventdatasize = info_length;
+ memcpy(&pcpes->event, info, info_length);
+
+ struct hleei_short hleei = {
+ .ipblength = sizeof(hleei),
+ .hashdataptr = data,
+ .hashdatalen = data_length,
+ .pcrindex = pcrIndex,
+ .logdataptr = _pcpes,
+ .logdatalen = info_length + offsetof(struct pcpes, event),
+ };
+
+ rc = hash_log_extend_event(&hleei, &hleeo);
+ } else {
+ rc = TCG_GENERAL_ERROR;
+ }
+
+ return rc;
+}
+
+
+/*
+ * Add a measurement to the list of measurements
+ * pcrIndex : PCR to be extended
+ * event_type : type of event; specs section on 'Event Types'
+ * data : additional parameter; used as parameter for
+ * 'action index'
+ */
+static u32
+tpm_add_measurement(u32 pcrIndex,
+ u16 event_type,
+ const char *string)
+{
+ u32 rc;
+ u32 len;
+
+ switch (event_type) {
+ case EV_SEPARATOR:
+ len = sizeof(evt_separator);
+ rc = tpm_add_measurement_to_log(pcrIndex, event_type,
+ (char *)NULL, 0,
+ (u8 *)evt_separator, len);
+ break;
+
+ case EV_ACTION:
+ rc = tpm_add_measurement_to_log(pcrIndex, event_type,
+ string, strlen(string),
+ (u8 *)string, strlen(string));
+ break;
+
+ default:
+ rc = TCG_INVALID_INPUT_PARA;
+ }
+
+ return rc;
+}
+
+
+static u32
+tpm_calling_int19h(void)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ if (!has_working_tpm())
+ return TCG_GENERAL_ERROR;
+
+ return tpm_add_measurement(4, EV_ACTION,
+ "Calling INT 19h");
+}
+
+/*
+ * Add event separators for PCRs 0 to 7; specs on 'Measuring Boot Events'
+ */
+u32
+tpm_add_event_separators(void)
+{
+ u32 rc;
+ u32 pcrIndex = 0;
+
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ if (!has_working_tpm())
+ return TCG_GENERAL_ERROR;
+
+ while (pcrIndex <= 7) {
+ rc = tpm_add_measurement(pcrIndex, EV_SEPARATOR, NULL);
+ if (rc)
+ break;
+ pcrIndex ++;
+ }
+
+ return rc;
+}
+
+
+/*
+ * Add a measurement regarding the boot device (CDRom, Floppy, HDD) to
+ * the list of measurements.
+ */
+static u32
+tpm_add_bootdevice(u32 bootcd, u32 bootdrv)
+{
+ const char *string;
+
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ if (!has_working_tpm())
+ return TCG_GENERAL_ERROR;
+
+ switch (bootcd) {
+ case 0:
+ switch (bootdrv) {
+ case 0:
+ string = "Booting BCV device 00h (Floppy)";
+ break;
+
+ case 0x80:
+ string = "Booting BCV device 80h (HDD)";
+ break;
+
+ default:
+ string = "Booting unknown device";
+ break;
+ }
+
+ break;
+
+ default:
+ string = "Booting from CD ROM device";
+ }
+
+ return tpm_add_measurement_to_log(4, EV_ACTION,
+ string, strlen(string),
+ (u8 *)string, strlen(string));
+}
+
+
+/*
+ * Add measurement to the log about option rom scan
+ */
+u32
+tpm_start_option_rom_scan(void)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ if (!has_working_tpm())
+ return TCG_GENERAL_ERROR;
+
+ return tpm_add_measurement(2, EV_ACTION,
+ "Start Option ROM Scan");
+}
+
+
+/*
+ * Add measurement to the log about an option rom
+ */
+u32
+tpm_option_rom(const void *addr, u32 len)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ if (!has_working_tpm())
+ return TCG_GENERAL_ERROR;
+
+ u32 rc;
+ struct pcctes_romex pcctes = {
+ .eventid = 7,
+ .eventdatasize = sizeof(u16) + sizeof(u16) + SHA1_BUFSIZE,
+ };
+
+ rc = sha1((const u8 *)addr, len, pcctes.digest);
+ if (rc)
+ return rc;
+
+ return tpm_add_measurement_to_log(2,
+ EV_EVENT_TAG,
+ (const char *)&pcctes, sizeof(pcctes),
+ (u8 *)&pcctes, sizeof(pcctes));
+}
+
+
+u32
+tpm_smbios_measure(void)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ if (!has_working_tpm())
+ return TCG_GENERAL_ERROR;
+
+ u32 rc;
+ struct pcctes pcctes = {
+ .eventid = 1,
+ .eventdatasize = SHA1_BUFSIZE,
+ };
+ struct smbios_entry_point *sep = SMBiosAddr;
+
+ dprintf(DEBUG_tcg, "TCGBIOS: SMBIOS at %p\n", sep);
+
+ if (!sep)
+ return 0;
+
+ rc = sha1((const u8 *)sep->structure_table_address,
+ sep->structure_table_length, pcctes.digest);
+ if (rc)
+ return rc;
+
+ return tpm_add_measurement_to_log(1,
+ EV_EVENT_TAG,
+ (const char *)&pcctes, sizeof(pcctes),
+ (u8 *)&pcctes, sizeof(pcctes));
+}
+
+
+/*
+ * Add a measurement related to Initial Program Loader to the log.
+ * Creates two log entries.
+ *
+ * Input parameter:
+ * bootcd : 0: MBR of hdd, 1: boot image, 2: boot catalog of El Torito
+ * addr : address where the IP data are located
+ * length : IP data length in bytes
+ */
+static u32
+tpm_ipl(enum ipltype bootcd, const u8 *addr, u32 length)
+{
+ u32 rc;
+ const char *string;
+
+ switch (bootcd) {
+ case IPL_EL_TORITO_1:
+ /* specs: see section 'El Torito' */
+ string = "EL TORITO IPL";
+ rc = tpm_add_measurement_to_log(4, EV_IPL,
+ string, strlen(string),
+ addr, length);
+ break;
+
+ case IPL_EL_TORITO_2:
+ /* specs: see section 'El Torito' */
+ string = "BOOT CATALOG";
+ rc = tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
+ string, strlen(string),
+ addr, length);
+ break;
+
+ default:
+ /* specs: see section 'Hard Disk Device or Hard Disk-Like Devices' */
+ /* equivalent to: dd if=/dev/hda ibs=1 count=440 | sha1sum */
+ string = "MBR";
+ rc = tpm_add_measurement_to_log(4, EV_IPL,
+ string, strlen(string),
+ addr, 0x1b8);
+
+ if (rc)
+ break;
+
+ /* equivalent to: dd if=/dev/hda ibs=1 count=72 skip=440 | sha1sum */
+ string = "MBR PARTITION_TABLE";
+ rc = tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
+ string, strlen(string),
+ addr + 0x1b8, 0x48);
+ }
+
+ return rc;
+}
+
+u32
+tpm_add_bcv(u32 bootdrv, const u8 *addr, u32 length)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ if (!has_working_tpm())
+ return TCG_GENERAL_ERROR;
+
+ u32 rc = tpm_add_bootdevice(0, bootdrv);
+ if (rc)
+ return rc;
+
+ return tpm_ipl(IPL_BCV, addr, length);
+}
+
+u32
+tpm_add_cdrom(u32 bootdrv, const u8 *addr, u32 length)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ if (!has_working_tpm())
+ return TCG_GENERAL_ERROR;
+
+ u32 rc = tpm_add_bootdevice(1, bootdrv);
+ if (rc)
+ return rc;
+
+ return tpm_ipl(IPL_EL_TORITO_1, addr, length);
+}
+
+u32
+tpm_add_cdrom_catalog(const u8 *addr, u32 length)
+{
+ if (!CONFIG_TCGBIOS)
+ return 0;
+
+ if (!has_working_tpm())
+ return TCG_GENERAL_ERROR;
+
+ u32 rc = tpm_add_bootdevice(1, 0);
+ if (rc)
+ return rc;
+
+ return tpm_ipl(IPL_EL_TORITO_2, addr, length);
+}
+
+void
+tpm_s3_resume(void)
+{
+ u32 rc;
+ u32 returnCode;
+
+ if (!CONFIG_TCGBIOS)
+ return;
+
+ if (!has_working_tpm())
+ return;
+
+ dprintf(DEBUG_tcg, "TCGBIOS: Resuming with TPM_Startup(ST_STATE)\n");
+
+ rc = build_and_send_cmd(0, TPM_ORD_Startup,
+ Startup_ST_STATE, sizeof(Startup_ST_STATE),
+ NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
+
+ dprintf(DEBUG_tcg, "TCGBIOS: ReturnCode from TPM_Startup = 0x%08x\n",
+ returnCode);
+
+ if (rc || returnCode)
+ goto err_exit;
+
+ return;
+
+err_exit:
+ dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
+
+ tpm_state.tpm_working = 0;
+}
diff --git a/qemu/roms/seabios/src/tcgbios.h b/qemu/roms/seabios/src/tcgbios.h
new file mode 100644
index 000000000..4b7eaabef
--- /dev/null
+++ b/qemu/roms/seabios/src/tcgbios.h
@@ -0,0 +1,375 @@
+#ifndef TCGBIOS_H
+#define TCGBIOS_H
+
+#include "types.h"
+
+/* Define for section 12.3 */
+#define TCG_PC_OK 0x0
+#define TCG_PC_TPMERROR 0x1
+#define TCG_PC_LOGOVERFLOW 0x2
+#define TCG_PC_UNSUPPORTED 0x3
+
+#define TPM_ALG_SHA 0x4
+
+#define TCG_MAGIC 0x41504354L
+#define TCG_VERSION_MAJOR 1
+#define TCG_VERSION_MINOR 2
+
+#define TPM_OK 0x0
+#define TPM_RET_BASE 0x1
+#define TCG_GENERAL_ERROR (TPM_RET_BASE + 0x0)
+#define TCG_TPM_IS_LOCKED (TPM_RET_BASE + 0x1)
+#define TCG_NO_RESPONSE (TPM_RET_BASE + 0x2)
+#define TCG_INVALID_RESPONSE (TPM_RET_BASE + 0x3)
+#define TCG_INVALID_ACCESS_REQUEST (TPM_RET_BASE + 0x4)
+#define TCG_FIRMWARE_ERROR (TPM_RET_BASE + 0x5)
+#define TCG_INTEGRITY_CHECK_FAILED (TPM_RET_BASE + 0x6)
+#define TCG_INVALID_DEVICE_ID (TPM_RET_BASE + 0x7)
+#define TCG_INVALID_VENDOR_ID (TPM_RET_BASE + 0x8)
+#define TCG_UNABLE_TO_OPEN (TPM_RET_BASE + 0x9)
+#define TCG_UNABLE_TO_CLOSE (TPM_RET_BASE + 0xa)
+#define TCG_RESPONSE_TIMEOUT (TPM_RET_BASE + 0xb)
+#define TCG_INVALID_COM_REQUEST (TPM_RET_BASE + 0xc)
+#define TCG_INVALID_ADR_REQUEST (TPM_RET_BASE + 0xd)
+#define TCG_WRITE_BYTE_ERROR (TPM_RET_BASE + 0xe)
+#define TCG_READ_BYTE_ERROR (TPM_RET_BASE + 0xf)
+#define TCG_BLOCK_WRITE_TIMEOUT (TPM_RET_BASE + 0x10)
+#define TCG_CHAR_WRITE_TIMEOUT (TPM_RET_BASE + 0x11)
+#define TCG_CHAR_READ_TIMEOUT (TPM_RET_BASE + 0x12)
+#define TCG_BLOCK_READ_TIMEOUT (TPM_RET_BASE + 0x13)
+#define TCG_TRANSFER_ABORT (TPM_RET_BASE + 0x14)
+#define TCG_INVALID_DRV_FUNCTION (TPM_RET_BASE + 0x15)
+#define TCG_OUTPUT_BUFFER_TOO_SHORT (TPM_RET_BASE + 0x16)
+#define TCG_FATAL_COM_ERROR (TPM_RET_BASE + 0x17)
+#define TCG_INVALID_INPUT_PARA (TPM_RET_BASE + 0x18)
+#define TCG_TCG_COMMAND_ERROR (TPM_RET_BASE + 0x19)
+#define TCG_INTERFACE_SHUTDOWN (TPM_RET_BASE + 0x20)
+//define TCG_PC_UNSUPPORTED (TPM_RET_BASE + 0x21)
+#define TCG_PC_TPM_NOT_PRESENT (TPM_RET_BASE + 0x22)
+#define TCG_PC_TPM_DEACTIVATED (TPM_RET_BASE + 0x23)
+
+
+#define TPM_ORD_SelfTestFull 0x00000050
+#define TPM_ORD_ForceClear 0x0000005d
+#define TPM_ORD_GetCapability 0x00000065
+#define TPM_ORD_PhysicalEnable 0x0000006f
+#define TPM_ORD_PhysicalDisable 0x00000070
+#define TPM_ORD_SetOwnerInstall 0x00000071
+#define TPM_ORD_PhysicalSetDeactivated 0x00000072
+#define TPM_ORD_Startup 0x00000099
+#define TPM_ORD_PhysicalPresence 0x4000000a
+#define TPM_ORD_Extend 0x00000014
+#define TPM_ORD_SHA1Start 0x000000a0
+#define TPM_ORD_SHA1Update 0x000000a1
+#define TPM_ORD_SHA1Complete 0x000000a2
+#define TSC_ORD_ResetEstablishmentBit 0x4000000b
+
+
+#define TPM_ST_CLEAR 0x1
+#define TPM_ST_STATE 0x2
+#define TPM_ST_DEACTIVATED 0x3
+
+
+/* TPM command error codes */
+#define TPM_INVALID_POSTINIT 0x26
+#define TPM_BAD_LOCALITY 0x3d
+
+/* TPM command tags */
+#define TPM_TAG_RQU_CMD 0x00c1
+
+/* interrupt identifiers (al register) */
+enum irq_ids {
+ TCG_StatusCheck = 0,
+ TCG_HashLogExtendEvent = 1,
+ TCG_PassThroughToTPM = 2,
+ TCG_ShutdownPreBootInterface = 3,
+ TCG_HashLogEvent = 4,
+ TCG_HashAll = 5,
+ TCG_TSS = 6,
+ TCG_CompactHashLogExtendEvent = 7,
+};
+
+/* event types: 10.4.1 / table 11 */
+#define EV_POST_CODE 1
+#define EV_SEPARATOR 4
+#define EV_ACTION 5
+#define EV_EVENT_TAG 6
+#define EV_COMPACT_HASH 12
+#define EV_IPL 13
+#define EV_IPL_PARTITION_DATA 14
+
+
+#define STATUS_FLAG_SHUTDOWN (1 << 0)
+
+#define SHA1_BUFSIZE 20
+
+
+struct iovec
+{
+ size_t length;
+ void *data;
+};
+
+
+/* Input and Output blocks for the TCG BIOS commands */
+
+struct hleei_short
+{
+ u16 ipblength;
+ u16 reserved;
+ const void *hashdataptr;
+ u32 hashdatalen;
+ u32 pcrindex;
+ const void *logdataptr;
+ u32 logdatalen;
+} PACKED;
+
+
+struct hleei_long
+{
+ u16 ipblength;
+ u16 reserved;
+ void *hashdataptr;
+ u32 hashdatalen;
+ u32 pcrindex;
+ u32 reserved2;
+ void *logdataptr;
+ u32 logdatalen;
+} PACKED;
+
+
+struct hleeo
+{
+ u16 opblength;
+ u16 reserved;
+ u32 eventnumber;
+ u8 digest[SHA1_BUFSIZE];
+} PACKED;
+
+
+struct pttti
+{
+ u16 ipblength;
+ u16 reserved;
+ u16 opblength;
+ u16 reserved2;
+ u8 tpmopin[0];
+} PACKED;
+
+
+struct pttto
+{
+ u16 opblength;
+ u16 reserved;
+ u8 tpmopout[0];
+};
+
+
+struct hlei
+{
+ u16 ipblength;
+ u16 reserved;
+ const void *hashdataptr;
+ u32 hashdatalen;
+ u32 pcrindex;
+ u32 logeventtype;
+ const void *logdataptr;
+ u32 logdatalen;
+} PACKED;
+
+
+struct hleo
+{
+ u16 opblength;
+ u16 reserved;
+ u32 eventnumber;
+} PACKED;
+
+
+struct hai
+{
+ u16 ipblength;
+ u16 reserved;
+ const void *hashdataptr;
+ u32 hashdatalen;
+ u32 algorithmid;
+} PACKED;
+
+
+struct ti
+{
+ u16 ipblength;
+ u16 reserved;
+ u16 opblength;
+ u16 reserved2;
+ u8 tssoperandin[0];
+} PACKED;
+
+
+struct to
+{
+ u16 opblength;
+ u16 reserved;
+ u8 tssoperandout[0];
+} PACKED;
+
+
+struct pcpes
+{
+ u32 pcrindex;
+ u32 eventtype;
+ u8 digest[SHA1_BUFSIZE];
+ u32 eventdatasize;
+ u32 event;
+} PACKED;
+
+struct pcctes
+{
+ u32 eventid;
+ u32 eventdatasize;
+ u8 digest[SHA1_BUFSIZE];
+} PACKED;
+
+struct pcctes_romex
+{
+ u32 eventid;
+ u32 eventdatasize;
+ u16 reserved;
+ u16 pfa;
+ u8 digest[SHA1_BUFSIZE];
+} PACKED;
+
+
+#define TPM_REQ_HEADER \
+ u16 tag; \
+ u32 totlen; \
+ u32 ordinal;
+
+#define TPM_REQ_HEADER_SIZE (sizeof(u16) + sizeof(u32) + sizeof(u32))
+
+#define TPM_RSP_HEADER \
+ u16 tag; \
+ u32 totlen; \
+ u32 errcode;
+
+#define TPM_RSP_HEADER_SIZE (sizeof(u16) + sizeof(u32) + sizeof(u32))
+
+struct tpm_req_header {
+ TPM_REQ_HEADER;
+} PACKED;
+
+
+struct tpm_rsp_header {
+ TPM_RSP_HEADER;
+} PACKED;
+
+
+struct tpm_req_extend {
+ TPM_REQ_HEADER
+ u32 pcrindex;
+ u8 digest[SHA1_BUFSIZE];
+} PACKED;
+
+
+struct tpm_rsp_extend {
+ TPM_RSP_HEADER
+ u8 digest[SHA1_BUFSIZE];
+} PACKED;
+
+
+struct tpm_req_getcap_perm_flags {
+ TPM_REQ_HEADER
+ u32 capArea;
+ u32 subCapSize;
+ u32 subCap;
+} PACKED;
+
+
+struct tpm_permanent_flags {
+ u16 tag;
+ u8 flags[20];
+} PACKED;
+
+
+enum permFlagsIndex {
+ PERM_FLAG_IDX_DISABLE = 0,
+ PERM_FLAG_IDX_OWNERSHIP,
+ PERM_FLAG_IDX_DEACTIVATED,
+ PERM_FLAG_IDX_READPUBEK,
+ PERM_FLAG_IDX_DISABLEOWNERCLEAR,
+ PERM_FLAG_IDX_ALLOW_MAINTENANCE,
+ PERM_FLAG_IDX_PHYSICAL_PRESENCE_LIFETIME_LOCK,
+ PERM_FLAG_IDX_PHYSICAL_PRESENCE_HW_ENABLE,
+};
+
+
+struct tpm_res_getcap_perm_flags {
+ TPM_RSP_HEADER
+ u32 size;
+ struct tpm_permanent_flags perm_flags;
+} PACKED;
+
+
+struct tpm_res_getcap_ownerauth {
+ TPM_RSP_HEADER
+ u32 size;
+ u8 flag;
+} PACKED;
+
+
+struct tpm_res_getcap_timeouts {
+ TPM_RSP_HEADER
+ u32 size;
+ u32 timeouts[4];
+} PACKED;
+
+
+struct tpm_res_getcap_durations {
+ TPM_RSP_HEADER
+ u32 size;
+ u32 durations[3];
+} PACKED;
+
+
+struct tpm_res_sha1start {
+ TPM_RSP_HEADER
+ u32 max_num_bytes;
+} PACKED;
+
+
+struct tpm_res_sha1complete {
+ TPM_RSP_HEADER
+ u8 hash[20];
+} PACKED;
+
+struct pttti_extend {
+ struct pttti pttti;
+ struct tpm_req_extend req;
+} PACKED;
+
+
+struct pttto_extend {
+ struct pttto pttto;
+ struct tpm_rsp_extend rsp;
+} PACKED;
+
+
+enum ipltype {
+ IPL_BCV = 0,
+ IPL_EL_TORITO_1,
+ IPL_EL_TORITO_2
+};
+
+
+struct bregs;
+void tpm_interrupt_handler32(struct bregs *regs);
+
+void tpm_setup(void);
+void tpm_prepboot(void);
+void tpm_s3_resume(void);
+u32 tpm_add_bcv(u32 bootdrv, const u8 *addr, u32 length);
+u32 tpm_add_cdrom(u32 bootdrv, const u8 *addr, u32 length);
+u32 tpm_add_cdrom_catalog(const u8 *addr, u32 length);
+u32 tpm_option_rom(const void *addr, u32 len);
+
+#endif /* TCGBIOS_H */
diff --git a/qemu/roms/seabios/src/types.h b/qemu/roms/seabios/src/types.h
index 097372cdb..19d9f6c14 100644
--- a/qemu/roms/seabios/src/types.h
+++ b/qemu/roms/seabios/src/types.h
@@ -70,7 +70,7 @@ extern void __force_link_error__only_in_16bit(void) __noreturn;
# define VARFSEG __section(".discard.varfseg." UNIQSEC) __VISIBLE __weak
// Designate a variable at a specific address in the f-segment.
# define VARFSEGFIXED(addr) __section(".discard.varfixed." UNIQSEC) __VISIBLE __weak
-// Verify a variable is only accessable via 32bit "init" functions
+// Verify a variable is only accessible via 32bit "init" functions
# define VARVERIFY32INIT __section(".discard.varinit." UNIQSEC)
// Designate top-level assembler as 16bit only.
# define ASM16(code) __ASM(code)
diff --git a/qemu/roms/seabios/src/util.h b/qemu/roms/seabios/src/util.h
index 09bb8a9f3..cba3359d5 100644
--- a/qemu/roms/seabios/src/util.h
+++ b/qemu/roms/seabios/src/util.h
@@ -43,17 +43,17 @@ void enable_bootsplash(void);
void disable_bootsplash(void);
// cdrom.c
-extern u8 CDRom_locks[];
extern struct eltorito_s CDEmu;
extern struct drive_s *cdemu_drive_gf;
struct disk_op_s;
-int process_cdemu_op(struct disk_op_s *op);
+int cdemu_process_op(struct disk_op_s *op);
void cdrom_prepboot(void);
int cdrom_boot(struct drive_s *drive_g);
// clock.c
void clock_setup(void);
void handle_1583(struct bregs *regs);
+void clock_poll_irq(void);
u32 irqtimer_calc_ticks(u32 count);
u32 irqtimer_calc(u32 msecs);
int irqtimer_check(u32 end);
@@ -75,6 +75,7 @@ u32 find_resume_vector(void);
void acpi_reboot(void);
void find_acpi_features(void);
extern struct smbios_entry_point *SMBiosAddr;
+struct smbios_entry_point *get_smbios_entry_point();
void copy_smbios(void *pos);
void display_uuid(void);
void copy_table(void *pos);
@@ -104,6 +105,9 @@ void mptable_setup(void);
// fw/mtrr.c
void mtrr_setup(void);
+// fw/multiboot.c
+void multiboot_init(void);
+
// fw/pciinit.c
extern const u8 pci_irqs[4];
void pci_setup(void);
@@ -139,15 +143,15 @@ extern struct floppy_ext_dbt_s diskette_param_table2;
void floppy_setup(void);
struct drive_s *init_floppy(int floppyid, int ftype);
int find_floppy_type(u32 size);
-int process_floppy_op(struct disk_op_s *op);
+int floppy_process_op(struct disk_op_s *op);
void floppy_tick(void);
// hw/ramdisk.c
void ramdisk_setup(void);
-int process_ramdisk_op(struct disk_op_s *op);
+int ramdisk_process_op(struct disk_op_s *op);
// hw/sdcard.c
-int process_sdcard_op(struct disk_op_s *op);
+int sdcard_process_op(struct disk_op_s *op);
void sdcard_setup(void);
// hw/timer.c
@@ -232,6 +236,6 @@ void vgahook_setup(struct pci_device *pci);
// version (auto generated file out/version.c)
-extern const char VERSION[];
+extern const char VERSION[], BUILDINFO[];
#endif // util.h
diff --git a/qemu/roms/seabios/src/version.c b/qemu/roms/seabios/src/version.c
new file mode 100644
index 000000000..a8a58cf09
--- /dev/null
+++ b/qemu/roms/seabios/src/version.c
@@ -0,0 +1,5 @@
+// Place build generated version into a C variable
+#include "autoversion.h"
+
+char VERSION[] = BUILD_VERSION;
+char BUILDINFO[] = BUILD_TOOLS;
diff --git a/qemu/roms/seabios/src/vgahooks.c b/qemu/roms/seabios/src/vgahooks.c
index 6a4acfeaf..48efb086c 100644
--- a/qemu/roms/seabios/src/vgahooks.c
+++ b/qemu/roms/seabios/src/vgahooks.c
@@ -124,7 +124,7 @@ getAMDRamSpeed(void)
/* int 0x15 - 5f18
- ECX = unknown/dont care
+ ECX = unknown/don't care
EBX[3..0] Frame Buffer Size 2^N MiB
EBX[7..4] Memory speed:
0: SDR 66Mhz
diff --git a/qemu/roms/seabios/src/x86.h b/qemu/roms/seabios/src/x86.h
index 7798b1c17..53378e9ed 100644
--- a/qemu/roms/seabios/src/x86.h
+++ b/qemu/roms/seabios/src/x86.h
@@ -75,14 +75,22 @@ static inline void __cpuid(u32 index, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx)
: "0" (index));
}
-static inline u32 getcr0(void) {
+static inline u32 cr0_read(void) {
u32 cr0;
asm("movl %%cr0, %0" : "=r"(cr0));
return cr0;
}
-static inline void setcr0(u32 cr0) {
+static inline void cr0_write(u32 cr0) {
asm("movl %0, %%cr0" : : "r"(cr0));
}
+static inline void cr0_mask(u32 off, u32 on) {
+ cr0_write((cr0_read() & ~off) | on);
+}
+static inline u16 cr0_vm86_read(void) {
+ u16 cr0;
+ asm("smsww %0" : "=r"(cr0));
+ return cr0;
+}
static inline u64 rdmsr(u32 index)
{
@@ -124,6 +132,13 @@ static inline u32 getesp(void) {
return esp;
}
+static inline u32 rol(u32 val, u16 rol) {
+ u32 res;
+ asm volatile("roll %%cl, %%eax"
+ : "=a" (res) : "a" (val), "c" (rol));
+ return res;
+}
+
static inline void outb(u8 value, u16 port) {
__asm__ __volatile__("outb %b0, %w1" : : "a"(value), "Nd"(port));
}
@@ -175,6 +190,14 @@ static inline void outsl(u16 port, u32 *data, u32 count) {
: "+c"(count), "+S"(data) : "d"(port) : "memory");
}
+/* Compiler barrier is enough as an x86 CPU does not reorder reads or writes */
+static inline void smp_rmb(void) {
+ barrier();
+}
+static inline void smp_wmb(void) {
+ barrier();
+}
+
static inline void writel(void *addr, u32 val) {
barrier();
*(volatile u32 *)addr = val;
diff --git a/qemu/roms/seabios/vgasrc/Kconfig b/qemu/roms/seabios/vgasrc/Kconfig
index 91d590ae2..f5098a4bd 100644
--- a/qemu/roms/seabios/vgasrc/Kconfig
+++ b/qemu/roms/seabios/vgasrc/Kconfig
@@ -58,6 +58,25 @@ menu "VGA ROM"
endchoice
choice
+ depends on VGA_BOCHS
+ prompt "bochs vga variant"
+ default VGA_BOCHS_STDVGA
+
+ config VGA_BOCHS_STDVGA
+ bool "qemu stdvga / bochs svga"
+
+ config VGA_BOCHS_VMWARE
+ bool "qemu vmware svga"
+
+ config VGA_BOCHS_QXL
+ bool "qemu qxl vga"
+
+ config VGA_BOCHS_VIRTIO
+ bool "qemu virtio vga"
+
+ endchoice
+
+ choice
depends on VGA_GEODEGX2 || VGA_GEODELX
prompt "Output Mode"
default VGA_OUTPUT_CRT
@@ -141,7 +160,10 @@ menu "VGA ROM"
hex
prompt "PCI Vendor ID" if OVERRIDE_PCI_ID
default 0x1013 if VGA_CIRRUS
- default 0x1234 if VGA_BOCHS
+ default 0x1234 if VGA_BOCHS_STDVGA
+ default 0x15ad if VGA_BOCHS_VMWARE
+ default 0x1b36 if VGA_BOCHS_QXL
+ default 0x1af4 if VGA_BOCHS_VIRTIO
default 0x100b if VGA_GEODEGX2
default 0x1022 if VGA_GEODELX
default 0x0000
@@ -153,7 +175,10 @@ menu "VGA ROM"
hex
prompt "PCI Vendor ID" if OVERRIDE_PCI_ID
default 0x00b8 if VGA_CIRRUS
- default 0x1111 if VGA_BOCHS
+ default 0x1111 if VGA_BOCHS_STDVGA
+ default 0x0405 if VGA_BOCHS_VMWARE
+ default 0x0100 if VGA_BOCHS_QXL
+ default 0x1050 if VGA_BOCHS_VIRTIO
default 0x0030 if VGA_GEODEGX2
default 0x2081 if VGA_GEODELX
default 0x0000
diff --git a/qemu/roms/seabios/vgasrc/geodevga.h b/qemu/roms/seabios/vgasrc/geodevga.h
index 61d78084d..c99f54bb1 100644
--- a/qemu/roms/seabios/vgasrc/geodevga.h
+++ b/qemu/roms/seabios/vgasrc/geodevga.h
@@ -2,7 +2,7 @@
//
// Copyright (C) 2009 Chris Kindt
//
-// Writen for Google Summer of Code 2009 for the coreboot project
+// Written for Google Summer of Code 2009 for the coreboot project
//
// This file may be distributed under the terms of the GNU LGPLv3 license.
diff --git a/qemu/roms/seabios/vgasrc/vgabios.c b/qemu/roms/seabios/vgasrc/vgabios.c
index 4aa50e1c1..f07e85bd3 100644
--- a/qemu/roms/seabios/vgasrc/vgabios.c
+++ b/qemu/roms/seabios/vgasrc/vgabios.c
@@ -304,6 +304,12 @@ vga_set_mode(int mode, int flags)
SET_BDA(video_mode, 0xff);
SET_BDA_EXT(vbe_mode, mode | (flags & MF_VBEFLAGS));
SET_BDA_EXT(vgamode_offset, (u32)vmode_g);
+ if (CONFIG_VGA_ALLOCATE_EXTRA_STACK)
+ // Disable extra stack if it appears a modern OS is in use.
+ // This works around bugs in some versions of Windows (Vista
+ // and possibly later) when the stack is in the e-segment.
+ MASK_BDA_EXT(flags, BF_EXTRA_STACK
+ , (flags & MF_LEGACY) ? BF_EXTRA_STACK : 0);
if (memmodel == MM_TEXT) {
SET_BDA(video_cols, width);
SET_BDA(video_rows, height-1);
diff --git a/qemu/roms/seabios/vgasrc/vgabios.h b/qemu/roms/seabios/vgasrc/vgabios.h
index fd796f2e6..831f69407 100644
--- a/qemu/roms/seabios/vgasrc/vgabios.h
+++ b/qemu/roms/seabios/vgasrc/vgabios.h
@@ -62,7 +62,8 @@ struct gfx_op {
#define GO_MEMSET 3
#define GO_MEMMOVE 4
-// Custom internal storage in BDA
+// Custom internal storage in BDA (don't change here without also
+// updating vgaentry.S)
#define VGA_CUSTOM_BDA 0xb9
struct vga_bda_s {
@@ -74,6 +75,7 @@ struct vga_bda_s {
#define BF_PM_MASK 0x0f
#define BF_EMULATE_TEXT 0x10
#define BF_SWCURSOR 0x20
+#define BF_EXTRA_STACK 0x40
#define GET_BDA_EXT(var) \
GET_FARVAR(SEG_BDA, ((struct vga_bda_s *)VGA_CUSTOM_BDA)->var)
diff --git a/qemu/roms/seabios/vgasrc/vgaentry.S b/qemu/roms/seabios/vgasrc/vgaentry.S
index d9ebdb93c..53be2b38c 100644
--- a/qemu/roms/seabios/vgasrc/vgaentry.S
+++ b/qemu/roms/seabios/vgasrc/vgaentry.S
@@ -86,14 +86,23 @@ entry_10:
ENTRY_ARG_VGA handle_10
iretw
+#define VGA_CUSTOM_BDA_FLAGS 0xb9
+#define BF_EXTRA_STACK 0x40
+
// Entry point using extra stack
DECLFUNC entry_10_extrastack
entry_10_extrastack:
cli
cld
- pushw %ds // Set %ds:%eax to space on ExtraStack
+ pushw %ds
pushl %eax
- movw %cs:ExtraStackSeg, %ds
+
+ movw $SEG_BDA, %ax // Check if extra stack is enabled
+ movw %ax, %ds
+ testb $BF_EXTRA_STACK, VGA_CUSTOM_BDA_FLAGS
+ jz 1f
+
+ movw %cs:ExtraStackSeg, %ds // Set %ds:%eax to space on ExtraStack
movl $(CONFIG_VGA_EXTRA_STACK_SIZE-PUSHBREGS_size-16), %eax
SAVEBREGS_POP_DSEAX // Save registers on extra stack
movl %esp, PUSHBREGS_size+8(%eax)
@@ -116,6 +125,11 @@ entry_10_extrastack:
RESTOREBREGS_DSEAX
iretw
+1: // Use regular entry point if the extra stack is disabled
+ popl %eax
+ popw %ds
+ jmp entry_10
+
// Timer irq handling
DECLFUNC entry_timer_hook
entry_timer_hook:
diff --git a/qemu/roms/seabios/vgasrc/vgafb.c b/qemu/roms/seabios/vgasrc/vgafb.c
index 1a94fcf70..5d1ecc936 100644
--- a/qemu/roms/seabios/vgasrc/vgafb.c
+++ b/qemu/roms/seabios/vgasrc/vgafb.c
@@ -273,28 +273,22 @@ gfx_direct(struct gfx_op *op)
int bypp = DIV_ROUND_UP(depth, 8);
void *dest_far = (fb + op->displaystart + op->y * op->linelength
+ op->x * bypp);
+ u8 data[64];
+ int i;
switch (op->op) {
default:
- case GO_READ8: {
- u8 data[64];
+ case GO_READ8:
memcpy_high(MAKE_FLATPTR(GET_SEG(SS), data), dest_far, bypp * 8);
- int i;
for (i=0; i<8; i++)
op->pixels[i] = reverse_color(depth, *(u32*)&data[i*bypp]);
break;
- }
- case GO_WRITE8: {
- u8 data[64];
- int i;
+ case GO_WRITE8:
for (i=0; i<8; i++)
*(u32*)&data[i*bypp] = get_color(depth, op->pixels[i]);
memcpy_high(dest_far, MAKE_FLATPTR(GET_SEG(SS), data), bypp * 8);
break;
- }
- case GO_MEMSET: {
+ case GO_MEMSET: ;
u32 color = get_color(depth, op->pixels[0]);
- u8 data[64];
- int i;
for (i=0; i<8; i++)
*(u32*)&data[i*bypp] = color;
memcpy_high(dest_far, MAKE_FLATPTR(GET_SEG(SS), data), bypp * 8);
@@ -303,7 +297,6 @@ gfx_direct(struct gfx_op *op)
memcpy_high(dest_far + op->linelength * i
, dest_far, op->xlen * bypp);
break;
- }
case GO_MEMMOVE: ;
void *src_far = (fb + op->displaystart + op->srcy * op->linelength
+ op->x * bypp);
diff --git a/qemu/roms/seabios/vgasrc/vgainit.c b/qemu/roms/seabios/vgasrc/vgainit.c
index 8d1226182..40997dbbd 100644
--- a/qemu/roms/seabios/vgasrc/vgainit.c
+++ b/qemu/roms/seabios/vgasrc/vgainit.c
@@ -150,6 +150,7 @@ vga_post(struct bregs *regs)
{
serial_debug_preinit();
dprintf(1, "Start SeaVGABIOS (version %s)\n", VERSION);
+ dprintf(1, "VGABUILD: %s\n", BUILDINFO);
debug_enter(regs, DEBUG_VGA_POST);
if (CONFIG_VGA_PCI && !GET_GLOBAL(HaveRunInit)) {
diff --git a/qemu/roms/seabios/vgasrc/vgaversion.c b/qemu/roms/seabios/vgasrc/vgaversion.c
new file mode 100644
index 000000000..1ef5ddb79
--- /dev/null
+++ b/qemu/roms/seabios/vgasrc/vgaversion.c
@@ -0,0 +1,6 @@
+// Place build generated version into a C variable
+#include "autovgaversion.h"
+#include "types.h"
+
+char VERSION[] VAR16 = BUILD_VERSION;
+char BUILDINFO[] VAR16 = BUILD_TOOLS;